blob: a9087b31bce9190b53b59c4a8f857dbd44e71e1a [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 *
Joe Eykholt48f00902009-08-25 14:01:50 -070094 * Locking note: must be called with the disc_mutex held.
Joe Eykholt9e9d0452009-08-25 14:01:18 -070095 */
96static struct fc_rport_priv *fc_rport_create(struct fc_lport *lport,
97 struct fc_rport_identifiers *ids)
Robert Love42e9a922008-12-09 15:10:17 -080098{
Joe Eykholtab28f1f2009-08-25 14:00:34 -070099 struct fc_rport_priv *rdata;
Robert Love42e9a922008-12-09 15:10:17 -0800100
Joe Eykholt9e9d0452009-08-25 14:01:18 -0700101 rdata = kzalloc(sizeof(*rdata), GFP_KERNEL);
102 if (!rdata)
Robert Love42e9a922008-12-09 15:10:17 -0800103 return NULL;
104
Joe Eykholtf211fa52009-08-25 14:01:01 -0700105 rdata->ids = *ids;
106 kref_init(&rdata->kref);
Robert Love42e9a922008-12-09 15:10:17 -0800107 mutex_init(&rdata->rp_mutex);
Joe Eykholt795d86f2009-08-25 14:00:39 -0700108 rdata->local_port = lport;
Robert Love42e9a922008-12-09 15:10:17 -0800109 rdata->rp_state = RPORT_ST_INIT;
110 rdata->event = RPORT_EV_NONE;
111 rdata->flags = FC_RP_FLAGS_REC_SUPPORTED;
Joe Eykholt795d86f2009-08-25 14:00:39 -0700112 rdata->e_d_tov = lport->e_d_tov;
113 rdata->r_a_tov = lport->r_a_tov;
Joe Eykholtf211fa52009-08-25 14:01:01 -0700114 rdata->maxframe_size = FC_MIN_MAX_PAYLOAD;
Robert Love42e9a922008-12-09 15:10:17 -0800115 INIT_DELAYED_WORK(&rdata->retry_work, fc_rport_timeout);
116 INIT_WORK(&rdata->event_work, fc_rport_work);
Joe Eykholt48f00902009-08-25 14:01:50 -0700117 if (ids->port_id != FC_FID_DIR_SERV)
118 list_add(&rdata->peers, &lport->disc.rports);
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700119 return rdata;
Robert Love42e9a922008-12-09 15:10:17 -0800120}
121
122/**
Joe Eykholtf211fa52009-08-25 14:01:01 -0700123 * fc_rport_destroy() - free a remote port after last reference is released.
124 * @kref: pointer to kref inside struct fc_rport_priv
125 */
126static void fc_rport_destroy(struct kref *kref)
127{
128 struct fc_rport_priv *rdata;
Joe Eykholtf211fa52009-08-25 14:01:01 -0700129
130 rdata = container_of(kref, struct fc_rport_priv, kref);
Joe Eykholt9e9d0452009-08-25 14:01:18 -0700131 kfree(rdata);
Joe Eykholtf211fa52009-08-25 14:01:01 -0700132}
133
134/**
Robert Love34f42a02009-02-27 10:55:45 -0800135 * fc_rport_state() - return a string for the state the rport is in
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700136 * @rdata: remote port private data
Robert Love42e9a922008-12-09 15:10:17 -0800137 */
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700138static const char *fc_rport_state(struct fc_rport_priv *rdata)
Robert Love42e9a922008-12-09 15:10:17 -0800139{
140 const char *cp;
Robert Love42e9a922008-12-09 15:10:17 -0800141
142 cp = fc_rport_state_names[rdata->rp_state];
143 if (!cp)
144 cp = "Unknown";
145 return cp;
146}
147
148/**
Robert Love34f42a02009-02-27 10:55:45 -0800149 * fc_set_rport_loss_tmo() - Set the remote port loss timeout in seconds.
Robert Love42e9a922008-12-09 15:10:17 -0800150 * @rport: Pointer to Fibre Channel remote port structure
151 * @timeout: timeout in seconds
152 */
153void fc_set_rport_loss_tmo(struct fc_rport *rport, u32 timeout)
154{
155 if (timeout)
156 rport->dev_loss_tmo = timeout + 5;
157 else
158 rport->dev_loss_tmo = 30;
159}
160EXPORT_SYMBOL(fc_set_rport_loss_tmo);
161
162/**
Robert Love34f42a02009-02-27 10:55:45 -0800163 * fc_plogi_get_maxframe() - Get max payload from the common service parameters
Robert Love42e9a922008-12-09 15:10:17 -0800164 * @flp: FLOGI payload structure
165 * @maxval: upper limit, may be less than what is in the service parameters
166 */
Robert Loveb2ab99c2009-02-27 10:55:50 -0800167static unsigned int fc_plogi_get_maxframe(struct fc_els_flogi *flp,
168 unsigned int maxval)
Robert Love42e9a922008-12-09 15:10:17 -0800169{
170 unsigned int mfs;
171
172 /*
173 * Get max payload from the common service parameters and the
174 * class 3 receive data field size.
175 */
176 mfs = ntohs(flp->fl_csp.sp_bb_data) & FC_SP_BB_DATA_MASK;
177 if (mfs >= FC_SP_MIN_MAX_PAYLOAD && mfs < maxval)
178 maxval = mfs;
179 mfs = ntohs(flp->fl_cssp[3 - 1].cp_rdfs);
180 if (mfs >= FC_SP_MIN_MAX_PAYLOAD && mfs < maxval)
181 maxval = mfs;
182 return maxval;
183}
184
185/**
Robert Love34f42a02009-02-27 10:55:45 -0800186 * fc_rport_state_enter() - Change the rport's state
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700187 * @rdata: The rport whose state should change
Robert Love42e9a922008-12-09 15:10:17 -0800188 * @new: The new state of the rport
189 *
190 * Locking Note: Called with the rport lock held
191 */
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700192static void fc_rport_state_enter(struct fc_rport_priv *rdata,
Robert Love42e9a922008-12-09 15:10:17 -0800193 enum fc_rport_state new)
194{
Robert Love42e9a922008-12-09 15:10:17 -0800195 if (rdata->rp_state != new)
196 rdata->retries = 0;
197 rdata->rp_state = new;
198}
199
200static void fc_rport_work(struct work_struct *work)
201{
Abhijeet Joglekar571f8242009-02-27 10:54:41 -0800202 u32 port_id;
Joe Eykholtab28f1f2009-08-25 14:00:34 -0700203 struct fc_rport_priv *rdata =
204 container_of(work, struct fc_rport_priv, event_work);
Joe Eykholt9e9d0452009-08-25 14:01:18 -0700205 struct fc_rport_libfc_priv *rp;
Robert Love42e9a922008-12-09 15:10:17 -0800206 enum fc_rport_event event;
Robert Love42e9a922008-12-09 15:10:17 -0800207 struct fc_lport *lport = rdata->local_port;
208 struct fc_rport_operations *rport_ops;
Joe Eykholt629f4422009-08-25 14:01:06 -0700209 struct fc_rport_identifiers ids;
Joe Eykholtf211fa52009-08-25 14:01:01 -0700210 struct fc_rport *rport;
Robert Love42e9a922008-12-09 15:10:17 -0800211
212 mutex_lock(&rdata->rp_mutex);
213 event = rdata->event;
214 rport_ops = rdata->ops;
Joe Eykholtf211fa52009-08-25 14:01:01 -0700215 rport = rdata->rport;
Robert Love42e9a922008-12-09 15:10:17 -0800216
Joe Eykholt9e9d0452009-08-25 14:01:18 -0700217 FC_RPORT_DBG(rdata, "work event %u\n", event);
218
Joe Eykholt629f4422009-08-25 14:01:06 -0700219 switch (event) {
Joe Eykholt4c0f62b2009-08-25 14:01:12 -0700220 case RPORT_EV_READY:
Joe Eykholtf211fa52009-08-25 14:01:01 -0700221 ids = rdata->ids;
Joe Eykholt5f7ea3b2009-07-29 17:04:49 -0700222 rdata->event = RPORT_EV_NONE;
Joe Eykholt9e9d0452009-08-25 14:01:18 -0700223 kref_get(&rdata->kref);
Robert Love42e9a922008-12-09 15:10:17 -0800224 mutex_unlock(&rdata->rp_mutex);
225
Joe Eykholt9e9d0452009-08-25 14:01:18 -0700226 if (!rport)
227 rport = fc_remote_port_add(lport->host, 0, &ids);
228 if (!rport) {
229 FC_RPORT_DBG(rdata, "Failed to add the rport\n");
230 lport->tt.rport_logoff(rdata);
231 kref_put(&rdata->kref, lport->tt.rport_destroy);
232 return;
Robert Love42e9a922008-12-09 15:10:17 -0800233 }
Joe Eykholt9e9d0452009-08-25 14:01:18 -0700234 mutex_lock(&rdata->rp_mutex);
235 if (rdata->rport)
236 FC_RPORT_DBG(rdata, "rport already allocated\n");
237 rdata->rport = rport;
238 rport->maxframe_size = rdata->maxframe_size;
239 rport->supported_classes = rdata->supported_classes;
240
241 rp = rport->dd_data;
242 rp->local_port = lport;
243 rp->rp_state = rdata->rp_state;
244 rp->flags = rdata->flags;
245 rp->e_d_tov = rdata->e_d_tov;
246 rp->r_a_tov = rdata->r_a_tov;
247 mutex_unlock(&rdata->rp_mutex);
248
249 if (rport_ops->event_callback) {
250 FC_RPORT_DBG(rdata, "callback ev %d\n", event);
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700251 rport_ops->event_callback(lport, rdata, event);
Joe Eykholt9e9d0452009-08-25 14:01:18 -0700252 }
253 kref_put(&rdata->kref, lport->tt.rport_destroy);
Joe Eykholt629f4422009-08-25 14:01:06 -0700254 break;
255
256 case RPORT_EV_FAILED:
257 case RPORT_EV_LOGO:
258 case RPORT_EV_STOP:
Joe Eykholt9e9d0452009-08-25 14:01:18 -0700259 port_id = rdata->ids.port_id;
Robert Love42e9a922008-12-09 15:10:17 -0800260 mutex_unlock(&rdata->rp_mutex);
Joe Eykholt9e9d0452009-08-25 14:01:18 -0700261
Joe Eykholt48f00902009-08-25 14:01:50 -0700262 if (port_id != FC_FID_DIR_SERV) {
263 mutex_lock(&lport->disc.disc_mutex);
264 list_del(&rdata->peers);
265 mutex_unlock(&lport->disc.disc_mutex);
266 }
267
Joe Eykholt9e9d0452009-08-25 14:01:18 -0700268 if (rport_ops->event_callback) {
269 FC_RPORT_DBG(rdata, "callback ev %d\n", event);
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700270 rport_ops->event_callback(lport, rdata, event);
Abhijeet Joglekar571f8242009-02-27 10:54:41 -0800271 }
Joe Eykholt9e9d0452009-08-25 14:01:18 -0700272 cancel_delayed_work_sync(&rdata->retry_work);
273
274 /*
275 * Reset any outstanding exchanges before freeing rport.
276 */
277 lport->tt.exch_mgr_reset(lport, 0, port_id);
278 lport->tt.exch_mgr_reset(lport, port_id, 0);
279
280 if (rport) {
281 rp = rport->dd_data;
282 rp->rp_state = RPORT_ST_DELETE;
283 mutex_lock(&rdata->rp_mutex);
284 rdata->rport = NULL;
285 mutex_unlock(&rdata->rp_mutex);
286 fc_remote_port_delete(rport);
287 }
288 kref_put(&rdata->kref, lport->tt.rport_destroy);
Joe Eykholt629f4422009-08-25 14:01:06 -0700289 break;
290
291 default:
Robert Love42e9a922008-12-09 15:10:17 -0800292 mutex_unlock(&rdata->rp_mutex);
Joe Eykholt629f4422009-08-25 14:01:06 -0700293 break;
294 }
Robert Love42e9a922008-12-09 15:10:17 -0800295}
296
297/**
Robert Love34f42a02009-02-27 10:55:45 -0800298 * fc_rport_login() - Start the remote port login state machine
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700299 * @rdata: private remote port
Robert Love42e9a922008-12-09 15:10:17 -0800300 *
301 * Locking Note: Called without the rport lock held. This
302 * function will hold the rport lock, call an _enter_*
303 * function and then unlock the rport.
304 */
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700305int fc_rport_login(struct fc_rport_priv *rdata)
Robert Love42e9a922008-12-09 15:10:17 -0800306{
Robert Love42e9a922008-12-09 15:10:17 -0800307 mutex_lock(&rdata->rp_mutex);
308
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700309 FC_RPORT_DBG(rdata, "Login to port\n");
Robert Love42e9a922008-12-09 15:10:17 -0800310
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700311 fc_rport_enter_plogi(rdata);
Robert Love42e9a922008-12-09 15:10:17 -0800312
313 mutex_unlock(&rdata->rp_mutex);
314
315 return 0;
316}
317
318/**
Joe Eykholt5f7ea3b2009-07-29 17:04:49 -0700319 * fc_rport_enter_delete() - schedule a remote port to be deleted.
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700320 * @rdata: private remote port
Joe Eykholt5f7ea3b2009-07-29 17:04:49 -0700321 * @event: event to report as the reason for deletion
322 *
323 * Locking Note: Called with the rport lock held.
324 *
325 * Allow state change into DELETE only once.
326 *
327 * Call queue_work only if there's no event already pending.
328 * Set the new event so that the old pending event will not occur.
329 * Since we have the mutex, even if fc_rport_work() is already started,
330 * it'll see the new event.
331 */
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700332static void fc_rport_enter_delete(struct fc_rport_priv *rdata,
Joe Eykholt5f7ea3b2009-07-29 17:04:49 -0700333 enum fc_rport_event event)
334{
Joe Eykholt5f7ea3b2009-07-29 17:04:49 -0700335 if (rdata->rp_state == RPORT_ST_DELETE)
336 return;
337
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700338 FC_RPORT_DBG(rdata, "Delete port\n");
Joe Eykholt5f7ea3b2009-07-29 17:04:49 -0700339
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700340 fc_rport_state_enter(rdata, RPORT_ST_DELETE);
Joe Eykholt5f7ea3b2009-07-29 17:04:49 -0700341
342 if (rdata->event == RPORT_EV_NONE)
343 queue_work(rport_event_queue, &rdata->event_work);
344 rdata->event = event;
345}
346
347/**
Robert Love34f42a02009-02-27 10:55:45 -0800348 * fc_rport_logoff() - Logoff and remove an rport
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700349 * @rdata: private remote port
Robert Love42e9a922008-12-09 15:10:17 -0800350 *
351 * Locking Note: Called without the rport lock held. This
352 * function will hold the rport lock, call an _enter_*
353 * function and then unlock the rport.
354 */
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700355int fc_rport_logoff(struct fc_rport_priv *rdata)
Robert Love42e9a922008-12-09 15:10:17 -0800356{
Robert Love42e9a922008-12-09 15:10:17 -0800357 mutex_lock(&rdata->rp_mutex);
358
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700359 FC_RPORT_DBG(rdata, "Remove port\n");
Robert Love42e9a922008-12-09 15:10:17 -0800360
Joe Eykholt14194052009-07-29 17:04:43 -0700361 if (rdata->rp_state == RPORT_ST_DELETE) {
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700362 FC_RPORT_DBG(rdata, "Port in Delete state, not removing\n");
Abhijeet Joglekarb4c6f542009-04-21 16:27:04 -0700363 mutex_unlock(&rdata->rp_mutex);
364 goto out;
365 }
366
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700367 fc_rport_enter_logo(rdata);
Robert Love42e9a922008-12-09 15:10:17 -0800368
369 /*
Joe Eykholt14194052009-07-29 17:04:43 -0700370 * Change the state to Delete so that we discard
Robert Love42e9a922008-12-09 15:10:17 -0800371 * the response.
372 */
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700373 fc_rport_enter_delete(rdata, RPORT_EV_STOP);
Robert Love42e9a922008-12-09 15:10:17 -0800374 mutex_unlock(&rdata->rp_mutex);
375
Abhijeet Joglekarb4c6f542009-04-21 16:27:04 -0700376out:
Robert Love42e9a922008-12-09 15:10:17 -0800377 return 0;
378}
379
380/**
Robert Love34f42a02009-02-27 10:55:45 -0800381 * fc_rport_enter_ready() - The rport is ready
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700382 * @rdata: private remote port
Robert Love42e9a922008-12-09 15:10:17 -0800383 *
384 * Locking Note: The rport lock is expected to be held before calling
385 * this routine.
386 */
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700387static void fc_rport_enter_ready(struct fc_rport_priv *rdata)
Robert Love42e9a922008-12-09 15:10:17 -0800388{
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700389 fc_rport_state_enter(rdata, RPORT_ST_READY);
Robert Love42e9a922008-12-09 15:10:17 -0800390
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700391 FC_RPORT_DBG(rdata, "Port is Ready\n");
Robert Love42e9a922008-12-09 15:10:17 -0800392
Joe Eykholt5f7ea3b2009-07-29 17:04:49 -0700393 if (rdata->event == RPORT_EV_NONE)
394 queue_work(rport_event_queue, &rdata->event_work);
Joe Eykholt4c0f62b2009-08-25 14:01:12 -0700395 rdata->event = RPORT_EV_READY;
Robert Love42e9a922008-12-09 15:10:17 -0800396}
397
398/**
Robert Love34f42a02009-02-27 10:55:45 -0800399 * fc_rport_timeout() - Handler for the retry_work timer.
Joe Eykholtab28f1f2009-08-25 14:00:34 -0700400 * @work: The work struct of the fc_rport_priv
Robert Love42e9a922008-12-09 15:10:17 -0800401 *
402 * Locking Note: Called without the rport lock held. This
403 * function will hold the rport lock, call an _enter_*
404 * function and then unlock the rport.
405 */
406static void fc_rport_timeout(struct work_struct *work)
407{
Joe Eykholtab28f1f2009-08-25 14:00:34 -0700408 struct fc_rport_priv *rdata =
409 container_of(work, struct fc_rport_priv, retry_work.work);
Robert Love42e9a922008-12-09 15:10:17 -0800410
411 mutex_lock(&rdata->rp_mutex);
412
413 switch (rdata->rp_state) {
414 case RPORT_ST_PLOGI:
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700415 fc_rport_enter_plogi(rdata);
Robert Love42e9a922008-12-09 15:10:17 -0800416 break;
417 case RPORT_ST_PRLI:
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700418 fc_rport_enter_prli(rdata);
Robert Love42e9a922008-12-09 15:10:17 -0800419 break;
420 case RPORT_ST_RTV:
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700421 fc_rport_enter_rtv(rdata);
Robert Love42e9a922008-12-09 15:10:17 -0800422 break;
423 case RPORT_ST_LOGO:
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700424 fc_rport_enter_logo(rdata);
Robert Love42e9a922008-12-09 15:10:17 -0800425 break;
426 case RPORT_ST_READY:
427 case RPORT_ST_INIT:
Joe Eykholt14194052009-07-29 17:04:43 -0700428 case RPORT_ST_DELETE:
Robert Love42e9a922008-12-09 15:10:17 -0800429 break;
430 }
431
432 mutex_unlock(&rdata->rp_mutex);
Robert Love42e9a922008-12-09 15:10:17 -0800433}
434
435/**
Robert Love34f42a02009-02-27 10:55:45 -0800436 * fc_rport_error() - Error handler, called once retries have been exhausted
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700437 * @rdata: private remote port
Robert Love42e9a922008-12-09 15:10:17 -0800438 * @fp: The frame pointer
439 *
Robert Love42e9a922008-12-09 15:10:17 -0800440 * Locking Note: The rport lock is expected to be held before
441 * calling this routine
442 */
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700443static void fc_rport_error(struct fc_rport_priv *rdata, struct fc_frame *fp)
Robert Love42e9a922008-12-09 15:10:17 -0800444{
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700445 FC_RPORT_DBG(rdata, "Error %ld in state %s, retries %d\n",
Joe Eykholtcdbe6df2009-08-25 14:01:39 -0700446 IS_ERR(fp) ? -PTR_ERR(fp) : 0,
447 fc_rport_state(rdata), rdata->retries);
Robert Love42e9a922008-12-09 15:10:17 -0800448
Chris Leech6755db12009-02-27 10:55:02 -0800449 switch (rdata->rp_state) {
450 case RPORT_ST_PLOGI:
451 case RPORT_ST_PRLI:
452 case RPORT_ST_LOGO:
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700453 fc_rport_enter_delete(rdata, RPORT_EV_FAILED);
Chris Leech6755db12009-02-27 10:55:02 -0800454 break;
455 case RPORT_ST_RTV:
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700456 fc_rport_enter_ready(rdata);
Chris Leech6755db12009-02-27 10:55:02 -0800457 break;
Joe Eykholt14194052009-07-29 17:04:43 -0700458 case RPORT_ST_DELETE:
Chris Leech6755db12009-02-27 10:55:02 -0800459 case RPORT_ST_READY:
460 case RPORT_ST_INIT:
461 break;
Robert Love42e9a922008-12-09 15:10:17 -0800462 }
463}
464
465/**
Robert Love34f42a02009-02-27 10:55:45 -0800466 * fc_rport_error_retry() - Error handler when retries are desired
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700467 * @rdata: private remote port data
Chris Leech6755db12009-02-27 10:55:02 -0800468 * @fp: The frame pointer
469 *
470 * If the error was an exchange timeout retry immediately,
471 * otherwise wait for E_D_TOV.
472 *
473 * Locking Note: The rport lock is expected to be held before
474 * calling this routine
475 */
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700476static void fc_rport_error_retry(struct fc_rport_priv *rdata,
477 struct fc_frame *fp)
Chris Leech6755db12009-02-27 10:55:02 -0800478{
Chris Leech6755db12009-02-27 10:55:02 -0800479 unsigned long delay = FC_DEF_E_D_TOV;
480
481 /* make sure this isn't an FC_EX_CLOSED error, never retry those */
482 if (PTR_ERR(fp) == -FC_EX_CLOSED)
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700483 return fc_rport_error(rdata, fp);
Chris Leech6755db12009-02-27 10:55:02 -0800484
Abhijeet Joglekara3666952009-05-01 10:01:26 -0700485 if (rdata->retries < rdata->local_port->max_rport_retry_count) {
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700486 FC_RPORT_DBG(rdata, "Error %ld in state %s, retrying\n",
487 PTR_ERR(fp), fc_rport_state(rdata));
Chris Leech6755db12009-02-27 10:55:02 -0800488 rdata->retries++;
489 /* no additional delay on exchange timeouts */
490 if (PTR_ERR(fp) == -FC_EX_TIMEOUT)
491 delay = 0;
Chris Leech6755db12009-02-27 10:55:02 -0800492 schedule_delayed_work(&rdata->retry_work, delay);
493 return;
494 }
495
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700496 return fc_rport_error(rdata, fp);
Chris Leech6755db12009-02-27 10:55:02 -0800497}
498
499/**
Robert Love34f42a02009-02-27 10:55:45 -0800500 * fc_rport_plogi_recv_resp() - Handle incoming ELS PLOGI response
Robert Love42e9a922008-12-09 15:10:17 -0800501 * @sp: current sequence in the PLOGI exchange
502 * @fp: response frame
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700503 * @rdata_arg: private remote port data
Robert Love42e9a922008-12-09 15:10:17 -0800504 *
505 * Locking Note: This function will be called without the rport lock
506 * held, but it will lock, call an _enter_* function or fc_rport_error
507 * and then unlock the rport.
508 */
509static void fc_rport_plogi_resp(struct fc_seq *sp, struct fc_frame *fp,
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700510 void *rdata_arg)
Robert Love42e9a922008-12-09 15:10:17 -0800511{
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700512 struct fc_rport_priv *rdata = rdata_arg;
Robert Love42e9a922008-12-09 15:10:17 -0800513 struct fc_lport *lport = rdata->local_port;
Robert Lovea29e7642009-04-21 16:27:41 -0700514 struct fc_els_flogi *plp = NULL;
Robert Love42e9a922008-12-09 15:10:17 -0800515 unsigned int tov;
516 u16 csp_seq;
517 u16 cssp_seq;
518 u8 op;
519
520 mutex_lock(&rdata->rp_mutex);
521
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700522 FC_RPORT_DBG(rdata, "Received a PLOGI response\n");
Robert Love42e9a922008-12-09 15:10:17 -0800523
524 if (rdata->rp_state != RPORT_ST_PLOGI) {
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700525 FC_RPORT_DBG(rdata, "Received a PLOGI response, but in state "
526 "%s\n", fc_rport_state(rdata));
Abhijeet Joglekar76f68042009-04-21 16:26:58 -0700527 if (IS_ERR(fp))
528 goto err;
Robert Love42e9a922008-12-09 15:10:17 -0800529 goto out;
530 }
531
Abhijeet Joglekar76f68042009-04-21 16:26:58 -0700532 if (IS_ERR(fp)) {
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700533 fc_rport_error_retry(rdata, fp);
Abhijeet Joglekar76f68042009-04-21 16:26:58 -0700534 goto err;
535 }
536
Robert Love42e9a922008-12-09 15:10:17 -0800537 op = fc_frame_payload_op(fp);
538 if (op == ELS_LS_ACC &&
539 (plp = fc_frame_payload_get(fp, sizeof(*plp))) != NULL) {
Joe Eykholtf211fa52009-08-25 14:01:01 -0700540 rdata->ids.port_name = get_unaligned_be64(&plp->fl_wwpn);
541 rdata->ids.node_name = get_unaligned_be64(&plp->fl_wwnn);
Robert Love42e9a922008-12-09 15:10:17 -0800542
543 tov = ntohl(plp->fl_csp.sp_e_d_tov);
544 if (ntohs(plp->fl_csp.sp_features) & FC_SP_FT_EDTR)
545 tov /= 1000;
546 if (tov > rdata->e_d_tov)
547 rdata->e_d_tov = tov;
548 csp_seq = ntohs(plp->fl_csp.sp_tot_seq);
549 cssp_seq = ntohs(plp->fl_cssp[3 - 1].cp_con_seq);
550 if (cssp_seq < csp_seq)
551 csp_seq = cssp_seq;
552 rdata->max_seq = csp_seq;
Joe Eykholtf211fa52009-08-25 14:01:01 -0700553 rdata->maxframe_size = fc_plogi_get_maxframe(plp, lport->mfs);
Robert Love42e9a922008-12-09 15:10:17 -0800554
555 /*
556 * If the rport is one of the well known addresses
557 * we skip PRLI and RTV and go straight to READY.
558 */
Joe Eykholtf211fa52009-08-25 14:01:01 -0700559 if (rdata->ids.port_id >= FC_FID_DOM_MGR)
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700560 fc_rport_enter_ready(rdata);
Robert Love42e9a922008-12-09 15:10:17 -0800561 else
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700562 fc_rport_enter_prli(rdata);
Robert Love42e9a922008-12-09 15:10:17 -0800563 } else
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700564 fc_rport_error_retry(rdata, fp);
Robert Love42e9a922008-12-09 15:10:17 -0800565
566out:
567 fc_frame_free(fp);
568err:
569 mutex_unlock(&rdata->rp_mutex);
Joe Eykholtf211fa52009-08-25 14:01:01 -0700570 kref_put(&rdata->kref, rdata->local_port->tt.rport_destroy);
Robert Love42e9a922008-12-09 15:10:17 -0800571}
572
573/**
Robert Love34f42a02009-02-27 10:55:45 -0800574 * fc_rport_enter_plogi() - Send Port Login (PLOGI) request to peer
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700575 * @rdata: private remote port data
Robert Love42e9a922008-12-09 15:10:17 -0800576 *
577 * Locking Note: The rport lock is expected to be held before calling
578 * this routine.
579 */
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700580static void fc_rport_enter_plogi(struct fc_rport_priv *rdata)
Robert Love42e9a922008-12-09 15:10:17 -0800581{
Robert Love42e9a922008-12-09 15:10:17 -0800582 struct fc_lport *lport = rdata->local_port;
583 struct fc_frame *fp;
584
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700585 FC_RPORT_DBG(rdata, "Port entered PLOGI state from %s state\n",
586 fc_rport_state(rdata));
Robert Love42e9a922008-12-09 15:10:17 -0800587
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700588 fc_rport_state_enter(rdata, RPORT_ST_PLOGI);
Robert Love42e9a922008-12-09 15:10:17 -0800589
Joe Eykholtf211fa52009-08-25 14:01:01 -0700590 rdata->maxframe_size = FC_MIN_MAX_PAYLOAD;
Robert Love42e9a922008-12-09 15:10:17 -0800591 fp = fc_frame_alloc(lport, sizeof(struct fc_els_flogi));
592 if (!fp) {
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700593 fc_rport_error_retry(rdata, fp);
Robert Love42e9a922008-12-09 15:10:17 -0800594 return;
595 }
596 rdata->e_d_tov = lport->e_d_tov;
597
Joe Eykholtf211fa52009-08-25 14:01:01 -0700598 if (!lport->tt.elsct_send(lport, rdata->ids.port_id, fp, ELS_PLOGI,
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700599 fc_rport_plogi_resp, rdata, lport->e_d_tov))
600 fc_rport_error_retry(rdata, fp);
Robert Love42e9a922008-12-09 15:10:17 -0800601 else
Joe Eykholtf211fa52009-08-25 14:01:01 -0700602 kref_get(&rdata->kref);
Robert Love42e9a922008-12-09 15:10:17 -0800603}
604
605/**
Robert Love34f42a02009-02-27 10:55:45 -0800606 * fc_rport_prli_resp() - Process Login (PRLI) response handler
Robert Love42e9a922008-12-09 15:10:17 -0800607 * @sp: current sequence in the PRLI exchange
608 * @fp: response frame
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700609 * @rdata_arg: private remote port data
Robert Love42e9a922008-12-09 15:10:17 -0800610 *
611 * Locking Note: This function will be called without the rport lock
612 * held, but it will lock, call an _enter_* function or fc_rport_error
613 * and then unlock the rport.
614 */
615static void fc_rport_prli_resp(struct fc_seq *sp, struct fc_frame *fp,
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700616 void *rdata_arg)
Robert Love42e9a922008-12-09 15:10:17 -0800617{
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700618 struct fc_rport_priv *rdata = rdata_arg;
Robert Love42e9a922008-12-09 15:10:17 -0800619 struct {
620 struct fc_els_prli prli;
621 struct fc_els_spp spp;
622 } *pp;
623 u32 roles = FC_RPORT_ROLE_UNKNOWN;
624 u32 fcp_parm = 0;
625 u8 op;
626
627 mutex_lock(&rdata->rp_mutex);
628
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700629 FC_RPORT_DBG(rdata, "Received a PRLI response\n");
Robert Love42e9a922008-12-09 15:10:17 -0800630
631 if (rdata->rp_state != RPORT_ST_PRLI) {
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700632 FC_RPORT_DBG(rdata, "Received a PRLI response, but in state "
633 "%s\n", fc_rport_state(rdata));
Abhijeet Joglekar76f68042009-04-21 16:26:58 -0700634 if (IS_ERR(fp))
635 goto err;
Robert Love42e9a922008-12-09 15:10:17 -0800636 goto out;
637 }
638
Abhijeet Joglekar76f68042009-04-21 16:26:58 -0700639 if (IS_ERR(fp)) {
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700640 fc_rport_error_retry(rdata, fp);
Abhijeet Joglekar76f68042009-04-21 16:26:58 -0700641 goto err;
642 }
643
Robert Love42e9a922008-12-09 15:10:17 -0800644 op = fc_frame_payload_op(fp);
645 if (op == ELS_LS_ACC) {
646 pp = fc_frame_payload_get(fp, sizeof(*pp));
647 if (pp && pp->prli.prli_spp_len >= sizeof(pp->spp)) {
648 fcp_parm = ntohl(pp->spp.spp_params);
649 if (fcp_parm & FCP_SPPF_RETRY)
650 rdata->flags |= FC_RP_FLAGS_RETRY;
651 }
652
Joe Eykholtf211fa52009-08-25 14:01:01 -0700653 rdata->supported_classes = FC_COS_CLASS3;
Robert Love42e9a922008-12-09 15:10:17 -0800654 if (fcp_parm & FCP_SPPF_INIT_FCN)
655 roles |= FC_RPORT_ROLE_FCP_INITIATOR;
656 if (fcp_parm & FCP_SPPF_TARG_FCN)
657 roles |= FC_RPORT_ROLE_FCP_TARGET;
658
Joe Eykholtf211fa52009-08-25 14:01:01 -0700659 rdata->ids.roles = roles;
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700660 fc_rport_enter_rtv(rdata);
Robert Love42e9a922008-12-09 15:10:17 -0800661
662 } else {
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700663 FC_RPORT_DBG(rdata, "Bad ELS response for PRLI command\n");
664 fc_rport_enter_delete(rdata, RPORT_EV_FAILED);
Robert Love42e9a922008-12-09 15:10:17 -0800665 }
666
667out:
668 fc_frame_free(fp);
669err:
670 mutex_unlock(&rdata->rp_mutex);
Joe Eykholtf211fa52009-08-25 14:01:01 -0700671 kref_put(&rdata->kref, rdata->local_port->tt.rport_destroy);
Robert Love42e9a922008-12-09 15:10:17 -0800672}
673
674/**
Robert Love34f42a02009-02-27 10:55:45 -0800675 * fc_rport_logo_resp() - Logout (LOGO) response handler
Robert Love42e9a922008-12-09 15:10:17 -0800676 * @sp: current sequence in the LOGO exchange
677 * @fp: response frame
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700678 * @rdata_arg: private remote port data
Robert Love42e9a922008-12-09 15:10:17 -0800679 *
680 * Locking Note: This function will be called without the rport lock
681 * held, but it will lock, call an _enter_* function or fc_rport_error
682 * and then unlock the rport.
683 */
684static void fc_rport_logo_resp(struct fc_seq *sp, struct fc_frame *fp,
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700685 void *rdata_arg)
Robert Love42e9a922008-12-09 15:10:17 -0800686{
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700687 struct fc_rport_priv *rdata = rdata_arg;
Robert Love42e9a922008-12-09 15:10:17 -0800688 u8 op;
689
690 mutex_lock(&rdata->rp_mutex);
691
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700692 FC_RPORT_DBG(rdata, "Received a LOGO response\n");
Robert Love42e9a922008-12-09 15:10:17 -0800693
Robert Love42e9a922008-12-09 15:10:17 -0800694 if (rdata->rp_state != RPORT_ST_LOGO) {
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700695 FC_RPORT_DBG(rdata, "Received a LOGO response, but in state "
696 "%s\n", fc_rport_state(rdata));
Abhijeet Joglekar76f68042009-04-21 16:26:58 -0700697 if (IS_ERR(fp))
698 goto err;
Robert Love42e9a922008-12-09 15:10:17 -0800699 goto out;
700 }
701
Abhijeet Joglekar76f68042009-04-21 16:26:58 -0700702 if (IS_ERR(fp)) {
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700703 fc_rport_error_retry(rdata, fp);
Abhijeet Joglekar76f68042009-04-21 16:26:58 -0700704 goto err;
705 }
706
Robert Love42e9a922008-12-09 15:10:17 -0800707 op = fc_frame_payload_op(fp);
708 if (op == ELS_LS_ACC) {
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700709 fc_rport_enter_rtv(rdata);
Robert Love42e9a922008-12-09 15:10:17 -0800710 } else {
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700711 FC_RPORT_DBG(rdata, "Bad ELS response for LOGO command\n");
712 fc_rport_enter_delete(rdata, RPORT_EV_LOGO);
Robert Love42e9a922008-12-09 15:10:17 -0800713 }
714
715out:
716 fc_frame_free(fp);
717err:
718 mutex_unlock(&rdata->rp_mutex);
Joe Eykholtf211fa52009-08-25 14:01:01 -0700719 kref_put(&rdata->kref, rdata->local_port->tt.rport_destroy);
Robert Love42e9a922008-12-09 15:10:17 -0800720}
721
722/**
Robert Love34f42a02009-02-27 10:55:45 -0800723 * fc_rport_enter_prli() - Send Process Login (PRLI) request to peer
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700724 * @rdata: private remote port data
Robert Love42e9a922008-12-09 15:10:17 -0800725 *
726 * Locking Note: The rport lock is expected to be held before calling
727 * this routine.
728 */
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700729static void fc_rport_enter_prli(struct fc_rport_priv *rdata)
Robert Love42e9a922008-12-09 15:10:17 -0800730{
Robert Love42e9a922008-12-09 15:10:17 -0800731 struct fc_lport *lport = rdata->local_port;
732 struct {
733 struct fc_els_prli prli;
734 struct fc_els_spp spp;
735 } *pp;
736 struct fc_frame *fp;
737
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700738 FC_RPORT_DBG(rdata, "Port entered PRLI state from %s state\n",
739 fc_rport_state(rdata));
Robert Love42e9a922008-12-09 15:10:17 -0800740
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700741 fc_rport_state_enter(rdata, RPORT_ST_PRLI);
Robert Love42e9a922008-12-09 15:10:17 -0800742
743 fp = fc_frame_alloc(lport, sizeof(*pp));
744 if (!fp) {
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700745 fc_rport_error_retry(rdata, fp);
Robert Love42e9a922008-12-09 15:10:17 -0800746 return;
747 }
748
Joe Eykholtf211fa52009-08-25 14:01:01 -0700749 if (!lport->tt.elsct_send(lport, rdata->ids.port_id, fp, ELS_PRLI,
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700750 fc_rport_prli_resp, rdata, lport->e_d_tov))
751 fc_rport_error_retry(rdata, fp);
Robert Love42e9a922008-12-09 15:10:17 -0800752 else
Joe Eykholtf211fa52009-08-25 14:01:01 -0700753 kref_get(&rdata->kref);
Robert Love42e9a922008-12-09 15:10:17 -0800754}
755
756/**
Robert Love34f42a02009-02-27 10:55:45 -0800757 * fc_rport_els_rtv_resp() - Request Timeout Value response handler
Robert Love42e9a922008-12-09 15:10:17 -0800758 * @sp: current sequence in the RTV exchange
759 * @fp: response frame
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700760 * @rdata_arg: private remote port data
Robert Love42e9a922008-12-09 15:10:17 -0800761 *
762 * Many targets don't seem to support this.
763 *
764 * Locking Note: This function will be called without the rport lock
765 * held, but it will lock, call an _enter_* function or fc_rport_error
766 * and then unlock the rport.
767 */
768static void fc_rport_rtv_resp(struct fc_seq *sp, struct fc_frame *fp,
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700769 void *rdata_arg)
Robert Love42e9a922008-12-09 15:10:17 -0800770{
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700771 struct fc_rport_priv *rdata = rdata_arg;
Robert Love42e9a922008-12-09 15:10:17 -0800772 u8 op;
773
774 mutex_lock(&rdata->rp_mutex);
775
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700776 FC_RPORT_DBG(rdata, "Received a RTV response\n");
Robert Love42e9a922008-12-09 15:10:17 -0800777
778 if (rdata->rp_state != RPORT_ST_RTV) {
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700779 FC_RPORT_DBG(rdata, "Received a RTV response, but in state "
780 "%s\n", fc_rport_state(rdata));
Abhijeet Joglekar76f68042009-04-21 16:26:58 -0700781 if (IS_ERR(fp))
782 goto err;
Robert Love42e9a922008-12-09 15:10:17 -0800783 goto out;
784 }
785
Abhijeet Joglekar76f68042009-04-21 16:26:58 -0700786 if (IS_ERR(fp)) {
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700787 fc_rport_error(rdata, fp);
Abhijeet Joglekar76f68042009-04-21 16:26:58 -0700788 goto err;
789 }
790
Robert Love42e9a922008-12-09 15:10:17 -0800791 op = fc_frame_payload_op(fp);
792 if (op == ELS_LS_ACC) {
793 struct fc_els_rtv_acc *rtv;
794 u32 toq;
795 u32 tov;
796
797 rtv = fc_frame_payload_get(fp, sizeof(*rtv));
798 if (rtv) {
799 toq = ntohl(rtv->rtv_toq);
800 tov = ntohl(rtv->rtv_r_a_tov);
801 if (tov == 0)
802 tov = 1;
803 rdata->r_a_tov = tov;
804 tov = ntohl(rtv->rtv_e_d_tov);
805 if (toq & FC_ELS_RTV_EDRES)
806 tov /= 1000000;
807 if (tov == 0)
808 tov = 1;
809 rdata->e_d_tov = tov;
810 }
811 }
812
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700813 fc_rport_enter_ready(rdata);
Robert Love42e9a922008-12-09 15:10:17 -0800814
815out:
816 fc_frame_free(fp);
817err:
818 mutex_unlock(&rdata->rp_mutex);
Joe Eykholtf211fa52009-08-25 14:01:01 -0700819 kref_put(&rdata->kref, rdata->local_port->tt.rport_destroy);
Robert Love42e9a922008-12-09 15:10:17 -0800820}
821
822/**
Robert Love34f42a02009-02-27 10:55:45 -0800823 * fc_rport_enter_rtv() - Send Request Timeout Value (RTV) request to peer
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700824 * @rdata: private remote port data
Robert Love42e9a922008-12-09 15:10:17 -0800825 *
826 * Locking Note: The rport lock is expected to be held before calling
827 * this routine.
828 */
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700829static void fc_rport_enter_rtv(struct fc_rport_priv *rdata)
Robert Love42e9a922008-12-09 15:10:17 -0800830{
831 struct fc_frame *fp;
Robert Love42e9a922008-12-09 15:10:17 -0800832 struct fc_lport *lport = rdata->local_port;
833
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700834 FC_RPORT_DBG(rdata, "Port entered RTV state from %s state\n",
835 fc_rport_state(rdata));
Robert Love42e9a922008-12-09 15:10:17 -0800836
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700837 fc_rport_state_enter(rdata, RPORT_ST_RTV);
Robert Love42e9a922008-12-09 15:10:17 -0800838
839 fp = fc_frame_alloc(lport, sizeof(struct fc_els_rtv));
840 if (!fp) {
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700841 fc_rport_error_retry(rdata, fp);
Robert Love42e9a922008-12-09 15:10:17 -0800842 return;
843 }
844
Joe Eykholtf211fa52009-08-25 14:01:01 -0700845 if (!lport->tt.elsct_send(lport, rdata->ids.port_id, fp, ELS_RTV,
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700846 fc_rport_rtv_resp, rdata, lport->e_d_tov))
847 fc_rport_error_retry(rdata, fp);
Robert Love42e9a922008-12-09 15:10:17 -0800848 else
Joe Eykholtf211fa52009-08-25 14:01:01 -0700849 kref_get(&rdata->kref);
Robert Love42e9a922008-12-09 15:10:17 -0800850}
851
852/**
Robert Love34f42a02009-02-27 10:55:45 -0800853 * fc_rport_enter_logo() - Send Logout (LOGO) request to peer
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700854 * @rdata: private remote port data
Robert Love42e9a922008-12-09 15:10:17 -0800855 *
856 * Locking Note: The rport lock is expected to be held before calling
857 * this routine.
858 */
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700859static void fc_rport_enter_logo(struct fc_rport_priv *rdata)
Robert Love42e9a922008-12-09 15:10:17 -0800860{
Robert Love42e9a922008-12-09 15:10:17 -0800861 struct fc_lport *lport = rdata->local_port;
862 struct fc_frame *fp;
863
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700864 FC_RPORT_DBG(rdata, "Port entered LOGO state from %s state\n",
865 fc_rport_state(rdata));
Robert Love42e9a922008-12-09 15:10:17 -0800866
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700867 fc_rport_state_enter(rdata, RPORT_ST_LOGO);
Robert Love42e9a922008-12-09 15:10:17 -0800868
869 fp = fc_frame_alloc(lport, sizeof(struct fc_els_logo));
870 if (!fp) {
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700871 fc_rport_error_retry(rdata, fp);
Robert Love42e9a922008-12-09 15:10:17 -0800872 return;
873 }
874
Joe Eykholtf211fa52009-08-25 14:01:01 -0700875 if (!lport->tt.elsct_send(lport, rdata->ids.port_id, fp, ELS_LOGO,
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700876 fc_rport_logo_resp, rdata, lport->e_d_tov))
877 fc_rport_error_retry(rdata, fp);
Robert Love42e9a922008-12-09 15:10:17 -0800878 else
Joe Eykholtf211fa52009-08-25 14:01:01 -0700879 kref_get(&rdata->kref);
Robert Love42e9a922008-12-09 15:10:17 -0800880}
881
882
883/**
Robert Love34f42a02009-02-27 10:55:45 -0800884 * fc_rport_recv_req() - Receive a request from a rport
Robert Love42e9a922008-12-09 15:10:17 -0800885 * @sp: current sequence in the PLOGI exchange
886 * @fp: response frame
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700887 * @rdata_arg: private remote port data
Robert Love42e9a922008-12-09 15:10:17 -0800888 *
889 * Locking Note: Called without the rport lock held. This
890 * function will hold the rport lock, call an _enter_*
891 * function and then unlock the rport.
892 */
893void fc_rport_recv_req(struct fc_seq *sp, struct fc_frame *fp,
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700894 struct fc_rport_priv *rdata)
Robert Love42e9a922008-12-09 15:10:17 -0800895{
Robert Love42e9a922008-12-09 15:10:17 -0800896 struct fc_lport *lport = rdata->local_port;
897
898 struct fc_frame_header *fh;
899 struct fc_seq_els_data els_data;
900 u8 op;
901
902 mutex_lock(&rdata->rp_mutex);
903
904 els_data.fp = NULL;
905 els_data.explan = ELS_EXPL_NONE;
906 els_data.reason = ELS_RJT_NONE;
907
908 fh = fc_frame_header_get(fp);
909
910 if (fh->fh_r_ctl == FC_RCTL_ELS_REQ && fh->fh_type == FC_TYPE_ELS) {
911 op = fc_frame_payload_op(fp);
912 switch (op) {
913 case ELS_PLOGI:
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700914 fc_rport_recv_plogi_req(rdata, sp, fp);
Robert Love42e9a922008-12-09 15:10:17 -0800915 break;
916 case ELS_PRLI:
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700917 fc_rport_recv_prli_req(rdata, sp, fp);
Robert Love42e9a922008-12-09 15:10:17 -0800918 break;
919 case ELS_PRLO:
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700920 fc_rport_recv_prlo_req(rdata, sp, fp);
Robert Love42e9a922008-12-09 15:10:17 -0800921 break;
922 case ELS_LOGO:
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700923 fc_rport_recv_logo_req(rdata, sp, fp);
Robert Love42e9a922008-12-09 15:10:17 -0800924 break;
925 case ELS_RRQ:
926 els_data.fp = fp;
927 lport->tt.seq_els_rsp_send(sp, ELS_RRQ, &els_data);
928 break;
929 case ELS_REC:
930 els_data.fp = fp;
931 lport->tt.seq_els_rsp_send(sp, ELS_REC, &els_data);
932 break;
933 default:
934 els_data.reason = ELS_RJT_UNSUP;
935 lport->tt.seq_els_rsp_send(sp, ELS_LS_RJT, &els_data);
936 break;
937 }
938 }
939
940 mutex_unlock(&rdata->rp_mutex);
941}
942
943/**
Robert Love34f42a02009-02-27 10:55:45 -0800944 * fc_rport_recv_plogi_req() - Handle incoming Port Login (PLOGI) request
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700945 * @rdata: private remote port data
Robert Love42e9a922008-12-09 15:10:17 -0800946 * @sp: current sequence in the PLOGI exchange
947 * @fp: PLOGI request frame
948 *
949 * Locking Note: The rport lock is exected to be held before calling
950 * this function.
951 */
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700952static void fc_rport_recv_plogi_req(struct fc_rport_priv *rdata,
Robert Love42e9a922008-12-09 15:10:17 -0800953 struct fc_seq *sp, struct fc_frame *rx_fp)
954{
Robert Love42e9a922008-12-09 15:10:17 -0800955 struct fc_lport *lport = rdata->local_port;
956 struct fc_frame *fp = rx_fp;
957 struct fc_exch *ep;
958 struct fc_frame_header *fh;
959 struct fc_els_flogi *pl;
960 struct fc_seq_els_data rjt_data;
961 u32 sid;
962 u64 wwpn;
963 u64 wwnn;
964 enum fc_els_rjt_reason reject = 0;
965 u32 f_ctl;
966 rjt_data.fp = NULL;
967
968 fh = fc_frame_header_get(fp);
969
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700970 FC_RPORT_DBG(rdata, "Received PLOGI request while in state %s\n",
971 fc_rport_state(rdata));
Robert Love42e9a922008-12-09 15:10:17 -0800972
973 sid = ntoh24(fh->fh_s_id);
974 pl = fc_frame_payload_get(fp, sizeof(*pl));
975 if (!pl) {
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700976 FC_RPORT_DBG(rdata, "Received PLOGI too short\n");
Robert Love42e9a922008-12-09 15:10:17 -0800977 WARN_ON(1);
978 /* XXX TBD: send reject? */
979 fc_frame_free(fp);
980 return;
981 }
982 wwpn = get_unaligned_be64(&pl->fl_wwpn);
983 wwnn = get_unaligned_be64(&pl->fl_wwnn);
984
985 /*
986 * If the session was just created, possibly due to the incoming PLOGI,
987 * set the state appropriately and accept the PLOGI.
988 *
989 * If we had also sent a PLOGI, and if the received PLOGI is from a
990 * higher WWPN, we accept it, otherwise an LS_RJT is sent with reason
991 * "command already in progress".
992 *
993 * XXX TBD: If the session was ready before, the PLOGI should result in
994 * all outstanding exchanges being reset.
995 */
996 switch (rdata->rp_state) {
997 case RPORT_ST_INIT:
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700998 FC_RPORT_DBG(rdata, "Received PLOGI, wwpn %llx state INIT "
Robert Love74147052009-06-10 15:31:10 -0700999 "- reject\n", (unsigned long long)wwpn);
Robert Love42e9a922008-12-09 15:10:17 -08001000 reject = ELS_RJT_UNSUP;
1001 break;
1002 case RPORT_ST_PLOGI:
Joe Eykholt9fb9d322009-08-25 14:00:50 -07001003 FC_RPORT_DBG(rdata, "Received PLOGI in PLOGI state %d\n",
Robert Love74147052009-06-10 15:31:10 -07001004 rdata->rp_state);
Robert Love42e9a922008-12-09 15:10:17 -08001005 if (wwpn < lport->wwpn)
1006 reject = ELS_RJT_INPROG;
1007 break;
1008 case RPORT_ST_PRLI:
1009 case RPORT_ST_READY:
Joe Eykholt9fb9d322009-08-25 14:00:50 -07001010 FC_RPORT_DBG(rdata, "Received PLOGI in logged-in state %d "
Robert Love74147052009-06-10 15:31:10 -07001011 "- ignored for now\n", rdata->rp_state);
Robert Love42e9a922008-12-09 15:10:17 -08001012 /* XXX TBD - should reset */
1013 break;
Joe Eykholt14194052009-07-29 17:04:43 -07001014 case RPORT_ST_DELETE:
Robert Love42e9a922008-12-09 15:10:17 -08001015 default:
Joe Eykholt9fb9d322009-08-25 14:00:50 -07001016 FC_RPORT_DBG(rdata, "Received PLOGI in unexpected "
Robert Love74147052009-06-10 15:31:10 -07001017 "state %d\n", rdata->rp_state);
Abhijeet Joglekarb4c6f542009-04-21 16:27:04 -07001018 fc_frame_free(fp);
1019 return;
Robert Love42e9a922008-12-09 15:10:17 -08001020 break;
1021 }
1022
1023 if (reject) {
1024 rjt_data.reason = reject;
1025 rjt_data.explan = ELS_EXPL_NONE;
1026 lport->tt.seq_els_rsp_send(sp, ELS_LS_RJT, &rjt_data);
1027 fc_frame_free(fp);
1028 } else {
1029 fp = fc_frame_alloc(lport, sizeof(*pl));
1030 if (fp == NULL) {
1031 fp = rx_fp;
1032 rjt_data.reason = ELS_RJT_UNAB;
1033 rjt_data.explan = ELS_EXPL_NONE;
1034 lport->tt.seq_els_rsp_send(sp, ELS_LS_RJT, &rjt_data);
1035 fc_frame_free(fp);
1036 } else {
1037 sp = lport->tt.seq_start_next(sp);
1038 WARN_ON(!sp);
Joe Eykholtf211fa52009-08-25 14:01:01 -07001039 rdata->ids.port_name = wwpn;
1040 rdata->ids.node_name = wwnn;
Robert Love42e9a922008-12-09 15:10:17 -08001041
1042 /*
1043 * Get session payload size from incoming PLOGI.
1044 */
Joe Eykholtf211fa52009-08-25 14:01:01 -07001045 rdata->maxframe_size =
Robert Love42e9a922008-12-09 15:10:17 -08001046 fc_plogi_get_maxframe(pl, lport->mfs);
1047 fc_frame_free(rx_fp);
1048 fc_plogi_fill(lport, fp, ELS_LS_ACC);
1049
1050 /*
1051 * Send LS_ACC. If this fails,
1052 * the originator should retry.
1053 */
1054 f_ctl = FC_FC_EX_CTX | FC_FC_LAST_SEQ;
1055 f_ctl |= FC_FC_END_SEQ | FC_FC_SEQ_INIT;
1056 ep = fc_seq_exch(sp);
1057 fc_fill_fc_hdr(fp, FC_RCTL_ELS_REP, ep->did, ep->sid,
1058 FC_TYPE_ELS, f_ctl, 0);
1059 lport->tt.seq_send(lport, sp, fp);
1060 if (rdata->rp_state == RPORT_ST_PLOGI)
Joe Eykholt9fb9d322009-08-25 14:00:50 -07001061 fc_rport_enter_prli(rdata);
Robert Love42e9a922008-12-09 15:10:17 -08001062 }
1063 }
1064}
1065
1066/**
Robert Love34f42a02009-02-27 10:55:45 -08001067 * fc_rport_recv_prli_req() - Handle incoming Process Login (PRLI) request
Joe Eykholt9fb9d322009-08-25 14:00:50 -07001068 * @rdata: private remote port data
Robert Love42e9a922008-12-09 15:10:17 -08001069 * @sp: current sequence in the PRLI exchange
1070 * @fp: PRLI request frame
1071 *
1072 * Locking Note: The rport lock is exected to be held before calling
1073 * this function.
1074 */
Joe Eykholt9fb9d322009-08-25 14:00:50 -07001075static void fc_rport_recv_prli_req(struct fc_rport_priv *rdata,
Robert Love42e9a922008-12-09 15:10:17 -08001076 struct fc_seq *sp, struct fc_frame *rx_fp)
1077{
Robert Love42e9a922008-12-09 15:10:17 -08001078 struct fc_lport *lport = rdata->local_port;
1079 struct fc_exch *ep;
1080 struct fc_frame *fp;
1081 struct fc_frame_header *fh;
1082 struct {
1083 struct fc_els_prli prli;
1084 struct fc_els_spp spp;
1085 } *pp;
1086 struct fc_els_spp *rspp; /* request service param page */
1087 struct fc_els_spp *spp; /* response spp */
1088 unsigned int len;
1089 unsigned int plen;
1090 enum fc_els_rjt_reason reason = ELS_RJT_UNAB;
1091 enum fc_els_rjt_explan explan = ELS_EXPL_NONE;
1092 enum fc_els_spp_resp resp;
1093 struct fc_seq_els_data rjt_data;
1094 u32 f_ctl;
1095 u32 fcp_parm;
1096 u32 roles = FC_RPORT_ROLE_UNKNOWN;
1097 rjt_data.fp = NULL;
1098
1099 fh = fc_frame_header_get(rx_fp);
1100
Joe Eykholt9fb9d322009-08-25 14:00:50 -07001101 FC_RPORT_DBG(rdata, "Received PRLI request while in state %s\n",
1102 fc_rport_state(rdata));
Robert Love42e9a922008-12-09 15:10:17 -08001103
1104 switch (rdata->rp_state) {
1105 case RPORT_ST_PRLI:
1106 case RPORT_ST_READY:
1107 reason = ELS_RJT_NONE;
1108 break;
1109 default:
Abhijeet Joglekarb4c6f542009-04-21 16:27:04 -07001110 fc_frame_free(rx_fp);
1111 return;
Robert Love42e9a922008-12-09 15:10:17 -08001112 break;
1113 }
1114 len = fr_len(rx_fp) - sizeof(*fh);
1115 pp = fc_frame_payload_get(rx_fp, sizeof(*pp));
1116 if (pp == NULL) {
1117 reason = ELS_RJT_PROT;
1118 explan = ELS_EXPL_INV_LEN;
1119 } else {
1120 plen = ntohs(pp->prli.prli_len);
1121 if ((plen % 4) != 0 || plen > len) {
1122 reason = ELS_RJT_PROT;
1123 explan = ELS_EXPL_INV_LEN;
1124 } else if (plen < len) {
1125 len = plen;
1126 }
1127 plen = pp->prli.prli_spp_len;
1128 if ((plen % 4) != 0 || plen < sizeof(*spp) ||
1129 plen > len || len < sizeof(*pp)) {
1130 reason = ELS_RJT_PROT;
1131 explan = ELS_EXPL_INV_LEN;
1132 }
1133 rspp = &pp->spp;
1134 }
1135 if (reason != ELS_RJT_NONE ||
1136 (fp = fc_frame_alloc(lport, len)) == NULL) {
1137 rjt_data.reason = reason;
1138 rjt_data.explan = explan;
1139 lport->tt.seq_els_rsp_send(sp, ELS_LS_RJT, &rjt_data);
1140 } else {
1141 sp = lport->tt.seq_start_next(sp);
1142 WARN_ON(!sp);
1143 pp = fc_frame_payload_get(fp, len);
1144 WARN_ON(!pp);
1145 memset(pp, 0, len);
1146 pp->prli.prli_cmd = ELS_LS_ACC;
1147 pp->prli.prli_spp_len = plen;
1148 pp->prli.prli_len = htons(len);
1149 len -= sizeof(struct fc_els_prli);
1150
1151 /*
1152 * Go through all the service parameter pages and build
1153 * response. If plen indicates longer SPP than standard,
1154 * use that. The entire response has been pre-cleared above.
1155 */
1156 spp = &pp->spp;
1157 while (len >= plen) {
1158 spp->spp_type = rspp->spp_type;
1159 spp->spp_type_ext = rspp->spp_type_ext;
1160 spp->spp_flags = rspp->spp_flags & FC_SPP_EST_IMG_PAIR;
1161 resp = FC_SPP_RESP_ACK;
1162 if (rspp->spp_flags & FC_SPP_RPA_VAL)
1163 resp = FC_SPP_RESP_NO_PA;
1164 switch (rspp->spp_type) {
1165 case 0: /* common to all FC-4 types */
1166 break;
1167 case FC_TYPE_FCP:
1168 fcp_parm = ntohl(rspp->spp_params);
1169 if (fcp_parm * FCP_SPPF_RETRY)
1170 rdata->flags |= FC_RP_FLAGS_RETRY;
Joe Eykholtf211fa52009-08-25 14:01:01 -07001171 rdata->supported_classes = FC_COS_CLASS3;
Robert Love42e9a922008-12-09 15:10:17 -08001172 if (fcp_parm & FCP_SPPF_INIT_FCN)
1173 roles |= FC_RPORT_ROLE_FCP_INITIATOR;
1174 if (fcp_parm & FCP_SPPF_TARG_FCN)
1175 roles |= FC_RPORT_ROLE_FCP_TARGET;
Joe Eykholtf211fa52009-08-25 14:01:01 -07001176 rdata->ids.roles = roles;
Robert Love42e9a922008-12-09 15:10:17 -08001177
1178 spp->spp_params =
1179 htonl(lport->service_params);
1180 break;
1181 default:
1182 resp = FC_SPP_RESP_INVL;
1183 break;
1184 }
1185 spp->spp_flags |= resp;
1186 len -= plen;
1187 rspp = (struct fc_els_spp *)((char *)rspp + plen);
1188 spp = (struct fc_els_spp *)((char *)spp + plen);
1189 }
1190
1191 /*
1192 * Send LS_ACC. If this fails, the originator should retry.
1193 */
1194 f_ctl = FC_FC_EX_CTX | FC_FC_LAST_SEQ;
1195 f_ctl |= FC_FC_END_SEQ | FC_FC_SEQ_INIT;
1196 ep = fc_seq_exch(sp);
1197 fc_fill_fc_hdr(fp, FC_RCTL_ELS_REP, ep->did, ep->sid,
1198 FC_TYPE_ELS, f_ctl, 0);
1199 lport->tt.seq_send(lport, sp, fp);
1200
1201 /*
1202 * Get lock and re-check state.
1203 */
1204 switch (rdata->rp_state) {
1205 case RPORT_ST_PRLI:
Joe Eykholt9fb9d322009-08-25 14:00:50 -07001206 fc_rport_enter_ready(rdata);
Robert Love42e9a922008-12-09 15:10:17 -08001207 break;
1208 case RPORT_ST_READY:
1209 break;
1210 default:
1211 break;
1212 }
1213 }
1214 fc_frame_free(rx_fp);
1215}
1216
1217/**
Robert Love34f42a02009-02-27 10:55:45 -08001218 * fc_rport_recv_prlo_req() - Handle incoming Process Logout (PRLO) request
Joe Eykholt9fb9d322009-08-25 14:00:50 -07001219 * @rdata: private remote port data
Robert Love42e9a922008-12-09 15:10:17 -08001220 * @sp: current sequence in the PRLO exchange
1221 * @fp: PRLO request frame
1222 *
1223 * Locking Note: The rport lock is exected to be held before calling
1224 * this function.
1225 */
Joe Eykholt9fb9d322009-08-25 14:00:50 -07001226static void fc_rport_recv_prlo_req(struct fc_rport_priv *rdata,
1227 struct fc_seq *sp,
Robert Love42e9a922008-12-09 15:10:17 -08001228 struct fc_frame *fp)
1229{
Robert Love42e9a922008-12-09 15:10:17 -08001230 struct fc_lport *lport = rdata->local_port;
1231
1232 struct fc_frame_header *fh;
1233 struct fc_seq_els_data rjt_data;
1234
1235 fh = fc_frame_header_get(fp);
1236
Joe Eykholt9fb9d322009-08-25 14:00:50 -07001237 FC_RPORT_DBG(rdata, "Received PRLO request while in state %s\n",
1238 fc_rport_state(rdata));
Robert Love42e9a922008-12-09 15:10:17 -08001239
Joe Eykholt14194052009-07-29 17:04:43 -07001240 if (rdata->rp_state == RPORT_ST_DELETE) {
Abhijeet Joglekarb4c6f542009-04-21 16:27:04 -07001241 fc_frame_free(fp);
1242 return;
1243 }
1244
Robert Love42e9a922008-12-09 15:10:17 -08001245 rjt_data.fp = NULL;
1246 rjt_data.reason = ELS_RJT_UNAB;
1247 rjt_data.explan = ELS_EXPL_NONE;
1248 lport->tt.seq_els_rsp_send(sp, ELS_LS_RJT, &rjt_data);
1249 fc_frame_free(fp);
1250}
1251
1252/**
Robert Love34f42a02009-02-27 10:55:45 -08001253 * fc_rport_recv_logo_req() - Handle incoming Logout (LOGO) request
Joe Eykholt9fb9d322009-08-25 14:00:50 -07001254 * @rdata: private remote port data
Robert Love42e9a922008-12-09 15:10:17 -08001255 * @sp: current sequence in the LOGO exchange
1256 * @fp: LOGO request frame
1257 *
1258 * Locking Note: The rport lock is exected to be held before calling
1259 * this function.
1260 */
Joe Eykholt9fb9d322009-08-25 14:00:50 -07001261static void fc_rport_recv_logo_req(struct fc_rport_priv *rdata,
1262 struct fc_seq *sp,
Robert Love42e9a922008-12-09 15:10:17 -08001263 struct fc_frame *fp)
1264{
1265 struct fc_frame_header *fh;
Robert Love42e9a922008-12-09 15:10:17 -08001266 struct fc_lport *lport = rdata->local_port;
1267
1268 fh = fc_frame_header_get(fp);
1269
Joe Eykholt9fb9d322009-08-25 14:00:50 -07001270 FC_RPORT_DBG(rdata, "Received LOGO request while in state %s\n",
1271 fc_rport_state(rdata));
Robert Love42e9a922008-12-09 15:10:17 -08001272
Joe Eykholt14194052009-07-29 17:04:43 -07001273 if (rdata->rp_state == RPORT_ST_DELETE) {
Abhijeet Joglekarb4c6f542009-04-21 16:27:04 -07001274 fc_frame_free(fp);
1275 return;
1276 }
1277
Joe Eykholt00fea932009-08-25 14:01:23 -07001278 fc_rport_enter_delete(rdata, RPORT_EV_LOGO);
Robert Love42e9a922008-12-09 15:10:17 -08001279
1280 lport->tt.seq_els_rsp_send(sp, ELS_LS_ACC, NULL);
1281 fc_frame_free(fp);
1282}
1283
1284static void fc_rport_flush_queue(void)
1285{
1286 flush_workqueue(rport_event_queue);
1287}
1288
Robert Love42e9a922008-12-09 15:10:17 -08001289int fc_rport_init(struct fc_lport *lport)
1290{
Robert Love5101ff92009-02-27 10:55:18 -08001291 if (!lport->tt.rport_create)
Joe Eykholt9e9d0452009-08-25 14:01:18 -07001292 lport->tt.rport_create = fc_rport_create;
Robert Love5101ff92009-02-27 10:55:18 -08001293
Robert Love42e9a922008-12-09 15:10:17 -08001294 if (!lport->tt.rport_login)
1295 lport->tt.rport_login = fc_rport_login;
1296
1297 if (!lport->tt.rport_logoff)
1298 lport->tt.rport_logoff = fc_rport_logoff;
1299
1300 if (!lport->tt.rport_recv_req)
1301 lport->tt.rport_recv_req = fc_rport_recv_req;
1302
1303 if (!lport->tt.rport_flush_queue)
1304 lport->tt.rport_flush_queue = fc_rport_flush_queue;
1305
Joe Eykholtf211fa52009-08-25 14:01:01 -07001306 if (!lport->tt.rport_destroy)
1307 lport->tt.rport_destroy = fc_rport_destroy;
1308
Robert Love42e9a922008-12-09 15:10:17 -08001309 return 0;
1310}
1311EXPORT_SYMBOL(fc_rport_init);
1312
Randy Dunlapb0d428a2009-04-27 21:49:31 -07001313int fc_setup_rport(void)
Robert Love42e9a922008-12-09 15:10:17 -08001314{
1315 rport_event_queue = create_singlethread_workqueue("fc_rport_eq");
1316 if (!rport_event_queue)
1317 return -ENOMEM;
1318 return 0;
1319}
1320EXPORT_SYMBOL(fc_setup_rport);
1321
Randy Dunlapb0d428a2009-04-27 21:49:31 -07001322void fc_destroy_rport(void)
Robert Love42e9a922008-12-09 15:10:17 -08001323{
1324 destroy_workqueue(rport_event_queue);
1325}
1326EXPORT_SYMBOL(fc_destroy_rport);
1327
1328void fc_rport_terminate_io(struct fc_rport *rport)
1329{
Joe Eykholtab28f1f2009-08-25 14:00:34 -07001330 struct fc_rport_libfc_priv *rp = rport->dd_data;
1331 struct fc_lport *lport = rp->local_port;
Robert Love42e9a922008-12-09 15:10:17 -08001332
Abhijeet Joglekar1f6ff362009-02-27 10:54:35 -08001333 lport->tt.exch_mgr_reset(lport, 0, rport->port_id);
1334 lport->tt.exch_mgr_reset(lport, rport->port_id, 0);
Robert Love42e9a922008-12-09 15:10:17 -08001335}
1336EXPORT_SYMBOL(fc_rport_terminate_io);