blob: 622285c81fef9668ef05340f0a90955b68720ff5 [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 Love8866a5d2009-11-03 11:45:58 -080058#include "fc_libfc.h"
59
Robert Love42e9a922008-12-09 15:10:17 -080060struct workqueue_struct *rport_event_queue;
61
Joe Eykholt9fb9d322009-08-25 14:00:50 -070062static void fc_rport_enter_plogi(struct fc_rport_priv *);
63static void fc_rport_enter_prli(struct fc_rport_priv *);
64static void fc_rport_enter_rtv(struct fc_rport_priv *);
65static void fc_rport_enter_ready(struct fc_rport_priv *);
66static void fc_rport_enter_logo(struct fc_rport_priv *);
Joe Eykholt370c3bd2009-08-25 14:03:47 -070067static void fc_rport_enter_adisc(struct fc_rport_priv *);
Robert Love42e9a922008-12-09 15:10:17 -080068
Joe Eykholt3ac6f982009-08-25 14:03:26 -070069static void fc_rport_recv_plogi_req(struct fc_lport *,
Robert Love42e9a922008-12-09 15:10:17 -080070 struct fc_seq *, struct fc_frame *);
Joe Eykholt9fb9d322009-08-25 14:00:50 -070071static void fc_rport_recv_prli_req(struct fc_rport_priv *,
Robert Love42e9a922008-12-09 15:10:17 -080072 struct fc_seq *, struct fc_frame *);
Joe Eykholt9fb9d322009-08-25 14:00:50 -070073static void fc_rport_recv_prlo_req(struct fc_rport_priv *,
Robert Love42e9a922008-12-09 15:10:17 -080074 struct fc_seq *, struct fc_frame *);
Joe Eykholt83fe6a92009-08-25 14:03:31 -070075static void fc_rport_recv_logo_req(struct fc_lport *,
Robert Love42e9a922008-12-09 15:10:17 -080076 struct fc_seq *, struct fc_frame *);
77static void fc_rport_timeout(struct work_struct *);
Joe Eykholt9fb9d322009-08-25 14:00:50 -070078static void fc_rport_error(struct fc_rport_priv *, struct fc_frame *);
79static void fc_rport_error_retry(struct fc_rport_priv *, struct fc_frame *);
Robert Love42e9a922008-12-09 15:10:17 -080080static void fc_rport_work(struct work_struct *);
81
82static const char *fc_rport_state_names[] = {
Robert Love42e9a922008-12-09 15:10:17 -080083 [RPORT_ST_INIT] = "Init",
84 [RPORT_ST_PLOGI] = "PLOGI",
85 [RPORT_ST_PRLI] = "PRLI",
86 [RPORT_ST_RTV] = "RTV",
87 [RPORT_ST_READY] = "Ready",
88 [RPORT_ST_LOGO] = "LOGO",
Joe Eykholt370c3bd2009-08-25 14:03:47 -070089 [RPORT_ST_ADISC] = "ADISC",
Joe Eykholt14194052009-07-29 17:04:43 -070090 [RPORT_ST_DELETE] = "Delete",
Joe Eykholtb4a9c7e2009-10-21 16:28:30 -070091 [RPORT_ST_RESTART] = "Restart",
Robert Love42e9a922008-12-09 15:10:17 -080092};
93
Joe Eykholt9e9d0452009-08-25 14:01:18 -070094/**
Joe Eykholt8025b5d2009-08-25 14:02:06 -070095 * fc_rport_lookup() - lookup a remote port by port_id
96 * @lport: Fibre Channel host port instance
97 * @port_id: remote port port_id to match
98 */
99static struct fc_rport_priv *fc_rport_lookup(const struct fc_lport *lport,
100 u32 port_id)
101{
102 struct fc_rport_priv *rdata;
103
104 list_for_each_entry(rdata, &lport->disc.rports, peers)
Joe Eykholtb4a9c7e2009-10-21 16:28:30 -0700105 if (rdata->ids.port_id == port_id)
Joe Eykholt8025b5d2009-08-25 14:02:06 -0700106 return rdata;
107 return NULL;
108}
109
110/**
Robert Love9737e6a2009-08-25 14:02:59 -0700111 * fc_rport_create() - Create a new remote port
112 * @lport: The local port that the new remote port is for
113 * @port_id: The port ID for the new remote port
Joe Eykholt9e9d0452009-08-25 14:01:18 -0700114 *
Joe Eykholt48f00902009-08-25 14:01:50 -0700115 * Locking note: must be called with the disc_mutex held.
Joe Eykholt9e9d0452009-08-25 14:01:18 -0700116 */
117static struct fc_rport_priv *fc_rport_create(struct fc_lport *lport,
Robert Love9737e6a2009-08-25 14:02:59 -0700118 u32 port_id)
Robert Love42e9a922008-12-09 15:10:17 -0800119{
Joe Eykholtab28f1f2009-08-25 14:00:34 -0700120 struct fc_rport_priv *rdata;
Robert Love42e9a922008-12-09 15:10:17 -0800121
Robert Love9737e6a2009-08-25 14:02:59 -0700122 rdata = lport->tt.rport_lookup(lport, port_id);
Joe Eykholt19f97e32009-08-25 14:01:55 -0700123 if (rdata)
124 return rdata;
125
Joe Eykholt9e9d0452009-08-25 14:01:18 -0700126 rdata = kzalloc(sizeof(*rdata), GFP_KERNEL);
127 if (!rdata)
Robert Love42e9a922008-12-09 15:10:17 -0800128 return NULL;
129
Robert Love9737e6a2009-08-25 14:02:59 -0700130 rdata->ids.node_name = -1;
131 rdata->ids.port_name = -1;
132 rdata->ids.port_id = port_id;
133 rdata->ids.roles = FC_RPORT_ROLE_UNKNOWN;
134
Joe Eykholtf211fa52009-08-25 14:01:01 -0700135 kref_init(&rdata->kref);
Robert Love42e9a922008-12-09 15:10:17 -0800136 mutex_init(&rdata->rp_mutex);
Joe Eykholt795d86f2009-08-25 14:00:39 -0700137 rdata->local_port = lport;
Robert Love42e9a922008-12-09 15:10:17 -0800138 rdata->rp_state = RPORT_ST_INIT;
139 rdata->event = RPORT_EV_NONE;
140 rdata->flags = FC_RP_FLAGS_REC_SUPPORTED;
Joe Eykholt795d86f2009-08-25 14:00:39 -0700141 rdata->e_d_tov = lport->e_d_tov;
142 rdata->r_a_tov = lport->r_a_tov;
Joe Eykholtf211fa52009-08-25 14:01:01 -0700143 rdata->maxframe_size = FC_MIN_MAX_PAYLOAD;
Robert Love42e9a922008-12-09 15:10:17 -0800144 INIT_DELAYED_WORK(&rdata->retry_work, fc_rport_timeout);
145 INIT_WORK(&rdata->event_work, fc_rport_work);
Robert Love9737e6a2009-08-25 14:02:59 -0700146 if (port_id != FC_FID_DIR_SERV)
Joe Eykholt48f00902009-08-25 14:01:50 -0700147 list_add(&rdata->peers, &lport->disc.rports);
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700148 return rdata;
Robert Love42e9a922008-12-09 15:10:17 -0800149}
150
151/**
Joe Eykholtf211fa52009-08-25 14:01:01 -0700152 * fc_rport_destroy() - free a remote port after last reference is released.
153 * @kref: pointer to kref inside struct fc_rport_priv
154 */
155static void fc_rport_destroy(struct kref *kref)
156{
157 struct fc_rport_priv *rdata;
Joe Eykholtf211fa52009-08-25 14:01:01 -0700158
159 rdata = container_of(kref, struct fc_rport_priv, kref);
Joe Eykholt9e9d0452009-08-25 14:01:18 -0700160 kfree(rdata);
Joe Eykholtf211fa52009-08-25 14:01:01 -0700161}
162
163/**
Robert Love34f42a02009-02-27 10:55:45 -0800164 * fc_rport_state() - return a string for the state the rport is in
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700165 * @rdata: remote port private data
Robert Love42e9a922008-12-09 15:10:17 -0800166 */
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700167static const char *fc_rport_state(struct fc_rport_priv *rdata)
Robert Love42e9a922008-12-09 15:10:17 -0800168{
169 const char *cp;
Robert Love42e9a922008-12-09 15:10:17 -0800170
171 cp = fc_rport_state_names[rdata->rp_state];
172 if (!cp)
173 cp = "Unknown";
174 return cp;
175}
176
177/**
Robert Love34f42a02009-02-27 10:55:45 -0800178 * fc_set_rport_loss_tmo() - Set the remote port loss timeout in seconds.
Robert Love42e9a922008-12-09 15:10:17 -0800179 * @rport: Pointer to Fibre Channel remote port structure
180 * @timeout: timeout in seconds
181 */
182void fc_set_rport_loss_tmo(struct fc_rport *rport, u32 timeout)
183{
184 if (timeout)
185 rport->dev_loss_tmo = timeout + 5;
186 else
187 rport->dev_loss_tmo = 30;
188}
189EXPORT_SYMBOL(fc_set_rport_loss_tmo);
190
191/**
Robert Love34f42a02009-02-27 10:55:45 -0800192 * fc_plogi_get_maxframe() - Get max payload from the common service parameters
Robert Love42e9a922008-12-09 15:10:17 -0800193 * @flp: FLOGI payload structure
194 * @maxval: upper limit, may be less than what is in the service parameters
195 */
Robert Loveb2ab99c2009-02-27 10:55:50 -0800196static unsigned int fc_plogi_get_maxframe(struct fc_els_flogi *flp,
197 unsigned int maxval)
Robert Love42e9a922008-12-09 15:10:17 -0800198{
199 unsigned int mfs;
200
201 /*
202 * Get max payload from the common service parameters and the
203 * class 3 receive data field size.
204 */
205 mfs = ntohs(flp->fl_csp.sp_bb_data) & FC_SP_BB_DATA_MASK;
206 if (mfs >= FC_SP_MIN_MAX_PAYLOAD && mfs < maxval)
207 maxval = mfs;
208 mfs = ntohs(flp->fl_cssp[3 - 1].cp_rdfs);
209 if (mfs >= FC_SP_MIN_MAX_PAYLOAD && mfs < maxval)
210 maxval = mfs;
211 return maxval;
212}
213
214/**
Robert Love34f42a02009-02-27 10:55:45 -0800215 * fc_rport_state_enter() - Change the rport's state
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700216 * @rdata: The rport whose state should change
Robert Love42e9a922008-12-09 15:10:17 -0800217 * @new: The new state of the rport
218 *
219 * Locking Note: Called with the rport lock held
220 */
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700221static void fc_rport_state_enter(struct fc_rport_priv *rdata,
Robert Love42e9a922008-12-09 15:10:17 -0800222 enum fc_rport_state new)
223{
Robert Love42e9a922008-12-09 15:10:17 -0800224 if (rdata->rp_state != new)
225 rdata->retries = 0;
226 rdata->rp_state = new;
227}
228
229static void fc_rport_work(struct work_struct *work)
230{
Abhijeet Joglekar571f8242009-02-27 10:54:41 -0800231 u32 port_id;
Joe Eykholtab28f1f2009-08-25 14:00:34 -0700232 struct fc_rport_priv *rdata =
233 container_of(work, struct fc_rport_priv, event_work);
Joe Eykholt9e9d0452009-08-25 14:01:18 -0700234 struct fc_rport_libfc_priv *rp;
Robert Love42e9a922008-12-09 15:10:17 -0800235 enum fc_rport_event event;
Robert Love42e9a922008-12-09 15:10:17 -0800236 struct fc_lport *lport = rdata->local_port;
237 struct fc_rport_operations *rport_ops;
Joe Eykholt629f4422009-08-25 14:01:06 -0700238 struct fc_rport_identifiers ids;
Joe Eykholtf211fa52009-08-25 14:01:01 -0700239 struct fc_rport *rport;
Joe Eykholtb4a9c7e2009-10-21 16:28:30 -0700240 int restart = 0;
Robert Love42e9a922008-12-09 15:10:17 -0800241
242 mutex_lock(&rdata->rp_mutex);
243 event = rdata->event;
244 rport_ops = rdata->ops;
Joe Eykholtf211fa52009-08-25 14:01:01 -0700245 rport = rdata->rport;
Robert Love42e9a922008-12-09 15:10:17 -0800246
Joe Eykholt9e9d0452009-08-25 14:01:18 -0700247 FC_RPORT_DBG(rdata, "work event %u\n", event);
248
Joe Eykholt629f4422009-08-25 14:01:06 -0700249 switch (event) {
Joe Eykholt4c0f62b2009-08-25 14:01:12 -0700250 case RPORT_EV_READY:
Joe Eykholtf211fa52009-08-25 14:01:01 -0700251 ids = rdata->ids;
Joe Eykholt5f7ea3b2009-07-29 17:04:49 -0700252 rdata->event = RPORT_EV_NONE;
Joe Eykholt9e9d0452009-08-25 14:01:18 -0700253 kref_get(&rdata->kref);
Robert Love42e9a922008-12-09 15:10:17 -0800254 mutex_unlock(&rdata->rp_mutex);
255
Joe Eykholt9e9d0452009-08-25 14:01:18 -0700256 if (!rport)
257 rport = fc_remote_port_add(lport->host, 0, &ids);
258 if (!rport) {
259 FC_RPORT_DBG(rdata, "Failed to add the rport\n");
260 lport->tt.rport_logoff(rdata);
261 kref_put(&rdata->kref, lport->tt.rport_destroy);
262 return;
Robert Love42e9a922008-12-09 15:10:17 -0800263 }
Joe Eykholt9e9d0452009-08-25 14:01:18 -0700264 mutex_lock(&rdata->rp_mutex);
265 if (rdata->rport)
266 FC_RPORT_DBG(rdata, "rport already allocated\n");
267 rdata->rport = rport;
268 rport->maxframe_size = rdata->maxframe_size;
269 rport->supported_classes = rdata->supported_classes;
270
271 rp = rport->dd_data;
272 rp->local_port = lport;
273 rp->rp_state = rdata->rp_state;
274 rp->flags = rdata->flags;
275 rp->e_d_tov = rdata->e_d_tov;
276 rp->r_a_tov = rdata->r_a_tov;
277 mutex_unlock(&rdata->rp_mutex);
278
Joe Eykholt83455922009-08-25 14:02:01 -0700279 if (rport_ops && rport_ops->event_callback) {
Joe Eykholt9e9d0452009-08-25 14:01:18 -0700280 FC_RPORT_DBG(rdata, "callback ev %d\n", event);
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700281 rport_ops->event_callback(lport, rdata, event);
Joe Eykholt9e9d0452009-08-25 14:01:18 -0700282 }
283 kref_put(&rdata->kref, lport->tt.rport_destroy);
Joe Eykholt629f4422009-08-25 14:01:06 -0700284 break;
285
286 case RPORT_EV_FAILED:
287 case RPORT_EV_LOGO:
288 case RPORT_EV_STOP:
Joe Eykholt9e9d0452009-08-25 14:01:18 -0700289 port_id = rdata->ids.port_id;
Robert Love42e9a922008-12-09 15:10:17 -0800290 mutex_unlock(&rdata->rp_mutex);
Joe Eykholt9e9d0452009-08-25 14:01:18 -0700291
Joe Eykholt48f00902009-08-25 14:01:50 -0700292 if (port_id != FC_FID_DIR_SERV) {
Joe Eykholtb4a9c7e2009-10-21 16:28:30 -0700293 /*
294 * We must drop rp_mutex before taking disc_mutex.
295 * Re-evaluate state to allow for restart.
296 * A transition to RESTART state must only happen
297 * while disc_mutex is held and rdata is on the list.
298 */
Joe Eykholt48f00902009-08-25 14:01:50 -0700299 mutex_lock(&lport->disc.disc_mutex);
Joe Eykholtb4a9c7e2009-10-21 16:28:30 -0700300 mutex_lock(&rdata->rp_mutex);
301 if (rdata->rp_state == RPORT_ST_RESTART)
302 restart = 1;
303 else
304 list_del(&rdata->peers);
305 mutex_unlock(&rdata->rp_mutex);
Joe Eykholt48f00902009-08-25 14:01:50 -0700306 mutex_unlock(&lport->disc.disc_mutex);
307 }
308
Joe Eykholt83455922009-08-25 14:02:01 -0700309 if (rport_ops && rport_ops->event_callback) {
Joe Eykholt9e9d0452009-08-25 14:01:18 -0700310 FC_RPORT_DBG(rdata, "callback ev %d\n", event);
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700311 rport_ops->event_callback(lport, rdata, event);
Abhijeet Joglekar571f8242009-02-27 10:54:41 -0800312 }
Joe Eykholt9e9d0452009-08-25 14:01:18 -0700313 cancel_delayed_work_sync(&rdata->retry_work);
314
315 /*
316 * Reset any outstanding exchanges before freeing rport.
317 */
318 lport->tt.exch_mgr_reset(lport, 0, port_id);
319 lport->tt.exch_mgr_reset(lport, port_id, 0);
320
321 if (rport) {
322 rp = rport->dd_data;
323 rp->rp_state = RPORT_ST_DELETE;
324 mutex_lock(&rdata->rp_mutex);
325 rdata->rport = NULL;
326 mutex_unlock(&rdata->rp_mutex);
327 fc_remote_port_delete(rport);
328 }
Joe Eykholtb4a9c7e2009-10-21 16:28:30 -0700329 if (restart) {
330 mutex_lock(&rdata->rp_mutex);
331 FC_RPORT_DBG(rdata, "work restart\n");
332 fc_rport_enter_plogi(rdata);
333 mutex_unlock(&rdata->rp_mutex);
334 } else
335 kref_put(&rdata->kref, lport->tt.rport_destroy);
Joe Eykholt629f4422009-08-25 14:01:06 -0700336 break;
337
338 default:
Robert Love42e9a922008-12-09 15:10:17 -0800339 mutex_unlock(&rdata->rp_mutex);
Joe Eykholt629f4422009-08-25 14:01:06 -0700340 break;
341 }
Robert Love42e9a922008-12-09 15:10:17 -0800342}
343
344/**
Robert Love34f42a02009-02-27 10:55:45 -0800345 * fc_rport_login() - Start the remote port login state machine
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700346 * @rdata: private remote port
Robert Love42e9a922008-12-09 15:10:17 -0800347 *
348 * Locking Note: Called without the rport lock held. This
349 * function will hold the rport lock, call an _enter_*
350 * function and then unlock the rport.
Joe Eykholt370c3bd2009-08-25 14:03:47 -0700351 *
352 * This indicates the intent to be logged into the remote port.
353 * If it appears we are already logged in, ADISC is used to verify
354 * the setup.
Robert Love42e9a922008-12-09 15:10:17 -0800355 */
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700356int fc_rport_login(struct fc_rport_priv *rdata)
Robert Love42e9a922008-12-09 15:10:17 -0800357{
Robert Love42e9a922008-12-09 15:10:17 -0800358 mutex_lock(&rdata->rp_mutex);
359
Joe Eykholt370c3bd2009-08-25 14:03:47 -0700360 switch (rdata->rp_state) {
361 case RPORT_ST_READY:
362 FC_RPORT_DBG(rdata, "ADISC port\n");
363 fc_rport_enter_adisc(rdata);
364 break;
Joe Eykholtb4a9c7e2009-10-21 16:28:30 -0700365 case RPORT_ST_RESTART:
366 break;
367 case RPORT_ST_DELETE:
368 FC_RPORT_DBG(rdata, "Restart deleted port\n");
369 fc_rport_state_enter(rdata, RPORT_ST_RESTART);
370 break;
Joe Eykholt370c3bd2009-08-25 14:03:47 -0700371 default:
372 FC_RPORT_DBG(rdata, "Login to port\n");
373 fc_rport_enter_plogi(rdata);
374 break;
375 }
Robert Love42e9a922008-12-09 15:10:17 -0800376 mutex_unlock(&rdata->rp_mutex);
377
378 return 0;
379}
380
381/**
Joe Eykholt5f7ea3b2009-07-29 17:04:49 -0700382 * fc_rport_enter_delete() - schedule a remote port to be deleted.
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700383 * @rdata: private remote port
Joe Eykholt5f7ea3b2009-07-29 17:04:49 -0700384 * @event: event to report as the reason for deletion
385 *
386 * Locking Note: Called with the rport lock held.
387 *
388 * Allow state change into DELETE only once.
389 *
390 * Call queue_work only if there's no event already pending.
391 * Set the new event so that the old pending event will not occur.
392 * Since we have the mutex, even if fc_rport_work() is already started,
393 * it'll see the new event.
394 */
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700395static void fc_rport_enter_delete(struct fc_rport_priv *rdata,
Joe Eykholt5f7ea3b2009-07-29 17:04:49 -0700396 enum fc_rport_event event)
397{
Joe Eykholt5f7ea3b2009-07-29 17:04:49 -0700398 if (rdata->rp_state == RPORT_ST_DELETE)
399 return;
400
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700401 FC_RPORT_DBG(rdata, "Delete port\n");
Joe Eykholt5f7ea3b2009-07-29 17:04:49 -0700402
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700403 fc_rport_state_enter(rdata, RPORT_ST_DELETE);
Joe Eykholt5f7ea3b2009-07-29 17:04:49 -0700404
405 if (rdata->event == RPORT_EV_NONE)
406 queue_work(rport_event_queue, &rdata->event_work);
407 rdata->event = event;
408}
409
410/**
Robert Love34f42a02009-02-27 10:55:45 -0800411 * fc_rport_logoff() - Logoff and remove an rport
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700412 * @rdata: private remote port
Robert Love42e9a922008-12-09 15:10:17 -0800413 *
414 * Locking Note: Called without the rport lock held. This
415 * function will hold the rport lock, call an _enter_*
416 * function and then unlock the rport.
417 */
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700418int fc_rport_logoff(struct fc_rport_priv *rdata)
Robert Love42e9a922008-12-09 15:10:17 -0800419{
Robert Love42e9a922008-12-09 15:10:17 -0800420 mutex_lock(&rdata->rp_mutex);
421
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700422 FC_RPORT_DBG(rdata, "Remove port\n");
Robert Love42e9a922008-12-09 15:10:17 -0800423
Joe Eykholt14194052009-07-29 17:04:43 -0700424 if (rdata->rp_state == RPORT_ST_DELETE) {
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700425 FC_RPORT_DBG(rdata, "Port in Delete state, not removing\n");
Abhijeet Joglekarb4c6f542009-04-21 16:27:04 -0700426 goto out;
427 }
428
Joe Eykholtb4a9c7e2009-10-21 16:28:30 -0700429 if (rdata->rp_state == RPORT_ST_RESTART)
430 FC_RPORT_DBG(rdata, "Port in Restart state, deleting\n");
431 else
432 fc_rport_enter_logo(rdata);
Robert Love42e9a922008-12-09 15:10:17 -0800433
434 /*
Joe Eykholt14194052009-07-29 17:04:43 -0700435 * Change the state to Delete so that we discard
Robert Love42e9a922008-12-09 15:10:17 -0800436 * the response.
437 */
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700438 fc_rport_enter_delete(rdata, RPORT_EV_STOP);
Abhijeet Joglekarb4c6f542009-04-21 16:27:04 -0700439out:
Joe Eykholtb4a9c7e2009-10-21 16:28:30 -0700440 mutex_unlock(&rdata->rp_mutex);
Robert Love42e9a922008-12-09 15:10:17 -0800441 return 0;
442}
443
444/**
Robert Love34f42a02009-02-27 10:55:45 -0800445 * fc_rport_enter_ready() - The rport is ready
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700446 * @rdata: private remote port
Robert Love42e9a922008-12-09 15:10:17 -0800447 *
448 * Locking Note: The rport lock is expected to be held before calling
449 * this routine.
450 */
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700451static void fc_rport_enter_ready(struct fc_rport_priv *rdata)
Robert Love42e9a922008-12-09 15:10:17 -0800452{
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700453 fc_rport_state_enter(rdata, RPORT_ST_READY);
Robert Love42e9a922008-12-09 15:10:17 -0800454
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700455 FC_RPORT_DBG(rdata, "Port is Ready\n");
Robert Love42e9a922008-12-09 15:10:17 -0800456
Joe Eykholt5f7ea3b2009-07-29 17:04:49 -0700457 if (rdata->event == RPORT_EV_NONE)
458 queue_work(rport_event_queue, &rdata->event_work);
Joe Eykholt4c0f62b2009-08-25 14:01:12 -0700459 rdata->event = RPORT_EV_READY;
Robert Love42e9a922008-12-09 15:10:17 -0800460}
461
462/**
Robert Love34f42a02009-02-27 10:55:45 -0800463 * fc_rport_timeout() - Handler for the retry_work timer.
Joe Eykholtab28f1f2009-08-25 14:00:34 -0700464 * @work: The work struct of the fc_rport_priv
Robert Love42e9a922008-12-09 15:10:17 -0800465 *
466 * Locking Note: Called without the rport lock held. This
467 * function will hold the rport lock, call an _enter_*
468 * function and then unlock the rport.
469 */
470static void fc_rport_timeout(struct work_struct *work)
471{
Joe Eykholtab28f1f2009-08-25 14:00:34 -0700472 struct fc_rport_priv *rdata =
473 container_of(work, struct fc_rport_priv, retry_work.work);
Robert Love42e9a922008-12-09 15:10:17 -0800474
475 mutex_lock(&rdata->rp_mutex);
476
477 switch (rdata->rp_state) {
478 case RPORT_ST_PLOGI:
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700479 fc_rport_enter_plogi(rdata);
Robert Love42e9a922008-12-09 15:10:17 -0800480 break;
481 case RPORT_ST_PRLI:
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700482 fc_rport_enter_prli(rdata);
Robert Love42e9a922008-12-09 15:10:17 -0800483 break;
484 case RPORT_ST_RTV:
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700485 fc_rport_enter_rtv(rdata);
Robert Love42e9a922008-12-09 15:10:17 -0800486 break;
487 case RPORT_ST_LOGO:
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700488 fc_rport_enter_logo(rdata);
Robert Love42e9a922008-12-09 15:10:17 -0800489 break;
Joe Eykholt370c3bd2009-08-25 14:03:47 -0700490 case RPORT_ST_ADISC:
491 fc_rport_enter_adisc(rdata);
492 break;
Robert Love42e9a922008-12-09 15:10:17 -0800493 case RPORT_ST_READY:
494 case RPORT_ST_INIT:
Joe Eykholt14194052009-07-29 17:04:43 -0700495 case RPORT_ST_DELETE:
Joe Eykholtb4a9c7e2009-10-21 16:28:30 -0700496 case RPORT_ST_RESTART:
Robert Love42e9a922008-12-09 15:10:17 -0800497 break;
498 }
499
500 mutex_unlock(&rdata->rp_mutex);
Robert Love42e9a922008-12-09 15:10:17 -0800501}
502
503/**
Robert Love34f42a02009-02-27 10:55:45 -0800504 * fc_rport_error() - Error handler, called once retries have been exhausted
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700505 * @rdata: private remote port
Robert Love42e9a922008-12-09 15:10:17 -0800506 * @fp: The frame pointer
507 *
Robert Love42e9a922008-12-09 15:10:17 -0800508 * Locking Note: The rport lock is expected to be held before
509 * calling this routine
510 */
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700511static void fc_rport_error(struct fc_rport_priv *rdata, struct fc_frame *fp)
Robert Love42e9a922008-12-09 15:10:17 -0800512{
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700513 FC_RPORT_DBG(rdata, "Error %ld in state %s, retries %d\n",
Joe Eykholtcdbe6df2009-08-25 14:01:39 -0700514 IS_ERR(fp) ? -PTR_ERR(fp) : 0,
515 fc_rport_state(rdata), rdata->retries);
Robert Love42e9a922008-12-09 15:10:17 -0800516
Chris Leech6755db12009-02-27 10:55:02 -0800517 switch (rdata->rp_state) {
518 case RPORT_ST_PLOGI:
Chris Leech6755db12009-02-27 10:55:02 -0800519 case RPORT_ST_LOGO:
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700520 fc_rport_enter_delete(rdata, RPORT_EV_FAILED);
Chris Leech6755db12009-02-27 10:55:02 -0800521 break;
522 case RPORT_ST_RTV:
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700523 fc_rport_enter_ready(rdata);
Chris Leech6755db12009-02-27 10:55:02 -0800524 break;
Joe Eykholt370c3bd2009-08-25 14:03:47 -0700525 case RPORT_ST_PRLI:
526 case RPORT_ST_ADISC:
527 fc_rport_enter_logo(rdata);
528 break;
Joe Eykholt14194052009-07-29 17:04:43 -0700529 case RPORT_ST_DELETE:
Joe Eykholtb4a9c7e2009-10-21 16:28:30 -0700530 case RPORT_ST_RESTART:
Chris Leech6755db12009-02-27 10:55:02 -0800531 case RPORT_ST_READY:
532 case RPORT_ST_INIT:
533 break;
Robert Love42e9a922008-12-09 15:10:17 -0800534 }
535}
536
537/**
Robert Love34f42a02009-02-27 10:55:45 -0800538 * fc_rport_error_retry() - Error handler when retries are desired
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700539 * @rdata: private remote port data
Chris Leech6755db12009-02-27 10:55:02 -0800540 * @fp: The frame pointer
541 *
542 * If the error was an exchange timeout retry immediately,
543 * otherwise wait for E_D_TOV.
544 *
545 * Locking Note: The rport lock is expected to be held before
546 * calling this routine
547 */
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700548static void fc_rport_error_retry(struct fc_rport_priv *rdata,
549 struct fc_frame *fp)
Chris Leech6755db12009-02-27 10:55:02 -0800550{
Chris Leech6755db12009-02-27 10:55:02 -0800551 unsigned long delay = FC_DEF_E_D_TOV;
552
553 /* make sure this isn't an FC_EX_CLOSED error, never retry those */
554 if (PTR_ERR(fp) == -FC_EX_CLOSED)
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700555 return fc_rport_error(rdata, fp);
Chris Leech6755db12009-02-27 10:55:02 -0800556
Abhijeet Joglekara3666952009-05-01 10:01:26 -0700557 if (rdata->retries < rdata->local_port->max_rport_retry_count) {
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700558 FC_RPORT_DBG(rdata, "Error %ld in state %s, retrying\n",
559 PTR_ERR(fp), fc_rport_state(rdata));
Chris Leech6755db12009-02-27 10:55:02 -0800560 rdata->retries++;
561 /* no additional delay on exchange timeouts */
562 if (PTR_ERR(fp) == -FC_EX_TIMEOUT)
563 delay = 0;
Chris Leech6755db12009-02-27 10:55:02 -0800564 schedule_delayed_work(&rdata->retry_work, delay);
565 return;
566 }
567
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700568 return fc_rport_error(rdata, fp);
Chris Leech6755db12009-02-27 10:55:02 -0800569}
570
571/**
Robert Love34f42a02009-02-27 10:55:45 -0800572 * fc_rport_plogi_recv_resp() - Handle incoming ELS PLOGI response
Robert Love42e9a922008-12-09 15:10:17 -0800573 * @sp: current sequence in the PLOGI exchange
574 * @fp: response frame
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700575 * @rdata_arg: private remote port data
Robert Love42e9a922008-12-09 15:10:17 -0800576 *
577 * Locking Note: This function will be called without the rport lock
578 * held, but it will lock, call an _enter_* function or fc_rport_error
579 * and then unlock the rport.
580 */
581static void fc_rport_plogi_resp(struct fc_seq *sp, struct fc_frame *fp,
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700582 void *rdata_arg)
Robert Love42e9a922008-12-09 15:10:17 -0800583{
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700584 struct fc_rport_priv *rdata = rdata_arg;
Robert Love42e9a922008-12-09 15:10:17 -0800585 struct fc_lport *lport = rdata->local_port;
Robert Lovea29e7642009-04-21 16:27:41 -0700586 struct fc_els_flogi *plp = NULL;
Robert Love42e9a922008-12-09 15:10:17 -0800587 unsigned int tov;
588 u16 csp_seq;
589 u16 cssp_seq;
590 u8 op;
591
592 mutex_lock(&rdata->rp_mutex);
593
Joe Eykholtf657d292009-08-25 14:03:21 -0700594 FC_RPORT_DBG(rdata, "Received a PLOGI %s\n", fc_els_resp_type(fp));
Robert Love42e9a922008-12-09 15:10:17 -0800595
596 if (rdata->rp_state != RPORT_ST_PLOGI) {
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700597 FC_RPORT_DBG(rdata, "Received a PLOGI response, but in state "
598 "%s\n", fc_rport_state(rdata));
Abhijeet Joglekar76f68042009-04-21 16:26:58 -0700599 if (IS_ERR(fp))
600 goto err;
Robert Love42e9a922008-12-09 15:10:17 -0800601 goto out;
602 }
603
Abhijeet Joglekar76f68042009-04-21 16:26:58 -0700604 if (IS_ERR(fp)) {
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700605 fc_rport_error_retry(rdata, fp);
Abhijeet Joglekar76f68042009-04-21 16:26:58 -0700606 goto err;
607 }
608
Robert Love42e9a922008-12-09 15:10:17 -0800609 op = fc_frame_payload_op(fp);
610 if (op == ELS_LS_ACC &&
611 (plp = fc_frame_payload_get(fp, sizeof(*plp))) != NULL) {
Joe Eykholtf211fa52009-08-25 14:01:01 -0700612 rdata->ids.port_name = get_unaligned_be64(&plp->fl_wwpn);
613 rdata->ids.node_name = get_unaligned_be64(&plp->fl_wwnn);
Robert Love42e9a922008-12-09 15:10:17 -0800614
615 tov = ntohl(plp->fl_csp.sp_e_d_tov);
616 if (ntohs(plp->fl_csp.sp_features) & FC_SP_FT_EDTR)
617 tov /= 1000;
618 if (tov > rdata->e_d_tov)
619 rdata->e_d_tov = tov;
620 csp_seq = ntohs(plp->fl_csp.sp_tot_seq);
621 cssp_seq = ntohs(plp->fl_cssp[3 - 1].cp_con_seq);
622 if (cssp_seq < csp_seq)
623 csp_seq = cssp_seq;
624 rdata->max_seq = csp_seq;
Joe Eykholtf211fa52009-08-25 14:01:01 -0700625 rdata->maxframe_size = fc_plogi_get_maxframe(plp, lport->mfs);
Joe Eykholt3ac6f982009-08-25 14:03:26 -0700626 fc_rport_enter_prli(rdata);
Robert Love42e9a922008-12-09 15:10:17 -0800627 } else
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700628 fc_rport_error_retry(rdata, fp);
Robert Love42e9a922008-12-09 15:10:17 -0800629
630out:
631 fc_frame_free(fp);
632err:
633 mutex_unlock(&rdata->rp_mutex);
Joe Eykholtf211fa52009-08-25 14:01:01 -0700634 kref_put(&rdata->kref, rdata->local_port->tt.rport_destroy);
Robert Love42e9a922008-12-09 15:10:17 -0800635}
636
637/**
Robert Love34f42a02009-02-27 10:55:45 -0800638 * fc_rport_enter_plogi() - Send Port Login (PLOGI) request to peer
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700639 * @rdata: private remote port data
Robert Love42e9a922008-12-09 15:10:17 -0800640 *
641 * Locking Note: The rport lock is expected to be held before calling
642 * this routine.
643 */
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700644static void fc_rport_enter_plogi(struct fc_rport_priv *rdata)
Robert Love42e9a922008-12-09 15:10:17 -0800645{
Robert Love42e9a922008-12-09 15:10:17 -0800646 struct fc_lport *lport = rdata->local_port;
647 struct fc_frame *fp;
648
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700649 FC_RPORT_DBG(rdata, "Port entered PLOGI state from %s state\n",
650 fc_rport_state(rdata));
Robert Love42e9a922008-12-09 15:10:17 -0800651
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700652 fc_rport_state_enter(rdata, RPORT_ST_PLOGI);
Robert Love42e9a922008-12-09 15:10:17 -0800653
Joe Eykholtf211fa52009-08-25 14:01:01 -0700654 rdata->maxframe_size = FC_MIN_MAX_PAYLOAD;
Robert Love42e9a922008-12-09 15:10:17 -0800655 fp = fc_frame_alloc(lport, sizeof(struct fc_els_flogi));
656 if (!fp) {
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700657 fc_rport_error_retry(rdata, fp);
Robert Love42e9a922008-12-09 15:10:17 -0800658 return;
659 }
660 rdata->e_d_tov = lport->e_d_tov;
661
Joe Eykholtf211fa52009-08-25 14:01:01 -0700662 if (!lport->tt.elsct_send(lport, rdata->ids.port_id, fp, ELS_PLOGI,
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700663 fc_rport_plogi_resp, rdata, lport->e_d_tov))
Chris Leech8f550f92009-10-21 16:28:09 -0700664 fc_rport_error_retry(rdata, NULL);
Robert Love42e9a922008-12-09 15:10:17 -0800665 else
Joe Eykholtf211fa52009-08-25 14:01:01 -0700666 kref_get(&rdata->kref);
Robert Love42e9a922008-12-09 15:10:17 -0800667}
668
669/**
Robert Love34f42a02009-02-27 10:55:45 -0800670 * fc_rport_prli_resp() - Process Login (PRLI) response handler
Robert Love42e9a922008-12-09 15:10:17 -0800671 * @sp: current sequence in the PRLI exchange
672 * @fp: response frame
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700673 * @rdata_arg: private remote port data
Robert Love42e9a922008-12-09 15:10:17 -0800674 *
675 * Locking Note: This function will be called without the rport lock
676 * held, but it will lock, call an _enter_* function or fc_rport_error
677 * and then unlock the rport.
678 */
679static void fc_rport_prli_resp(struct fc_seq *sp, struct fc_frame *fp,
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700680 void *rdata_arg)
Robert Love42e9a922008-12-09 15:10:17 -0800681{
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700682 struct fc_rport_priv *rdata = rdata_arg;
Robert Love42e9a922008-12-09 15:10:17 -0800683 struct {
684 struct fc_els_prli prli;
685 struct fc_els_spp spp;
686 } *pp;
687 u32 roles = FC_RPORT_ROLE_UNKNOWN;
688 u32 fcp_parm = 0;
689 u8 op;
690
691 mutex_lock(&rdata->rp_mutex);
692
Joe Eykholtf657d292009-08-25 14:03:21 -0700693 FC_RPORT_DBG(rdata, "Received a PRLI %s\n", fc_els_resp_type(fp));
Robert Love42e9a922008-12-09 15:10:17 -0800694
695 if (rdata->rp_state != RPORT_ST_PRLI) {
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700696 FC_RPORT_DBG(rdata, "Received a PRLI response, but in state "
697 "%s\n", fc_rport_state(rdata));
Abhijeet Joglekar76f68042009-04-21 16:26:58 -0700698 if (IS_ERR(fp))
699 goto err;
Robert Love42e9a922008-12-09 15:10:17 -0800700 goto out;
701 }
702
Abhijeet Joglekar76f68042009-04-21 16:26:58 -0700703 if (IS_ERR(fp)) {
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700704 fc_rport_error_retry(rdata, fp);
Abhijeet Joglekar76f68042009-04-21 16:26:58 -0700705 goto err;
706 }
707
Robert Love6bd054c2009-08-25 14:03:04 -0700708 /* reinitialize remote port roles */
709 rdata->ids.roles = FC_RPORT_ROLE_UNKNOWN;
710
Robert Love42e9a922008-12-09 15:10:17 -0800711 op = fc_frame_payload_op(fp);
712 if (op == ELS_LS_ACC) {
713 pp = fc_frame_payload_get(fp, sizeof(*pp));
714 if (pp && pp->prli.prli_spp_len >= sizeof(pp->spp)) {
715 fcp_parm = ntohl(pp->spp.spp_params);
716 if (fcp_parm & FCP_SPPF_RETRY)
717 rdata->flags |= FC_RP_FLAGS_RETRY;
718 }
719
Joe Eykholtf211fa52009-08-25 14:01:01 -0700720 rdata->supported_classes = FC_COS_CLASS3;
Robert Love42e9a922008-12-09 15:10:17 -0800721 if (fcp_parm & FCP_SPPF_INIT_FCN)
722 roles |= FC_RPORT_ROLE_FCP_INITIATOR;
723 if (fcp_parm & FCP_SPPF_TARG_FCN)
724 roles |= FC_RPORT_ROLE_FCP_TARGET;
725
Joe Eykholtf211fa52009-08-25 14:01:01 -0700726 rdata->ids.roles = roles;
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700727 fc_rport_enter_rtv(rdata);
Robert Love42e9a922008-12-09 15:10:17 -0800728
729 } else {
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700730 FC_RPORT_DBG(rdata, "Bad ELS response for PRLI command\n");
731 fc_rport_enter_delete(rdata, RPORT_EV_FAILED);
Robert Love42e9a922008-12-09 15:10:17 -0800732 }
733
734out:
735 fc_frame_free(fp);
736err:
737 mutex_unlock(&rdata->rp_mutex);
Joe Eykholtf211fa52009-08-25 14:01:01 -0700738 kref_put(&rdata->kref, rdata->local_port->tt.rport_destroy);
Robert Love42e9a922008-12-09 15:10:17 -0800739}
740
741/**
Robert Love34f42a02009-02-27 10:55:45 -0800742 * fc_rport_logo_resp() - Logout (LOGO) response handler
Robert Love42e9a922008-12-09 15:10:17 -0800743 * @sp: current sequence in the LOGO exchange
744 * @fp: response frame
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700745 * @rdata_arg: private remote port data
Robert Love42e9a922008-12-09 15:10:17 -0800746 *
747 * Locking Note: This function will be called without the rport lock
748 * held, but it will lock, call an _enter_* function or fc_rport_error
749 * and then unlock the rport.
750 */
751static void fc_rport_logo_resp(struct fc_seq *sp, struct fc_frame *fp,
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700752 void *rdata_arg)
Robert Love42e9a922008-12-09 15:10:17 -0800753{
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700754 struct fc_rport_priv *rdata = rdata_arg;
Robert Love42e9a922008-12-09 15:10:17 -0800755 u8 op;
756
757 mutex_lock(&rdata->rp_mutex);
758
Joe Eykholtf657d292009-08-25 14:03:21 -0700759 FC_RPORT_DBG(rdata, "Received a LOGO %s\n", fc_els_resp_type(fp));
Robert Love42e9a922008-12-09 15:10:17 -0800760
Robert Love42e9a922008-12-09 15:10:17 -0800761 if (rdata->rp_state != RPORT_ST_LOGO) {
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700762 FC_RPORT_DBG(rdata, "Received a LOGO response, but in state "
763 "%s\n", fc_rport_state(rdata));
Abhijeet Joglekar76f68042009-04-21 16:26:58 -0700764 if (IS_ERR(fp))
765 goto err;
Robert Love42e9a922008-12-09 15:10:17 -0800766 goto out;
767 }
768
Abhijeet Joglekar76f68042009-04-21 16:26:58 -0700769 if (IS_ERR(fp)) {
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700770 fc_rport_error_retry(rdata, fp);
Abhijeet Joglekar76f68042009-04-21 16:26:58 -0700771 goto err;
772 }
773
Robert Love42e9a922008-12-09 15:10:17 -0800774 op = fc_frame_payload_op(fp);
Joe Eykholt68a17502009-08-25 14:03:42 -0700775 if (op != ELS_LS_ACC)
776 FC_RPORT_DBG(rdata, "Bad ELS response op %x for LOGO command\n",
777 op);
778 fc_rport_enter_delete(rdata, RPORT_EV_LOGO);
Robert Love42e9a922008-12-09 15:10:17 -0800779
780out:
781 fc_frame_free(fp);
782err:
783 mutex_unlock(&rdata->rp_mutex);
Joe Eykholtf211fa52009-08-25 14:01:01 -0700784 kref_put(&rdata->kref, rdata->local_port->tt.rport_destroy);
Robert Love42e9a922008-12-09 15:10:17 -0800785}
786
787/**
Robert Love34f42a02009-02-27 10:55:45 -0800788 * fc_rport_enter_prli() - Send Process Login (PRLI) request to peer
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700789 * @rdata: private remote port data
Robert Love42e9a922008-12-09 15:10:17 -0800790 *
791 * Locking Note: The rport lock is expected to be held before calling
792 * this routine.
793 */
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700794static void fc_rport_enter_prli(struct fc_rport_priv *rdata)
Robert Love42e9a922008-12-09 15:10:17 -0800795{
Robert Love42e9a922008-12-09 15:10:17 -0800796 struct fc_lport *lport = rdata->local_port;
797 struct {
798 struct fc_els_prli prli;
799 struct fc_els_spp spp;
800 } *pp;
801 struct fc_frame *fp;
802
Joe Eykholt3ac6f982009-08-25 14:03:26 -0700803 /*
804 * If the rport is one of the well known addresses
805 * we skip PRLI and RTV and go straight to READY.
806 */
807 if (rdata->ids.port_id >= FC_FID_DOM_MGR) {
808 fc_rport_enter_ready(rdata);
809 return;
810 }
811
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700812 FC_RPORT_DBG(rdata, "Port entered PRLI state from %s state\n",
813 fc_rport_state(rdata));
Robert Love42e9a922008-12-09 15:10:17 -0800814
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700815 fc_rport_state_enter(rdata, RPORT_ST_PRLI);
Robert Love42e9a922008-12-09 15:10:17 -0800816
817 fp = fc_frame_alloc(lport, sizeof(*pp));
818 if (!fp) {
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700819 fc_rport_error_retry(rdata, fp);
Robert Love42e9a922008-12-09 15:10:17 -0800820 return;
821 }
822
Joe Eykholtf211fa52009-08-25 14:01:01 -0700823 if (!lport->tt.elsct_send(lport, rdata->ids.port_id, fp, ELS_PRLI,
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700824 fc_rport_prli_resp, rdata, lport->e_d_tov))
Chris Leech8f550f92009-10-21 16:28:09 -0700825 fc_rport_error_retry(rdata, NULL);
Robert Love42e9a922008-12-09 15:10:17 -0800826 else
Joe Eykholtf211fa52009-08-25 14:01:01 -0700827 kref_get(&rdata->kref);
Robert Love42e9a922008-12-09 15:10:17 -0800828}
829
830/**
Robert Love34f42a02009-02-27 10:55:45 -0800831 * fc_rport_els_rtv_resp() - Request Timeout Value response handler
Robert Love42e9a922008-12-09 15:10:17 -0800832 * @sp: current sequence in the RTV exchange
833 * @fp: response frame
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700834 * @rdata_arg: private remote port data
Robert Love42e9a922008-12-09 15:10:17 -0800835 *
836 * Many targets don't seem to support this.
837 *
838 * Locking Note: This function will be called without the rport lock
839 * held, but it will lock, call an _enter_* function or fc_rport_error
840 * and then unlock the rport.
841 */
842static void fc_rport_rtv_resp(struct fc_seq *sp, struct fc_frame *fp,
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700843 void *rdata_arg)
Robert Love42e9a922008-12-09 15:10:17 -0800844{
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700845 struct fc_rport_priv *rdata = rdata_arg;
Robert Love42e9a922008-12-09 15:10:17 -0800846 u8 op;
847
848 mutex_lock(&rdata->rp_mutex);
849
Joe Eykholtf657d292009-08-25 14:03:21 -0700850 FC_RPORT_DBG(rdata, "Received a RTV %s\n", fc_els_resp_type(fp));
Robert Love42e9a922008-12-09 15:10:17 -0800851
852 if (rdata->rp_state != RPORT_ST_RTV) {
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700853 FC_RPORT_DBG(rdata, "Received a RTV response, but in state "
854 "%s\n", fc_rport_state(rdata));
Abhijeet Joglekar76f68042009-04-21 16:26:58 -0700855 if (IS_ERR(fp))
856 goto err;
Robert Love42e9a922008-12-09 15:10:17 -0800857 goto out;
858 }
859
Abhijeet Joglekar76f68042009-04-21 16:26:58 -0700860 if (IS_ERR(fp)) {
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700861 fc_rport_error(rdata, fp);
Abhijeet Joglekar76f68042009-04-21 16:26:58 -0700862 goto err;
863 }
864
Robert Love42e9a922008-12-09 15:10:17 -0800865 op = fc_frame_payload_op(fp);
866 if (op == ELS_LS_ACC) {
867 struct fc_els_rtv_acc *rtv;
868 u32 toq;
869 u32 tov;
870
871 rtv = fc_frame_payload_get(fp, sizeof(*rtv));
872 if (rtv) {
873 toq = ntohl(rtv->rtv_toq);
874 tov = ntohl(rtv->rtv_r_a_tov);
875 if (tov == 0)
876 tov = 1;
877 rdata->r_a_tov = tov;
878 tov = ntohl(rtv->rtv_e_d_tov);
879 if (toq & FC_ELS_RTV_EDRES)
880 tov /= 1000000;
881 if (tov == 0)
882 tov = 1;
883 rdata->e_d_tov = tov;
884 }
885 }
886
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700887 fc_rport_enter_ready(rdata);
Robert Love42e9a922008-12-09 15:10:17 -0800888
889out:
890 fc_frame_free(fp);
891err:
892 mutex_unlock(&rdata->rp_mutex);
Joe Eykholtf211fa52009-08-25 14:01:01 -0700893 kref_put(&rdata->kref, rdata->local_port->tt.rport_destroy);
Robert Love42e9a922008-12-09 15:10:17 -0800894}
895
896/**
Robert Love34f42a02009-02-27 10:55:45 -0800897 * fc_rport_enter_rtv() - Send Request Timeout Value (RTV) request to peer
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700898 * @rdata: private remote port data
Robert Love42e9a922008-12-09 15:10:17 -0800899 *
900 * Locking Note: The rport lock is expected to be held before calling
901 * this routine.
902 */
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700903static void fc_rport_enter_rtv(struct fc_rport_priv *rdata)
Robert Love42e9a922008-12-09 15:10:17 -0800904{
905 struct fc_frame *fp;
Robert Love42e9a922008-12-09 15:10:17 -0800906 struct fc_lport *lport = rdata->local_port;
907
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700908 FC_RPORT_DBG(rdata, "Port entered RTV state from %s state\n",
909 fc_rport_state(rdata));
Robert Love42e9a922008-12-09 15:10:17 -0800910
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700911 fc_rport_state_enter(rdata, RPORT_ST_RTV);
Robert Love42e9a922008-12-09 15:10:17 -0800912
913 fp = fc_frame_alloc(lport, sizeof(struct fc_els_rtv));
914 if (!fp) {
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700915 fc_rport_error_retry(rdata, fp);
Robert Love42e9a922008-12-09 15:10:17 -0800916 return;
917 }
918
Joe Eykholtf211fa52009-08-25 14:01:01 -0700919 if (!lport->tt.elsct_send(lport, rdata->ids.port_id, fp, ELS_RTV,
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700920 fc_rport_rtv_resp, rdata, lport->e_d_tov))
Chris Leech8f550f92009-10-21 16:28:09 -0700921 fc_rport_error_retry(rdata, NULL);
Robert Love42e9a922008-12-09 15:10:17 -0800922 else
Joe Eykholtf211fa52009-08-25 14:01:01 -0700923 kref_get(&rdata->kref);
Robert Love42e9a922008-12-09 15:10:17 -0800924}
925
926/**
Robert Love34f42a02009-02-27 10:55:45 -0800927 * fc_rport_enter_logo() - Send Logout (LOGO) request to peer
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700928 * @rdata: private remote port data
Robert Love42e9a922008-12-09 15:10:17 -0800929 *
930 * Locking Note: The rport lock is expected to be held before calling
931 * this routine.
932 */
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700933static void fc_rport_enter_logo(struct fc_rport_priv *rdata)
Robert Love42e9a922008-12-09 15:10:17 -0800934{
Robert Love42e9a922008-12-09 15:10:17 -0800935 struct fc_lport *lport = rdata->local_port;
936 struct fc_frame *fp;
937
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700938 FC_RPORT_DBG(rdata, "Port entered LOGO state from %s state\n",
939 fc_rport_state(rdata));
Robert Love42e9a922008-12-09 15:10:17 -0800940
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700941 fc_rport_state_enter(rdata, RPORT_ST_LOGO);
Robert Love42e9a922008-12-09 15:10:17 -0800942
943 fp = fc_frame_alloc(lport, sizeof(struct fc_els_logo));
944 if (!fp) {
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700945 fc_rport_error_retry(rdata, fp);
Robert Love42e9a922008-12-09 15:10:17 -0800946 return;
947 }
948
Joe Eykholtf211fa52009-08-25 14:01:01 -0700949 if (!lport->tt.elsct_send(lport, rdata->ids.port_id, fp, ELS_LOGO,
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700950 fc_rport_logo_resp, rdata, lport->e_d_tov))
Chris Leech8f550f92009-10-21 16:28:09 -0700951 fc_rport_error_retry(rdata, NULL);
Robert Love42e9a922008-12-09 15:10:17 -0800952 else
Joe Eykholtf211fa52009-08-25 14:01:01 -0700953 kref_get(&rdata->kref);
Robert Love42e9a922008-12-09 15:10:17 -0800954}
955
Robert Love42e9a922008-12-09 15:10:17 -0800956/**
Joe Eykholt370c3bd2009-08-25 14:03:47 -0700957 * fc_rport_els_adisc_resp() - Address Discovery response handler
958 * @sp: current sequence in the ADISC exchange
959 * @fp: response frame
960 * @rdata_arg: remote port private.
961 *
962 * Locking Note: This function will be called without the rport lock
963 * held, but it will lock, call an _enter_* function or fc_rport_error
964 * and then unlock the rport.
965 */
966static void fc_rport_adisc_resp(struct fc_seq *sp, struct fc_frame *fp,
967 void *rdata_arg)
968{
969 struct fc_rport_priv *rdata = rdata_arg;
970 struct fc_els_adisc *adisc;
971 u8 op;
972
973 mutex_lock(&rdata->rp_mutex);
974
975 FC_RPORT_DBG(rdata, "Received a ADISC response\n");
976
977 if (rdata->rp_state != RPORT_ST_ADISC) {
978 FC_RPORT_DBG(rdata, "Received a ADISC resp but in state %s\n",
979 fc_rport_state(rdata));
980 if (IS_ERR(fp))
981 goto err;
982 goto out;
983 }
984
985 if (IS_ERR(fp)) {
986 fc_rport_error(rdata, fp);
987 goto err;
988 }
989
990 /*
991 * If address verification failed. Consider us logged out of the rport.
992 * Since the rport is still in discovery, we want to be
993 * logged in, so go to PLOGI state. Otherwise, go back to READY.
994 */
995 op = fc_frame_payload_op(fp);
996 adisc = fc_frame_payload_get(fp, sizeof(*adisc));
997 if (op != ELS_LS_ACC || !adisc ||
998 ntoh24(adisc->adisc_port_id) != rdata->ids.port_id ||
999 get_unaligned_be64(&adisc->adisc_wwpn) != rdata->ids.port_name ||
1000 get_unaligned_be64(&adisc->adisc_wwnn) != rdata->ids.node_name) {
1001 FC_RPORT_DBG(rdata, "ADISC error or mismatch\n");
1002 fc_rport_enter_plogi(rdata);
1003 } else {
1004 FC_RPORT_DBG(rdata, "ADISC OK\n");
1005 fc_rport_enter_ready(rdata);
1006 }
1007out:
1008 fc_frame_free(fp);
1009err:
1010 mutex_unlock(&rdata->rp_mutex);
1011 kref_put(&rdata->kref, rdata->local_port->tt.rport_destroy);
1012}
1013
1014/**
1015 * fc_rport_enter_adisc() - Send Address Discover (ADISC) request to peer
1016 * @rdata: remote port private data
1017 *
1018 * Locking Note: The rport lock is expected to be held before calling
1019 * this routine.
1020 */
1021static void fc_rport_enter_adisc(struct fc_rport_priv *rdata)
1022{
1023 struct fc_lport *lport = rdata->local_port;
1024 struct fc_frame *fp;
1025
1026 FC_RPORT_DBG(rdata, "sending ADISC from %s state\n",
1027 fc_rport_state(rdata));
1028
1029 fc_rport_state_enter(rdata, RPORT_ST_ADISC);
1030
1031 fp = fc_frame_alloc(lport, sizeof(struct fc_els_adisc));
1032 if (!fp) {
1033 fc_rport_error_retry(rdata, fp);
1034 return;
1035 }
1036 if (!lport->tt.elsct_send(lport, rdata->ids.port_id, fp, ELS_ADISC,
1037 fc_rport_adisc_resp, rdata, lport->e_d_tov))
Chris Leech8f550f92009-10-21 16:28:09 -07001038 fc_rport_error_retry(rdata, NULL);
Joe Eykholt370c3bd2009-08-25 14:03:47 -07001039 else
1040 kref_get(&rdata->kref);
1041}
1042
1043/**
Joe Eykholt8abbe3a2009-08-25 14:03:52 -07001044 * fc_rport_recv_adisc_req() - Handle incoming Address Discovery (ADISC) Request
1045 * @rdata: remote port private
1046 * @sp: current sequence in the ADISC exchange
1047 * @in_fp: ADISC request frame
1048 *
1049 * Locking Note: Called with the lport and rport locks held.
1050 */
1051static void fc_rport_recv_adisc_req(struct fc_rport_priv *rdata,
1052 struct fc_seq *sp, struct fc_frame *in_fp)
1053{
1054 struct fc_lport *lport = rdata->local_port;
1055 struct fc_frame *fp;
1056 struct fc_exch *ep = fc_seq_exch(sp);
1057 struct fc_els_adisc *adisc;
1058 struct fc_seq_els_data rjt_data;
1059 u32 f_ctl;
1060
1061 FC_RPORT_DBG(rdata, "Received ADISC request\n");
1062
1063 adisc = fc_frame_payload_get(in_fp, sizeof(*adisc));
1064 if (!adisc) {
1065 rjt_data.fp = NULL;
1066 rjt_data.reason = ELS_RJT_PROT;
1067 rjt_data.explan = ELS_EXPL_INV_LEN;
1068 lport->tt.seq_els_rsp_send(sp, ELS_LS_RJT, &rjt_data);
1069 goto drop;
1070 }
1071
1072 fp = fc_frame_alloc(lport, sizeof(*adisc));
1073 if (!fp)
1074 goto drop;
1075 fc_adisc_fill(lport, fp);
1076 adisc = fc_frame_payload_get(fp, sizeof(*adisc));
1077 adisc->adisc_cmd = ELS_LS_ACC;
1078 sp = lport->tt.seq_start_next(sp);
1079 f_ctl = FC_FC_EX_CTX | FC_FC_LAST_SEQ | FC_FC_END_SEQ | FC_FC_SEQ_INIT;
1080 fc_fill_fc_hdr(fp, FC_RCTL_ELS_REP, ep->did, ep->sid,
1081 FC_TYPE_ELS, f_ctl, 0);
1082 lport->tt.seq_send(lport, sp, fp);
1083drop:
1084 fc_frame_free(in_fp);
1085}
1086
1087/**
Joe Eykholt83fe6a92009-08-25 14:03:31 -07001088 * fc_rport_recv_els_req() - handle a validated ELS request.
1089 * @lport: Fibre Channel local port
Robert Love42e9a922008-12-09 15:10:17 -08001090 * @sp: current sequence in the PLOGI exchange
1091 * @fp: response frame
Joe Eykholt83fe6a92009-08-25 14:03:31 -07001092 *
1093 * Handle incoming ELS requests that require port login.
1094 * The ELS opcode has already been validated by the caller.
Robert Love42e9a922008-12-09 15:10:17 -08001095 *
Joe Eykholt131203a2009-08-25 14:03:10 -07001096 * Locking Note: Called with the lport lock held.
Robert Love42e9a922008-12-09 15:10:17 -08001097 */
Joe Eykholt83fe6a92009-08-25 14:03:31 -07001098static void fc_rport_recv_els_req(struct fc_lport *lport,
1099 struct fc_seq *sp, struct fc_frame *fp)
Robert Love42e9a922008-12-09 15:10:17 -08001100{
Joe Eykholt131203a2009-08-25 14:03:10 -07001101 struct fc_rport_priv *rdata;
Robert Love42e9a922008-12-09 15:10:17 -08001102 struct fc_frame_header *fh;
1103 struct fc_seq_els_data els_data;
Robert Love42e9a922008-12-09 15:10:17 -08001104
Robert Love42e9a922008-12-09 15:10:17 -08001105 els_data.fp = NULL;
Joe Eykholt83fe6a92009-08-25 14:03:31 -07001106 els_data.reason = ELS_RJT_UNAB;
1107 els_data.explan = ELS_EXPL_PLOGI_REQD;
Joe Eykholt3ac6f982009-08-25 14:03:26 -07001108
Robert Love42e9a922008-12-09 15:10:17 -08001109 fh = fc_frame_header_get(fp);
1110
Joe Eykholt25b37b92009-08-25 14:03:15 -07001111 mutex_lock(&lport->disc.disc_mutex);
Joe Eykholt83fe6a92009-08-25 14:03:31 -07001112 rdata = lport->tt.rport_lookup(lport, ntoh24(fh->fh_s_id));
Joe Eykholt131203a2009-08-25 14:03:10 -07001113 if (!rdata) {
Joe Eykholt25b37b92009-08-25 14:03:15 -07001114 mutex_unlock(&lport->disc.disc_mutex);
Joe Eykholt83fe6a92009-08-25 14:03:31 -07001115 goto reject;
Joe Eykholt131203a2009-08-25 14:03:10 -07001116 }
1117 mutex_lock(&rdata->rp_mutex);
Joe Eykholt25b37b92009-08-25 14:03:15 -07001118 mutex_unlock(&lport->disc.disc_mutex);
Joe Eykholt131203a2009-08-25 14:03:10 -07001119
Joe Eykholt83fe6a92009-08-25 14:03:31 -07001120 switch (rdata->rp_state) {
1121 case RPORT_ST_PRLI:
1122 case RPORT_ST_RTV:
1123 case RPORT_ST_READY:
Joe Eykholt370c3bd2009-08-25 14:03:47 -07001124 case RPORT_ST_ADISC:
Joe Eykholt83fe6a92009-08-25 14:03:31 -07001125 break;
1126 default:
1127 mutex_unlock(&rdata->rp_mutex);
1128 goto reject;
1129 }
1130
1131 switch (fc_frame_payload_op(fp)) {
Joe Eykholt131203a2009-08-25 14:03:10 -07001132 case ELS_PRLI:
1133 fc_rport_recv_prli_req(rdata, sp, fp);
1134 break;
1135 case ELS_PRLO:
1136 fc_rport_recv_prlo_req(rdata, sp, fp);
1137 break;
Joe Eykholt8abbe3a2009-08-25 14:03:52 -07001138 case ELS_ADISC:
1139 fc_rport_recv_adisc_req(rdata, sp, fp);
1140 break;
Joe Eykholt131203a2009-08-25 14:03:10 -07001141 case ELS_RRQ:
1142 els_data.fp = fp;
1143 lport->tt.seq_els_rsp_send(sp, ELS_RRQ, &els_data);
1144 break;
1145 case ELS_REC:
1146 els_data.fp = fp;
1147 lport->tt.seq_els_rsp_send(sp, ELS_REC, &els_data);
1148 break;
1149 default:
Joe Eykholt83fe6a92009-08-25 14:03:31 -07001150 fc_frame_free(fp); /* can't happen */
Joe Eykholt131203a2009-08-25 14:03:10 -07001151 break;
Robert Love42e9a922008-12-09 15:10:17 -08001152 }
1153
1154 mutex_unlock(&rdata->rp_mutex);
Joe Eykholt83fe6a92009-08-25 14:03:31 -07001155 return;
1156
1157reject:
1158 lport->tt.seq_els_rsp_send(sp, ELS_LS_RJT, &els_data);
1159 fc_frame_free(fp);
1160}
1161
1162/**
1163 * fc_rport_recv_req() - Handle a received ELS request from a rport
1164 * @sp: current sequence in the PLOGI exchange
1165 * @fp: response frame
1166 * @lport: Fibre Channel local port
1167 *
1168 * Locking Note: Called with the lport lock held.
1169 */
1170void fc_rport_recv_req(struct fc_seq *sp, struct fc_frame *fp,
1171 struct fc_lport *lport)
1172{
1173 struct fc_seq_els_data els_data;
1174
1175 /*
1176 * Handle PLOGI and LOGO requests separately, since they
1177 * don't require prior login.
1178 * Check for unsupported opcodes first and reject them.
1179 * For some ops, it would be incorrect to reject with "PLOGI required".
1180 */
1181 switch (fc_frame_payload_op(fp)) {
1182 case ELS_PLOGI:
1183 fc_rport_recv_plogi_req(lport, sp, fp);
1184 break;
1185 case ELS_LOGO:
1186 fc_rport_recv_logo_req(lport, sp, fp);
1187 break;
1188 case ELS_PRLI:
1189 case ELS_PRLO:
Joe Eykholt8abbe3a2009-08-25 14:03:52 -07001190 case ELS_ADISC:
Joe Eykholt83fe6a92009-08-25 14:03:31 -07001191 case ELS_RRQ:
1192 case ELS_REC:
1193 fc_rport_recv_els_req(lport, sp, fp);
1194 break;
1195 default:
1196 fc_frame_free(fp);
1197 els_data.fp = NULL;
1198 els_data.reason = ELS_RJT_UNSUP;
1199 els_data.explan = ELS_EXPL_NONE;
1200 lport->tt.seq_els_rsp_send(sp, ELS_LS_RJT, &els_data);
1201 break;
1202 }
Robert Love42e9a922008-12-09 15:10:17 -08001203}
1204
1205/**
Robert Love34f42a02009-02-27 10:55:45 -08001206 * fc_rport_recv_plogi_req() - Handle incoming Port Login (PLOGI) request
Joe Eykholt3ac6f982009-08-25 14:03:26 -07001207 * @lport: local port
Robert Love42e9a922008-12-09 15:10:17 -08001208 * @sp: current sequence in the PLOGI exchange
1209 * @fp: PLOGI request frame
1210 *
Joe Eykholt3ac6f982009-08-25 14:03:26 -07001211 * Locking Note: The rport lock is held before calling this function.
Robert Love42e9a922008-12-09 15:10:17 -08001212 */
Joe Eykholt3ac6f982009-08-25 14:03:26 -07001213static void fc_rport_recv_plogi_req(struct fc_lport *lport,
Robert Love42e9a922008-12-09 15:10:17 -08001214 struct fc_seq *sp, struct fc_frame *rx_fp)
1215{
Joe Eykholt3ac6f982009-08-25 14:03:26 -07001216 struct fc_disc *disc;
1217 struct fc_rport_priv *rdata;
Robert Love42e9a922008-12-09 15:10:17 -08001218 struct fc_frame *fp = rx_fp;
1219 struct fc_exch *ep;
1220 struct fc_frame_header *fh;
1221 struct fc_els_flogi *pl;
1222 struct fc_seq_els_data rjt_data;
Joe Eykholt3ac6f982009-08-25 14:03:26 -07001223 u32 sid, f_ctl;
1224
Robert Love42e9a922008-12-09 15:10:17 -08001225 rjt_data.fp = NULL;
Robert Love42e9a922008-12-09 15:10:17 -08001226 fh = fc_frame_header_get(fp);
Robert Love42e9a922008-12-09 15:10:17 -08001227 sid = ntoh24(fh->fh_s_id);
Joe Eykholt3ac6f982009-08-25 14:03:26 -07001228
1229 FC_RPORT_ID_DBG(lport, sid, "Received PLOGI request\n");
1230
Robert Love42e9a922008-12-09 15:10:17 -08001231 pl = fc_frame_payload_get(fp, sizeof(*pl));
1232 if (!pl) {
Joe Eykholt3ac6f982009-08-25 14:03:26 -07001233 FC_RPORT_ID_DBG(lport, sid, "Received PLOGI too short\n");
1234 rjt_data.reason = ELS_RJT_PROT;
1235 rjt_data.explan = ELS_EXPL_INV_LEN;
1236 goto reject;
Robert Love42e9a922008-12-09 15:10:17 -08001237 }
Joe Eykholt3ac6f982009-08-25 14:03:26 -07001238
1239 disc = &lport->disc;
1240 mutex_lock(&disc->disc_mutex);
1241 rdata = lport->tt.rport_create(lport, sid);
1242 if (!rdata) {
1243 mutex_unlock(&disc->disc_mutex);
1244 rjt_data.reason = ELS_RJT_UNAB;
1245 rjt_data.explan = ELS_EXPL_INSUF_RES;
1246 goto reject;
1247 }
1248
1249 mutex_lock(&rdata->rp_mutex);
1250 mutex_unlock(&disc->disc_mutex);
1251
1252 rdata->ids.port_name = get_unaligned_be64(&pl->fl_wwpn);
1253 rdata->ids.node_name = get_unaligned_be64(&pl->fl_wwnn);
Robert Love42e9a922008-12-09 15:10:17 -08001254
1255 /*
Joe Eykholt3ac6f982009-08-25 14:03:26 -07001256 * If the rport was just created, possibly due to the incoming PLOGI,
Robert Love42e9a922008-12-09 15:10:17 -08001257 * set the state appropriately and accept the PLOGI.
1258 *
1259 * If we had also sent a PLOGI, and if the received PLOGI is from a
1260 * higher WWPN, we accept it, otherwise an LS_RJT is sent with reason
1261 * "command already in progress".
1262 *
1263 * XXX TBD: If the session was ready before, the PLOGI should result in
1264 * all outstanding exchanges being reset.
1265 */
1266 switch (rdata->rp_state) {
1267 case RPORT_ST_INIT:
Joe Eykholt3ac6f982009-08-25 14:03:26 -07001268 FC_RPORT_DBG(rdata, "Received PLOGI in INIT state\n");
Robert Love42e9a922008-12-09 15:10:17 -08001269 break;
1270 case RPORT_ST_PLOGI:
Joe Eykholt3ac6f982009-08-25 14:03:26 -07001271 FC_RPORT_DBG(rdata, "Received PLOGI in PLOGI state\n");
1272 if (rdata->ids.port_name < lport->wwpn) {
1273 mutex_unlock(&rdata->rp_mutex);
1274 rjt_data.reason = ELS_RJT_INPROG;
1275 rjt_data.explan = ELS_EXPL_NONE;
1276 goto reject;
1277 }
Robert Love42e9a922008-12-09 15:10:17 -08001278 break;
1279 case RPORT_ST_PRLI:
Joe Eykholtb4a9c7e2009-10-21 16:28:30 -07001280 case RPORT_ST_RTV:
Robert Love42e9a922008-12-09 15:10:17 -08001281 case RPORT_ST_READY:
Joe Eykholt370c3bd2009-08-25 14:03:47 -07001282 case RPORT_ST_ADISC:
1283 FC_RPORT_DBG(rdata, "Received PLOGI in logged-in state %d "
1284 "- ignored for now\n", rdata->rp_state);
1285 /* XXX TBD - should reset */
Robert Love42e9a922008-12-09 15:10:17 -08001286 break;
Joe Eykholt14194052009-07-29 17:04:43 -07001287 case RPORT_ST_DELETE:
Joe Eykholtb4a9c7e2009-10-21 16:28:30 -07001288 case RPORT_ST_LOGO:
1289 case RPORT_ST_RESTART:
1290 FC_RPORT_DBG(rdata, "Received PLOGI in state %s - send busy\n",
1291 fc_rport_state(rdata));
1292 mutex_unlock(&rdata->rp_mutex);
1293 rjt_data.reason = ELS_RJT_BUSY;
1294 rjt_data.explan = ELS_EXPL_NONE;
1295 goto reject;
Robert Love42e9a922008-12-09 15:10:17 -08001296 }
1297
Joe Eykholt3ac6f982009-08-25 14:03:26 -07001298 /*
1299 * Get session payload size from incoming PLOGI.
1300 */
1301 rdata->maxframe_size = fc_plogi_get_maxframe(pl, lport->mfs);
1302 fc_frame_free(rx_fp);
Robert Love42e9a922008-12-09 15:10:17 -08001303
Joe Eykholt3ac6f982009-08-25 14:03:26 -07001304 /*
1305 * Send LS_ACC. If this fails, the originator should retry.
1306 */
1307 sp = lport->tt.seq_start_next(sp);
1308 if (!sp)
1309 goto out;
1310 fp = fc_frame_alloc(lport, sizeof(*pl));
1311 if (!fp)
1312 goto out;
Robert Love42e9a922008-12-09 15:10:17 -08001313
Joe Eykholt3ac6f982009-08-25 14:03:26 -07001314 fc_plogi_fill(lport, fp, ELS_LS_ACC);
1315 f_ctl = FC_FC_EX_CTX | FC_FC_LAST_SEQ | FC_FC_END_SEQ | FC_FC_SEQ_INIT;
1316 ep = fc_seq_exch(sp);
1317 fc_fill_fc_hdr(fp, FC_RCTL_ELS_REP, ep->did, ep->sid,
1318 FC_TYPE_ELS, f_ctl, 0);
1319 lport->tt.seq_send(lport, sp, fp);
1320 fc_rport_enter_prli(rdata);
1321out:
1322 mutex_unlock(&rdata->rp_mutex);
1323 return;
1324
1325reject:
1326 lport->tt.seq_els_rsp_send(sp, ELS_LS_RJT, &rjt_data);
1327 fc_frame_free(fp);
Robert Love42e9a922008-12-09 15:10:17 -08001328}
1329
1330/**
Robert Love34f42a02009-02-27 10:55:45 -08001331 * fc_rport_recv_prli_req() - Handle incoming Process Login (PRLI) request
Joe Eykholt9fb9d322009-08-25 14:00:50 -07001332 * @rdata: private remote port data
Robert Love42e9a922008-12-09 15:10:17 -08001333 * @sp: current sequence in the PRLI exchange
1334 * @fp: PRLI request frame
1335 *
1336 * Locking Note: The rport lock is exected to be held before calling
1337 * this function.
1338 */
Joe Eykholt9fb9d322009-08-25 14:00:50 -07001339static void fc_rport_recv_prli_req(struct fc_rport_priv *rdata,
Robert Love42e9a922008-12-09 15:10:17 -08001340 struct fc_seq *sp, struct fc_frame *rx_fp)
1341{
Robert Love42e9a922008-12-09 15:10:17 -08001342 struct fc_lport *lport = rdata->local_port;
1343 struct fc_exch *ep;
1344 struct fc_frame *fp;
1345 struct fc_frame_header *fh;
1346 struct {
1347 struct fc_els_prli prli;
1348 struct fc_els_spp spp;
1349 } *pp;
1350 struct fc_els_spp *rspp; /* request service param page */
1351 struct fc_els_spp *spp; /* response spp */
1352 unsigned int len;
1353 unsigned int plen;
1354 enum fc_els_rjt_reason reason = ELS_RJT_UNAB;
1355 enum fc_els_rjt_explan explan = ELS_EXPL_NONE;
1356 enum fc_els_spp_resp resp;
1357 struct fc_seq_els_data rjt_data;
1358 u32 f_ctl;
1359 u32 fcp_parm;
1360 u32 roles = FC_RPORT_ROLE_UNKNOWN;
1361 rjt_data.fp = NULL;
1362
1363 fh = fc_frame_header_get(rx_fp);
1364
Joe Eykholt9fb9d322009-08-25 14:00:50 -07001365 FC_RPORT_DBG(rdata, "Received PRLI request while in state %s\n",
1366 fc_rport_state(rdata));
Robert Love42e9a922008-12-09 15:10:17 -08001367
1368 switch (rdata->rp_state) {
1369 case RPORT_ST_PRLI:
Joe Eykholt3ac6f982009-08-25 14:03:26 -07001370 case RPORT_ST_RTV:
Robert Love42e9a922008-12-09 15:10:17 -08001371 case RPORT_ST_READY:
Joe Eykholt370c3bd2009-08-25 14:03:47 -07001372 case RPORT_ST_ADISC:
Robert Love42e9a922008-12-09 15:10:17 -08001373 reason = ELS_RJT_NONE;
1374 break;
1375 default:
Abhijeet Joglekarb4c6f542009-04-21 16:27:04 -07001376 fc_frame_free(rx_fp);
1377 return;
Robert Love42e9a922008-12-09 15:10:17 -08001378 break;
1379 }
1380 len = fr_len(rx_fp) - sizeof(*fh);
1381 pp = fc_frame_payload_get(rx_fp, sizeof(*pp));
1382 if (pp == NULL) {
1383 reason = ELS_RJT_PROT;
1384 explan = ELS_EXPL_INV_LEN;
1385 } else {
1386 plen = ntohs(pp->prli.prli_len);
1387 if ((plen % 4) != 0 || plen > len) {
1388 reason = ELS_RJT_PROT;
1389 explan = ELS_EXPL_INV_LEN;
1390 } else if (plen < len) {
1391 len = plen;
1392 }
1393 plen = pp->prli.prli_spp_len;
1394 if ((plen % 4) != 0 || plen < sizeof(*spp) ||
1395 plen > len || len < sizeof(*pp)) {
1396 reason = ELS_RJT_PROT;
1397 explan = ELS_EXPL_INV_LEN;
1398 }
1399 rspp = &pp->spp;
1400 }
1401 if (reason != ELS_RJT_NONE ||
1402 (fp = fc_frame_alloc(lport, len)) == NULL) {
1403 rjt_data.reason = reason;
1404 rjt_data.explan = explan;
1405 lport->tt.seq_els_rsp_send(sp, ELS_LS_RJT, &rjt_data);
1406 } else {
1407 sp = lport->tt.seq_start_next(sp);
1408 WARN_ON(!sp);
1409 pp = fc_frame_payload_get(fp, len);
1410 WARN_ON(!pp);
1411 memset(pp, 0, len);
1412 pp->prli.prli_cmd = ELS_LS_ACC;
1413 pp->prli.prli_spp_len = plen;
1414 pp->prli.prli_len = htons(len);
1415 len -= sizeof(struct fc_els_prli);
1416
Robert Love6bd054c2009-08-25 14:03:04 -07001417 /* reinitialize remote port roles */
1418 rdata->ids.roles = FC_RPORT_ROLE_UNKNOWN;
1419
Robert Love42e9a922008-12-09 15:10:17 -08001420 /*
1421 * Go through all the service parameter pages and build
1422 * response. If plen indicates longer SPP than standard,
1423 * use that. The entire response has been pre-cleared above.
1424 */
1425 spp = &pp->spp;
1426 while (len >= plen) {
1427 spp->spp_type = rspp->spp_type;
1428 spp->spp_type_ext = rspp->spp_type_ext;
1429 spp->spp_flags = rspp->spp_flags & FC_SPP_EST_IMG_PAIR;
1430 resp = FC_SPP_RESP_ACK;
1431 if (rspp->spp_flags & FC_SPP_RPA_VAL)
1432 resp = FC_SPP_RESP_NO_PA;
1433 switch (rspp->spp_type) {
1434 case 0: /* common to all FC-4 types */
1435 break;
1436 case FC_TYPE_FCP:
1437 fcp_parm = ntohl(rspp->spp_params);
Joe Eykholt85b58932009-10-21 16:26:45 -07001438 if (fcp_parm & FCP_SPPF_RETRY)
Robert Love42e9a922008-12-09 15:10:17 -08001439 rdata->flags |= FC_RP_FLAGS_RETRY;
Joe Eykholtf211fa52009-08-25 14:01:01 -07001440 rdata->supported_classes = FC_COS_CLASS3;
Robert Love42e9a922008-12-09 15:10:17 -08001441 if (fcp_parm & FCP_SPPF_INIT_FCN)
1442 roles |= FC_RPORT_ROLE_FCP_INITIATOR;
1443 if (fcp_parm & FCP_SPPF_TARG_FCN)
1444 roles |= FC_RPORT_ROLE_FCP_TARGET;
Joe Eykholtf211fa52009-08-25 14:01:01 -07001445 rdata->ids.roles = roles;
Robert Love42e9a922008-12-09 15:10:17 -08001446
1447 spp->spp_params =
1448 htonl(lport->service_params);
1449 break;
1450 default:
1451 resp = FC_SPP_RESP_INVL;
1452 break;
1453 }
1454 spp->spp_flags |= resp;
1455 len -= plen;
1456 rspp = (struct fc_els_spp *)((char *)rspp + plen);
1457 spp = (struct fc_els_spp *)((char *)spp + plen);
1458 }
1459
1460 /*
1461 * Send LS_ACC. If this fails, the originator should retry.
1462 */
1463 f_ctl = FC_FC_EX_CTX | FC_FC_LAST_SEQ;
1464 f_ctl |= FC_FC_END_SEQ | FC_FC_SEQ_INIT;
1465 ep = fc_seq_exch(sp);
1466 fc_fill_fc_hdr(fp, FC_RCTL_ELS_REP, ep->did, ep->sid,
1467 FC_TYPE_ELS, f_ctl, 0);
1468 lport->tt.seq_send(lport, sp, fp);
1469
1470 /*
1471 * Get lock and re-check state.
1472 */
1473 switch (rdata->rp_state) {
1474 case RPORT_ST_PRLI:
Joe Eykholt9fb9d322009-08-25 14:00:50 -07001475 fc_rport_enter_ready(rdata);
Robert Love42e9a922008-12-09 15:10:17 -08001476 break;
1477 case RPORT_ST_READY:
Joe Eykholt370c3bd2009-08-25 14:03:47 -07001478 case RPORT_ST_ADISC:
Robert Love42e9a922008-12-09 15:10:17 -08001479 break;
1480 default:
1481 break;
1482 }
1483 }
1484 fc_frame_free(rx_fp);
1485}
1486
1487/**
Robert Love34f42a02009-02-27 10:55:45 -08001488 * fc_rport_recv_prlo_req() - Handle incoming Process Logout (PRLO) request
Joe Eykholt9fb9d322009-08-25 14:00:50 -07001489 * @rdata: private remote port data
Robert Love42e9a922008-12-09 15:10:17 -08001490 * @sp: current sequence in the PRLO exchange
1491 * @fp: PRLO request frame
1492 *
1493 * Locking Note: The rport lock is exected to be held before calling
1494 * this function.
1495 */
Joe Eykholt9fb9d322009-08-25 14:00:50 -07001496static void fc_rport_recv_prlo_req(struct fc_rport_priv *rdata,
1497 struct fc_seq *sp,
Robert Love42e9a922008-12-09 15:10:17 -08001498 struct fc_frame *fp)
1499{
Robert Love42e9a922008-12-09 15:10:17 -08001500 struct fc_lport *lport = rdata->local_port;
1501
1502 struct fc_frame_header *fh;
1503 struct fc_seq_els_data rjt_data;
1504
1505 fh = fc_frame_header_get(fp);
1506
Joe Eykholt9fb9d322009-08-25 14:00:50 -07001507 FC_RPORT_DBG(rdata, "Received PRLO request while in state %s\n",
1508 fc_rport_state(rdata));
Robert Love42e9a922008-12-09 15:10:17 -08001509
1510 rjt_data.fp = NULL;
1511 rjt_data.reason = ELS_RJT_UNAB;
1512 rjt_data.explan = ELS_EXPL_NONE;
1513 lport->tt.seq_els_rsp_send(sp, ELS_LS_RJT, &rjt_data);
1514 fc_frame_free(fp);
1515}
1516
1517/**
Robert Love34f42a02009-02-27 10:55:45 -08001518 * fc_rport_recv_logo_req() - Handle incoming Logout (LOGO) request
Joe Eykholt83fe6a92009-08-25 14:03:31 -07001519 * @lport: local port.
Robert Love42e9a922008-12-09 15:10:17 -08001520 * @sp: current sequence in the LOGO exchange
1521 * @fp: LOGO request frame
1522 *
1523 * Locking Note: The rport lock is exected to be held before calling
1524 * this function.
1525 */
Joe Eykholt83fe6a92009-08-25 14:03:31 -07001526static void fc_rport_recv_logo_req(struct fc_lport *lport,
Joe Eykholt9fb9d322009-08-25 14:00:50 -07001527 struct fc_seq *sp,
Robert Love42e9a922008-12-09 15:10:17 -08001528 struct fc_frame *fp)
1529{
1530 struct fc_frame_header *fh;
Joe Eykholt83fe6a92009-08-25 14:03:31 -07001531 struct fc_rport_priv *rdata;
1532 u32 sid;
Robert Love42e9a922008-12-09 15:10:17 -08001533
Joe Eykholtfeab4ae2009-08-25 14:03:36 -07001534 lport->tt.seq_els_rsp_send(sp, ELS_LS_ACC, NULL);
1535
Robert Love42e9a922008-12-09 15:10:17 -08001536 fh = fc_frame_header_get(fp);
Joe Eykholt83fe6a92009-08-25 14:03:31 -07001537 sid = ntoh24(fh->fh_s_id);
Robert Love42e9a922008-12-09 15:10:17 -08001538
Joe Eykholt83fe6a92009-08-25 14:03:31 -07001539 mutex_lock(&lport->disc.disc_mutex);
1540 rdata = lport->tt.rport_lookup(lport, sid);
1541 if (rdata) {
1542 mutex_lock(&rdata->rp_mutex);
1543 FC_RPORT_DBG(rdata, "Received LOGO request while in state %s\n",
1544 fc_rport_state(rdata));
Joe Eykholtfeab4ae2009-08-25 14:03:36 -07001545
Joe Eykholtb4a9c7e2009-10-21 16:28:30 -07001546 fc_rport_enter_delete(rdata, RPORT_EV_LOGO);
1547
Joe Eykholtfeab4ae2009-08-25 14:03:36 -07001548 /*
Joe Eykholtb4a9c7e2009-10-21 16:28:30 -07001549 * If the remote port was created due to discovery, set state
1550 * to log back in. It may have seen a stale RSCN about us.
Joe Eykholtfeab4ae2009-08-25 14:03:36 -07001551 */
Joe Eykholtb4a9c7e2009-10-21 16:28:30 -07001552 if (rdata->disc_id)
1553 fc_rport_state_enter(rdata, RPORT_ST_RESTART);
Joe Eykholt83fe6a92009-08-25 14:03:31 -07001554 mutex_unlock(&rdata->rp_mutex);
1555 } else
1556 FC_RPORT_ID_DBG(lport, sid,
1557 "Received LOGO from non-logged-in port\n");
1558 mutex_unlock(&lport->disc.disc_mutex);
Robert Love42e9a922008-12-09 15:10:17 -08001559 fc_frame_free(fp);
1560}
1561
1562static void fc_rport_flush_queue(void)
1563{
1564 flush_workqueue(rport_event_queue);
1565}
1566
Robert Love42e9a922008-12-09 15:10:17 -08001567int fc_rport_init(struct fc_lport *lport)
1568{
Joe Eykholt8025b5d2009-08-25 14:02:06 -07001569 if (!lport->tt.rport_lookup)
1570 lport->tt.rport_lookup = fc_rport_lookup;
1571
Robert Love5101ff92009-02-27 10:55:18 -08001572 if (!lport->tt.rport_create)
Joe Eykholt9e9d0452009-08-25 14:01:18 -07001573 lport->tt.rport_create = fc_rport_create;
Robert Love5101ff92009-02-27 10:55:18 -08001574
Robert Love42e9a922008-12-09 15:10:17 -08001575 if (!lport->tt.rport_login)
1576 lport->tt.rport_login = fc_rport_login;
1577
1578 if (!lport->tt.rport_logoff)
1579 lport->tt.rport_logoff = fc_rport_logoff;
1580
1581 if (!lport->tt.rport_recv_req)
1582 lport->tt.rport_recv_req = fc_rport_recv_req;
1583
1584 if (!lport->tt.rport_flush_queue)
1585 lport->tt.rport_flush_queue = fc_rport_flush_queue;
1586
Joe Eykholtf211fa52009-08-25 14:01:01 -07001587 if (!lport->tt.rport_destroy)
1588 lport->tt.rport_destroy = fc_rport_destroy;
1589
Robert Love42e9a922008-12-09 15:10:17 -08001590 return 0;
1591}
1592EXPORT_SYMBOL(fc_rport_init);
1593
Randy Dunlapb0d428a2009-04-27 21:49:31 -07001594int fc_setup_rport(void)
Robert Love42e9a922008-12-09 15:10:17 -08001595{
1596 rport_event_queue = create_singlethread_workqueue("fc_rport_eq");
1597 if (!rport_event_queue)
1598 return -ENOMEM;
1599 return 0;
1600}
Robert Love42e9a922008-12-09 15:10:17 -08001601
Randy Dunlapb0d428a2009-04-27 21:49:31 -07001602void fc_destroy_rport(void)
Robert Love42e9a922008-12-09 15:10:17 -08001603{
1604 destroy_workqueue(rport_event_queue);
1605}
Robert Love42e9a922008-12-09 15:10:17 -08001606
1607void fc_rport_terminate_io(struct fc_rport *rport)
1608{
Joe Eykholtab28f1f2009-08-25 14:00:34 -07001609 struct fc_rport_libfc_priv *rp = rport->dd_data;
1610 struct fc_lport *lport = rp->local_port;
Robert Love42e9a922008-12-09 15:10:17 -08001611
Abhijeet Joglekar1f6ff362009-02-27 10:54:35 -08001612 lport->tt.exch_mgr_reset(lport, 0, rport->port_id);
1613 lport->tt.exch_mgr_reset(lport, rport->port_id, 0);
Robert Love42e9a922008-12-09 15:10:17 -08001614}
1615EXPORT_SYMBOL(fc_rport_terminate_io);