blob: 6ecf36d4708c0a8cc2623f3c6bc37b23cd535830 [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
Joe Eykholt9e9d0452009-08-25 14:01:18 -070089/**
90 * fc_rport_create() - create remote port in INIT state.
91 * @lport: local port.
92 * @ids: remote port identifiers.
93 *
94 * Locking note: this may be called without locks held, but
95 * is usually called from discovery with the disc_mutex held.
96 */
97static struct fc_rport_priv *fc_rport_create(struct fc_lport *lport,
98 struct fc_rport_identifiers *ids)
Robert Love42e9a922008-12-09 15:10:17 -080099{
Joe Eykholtab28f1f2009-08-25 14:00:34 -0700100 struct fc_rport_priv *rdata;
Robert Love42e9a922008-12-09 15:10:17 -0800101
Joe Eykholt9e9d0452009-08-25 14:01:18 -0700102 rdata = kzalloc(sizeof(*rdata), GFP_KERNEL);
103 if (!rdata)
Robert Love42e9a922008-12-09 15:10:17 -0800104 return NULL;
105
Joe Eykholtf211fa52009-08-25 14:01:01 -0700106 rdata->ids = *ids;
107 kref_init(&rdata->kref);
Robert Love42e9a922008-12-09 15:10:17 -0800108 mutex_init(&rdata->rp_mutex);
Joe Eykholt795d86f2009-08-25 14:00:39 -0700109 rdata->local_port = lport;
Robert Love42e9a922008-12-09 15:10:17 -0800110 rdata->rp_state = RPORT_ST_INIT;
111 rdata->event = RPORT_EV_NONE;
112 rdata->flags = FC_RP_FLAGS_REC_SUPPORTED;
Joe Eykholt795d86f2009-08-25 14:00:39 -0700113 rdata->e_d_tov = lport->e_d_tov;
114 rdata->r_a_tov = lport->r_a_tov;
Joe Eykholtf211fa52009-08-25 14:01:01 -0700115 rdata->maxframe_size = FC_MIN_MAX_PAYLOAD;
Robert Love42e9a922008-12-09 15:10:17 -0800116 INIT_DELAYED_WORK(&rdata->retry_work, fc_rport_timeout);
117 INIT_WORK(&rdata->event_work, fc_rport_work);
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700118 return rdata;
Robert Love42e9a922008-12-09 15:10:17 -0800119}
120
121/**
Joe Eykholtf211fa52009-08-25 14:01:01 -0700122 * fc_rport_destroy() - free a remote port after last reference is released.
123 * @kref: pointer to kref inside struct fc_rport_priv
124 */
125static void fc_rport_destroy(struct kref *kref)
126{
127 struct fc_rport_priv *rdata;
Joe Eykholtf211fa52009-08-25 14:01:01 -0700128
129 rdata = container_of(kref, struct fc_rport_priv, kref);
Joe Eykholt9e9d0452009-08-25 14:01:18 -0700130 kfree(rdata);
Joe Eykholtf211fa52009-08-25 14:01:01 -0700131}
132
133/**
Robert Love34f42a02009-02-27 10:55:45 -0800134 * fc_rport_state() - return a string for the state the rport is in
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700135 * @rdata: remote port private data
Robert Love42e9a922008-12-09 15:10:17 -0800136 */
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700137static const char *fc_rport_state(struct fc_rport_priv *rdata)
Robert Love42e9a922008-12-09 15:10:17 -0800138{
139 const char *cp;
Robert Love42e9a922008-12-09 15:10:17 -0800140
141 cp = fc_rport_state_names[rdata->rp_state];
142 if (!cp)
143 cp = "Unknown";
144 return cp;
145}
146
147/**
Robert Love34f42a02009-02-27 10:55:45 -0800148 * fc_set_rport_loss_tmo() - Set the remote port loss timeout in seconds.
Robert Love42e9a922008-12-09 15:10:17 -0800149 * @rport: Pointer to Fibre Channel remote port structure
150 * @timeout: timeout in seconds
151 */
152void fc_set_rport_loss_tmo(struct fc_rport *rport, u32 timeout)
153{
154 if (timeout)
155 rport->dev_loss_tmo = timeout + 5;
156 else
157 rport->dev_loss_tmo = 30;
158}
159EXPORT_SYMBOL(fc_set_rport_loss_tmo);
160
161/**
Robert Love34f42a02009-02-27 10:55:45 -0800162 * fc_plogi_get_maxframe() - Get max payload from the common service parameters
Robert Love42e9a922008-12-09 15:10:17 -0800163 * @flp: FLOGI payload structure
164 * @maxval: upper limit, may be less than what is in the service parameters
165 */
Robert Loveb2ab99c2009-02-27 10:55:50 -0800166static unsigned int fc_plogi_get_maxframe(struct fc_els_flogi *flp,
167 unsigned int maxval)
Robert Love42e9a922008-12-09 15:10:17 -0800168{
169 unsigned int mfs;
170
171 /*
172 * Get max payload from the common service parameters and the
173 * class 3 receive data field size.
174 */
175 mfs = ntohs(flp->fl_csp.sp_bb_data) & FC_SP_BB_DATA_MASK;
176 if (mfs >= FC_SP_MIN_MAX_PAYLOAD && mfs < maxval)
177 maxval = mfs;
178 mfs = ntohs(flp->fl_cssp[3 - 1].cp_rdfs);
179 if (mfs >= FC_SP_MIN_MAX_PAYLOAD && mfs < maxval)
180 maxval = mfs;
181 return maxval;
182}
183
184/**
Robert Love34f42a02009-02-27 10:55:45 -0800185 * fc_rport_state_enter() - Change the rport's state
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700186 * @rdata: The rport whose state should change
Robert Love42e9a922008-12-09 15:10:17 -0800187 * @new: The new state of the rport
188 *
189 * Locking Note: Called with the rport lock held
190 */
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700191static void fc_rport_state_enter(struct fc_rport_priv *rdata,
Robert Love42e9a922008-12-09 15:10:17 -0800192 enum fc_rport_state new)
193{
Robert Love42e9a922008-12-09 15:10:17 -0800194 if (rdata->rp_state != new)
195 rdata->retries = 0;
196 rdata->rp_state = new;
197}
198
199static void fc_rport_work(struct work_struct *work)
200{
Abhijeet Joglekar571f8242009-02-27 10:54:41 -0800201 u32 port_id;
Joe Eykholtab28f1f2009-08-25 14:00:34 -0700202 struct fc_rport_priv *rdata =
203 container_of(work, struct fc_rport_priv, event_work);
Joe Eykholt9e9d0452009-08-25 14:01:18 -0700204 struct fc_rport_libfc_priv *rp;
Robert Love42e9a922008-12-09 15:10:17 -0800205 enum fc_rport_event event;
Robert Love42e9a922008-12-09 15:10:17 -0800206 struct fc_lport *lport = rdata->local_port;
207 struct fc_rport_operations *rport_ops;
Joe Eykholt629f4422009-08-25 14:01:06 -0700208 struct fc_rport_identifiers ids;
Joe Eykholtf211fa52009-08-25 14:01:01 -0700209 struct fc_rport *rport;
Robert Love42e9a922008-12-09 15:10:17 -0800210
211 mutex_lock(&rdata->rp_mutex);
212 event = rdata->event;
213 rport_ops = rdata->ops;
Joe Eykholtf211fa52009-08-25 14:01:01 -0700214 rport = rdata->rport;
Robert Love42e9a922008-12-09 15:10:17 -0800215
Joe Eykholt9e9d0452009-08-25 14:01:18 -0700216 FC_RPORT_DBG(rdata, "work event %u\n", event);
217
Joe Eykholt629f4422009-08-25 14:01:06 -0700218 switch (event) {
Joe Eykholt4c0f62b2009-08-25 14:01:12 -0700219 case RPORT_EV_READY:
Joe Eykholtf211fa52009-08-25 14:01:01 -0700220 ids = rdata->ids;
Joe Eykholt5f7ea3b2009-07-29 17:04:49 -0700221 rdata->event = RPORT_EV_NONE;
Joe Eykholt9e9d0452009-08-25 14:01:18 -0700222 kref_get(&rdata->kref);
Robert Love42e9a922008-12-09 15:10:17 -0800223 mutex_unlock(&rdata->rp_mutex);
224
Joe Eykholt9e9d0452009-08-25 14:01:18 -0700225 if (!rport)
226 rport = fc_remote_port_add(lport->host, 0, &ids);
227 if (!rport) {
228 FC_RPORT_DBG(rdata, "Failed to add the rport\n");
229 lport->tt.rport_logoff(rdata);
230 kref_put(&rdata->kref, lport->tt.rport_destroy);
231 return;
Robert Love42e9a922008-12-09 15:10:17 -0800232 }
Joe Eykholt9e9d0452009-08-25 14:01:18 -0700233 mutex_lock(&rdata->rp_mutex);
234 if (rdata->rport)
235 FC_RPORT_DBG(rdata, "rport already allocated\n");
236 rdata->rport = rport;
237 rport->maxframe_size = rdata->maxframe_size;
238 rport->supported_classes = rdata->supported_classes;
239
240 rp = rport->dd_data;
241 rp->local_port = lport;
242 rp->rp_state = rdata->rp_state;
243 rp->flags = rdata->flags;
244 rp->e_d_tov = rdata->e_d_tov;
245 rp->r_a_tov = rdata->r_a_tov;
246 mutex_unlock(&rdata->rp_mutex);
247
248 if (rport_ops->event_callback) {
249 FC_RPORT_DBG(rdata, "callback ev %d\n", event);
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700250 rport_ops->event_callback(lport, rdata, event);
Joe Eykholt9e9d0452009-08-25 14:01:18 -0700251 }
252 kref_put(&rdata->kref, lport->tt.rport_destroy);
Joe Eykholt629f4422009-08-25 14:01:06 -0700253 break;
254
255 case RPORT_EV_FAILED:
256 case RPORT_EV_LOGO:
257 case RPORT_EV_STOP:
Joe Eykholt9e9d0452009-08-25 14:01:18 -0700258 port_id = rdata->ids.port_id;
Robert Love42e9a922008-12-09 15:10:17 -0800259 mutex_unlock(&rdata->rp_mutex);
Joe Eykholt9e9d0452009-08-25 14:01:18 -0700260
261 if (rport_ops->event_callback) {
262 FC_RPORT_DBG(rdata, "callback ev %d\n", event);
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700263 rport_ops->event_callback(lport, rdata, event);
Abhijeet Joglekar571f8242009-02-27 10:54:41 -0800264 }
Joe Eykholt9e9d0452009-08-25 14:01:18 -0700265 cancel_delayed_work_sync(&rdata->retry_work);
266
267 /*
268 * Reset any outstanding exchanges before freeing rport.
269 */
270 lport->tt.exch_mgr_reset(lport, 0, port_id);
271 lport->tt.exch_mgr_reset(lport, port_id, 0);
272
273 if (rport) {
274 rp = rport->dd_data;
275 rp->rp_state = RPORT_ST_DELETE;
276 mutex_lock(&rdata->rp_mutex);
277 rdata->rport = NULL;
278 mutex_unlock(&rdata->rp_mutex);
279 fc_remote_port_delete(rport);
280 }
281 kref_put(&rdata->kref, lport->tt.rport_destroy);
Joe Eykholt629f4422009-08-25 14:01:06 -0700282 break;
283
284 default:
Robert Love42e9a922008-12-09 15:10:17 -0800285 mutex_unlock(&rdata->rp_mutex);
Joe Eykholt629f4422009-08-25 14:01:06 -0700286 break;
287 }
Robert Love42e9a922008-12-09 15:10:17 -0800288}
289
290/**
Robert Love34f42a02009-02-27 10:55:45 -0800291 * fc_rport_login() - Start the remote port login state machine
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700292 * @rdata: private remote port
Robert Love42e9a922008-12-09 15:10:17 -0800293 *
294 * Locking Note: Called without the rport lock held. This
295 * function will hold the rport lock, call an _enter_*
296 * function and then unlock the rport.
297 */
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700298int fc_rport_login(struct fc_rport_priv *rdata)
Robert Love42e9a922008-12-09 15:10:17 -0800299{
Robert Love42e9a922008-12-09 15:10:17 -0800300 mutex_lock(&rdata->rp_mutex);
301
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700302 FC_RPORT_DBG(rdata, "Login to port\n");
Robert Love42e9a922008-12-09 15:10:17 -0800303
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700304 fc_rport_enter_plogi(rdata);
Robert Love42e9a922008-12-09 15:10:17 -0800305
306 mutex_unlock(&rdata->rp_mutex);
307
308 return 0;
309}
310
311/**
Joe Eykholt5f7ea3b2009-07-29 17:04:49 -0700312 * fc_rport_enter_delete() - schedule a remote port to be deleted.
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700313 * @rdata: private remote port
Joe Eykholt5f7ea3b2009-07-29 17:04:49 -0700314 * @event: event to report as the reason for deletion
315 *
316 * Locking Note: Called with the rport lock held.
317 *
318 * Allow state change into DELETE only once.
319 *
320 * Call queue_work only if there's no event already pending.
321 * Set the new event so that the old pending event will not occur.
322 * Since we have the mutex, even if fc_rport_work() is already started,
323 * it'll see the new event.
324 */
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700325static void fc_rport_enter_delete(struct fc_rport_priv *rdata,
Joe Eykholt5f7ea3b2009-07-29 17:04:49 -0700326 enum fc_rport_event event)
327{
Joe Eykholt5f7ea3b2009-07-29 17:04:49 -0700328 if (rdata->rp_state == RPORT_ST_DELETE)
329 return;
330
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700331 FC_RPORT_DBG(rdata, "Delete port\n");
Joe Eykholt5f7ea3b2009-07-29 17:04:49 -0700332
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700333 fc_rport_state_enter(rdata, RPORT_ST_DELETE);
Joe Eykholt5f7ea3b2009-07-29 17:04:49 -0700334
335 if (rdata->event == RPORT_EV_NONE)
336 queue_work(rport_event_queue, &rdata->event_work);
337 rdata->event = event;
338}
339
340/**
Robert Love34f42a02009-02-27 10:55:45 -0800341 * fc_rport_logoff() - Logoff and remove an rport
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700342 * @rdata: private remote port
Robert Love42e9a922008-12-09 15:10:17 -0800343 *
344 * Locking Note: Called without the rport lock held. This
345 * function will hold the rport lock, call an _enter_*
346 * function and then unlock the rport.
347 */
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700348int fc_rport_logoff(struct fc_rport_priv *rdata)
Robert Love42e9a922008-12-09 15:10:17 -0800349{
Robert Love42e9a922008-12-09 15:10:17 -0800350 mutex_lock(&rdata->rp_mutex);
351
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700352 FC_RPORT_DBG(rdata, "Remove port\n");
Robert Love42e9a922008-12-09 15:10:17 -0800353
Joe Eykholt14194052009-07-29 17:04:43 -0700354 if (rdata->rp_state == RPORT_ST_DELETE) {
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700355 FC_RPORT_DBG(rdata, "Port in Delete state, not removing\n");
Abhijeet Joglekarb4c6f542009-04-21 16:27:04 -0700356 mutex_unlock(&rdata->rp_mutex);
357 goto out;
358 }
359
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700360 fc_rport_enter_logo(rdata);
Robert Love42e9a922008-12-09 15:10:17 -0800361
362 /*
Joe Eykholt14194052009-07-29 17:04:43 -0700363 * Change the state to Delete so that we discard
Robert Love42e9a922008-12-09 15:10:17 -0800364 * the response.
365 */
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700366 fc_rport_enter_delete(rdata, RPORT_EV_STOP);
Robert Love42e9a922008-12-09 15:10:17 -0800367 mutex_unlock(&rdata->rp_mutex);
368
Abhijeet Joglekarb4c6f542009-04-21 16:27:04 -0700369out:
Robert Love42e9a922008-12-09 15:10:17 -0800370 return 0;
371}
372
373/**
Robert Love34f42a02009-02-27 10:55:45 -0800374 * fc_rport_enter_ready() - The rport is ready
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700375 * @rdata: private remote port
Robert Love42e9a922008-12-09 15:10:17 -0800376 *
377 * Locking Note: The rport lock is expected to be held before calling
378 * this routine.
379 */
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700380static void fc_rport_enter_ready(struct fc_rport_priv *rdata)
Robert Love42e9a922008-12-09 15:10:17 -0800381{
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700382 fc_rport_state_enter(rdata, RPORT_ST_READY);
Robert Love42e9a922008-12-09 15:10:17 -0800383
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700384 FC_RPORT_DBG(rdata, "Port is Ready\n");
Robert Love42e9a922008-12-09 15:10:17 -0800385
Joe Eykholt5f7ea3b2009-07-29 17:04:49 -0700386 if (rdata->event == RPORT_EV_NONE)
387 queue_work(rport_event_queue, &rdata->event_work);
Joe Eykholt4c0f62b2009-08-25 14:01:12 -0700388 rdata->event = RPORT_EV_READY;
Robert Love42e9a922008-12-09 15:10:17 -0800389}
390
391/**
Robert Love34f42a02009-02-27 10:55:45 -0800392 * fc_rport_timeout() - Handler for the retry_work timer.
Joe Eykholtab28f1f2009-08-25 14:00:34 -0700393 * @work: The work struct of the fc_rport_priv
Robert Love42e9a922008-12-09 15:10:17 -0800394 *
395 * Locking Note: Called without the rport lock held. This
396 * function will hold the rport lock, call an _enter_*
397 * function and then unlock the rport.
398 */
399static void fc_rport_timeout(struct work_struct *work)
400{
Joe Eykholtab28f1f2009-08-25 14:00:34 -0700401 struct fc_rport_priv *rdata =
402 container_of(work, struct fc_rport_priv, retry_work.work);
Robert Love42e9a922008-12-09 15:10:17 -0800403
404 mutex_lock(&rdata->rp_mutex);
405
406 switch (rdata->rp_state) {
407 case RPORT_ST_PLOGI:
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700408 fc_rport_enter_plogi(rdata);
Robert Love42e9a922008-12-09 15:10:17 -0800409 break;
410 case RPORT_ST_PRLI:
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700411 fc_rport_enter_prli(rdata);
Robert Love42e9a922008-12-09 15:10:17 -0800412 break;
413 case RPORT_ST_RTV:
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700414 fc_rport_enter_rtv(rdata);
Robert Love42e9a922008-12-09 15:10:17 -0800415 break;
416 case RPORT_ST_LOGO:
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700417 fc_rport_enter_logo(rdata);
Robert Love42e9a922008-12-09 15:10:17 -0800418 break;
419 case RPORT_ST_READY:
420 case RPORT_ST_INIT:
Joe Eykholt14194052009-07-29 17:04:43 -0700421 case RPORT_ST_DELETE:
Robert Love42e9a922008-12-09 15:10:17 -0800422 break;
423 }
424
425 mutex_unlock(&rdata->rp_mutex);
Robert Love42e9a922008-12-09 15:10:17 -0800426}
427
428/**
Robert Love34f42a02009-02-27 10:55:45 -0800429 * fc_rport_error() - Error handler, called once retries have been exhausted
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700430 * @rdata: private remote port
Robert Love42e9a922008-12-09 15:10:17 -0800431 * @fp: The frame pointer
432 *
Robert Love42e9a922008-12-09 15:10:17 -0800433 * Locking Note: The rport lock is expected to be held before
434 * calling this routine
435 */
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700436static void fc_rport_error(struct fc_rport_priv *rdata, struct fc_frame *fp)
Robert Love42e9a922008-12-09 15:10:17 -0800437{
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700438 FC_RPORT_DBG(rdata, "Error %ld in state %s, retries %d\n",
Joe Eykholtcdbe6df2009-08-25 14:01:39 -0700439 IS_ERR(fp) ? -PTR_ERR(fp) : 0,
440 fc_rport_state(rdata), rdata->retries);
Robert Love42e9a922008-12-09 15:10:17 -0800441
Chris Leech6755db12009-02-27 10:55:02 -0800442 switch (rdata->rp_state) {
443 case RPORT_ST_PLOGI:
444 case RPORT_ST_PRLI:
445 case RPORT_ST_LOGO:
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700446 fc_rport_enter_delete(rdata, RPORT_EV_FAILED);
Chris Leech6755db12009-02-27 10:55:02 -0800447 break;
448 case RPORT_ST_RTV:
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700449 fc_rport_enter_ready(rdata);
Chris Leech6755db12009-02-27 10:55:02 -0800450 break;
Joe Eykholt14194052009-07-29 17:04:43 -0700451 case RPORT_ST_DELETE:
Chris Leech6755db12009-02-27 10:55:02 -0800452 case RPORT_ST_READY:
453 case RPORT_ST_INIT:
454 break;
Robert Love42e9a922008-12-09 15:10:17 -0800455 }
456}
457
458/**
Robert Love34f42a02009-02-27 10:55:45 -0800459 * fc_rport_error_retry() - Error handler when retries are desired
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700460 * @rdata: private remote port data
Chris Leech6755db12009-02-27 10:55:02 -0800461 * @fp: The frame pointer
462 *
463 * If the error was an exchange timeout retry immediately,
464 * otherwise wait for E_D_TOV.
465 *
466 * Locking Note: The rport lock is expected to be held before
467 * calling this routine
468 */
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700469static void fc_rport_error_retry(struct fc_rport_priv *rdata,
470 struct fc_frame *fp)
Chris Leech6755db12009-02-27 10:55:02 -0800471{
Chris Leech6755db12009-02-27 10:55:02 -0800472 unsigned long delay = FC_DEF_E_D_TOV;
473
474 /* make sure this isn't an FC_EX_CLOSED error, never retry those */
475 if (PTR_ERR(fp) == -FC_EX_CLOSED)
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700476 return fc_rport_error(rdata, fp);
Chris Leech6755db12009-02-27 10:55:02 -0800477
Abhijeet Joglekara3666952009-05-01 10:01:26 -0700478 if (rdata->retries < rdata->local_port->max_rport_retry_count) {
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700479 FC_RPORT_DBG(rdata, "Error %ld in state %s, retrying\n",
480 PTR_ERR(fp), fc_rport_state(rdata));
Chris Leech6755db12009-02-27 10:55:02 -0800481 rdata->retries++;
482 /* no additional delay on exchange timeouts */
483 if (PTR_ERR(fp) == -FC_EX_TIMEOUT)
484 delay = 0;
Chris Leech6755db12009-02-27 10:55:02 -0800485 schedule_delayed_work(&rdata->retry_work, delay);
486 return;
487 }
488
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700489 return fc_rport_error(rdata, fp);
Chris Leech6755db12009-02-27 10:55:02 -0800490}
491
492/**
Robert Love34f42a02009-02-27 10:55:45 -0800493 * fc_rport_plogi_recv_resp() - Handle incoming ELS PLOGI response
Robert Love42e9a922008-12-09 15:10:17 -0800494 * @sp: current sequence in the PLOGI exchange
495 * @fp: response frame
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700496 * @rdata_arg: private remote port data
Robert Love42e9a922008-12-09 15:10:17 -0800497 *
498 * Locking Note: This function will be called without the rport lock
499 * held, but it will lock, call an _enter_* function or fc_rport_error
500 * and then unlock the rport.
501 */
502static void fc_rport_plogi_resp(struct fc_seq *sp, struct fc_frame *fp,
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700503 void *rdata_arg)
Robert Love42e9a922008-12-09 15:10:17 -0800504{
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700505 struct fc_rport_priv *rdata = rdata_arg;
Robert Love42e9a922008-12-09 15:10:17 -0800506 struct fc_lport *lport = rdata->local_port;
Robert Lovea29e7642009-04-21 16:27:41 -0700507 struct fc_els_flogi *plp = NULL;
Robert Love42e9a922008-12-09 15:10:17 -0800508 unsigned int tov;
509 u16 csp_seq;
510 u16 cssp_seq;
511 u8 op;
512
513 mutex_lock(&rdata->rp_mutex);
514
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700515 FC_RPORT_DBG(rdata, "Received a PLOGI response\n");
Robert Love42e9a922008-12-09 15:10:17 -0800516
517 if (rdata->rp_state != RPORT_ST_PLOGI) {
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700518 FC_RPORT_DBG(rdata, "Received a PLOGI response, but in state "
519 "%s\n", fc_rport_state(rdata));
Abhijeet Joglekar76f68042009-04-21 16:26:58 -0700520 if (IS_ERR(fp))
521 goto err;
Robert Love42e9a922008-12-09 15:10:17 -0800522 goto out;
523 }
524
Abhijeet Joglekar76f68042009-04-21 16:26:58 -0700525 if (IS_ERR(fp)) {
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700526 fc_rport_error_retry(rdata, fp);
Abhijeet Joglekar76f68042009-04-21 16:26:58 -0700527 goto err;
528 }
529
Robert Love42e9a922008-12-09 15:10:17 -0800530 op = fc_frame_payload_op(fp);
531 if (op == ELS_LS_ACC &&
532 (plp = fc_frame_payload_get(fp, sizeof(*plp))) != NULL) {
Joe Eykholtf211fa52009-08-25 14:01:01 -0700533 rdata->ids.port_name = get_unaligned_be64(&plp->fl_wwpn);
534 rdata->ids.node_name = get_unaligned_be64(&plp->fl_wwnn);
Robert Love42e9a922008-12-09 15:10:17 -0800535
536 tov = ntohl(plp->fl_csp.sp_e_d_tov);
537 if (ntohs(plp->fl_csp.sp_features) & FC_SP_FT_EDTR)
538 tov /= 1000;
539 if (tov > rdata->e_d_tov)
540 rdata->e_d_tov = tov;
541 csp_seq = ntohs(plp->fl_csp.sp_tot_seq);
542 cssp_seq = ntohs(plp->fl_cssp[3 - 1].cp_con_seq);
543 if (cssp_seq < csp_seq)
544 csp_seq = cssp_seq;
545 rdata->max_seq = csp_seq;
Joe Eykholtf211fa52009-08-25 14:01:01 -0700546 rdata->maxframe_size = fc_plogi_get_maxframe(plp, lport->mfs);
Robert Love42e9a922008-12-09 15:10:17 -0800547
548 /*
549 * If the rport is one of the well known addresses
550 * we skip PRLI and RTV and go straight to READY.
551 */
Joe Eykholtf211fa52009-08-25 14:01:01 -0700552 if (rdata->ids.port_id >= FC_FID_DOM_MGR)
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700553 fc_rport_enter_ready(rdata);
Robert Love42e9a922008-12-09 15:10:17 -0800554 else
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700555 fc_rport_enter_prli(rdata);
Robert Love42e9a922008-12-09 15:10:17 -0800556 } else
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700557 fc_rport_error_retry(rdata, fp);
Robert Love42e9a922008-12-09 15:10:17 -0800558
559out:
560 fc_frame_free(fp);
561err:
562 mutex_unlock(&rdata->rp_mutex);
Joe Eykholtf211fa52009-08-25 14:01:01 -0700563 kref_put(&rdata->kref, rdata->local_port->tt.rport_destroy);
Robert Love42e9a922008-12-09 15:10:17 -0800564}
565
566/**
Robert Love34f42a02009-02-27 10:55:45 -0800567 * fc_rport_enter_plogi() - Send Port Login (PLOGI) request to peer
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700568 * @rdata: private remote port data
Robert Love42e9a922008-12-09 15:10:17 -0800569 *
570 * Locking Note: The rport lock is expected to be held before calling
571 * this routine.
572 */
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700573static void fc_rport_enter_plogi(struct fc_rport_priv *rdata)
Robert Love42e9a922008-12-09 15:10:17 -0800574{
Robert Love42e9a922008-12-09 15:10:17 -0800575 struct fc_lport *lport = rdata->local_port;
576 struct fc_frame *fp;
577
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700578 FC_RPORT_DBG(rdata, "Port entered PLOGI state from %s state\n",
579 fc_rport_state(rdata));
Robert Love42e9a922008-12-09 15:10:17 -0800580
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700581 fc_rport_state_enter(rdata, RPORT_ST_PLOGI);
Robert Love42e9a922008-12-09 15:10:17 -0800582
Joe Eykholtf211fa52009-08-25 14:01:01 -0700583 rdata->maxframe_size = FC_MIN_MAX_PAYLOAD;
Robert Love42e9a922008-12-09 15:10:17 -0800584 fp = fc_frame_alloc(lport, sizeof(struct fc_els_flogi));
585 if (!fp) {
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700586 fc_rport_error_retry(rdata, fp);
Robert Love42e9a922008-12-09 15:10:17 -0800587 return;
588 }
589 rdata->e_d_tov = lport->e_d_tov;
590
Joe Eykholtf211fa52009-08-25 14:01:01 -0700591 if (!lport->tt.elsct_send(lport, rdata->ids.port_id, fp, ELS_PLOGI,
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700592 fc_rport_plogi_resp, rdata, lport->e_d_tov))
593 fc_rport_error_retry(rdata, fp);
Robert Love42e9a922008-12-09 15:10:17 -0800594 else
Joe Eykholtf211fa52009-08-25 14:01:01 -0700595 kref_get(&rdata->kref);
Robert Love42e9a922008-12-09 15:10:17 -0800596}
597
598/**
Robert Love34f42a02009-02-27 10:55:45 -0800599 * fc_rport_prli_resp() - Process Login (PRLI) response handler
Robert Love42e9a922008-12-09 15:10:17 -0800600 * @sp: current sequence in the PRLI exchange
601 * @fp: response frame
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700602 * @rdata_arg: private remote port data
Robert Love42e9a922008-12-09 15:10:17 -0800603 *
604 * Locking Note: This function will be called without the rport lock
605 * held, but it will lock, call an _enter_* function or fc_rport_error
606 * and then unlock the rport.
607 */
608static void fc_rport_prli_resp(struct fc_seq *sp, struct fc_frame *fp,
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700609 void *rdata_arg)
Robert Love42e9a922008-12-09 15:10:17 -0800610{
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700611 struct fc_rport_priv *rdata = rdata_arg;
Robert Love42e9a922008-12-09 15:10:17 -0800612 struct {
613 struct fc_els_prli prli;
614 struct fc_els_spp spp;
615 } *pp;
616 u32 roles = FC_RPORT_ROLE_UNKNOWN;
617 u32 fcp_parm = 0;
618 u8 op;
619
620 mutex_lock(&rdata->rp_mutex);
621
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700622 FC_RPORT_DBG(rdata, "Received a PRLI response\n");
Robert Love42e9a922008-12-09 15:10:17 -0800623
624 if (rdata->rp_state != RPORT_ST_PRLI) {
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700625 FC_RPORT_DBG(rdata, "Received a PRLI response, but in state "
626 "%s\n", fc_rport_state(rdata));
Abhijeet Joglekar76f68042009-04-21 16:26:58 -0700627 if (IS_ERR(fp))
628 goto err;
Robert Love42e9a922008-12-09 15:10:17 -0800629 goto out;
630 }
631
Abhijeet Joglekar76f68042009-04-21 16:26:58 -0700632 if (IS_ERR(fp)) {
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700633 fc_rport_error_retry(rdata, fp);
Abhijeet Joglekar76f68042009-04-21 16:26:58 -0700634 goto err;
635 }
636
Robert Love42e9a922008-12-09 15:10:17 -0800637 op = fc_frame_payload_op(fp);
638 if (op == ELS_LS_ACC) {
639 pp = fc_frame_payload_get(fp, sizeof(*pp));
640 if (pp && pp->prli.prli_spp_len >= sizeof(pp->spp)) {
641 fcp_parm = ntohl(pp->spp.spp_params);
642 if (fcp_parm & FCP_SPPF_RETRY)
643 rdata->flags |= FC_RP_FLAGS_RETRY;
644 }
645
Joe Eykholtf211fa52009-08-25 14:01:01 -0700646 rdata->supported_classes = FC_COS_CLASS3;
Robert Love42e9a922008-12-09 15:10:17 -0800647 if (fcp_parm & FCP_SPPF_INIT_FCN)
648 roles |= FC_RPORT_ROLE_FCP_INITIATOR;
649 if (fcp_parm & FCP_SPPF_TARG_FCN)
650 roles |= FC_RPORT_ROLE_FCP_TARGET;
651
Joe Eykholtf211fa52009-08-25 14:01:01 -0700652 rdata->ids.roles = roles;
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700653 fc_rport_enter_rtv(rdata);
Robert Love42e9a922008-12-09 15:10:17 -0800654
655 } else {
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700656 FC_RPORT_DBG(rdata, "Bad ELS response for PRLI command\n");
657 fc_rport_enter_delete(rdata, RPORT_EV_FAILED);
Robert Love42e9a922008-12-09 15:10:17 -0800658 }
659
660out:
661 fc_frame_free(fp);
662err:
663 mutex_unlock(&rdata->rp_mutex);
Joe Eykholtf211fa52009-08-25 14:01:01 -0700664 kref_put(&rdata->kref, rdata->local_port->tt.rport_destroy);
Robert Love42e9a922008-12-09 15:10:17 -0800665}
666
667/**
Robert Love34f42a02009-02-27 10:55:45 -0800668 * fc_rport_logo_resp() - Logout (LOGO) response handler
Robert Love42e9a922008-12-09 15:10:17 -0800669 * @sp: current sequence in the LOGO exchange
670 * @fp: response frame
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700671 * @rdata_arg: private remote port data
Robert Love42e9a922008-12-09 15:10:17 -0800672 *
673 * Locking Note: This function will be called without the rport lock
674 * held, but it will lock, call an _enter_* function or fc_rport_error
675 * and then unlock the rport.
676 */
677static void fc_rport_logo_resp(struct fc_seq *sp, struct fc_frame *fp,
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700678 void *rdata_arg)
Robert Love42e9a922008-12-09 15:10:17 -0800679{
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700680 struct fc_rport_priv *rdata = rdata_arg;
Robert Love42e9a922008-12-09 15:10:17 -0800681 u8 op;
682
683 mutex_lock(&rdata->rp_mutex);
684
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700685 FC_RPORT_DBG(rdata, "Received a LOGO response\n");
Robert Love42e9a922008-12-09 15:10:17 -0800686
Robert Love42e9a922008-12-09 15:10:17 -0800687 if (rdata->rp_state != RPORT_ST_LOGO) {
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700688 FC_RPORT_DBG(rdata, "Received a LOGO response, but in state "
689 "%s\n", fc_rport_state(rdata));
Abhijeet Joglekar76f68042009-04-21 16:26:58 -0700690 if (IS_ERR(fp))
691 goto err;
Robert Love42e9a922008-12-09 15:10:17 -0800692 goto out;
693 }
694
Abhijeet Joglekar76f68042009-04-21 16:26:58 -0700695 if (IS_ERR(fp)) {
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700696 fc_rport_error_retry(rdata, fp);
Abhijeet Joglekar76f68042009-04-21 16:26:58 -0700697 goto err;
698 }
699
Robert Love42e9a922008-12-09 15:10:17 -0800700 op = fc_frame_payload_op(fp);
701 if (op == ELS_LS_ACC) {
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700702 fc_rport_enter_rtv(rdata);
Robert Love42e9a922008-12-09 15:10:17 -0800703 } else {
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700704 FC_RPORT_DBG(rdata, "Bad ELS response for LOGO command\n");
705 fc_rport_enter_delete(rdata, RPORT_EV_LOGO);
Robert Love42e9a922008-12-09 15:10:17 -0800706 }
707
708out:
709 fc_frame_free(fp);
710err:
711 mutex_unlock(&rdata->rp_mutex);
Joe Eykholtf211fa52009-08-25 14:01:01 -0700712 kref_put(&rdata->kref, rdata->local_port->tt.rport_destroy);
Robert Love42e9a922008-12-09 15:10:17 -0800713}
714
715/**
Robert Love34f42a02009-02-27 10:55:45 -0800716 * fc_rport_enter_prli() - Send Process Login (PRLI) request to peer
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700717 * @rdata: private remote port data
Robert Love42e9a922008-12-09 15:10:17 -0800718 *
719 * Locking Note: The rport lock is expected to be held before calling
720 * this routine.
721 */
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700722static void fc_rport_enter_prli(struct fc_rport_priv *rdata)
Robert Love42e9a922008-12-09 15:10:17 -0800723{
Robert Love42e9a922008-12-09 15:10:17 -0800724 struct fc_lport *lport = rdata->local_port;
725 struct {
726 struct fc_els_prli prli;
727 struct fc_els_spp spp;
728 } *pp;
729 struct fc_frame *fp;
730
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700731 FC_RPORT_DBG(rdata, "Port entered PRLI state from %s state\n",
732 fc_rport_state(rdata));
Robert Love42e9a922008-12-09 15:10:17 -0800733
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700734 fc_rport_state_enter(rdata, RPORT_ST_PRLI);
Robert Love42e9a922008-12-09 15:10:17 -0800735
736 fp = fc_frame_alloc(lport, sizeof(*pp));
737 if (!fp) {
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700738 fc_rport_error_retry(rdata, fp);
Robert Love42e9a922008-12-09 15:10:17 -0800739 return;
740 }
741
Joe Eykholtf211fa52009-08-25 14:01:01 -0700742 if (!lport->tt.elsct_send(lport, rdata->ids.port_id, fp, ELS_PRLI,
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700743 fc_rport_prli_resp, rdata, lport->e_d_tov))
744 fc_rport_error_retry(rdata, fp);
Robert Love42e9a922008-12-09 15:10:17 -0800745 else
Joe Eykholtf211fa52009-08-25 14:01:01 -0700746 kref_get(&rdata->kref);
Robert Love42e9a922008-12-09 15:10:17 -0800747}
748
749/**
Robert Love34f42a02009-02-27 10:55:45 -0800750 * fc_rport_els_rtv_resp() - Request Timeout Value response handler
Robert Love42e9a922008-12-09 15:10:17 -0800751 * @sp: current sequence in the RTV exchange
752 * @fp: response frame
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700753 * @rdata_arg: private remote port data
Robert Love42e9a922008-12-09 15:10:17 -0800754 *
755 * Many targets don't seem to support this.
756 *
757 * Locking Note: This function will be called without the rport lock
758 * held, but it will lock, call an _enter_* function or fc_rport_error
759 * and then unlock the rport.
760 */
761static void fc_rport_rtv_resp(struct fc_seq *sp, struct fc_frame *fp,
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700762 void *rdata_arg)
Robert Love42e9a922008-12-09 15:10:17 -0800763{
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700764 struct fc_rport_priv *rdata = rdata_arg;
Robert Love42e9a922008-12-09 15:10:17 -0800765 u8 op;
766
767 mutex_lock(&rdata->rp_mutex);
768
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700769 FC_RPORT_DBG(rdata, "Received a RTV response\n");
Robert Love42e9a922008-12-09 15:10:17 -0800770
771 if (rdata->rp_state != RPORT_ST_RTV) {
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700772 FC_RPORT_DBG(rdata, "Received a RTV response, but in state "
773 "%s\n", fc_rport_state(rdata));
Abhijeet Joglekar76f68042009-04-21 16:26:58 -0700774 if (IS_ERR(fp))
775 goto err;
Robert Love42e9a922008-12-09 15:10:17 -0800776 goto out;
777 }
778
Abhijeet Joglekar76f68042009-04-21 16:26:58 -0700779 if (IS_ERR(fp)) {
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700780 fc_rport_error(rdata, fp);
Abhijeet Joglekar76f68042009-04-21 16:26:58 -0700781 goto err;
782 }
783
Robert Love42e9a922008-12-09 15:10:17 -0800784 op = fc_frame_payload_op(fp);
785 if (op == ELS_LS_ACC) {
786 struct fc_els_rtv_acc *rtv;
787 u32 toq;
788 u32 tov;
789
790 rtv = fc_frame_payload_get(fp, sizeof(*rtv));
791 if (rtv) {
792 toq = ntohl(rtv->rtv_toq);
793 tov = ntohl(rtv->rtv_r_a_tov);
794 if (tov == 0)
795 tov = 1;
796 rdata->r_a_tov = tov;
797 tov = ntohl(rtv->rtv_e_d_tov);
798 if (toq & FC_ELS_RTV_EDRES)
799 tov /= 1000000;
800 if (tov == 0)
801 tov = 1;
802 rdata->e_d_tov = tov;
803 }
804 }
805
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700806 fc_rport_enter_ready(rdata);
Robert Love42e9a922008-12-09 15:10:17 -0800807
808out:
809 fc_frame_free(fp);
810err:
811 mutex_unlock(&rdata->rp_mutex);
Joe Eykholtf211fa52009-08-25 14:01:01 -0700812 kref_put(&rdata->kref, rdata->local_port->tt.rport_destroy);
Robert Love42e9a922008-12-09 15:10:17 -0800813}
814
815/**
Robert Love34f42a02009-02-27 10:55:45 -0800816 * fc_rport_enter_rtv() - Send Request Timeout Value (RTV) request to peer
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700817 * @rdata: private remote port data
Robert Love42e9a922008-12-09 15:10:17 -0800818 *
819 * Locking Note: The rport lock is expected to be held before calling
820 * this routine.
821 */
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700822static void fc_rport_enter_rtv(struct fc_rport_priv *rdata)
Robert Love42e9a922008-12-09 15:10:17 -0800823{
824 struct fc_frame *fp;
Robert Love42e9a922008-12-09 15:10:17 -0800825 struct fc_lport *lport = rdata->local_port;
826
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700827 FC_RPORT_DBG(rdata, "Port entered RTV state from %s state\n",
828 fc_rport_state(rdata));
Robert Love42e9a922008-12-09 15:10:17 -0800829
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700830 fc_rport_state_enter(rdata, RPORT_ST_RTV);
Robert Love42e9a922008-12-09 15:10:17 -0800831
832 fp = fc_frame_alloc(lport, sizeof(struct fc_els_rtv));
833 if (!fp) {
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700834 fc_rport_error_retry(rdata, fp);
Robert Love42e9a922008-12-09 15:10:17 -0800835 return;
836 }
837
Joe Eykholtf211fa52009-08-25 14:01:01 -0700838 if (!lport->tt.elsct_send(lport, rdata->ids.port_id, fp, ELS_RTV,
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700839 fc_rport_rtv_resp, rdata, lport->e_d_tov))
840 fc_rport_error_retry(rdata, fp);
Robert Love42e9a922008-12-09 15:10:17 -0800841 else
Joe Eykholtf211fa52009-08-25 14:01:01 -0700842 kref_get(&rdata->kref);
Robert Love42e9a922008-12-09 15:10:17 -0800843}
844
845/**
Robert Love34f42a02009-02-27 10:55:45 -0800846 * fc_rport_enter_logo() - Send Logout (LOGO) request to peer
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700847 * @rdata: private remote port data
Robert Love42e9a922008-12-09 15:10:17 -0800848 *
849 * Locking Note: The rport lock is expected to be held before calling
850 * this routine.
851 */
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700852static void fc_rport_enter_logo(struct fc_rport_priv *rdata)
Robert Love42e9a922008-12-09 15:10:17 -0800853{
Robert Love42e9a922008-12-09 15:10:17 -0800854 struct fc_lport *lport = rdata->local_port;
855 struct fc_frame *fp;
856
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700857 FC_RPORT_DBG(rdata, "Port entered LOGO state from %s state\n",
858 fc_rport_state(rdata));
Robert Love42e9a922008-12-09 15:10:17 -0800859
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700860 fc_rport_state_enter(rdata, RPORT_ST_LOGO);
Robert Love42e9a922008-12-09 15:10:17 -0800861
862 fp = fc_frame_alloc(lport, sizeof(struct fc_els_logo));
863 if (!fp) {
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700864 fc_rport_error_retry(rdata, fp);
Robert Love42e9a922008-12-09 15:10:17 -0800865 return;
866 }
867
Joe Eykholtf211fa52009-08-25 14:01:01 -0700868 if (!lport->tt.elsct_send(lport, rdata->ids.port_id, fp, ELS_LOGO,
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700869 fc_rport_logo_resp, rdata, lport->e_d_tov))
870 fc_rport_error_retry(rdata, fp);
Robert Love42e9a922008-12-09 15:10:17 -0800871 else
Joe Eykholtf211fa52009-08-25 14:01:01 -0700872 kref_get(&rdata->kref);
Robert Love42e9a922008-12-09 15:10:17 -0800873}
874
875
876/**
Robert Love34f42a02009-02-27 10:55:45 -0800877 * fc_rport_recv_req() - Receive a request from a rport
Robert Love42e9a922008-12-09 15:10:17 -0800878 * @sp: current sequence in the PLOGI exchange
879 * @fp: response frame
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700880 * @rdata_arg: private remote port data
Robert Love42e9a922008-12-09 15:10:17 -0800881 *
882 * Locking Note: Called without the rport lock held. This
883 * function will hold the rport lock, call an _enter_*
884 * function and then unlock the rport.
885 */
886void fc_rport_recv_req(struct fc_seq *sp, struct fc_frame *fp,
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700887 struct fc_rport_priv *rdata)
Robert Love42e9a922008-12-09 15:10:17 -0800888{
Robert Love42e9a922008-12-09 15:10:17 -0800889 struct fc_lport *lport = rdata->local_port;
890
891 struct fc_frame_header *fh;
892 struct fc_seq_els_data els_data;
893 u8 op;
894
895 mutex_lock(&rdata->rp_mutex);
896
897 els_data.fp = NULL;
898 els_data.explan = ELS_EXPL_NONE;
899 els_data.reason = ELS_RJT_NONE;
900
901 fh = fc_frame_header_get(fp);
902
903 if (fh->fh_r_ctl == FC_RCTL_ELS_REQ && fh->fh_type == FC_TYPE_ELS) {
904 op = fc_frame_payload_op(fp);
905 switch (op) {
906 case ELS_PLOGI:
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700907 fc_rport_recv_plogi_req(rdata, sp, fp);
Robert Love42e9a922008-12-09 15:10:17 -0800908 break;
909 case ELS_PRLI:
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700910 fc_rport_recv_prli_req(rdata, sp, fp);
Robert Love42e9a922008-12-09 15:10:17 -0800911 break;
912 case ELS_PRLO:
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700913 fc_rport_recv_prlo_req(rdata, sp, fp);
Robert Love42e9a922008-12-09 15:10:17 -0800914 break;
915 case ELS_LOGO:
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700916 fc_rport_recv_logo_req(rdata, sp, fp);
Robert Love42e9a922008-12-09 15:10:17 -0800917 break;
918 case ELS_RRQ:
919 els_data.fp = fp;
920 lport->tt.seq_els_rsp_send(sp, ELS_RRQ, &els_data);
921 break;
922 case ELS_REC:
923 els_data.fp = fp;
924 lport->tt.seq_els_rsp_send(sp, ELS_REC, &els_data);
925 break;
926 default:
927 els_data.reason = ELS_RJT_UNSUP;
928 lport->tt.seq_els_rsp_send(sp, ELS_LS_RJT, &els_data);
929 break;
930 }
931 }
932
933 mutex_unlock(&rdata->rp_mutex);
934}
935
936/**
Robert Love34f42a02009-02-27 10:55:45 -0800937 * fc_rport_recv_plogi_req() - Handle incoming Port Login (PLOGI) request
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700938 * @rdata: private remote port data
Robert Love42e9a922008-12-09 15:10:17 -0800939 * @sp: current sequence in the PLOGI exchange
940 * @fp: PLOGI request frame
941 *
942 * Locking Note: The rport lock is exected to be held before calling
943 * this function.
944 */
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700945static void fc_rport_recv_plogi_req(struct fc_rport_priv *rdata,
Robert Love42e9a922008-12-09 15:10:17 -0800946 struct fc_seq *sp, struct fc_frame *rx_fp)
947{
Robert Love42e9a922008-12-09 15:10:17 -0800948 struct fc_lport *lport = rdata->local_port;
949 struct fc_frame *fp = rx_fp;
950 struct fc_exch *ep;
951 struct fc_frame_header *fh;
952 struct fc_els_flogi *pl;
953 struct fc_seq_els_data rjt_data;
954 u32 sid;
955 u64 wwpn;
956 u64 wwnn;
957 enum fc_els_rjt_reason reject = 0;
958 u32 f_ctl;
959 rjt_data.fp = NULL;
960
961 fh = fc_frame_header_get(fp);
962
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700963 FC_RPORT_DBG(rdata, "Received PLOGI request while in state %s\n",
964 fc_rport_state(rdata));
Robert Love42e9a922008-12-09 15:10:17 -0800965
966 sid = ntoh24(fh->fh_s_id);
967 pl = fc_frame_payload_get(fp, sizeof(*pl));
968 if (!pl) {
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700969 FC_RPORT_DBG(rdata, "Received PLOGI too short\n");
Robert Love42e9a922008-12-09 15:10:17 -0800970 WARN_ON(1);
971 /* XXX TBD: send reject? */
972 fc_frame_free(fp);
973 return;
974 }
975 wwpn = get_unaligned_be64(&pl->fl_wwpn);
976 wwnn = get_unaligned_be64(&pl->fl_wwnn);
977
978 /*
979 * If the session was just created, possibly due to the incoming PLOGI,
980 * set the state appropriately and accept the PLOGI.
981 *
982 * If we had also sent a PLOGI, and if the received PLOGI is from a
983 * higher WWPN, we accept it, otherwise an LS_RJT is sent with reason
984 * "command already in progress".
985 *
986 * XXX TBD: If the session was ready before, the PLOGI should result in
987 * all outstanding exchanges being reset.
988 */
989 switch (rdata->rp_state) {
990 case RPORT_ST_INIT:
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700991 FC_RPORT_DBG(rdata, "Received PLOGI, wwpn %llx state INIT "
Robert Love74147052009-06-10 15:31:10 -0700992 "- reject\n", (unsigned long long)wwpn);
Robert Love42e9a922008-12-09 15:10:17 -0800993 reject = ELS_RJT_UNSUP;
994 break;
995 case RPORT_ST_PLOGI:
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700996 FC_RPORT_DBG(rdata, "Received PLOGI in PLOGI state %d\n",
Robert Love74147052009-06-10 15:31:10 -0700997 rdata->rp_state);
Robert Love42e9a922008-12-09 15:10:17 -0800998 if (wwpn < lport->wwpn)
999 reject = ELS_RJT_INPROG;
1000 break;
1001 case RPORT_ST_PRLI:
1002 case RPORT_ST_READY:
Joe Eykholt9fb9d322009-08-25 14:00:50 -07001003 FC_RPORT_DBG(rdata, "Received PLOGI in logged-in state %d "
Robert Love74147052009-06-10 15:31:10 -07001004 "- ignored for now\n", rdata->rp_state);
Robert Love42e9a922008-12-09 15:10:17 -08001005 /* XXX TBD - should reset */
1006 break;
Joe Eykholt14194052009-07-29 17:04:43 -07001007 case RPORT_ST_DELETE:
Robert Love42e9a922008-12-09 15:10:17 -08001008 default:
Joe Eykholt9fb9d322009-08-25 14:00:50 -07001009 FC_RPORT_DBG(rdata, "Received PLOGI in unexpected "
Robert Love74147052009-06-10 15:31:10 -07001010 "state %d\n", rdata->rp_state);
Abhijeet Joglekarb4c6f542009-04-21 16:27:04 -07001011 fc_frame_free(fp);
1012 return;
Robert Love42e9a922008-12-09 15:10:17 -08001013 break;
1014 }
1015
1016 if (reject) {
1017 rjt_data.reason = reject;
1018 rjt_data.explan = ELS_EXPL_NONE;
1019 lport->tt.seq_els_rsp_send(sp, ELS_LS_RJT, &rjt_data);
1020 fc_frame_free(fp);
1021 } else {
1022 fp = fc_frame_alloc(lport, sizeof(*pl));
1023 if (fp == NULL) {
1024 fp = rx_fp;
1025 rjt_data.reason = ELS_RJT_UNAB;
1026 rjt_data.explan = ELS_EXPL_NONE;
1027 lport->tt.seq_els_rsp_send(sp, ELS_LS_RJT, &rjt_data);
1028 fc_frame_free(fp);
1029 } else {
1030 sp = lport->tt.seq_start_next(sp);
1031 WARN_ON(!sp);
Joe Eykholtf211fa52009-08-25 14:01:01 -07001032 rdata->ids.port_name = wwpn;
1033 rdata->ids.node_name = wwnn;
Robert Love42e9a922008-12-09 15:10:17 -08001034
1035 /*
1036 * Get session payload size from incoming PLOGI.
1037 */
Joe Eykholtf211fa52009-08-25 14:01:01 -07001038 rdata->maxframe_size =
Robert Love42e9a922008-12-09 15:10:17 -08001039 fc_plogi_get_maxframe(pl, lport->mfs);
1040 fc_frame_free(rx_fp);
1041 fc_plogi_fill(lport, fp, ELS_LS_ACC);
1042
1043 /*
1044 * Send LS_ACC. If this fails,
1045 * the originator should retry.
1046 */
1047 f_ctl = FC_FC_EX_CTX | FC_FC_LAST_SEQ;
1048 f_ctl |= FC_FC_END_SEQ | FC_FC_SEQ_INIT;
1049 ep = fc_seq_exch(sp);
1050 fc_fill_fc_hdr(fp, FC_RCTL_ELS_REP, ep->did, ep->sid,
1051 FC_TYPE_ELS, f_ctl, 0);
1052 lport->tt.seq_send(lport, sp, fp);
1053 if (rdata->rp_state == RPORT_ST_PLOGI)
Joe Eykholt9fb9d322009-08-25 14:00:50 -07001054 fc_rport_enter_prli(rdata);
Robert Love42e9a922008-12-09 15:10:17 -08001055 }
1056 }
1057}
1058
1059/**
Robert Love34f42a02009-02-27 10:55:45 -08001060 * fc_rport_recv_prli_req() - Handle incoming Process Login (PRLI) request
Joe Eykholt9fb9d322009-08-25 14:00:50 -07001061 * @rdata: private remote port data
Robert Love42e9a922008-12-09 15:10:17 -08001062 * @sp: current sequence in the PRLI exchange
1063 * @fp: PRLI request frame
1064 *
1065 * Locking Note: The rport lock is exected to be held before calling
1066 * this function.
1067 */
Joe Eykholt9fb9d322009-08-25 14:00:50 -07001068static void fc_rport_recv_prli_req(struct fc_rport_priv *rdata,
Robert Love42e9a922008-12-09 15:10:17 -08001069 struct fc_seq *sp, struct fc_frame *rx_fp)
1070{
Robert Love42e9a922008-12-09 15:10:17 -08001071 struct fc_lport *lport = rdata->local_port;
1072 struct fc_exch *ep;
1073 struct fc_frame *fp;
1074 struct fc_frame_header *fh;
1075 struct {
1076 struct fc_els_prli prli;
1077 struct fc_els_spp spp;
1078 } *pp;
1079 struct fc_els_spp *rspp; /* request service param page */
1080 struct fc_els_spp *spp; /* response spp */
1081 unsigned int len;
1082 unsigned int plen;
1083 enum fc_els_rjt_reason reason = ELS_RJT_UNAB;
1084 enum fc_els_rjt_explan explan = ELS_EXPL_NONE;
1085 enum fc_els_spp_resp resp;
1086 struct fc_seq_els_data rjt_data;
1087 u32 f_ctl;
1088 u32 fcp_parm;
1089 u32 roles = FC_RPORT_ROLE_UNKNOWN;
1090 rjt_data.fp = NULL;
1091
1092 fh = fc_frame_header_get(rx_fp);
1093
Joe Eykholt9fb9d322009-08-25 14:00:50 -07001094 FC_RPORT_DBG(rdata, "Received PRLI request while in state %s\n",
1095 fc_rport_state(rdata));
Robert Love42e9a922008-12-09 15:10:17 -08001096
1097 switch (rdata->rp_state) {
1098 case RPORT_ST_PRLI:
1099 case RPORT_ST_READY:
1100 reason = ELS_RJT_NONE;
1101 break;
1102 default:
Abhijeet Joglekarb4c6f542009-04-21 16:27:04 -07001103 fc_frame_free(rx_fp);
1104 return;
Robert Love42e9a922008-12-09 15:10:17 -08001105 break;
1106 }
1107 len = fr_len(rx_fp) - sizeof(*fh);
1108 pp = fc_frame_payload_get(rx_fp, sizeof(*pp));
1109 if (pp == NULL) {
1110 reason = ELS_RJT_PROT;
1111 explan = ELS_EXPL_INV_LEN;
1112 } else {
1113 plen = ntohs(pp->prli.prli_len);
1114 if ((plen % 4) != 0 || plen > len) {
1115 reason = ELS_RJT_PROT;
1116 explan = ELS_EXPL_INV_LEN;
1117 } else if (plen < len) {
1118 len = plen;
1119 }
1120 plen = pp->prli.prli_spp_len;
1121 if ((plen % 4) != 0 || plen < sizeof(*spp) ||
1122 plen > len || len < sizeof(*pp)) {
1123 reason = ELS_RJT_PROT;
1124 explan = ELS_EXPL_INV_LEN;
1125 }
1126 rspp = &pp->spp;
1127 }
1128 if (reason != ELS_RJT_NONE ||
1129 (fp = fc_frame_alloc(lport, len)) == NULL) {
1130 rjt_data.reason = reason;
1131 rjt_data.explan = explan;
1132 lport->tt.seq_els_rsp_send(sp, ELS_LS_RJT, &rjt_data);
1133 } else {
1134 sp = lport->tt.seq_start_next(sp);
1135 WARN_ON(!sp);
1136 pp = fc_frame_payload_get(fp, len);
1137 WARN_ON(!pp);
1138 memset(pp, 0, len);
1139 pp->prli.prli_cmd = ELS_LS_ACC;
1140 pp->prli.prli_spp_len = plen;
1141 pp->prli.prli_len = htons(len);
1142 len -= sizeof(struct fc_els_prli);
1143
1144 /*
1145 * Go through all the service parameter pages and build
1146 * response. If plen indicates longer SPP than standard,
1147 * use that. The entire response has been pre-cleared above.
1148 */
1149 spp = &pp->spp;
1150 while (len >= plen) {
1151 spp->spp_type = rspp->spp_type;
1152 spp->spp_type_ext = rspp->spp_type_ext;
1153 spp->spp_flags = rspp->spp_flags & FC_SPP_EST_IMG_PAIR;
1154 resp = FC_SPP_RESP_ACK;
1155 if (rspp->spp_flags & FC_SPP_RPA_VAL)
1156 resp = FC_SPP_RESP_NO_PA;
1157 switch (rspp->spp_type) {
1158 case 0: /* common to all FC-4 types */
1159 break;
1160 case FC_TYPE_FCP:
1161 fcp_parm = ntohl(rspp->spp_params);
1162 if (fcp_parm * FCP_SPPF_RETRY)
1163 rdata->flags |= FC_RP_FLAGS_RETRY;
Joe Eykholtf211fa52009-08-25 14:01:01 -07001164 rdata->supported_classes = FC_COS_CLASS3;
Robert Love42e9a922008-12-09 15:10:17 -08001165 if (fcp_parm & FCP_SPPF_INIT_FCN)
1166 roles |= FC_RPORT_ROLE_FCP_INITIATOR;
1167 if (fcp_parm & FCP_SPPF_TARG_FCN)
1168 roles |= FC_RPORT_ROLE_FCP_TARGET;
Joe Eykholtf211fa52009-08-25 14:01:01 -07001169 rdata->ids.roles = roles;
Robert Love42e9a922008-12-09 15:10:17 -08001170
1171 spp->spp_params =
1172 htonl(lport->service_params);
1173 break;
1174 default:
1175 resp = FC_SPP_RESP_INVL;
1176 break;
1177 }
1178 spp->spp_flags |= resp;
1179 len -= plen;
1180 rspp = (struct fc_els_spp *)((char *)rspp + plen);
1181 spp = (struct fc_els_spp *)((char *)spp + plen);
1182 }
1183
1184 /*
1185 * Send LS_ACC. If this fails, the originator should retry.
1186 */
1187 f_ctl = FC_FC_EX_CTX | FC_FC_LAST_SEQ;
1188 f_ctl |= FC_FC_END_SEQ | FC_FC_SEQ_INIT;
1189 ep = fc_seq_exch(sp);
1190 fc_fill_fc_hdr(fp, FC_RCTL_ELS_REP, ep->did, ep->sid,
1191 FC_TYPE_ELS, f_ctl, 0);
1192 lport->tt.seq_send(lport, sp, fp);
1193
1194 /*
1195 * Get lock and re-check state.
1196 */
1197 switch (rdata->rp_state) {
1198 case RPORT_ST_PRLI:
Joe Eykholt9fb9d322009-08-25 14:00:50 -07001199 fc_rport_enter_ready(rdata);
Robert Love42e9a922008-12-09 15:10:17 -08001200 break;
1201 case RPORT_ST_READY:
1202 break;
1203 default:
1204 break;
1205 }
1206 }
1207 fc_frame_free(rx_fp);
1208}
1209
1210/**
Robert Love34f42a02009-02-27 10:55:45 -08001211 * fc_rport_recv_prlo_req() - Handle incoming Process Logout (PRLO) request
Joe Eykholt9fb9d322009-08-25 14:00:50 -07001212 * @rdata: private remote port data
Robert Love42e9a922008-12-09 15:10:17 -08001213 * @sp: current sequence in the PRLO exchange
1214 * @fp: PRLO request frame
1215 *
1216 * Locking Note: The rport lock is exected to be held before calling
1217 * this function.
1218 */
Joe Eykholt9fb9d322009-08-25 14:00:50 -07001219static void fc_rport_recv_prlo_req(struct fc_rport_priv *rdata,
1220 struct fc_seq *sp,
Robert Love42e9a922008-12-09 15:10:17 -08001221 struct fc_frame *fp)
1222{
Robert Love42e9a922008-12-09 15:10:17 -08001223 struct fc_lport *lport = rdata->local_port;
1224
1225 struct fc_frame_header *fh;
1226 struct fc_seq_els_data rjt_data;
1227
1228 fh = fc_frame_header_get(fp);
1229
Joe Eykholt9fb9d322009-08-25 14:00:50 -07001230 FC_RPORT_DBG(rdata, "Received PRLO request while in state %s\n",
1231 fc_rport_state(rdata));
Robert Love42e9a922008-12-09 15:10:17 -08001232
Joe Eykholt14194052009-07-29 17:04:43 -07001233 if (rdata->rp_state == RPORT_ST_DELETE) {
Abhijeet Joglekarb4c6f542009-04-21 16:27:04 -07001234 fc_frame_free(fp);
1235 return;
1236 }
1237
Robert Love42e9a922008-12-09 15:10:17 -08001238 rjt_data.fp = NULL;
1239 rjt_data.reason = ELS_RJT_UNAB;
1240 rjt_data.explan = ELS_EXPL_NONE;
1241 lport->tt.seq_els_rsp_send(sp, ELS_LS_RJT, &rjt_data);
1242 fc_frame_free(fp);
1243}
1244
1245/**
Robert Love34f42a02009-02-27 10:55:45 -08001246 * fc_rport_recv_logo_req() - Handle incoming Logout (LOGO) request
Joe Eykholt9fb9d322009-08-25 14:00:50 -07001247 * @rdata: private remote port data
Robert Love42e9a922008-12-09 15:10:17 -08001248 * @sp: current sequence in the LOGO exchange
1249 * @fp: LOGO request frame
1250 *
1251 * Locking Note: The rport lock is exected to be held before calling
1252 * this function.
1253 */
Joe Eykholt9fb9d322009-08-25 14:00:50 -07001254static void fc_rport_recv_logo_req(struct fc_rport_priv *rdata,
1255 struct fc_seq *sp,
Robert Love42e9a922008-12-09 15:10:17 -08001256 struct fc_frame *fp)
1257{
1258 struct fc_frame_header *fh;
Robert Love42e9a922008-12-09 15:10:17 -08001259 struct fc_lport *lport = rdata->local_port;
1260
1261 fh = fc_frame_header_get(fp);
1262
Joe Eykholt9fb9d322009-08-25 14:00:50 -07001263 FC_RPORT_DBG(rdata, "Received LOGO request while in state %s\n",
1264 fc_rport_state(rdata));
Robert Love42e9a922008-12-09 15:10:17 -08001265
Joe Eykholt14194052009-07-29 17:04:43 -07001266 if (rdata->rp_state == RPORT_ST_DELETE) {
Abhijeet Joglekarb4c6f542009-04-21 16:27:04 -07001267 fc_frame_free(fp);
1268 return;
1269 }
1270
Joe Eykholt00fea932009-08-25 14:01:23 -07001271 fc_rport_enter_delete(rdata, RPORT_EV_LOGO);
Robert Love42e9a922008-12-09 15:10:17 -08001272
1273 lport->tt.seq_els_rsp_send(sp, ELS_LS_ACC, NULL);
1274 fc_frame_free(fp);
1275}
1276
1277static void fc_rport_flush_queue(void)
1278{
1279 flush_workqueue(rport_event_queue);
1280}
1281
Robert Love42e9a922008-12-09 15:10:17 -08001282int fc_rport_init(struct fc_lport *lport)
1283{
Robert Love5101ff92009-02-27 10:55:18 -08001284 if (!lport->tt.rport_create)
Joe Eykholt9e9d0452009-08-25 14:01:18 -07001285 lport->tt.rport_create = fc_rport_create;
Robert Love5101ff92009-02-27 10:55:18 -08001286
Robert Love42e9a922008-12-09 15:10:17 -08001287 if (!lport->tt.rport_login)
1288 lport->tt.rport_login = fc_rport_login;
1289
1290 if (!lport->tt.rport_logoff)
1291 lport->tt.rport_logoff = fc_rport_logoff;
1292
1293 if (!lport->tt.rport_recv_req)
1294 lport->tt.rport_recv_req = fc_rport_recv_req;
1295
1296 if (!lport->tt.rport_flush_queue)
1297 lport->tt.rport_flush_queue = fc_rport_flush_queue;
1298
Joe Eykholtf211fa52009-08-25 14:01:01 -07001299 if (!lport->tt.rport_destroy)
1300 lport->tt.rport_destroy = fc_rport_destroy;
1301
Robert Love42e9a922008-12-09 15:10:17 -08001302 return 0;
1303}
1304EXPORT_SYMBOL(fc_rport_init);
1305
Randy Dunlapb0d428a2009-04-27 21:49:31 -07001306int fc_setup_rport(void)
Robert Love42e9a922008-12-09 15:10:17 -08001307{
1308 rport_event_queue = create_singlethread_workqueue("fc_rport_eq");
1309 if (!rport_event_queue)
1310 return -ENOMEM;
1311 return 0;
1312}
1313EXPORT_SYMBOL(fc_setup_rport);
1314
Randy Dunlapb0d428a2009-04-27 21:49:31 -07001315void fc_destroy_rport(void)
Robert Love42e9a922008-12-09 15:10:17 -08001316{
1317 destroy_workqueue(rport_event_queue);
1318}
1319EXPORT_SYMBOL(fc_destroy_rport);
1320
1321void fc_rport_terminate_io(struct fc_rport *rport)
1322{
Joe Eykholtab28f1f2009-08-25 14:00:34 -07001323 struct fc_rport_libfc_priv *rp = rport->dd_data;
1324 struct fc_lport *lport = rp->local_port;
Robert Love42e9a922008-12-09 15:10:17 -08001325
Abhijeet Joglekar1f6ff362009-02-27 10:54:35 -08001326 lport->tt.exch_mgr_reset(lport, 0, rport->port_id);
1327 lport->tt.exch_mgr_reset(lport, rport->port_id, 0);
Robert Love42e9a922008-12-09 15:10:17 -08001328}
1329EXPORT_SYMBOL(fc_rport_terminate_io);