blob: 99ac056293f526187d0b4e3564e45103df938830 [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/**
Joe Eykholt8025b5d2009-08-25 14:02:06 -070090 * fc_rport_lookup() - lookup a remote port by port_id
91 * @lport: Fibre Channel host port instance
92 * @port_id: remote port port_id to match
93 */
94static struct fc_rport_priv *fc_rport_lookup(const struct fc_lport *lport,
95 u32 port_id)
96{
97 struct fc_rport_priv *rdata;
98
99 list_for_each_entry(rdata, &lport->disc.rports, peers)
100 if (rdata->ids.port_id == port_id &&
101 rdata->rp_state != RPORT_ST_DELETE)
102 return rdata;
103 return NULL;
104}
105
106/**
Joe Eykholt9e9d0452009-08-25 14:01:18 -0700107 * fc_rport_create() - create remote port in INIT state.
108 * @lport: local port.
109 * @ids: remote port identifiers.
110 *
Joe Eykholt48f00902009-08-25 14:01:50 -0700111 * Locking note: must be called with the disc_mutex held.
Joe Eykholt9e9d0452009-08-25 14:01:18 -0700112 */
113static struct fc_rport_priv *fc_rport_create(struct fc_lport *lport,
114 struct fc_rport_identifiers *ids)
Robert Love42e9a922008-12-09 15:10:17 -0800115{
Joe Eykholtab28f1f2009-08-25 14:00:34 -0700116 struct fc_rport_priv *rdata;
Robert Love42e9a922008-12-09 15:10:17 -0800117
Joe Eykholt19f97e32009-08-25 14:01:55 -0700118 rdata = lport->tt.rport_lookup(lport, ids->port_id);
119 if (rdata)
120 return rdata;
121
Joe Eykholt9e9d0452009-08-25 14:01:18 -0700122 rdata = kzalloc(sizeof(*rdata), GFP_KERNEL);
123 if (!rdata)
Robert Love42e9a922008-12-09 15:10:17 -0800124 return NULL;
125
Joe Eykholtf211fa52009-08-25 14:01:01 -0700126 rdata->ids = *ids;
127 kref_init(&rdata->kref);
Robert Love42e9a922008-12-09 15:10:17 -0800128 mutex_init(&rdata->rp_mutex);
Joe Eykholt795d86f2009-08-25 14:00:39 -0700129 rdata->local_port = lport;
Robert Love42e9a922008-12-09 15:10:17 -0800130 rdata->rp_state = RPORT_ST_INIT;
131 rdata->event = RPORT_EV_NONE;
132 rdata->flags = FC_RP_FLAGS_REC_SUPPORTED;
Joe Eykholt795d86f2009-08-25 14:00:39 -0700133 rdata->e_d_tov = lport->e_d_tov;
134 rdata->r_a_tov = lport->r_a_tov;
Joe Eykholtf211fa52009-08-25 14:01:01 -0700135 rdata->maxframe_size = FC_MIN_MAX_PAYLOAD;
Robert Love42e9a922008-12-09 15:10:17 -0800136 INIT_DELAYED_WORK(&rdata->retry_work, fc_rport_timeout);
137 INIT_WORK(&rdata->event_work, fc_rport_work);
Joe Eykholt48f00902009-08-25 14:01:50 -0700138 if (ids->port_id != FC_FID_DIR_SERV)
139 list_add(&rdata->peers, &lport->disc.rports);
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700140 return rdata;
Robert Love42e9a922008-12-09 15:10:17 -0800141}
142
143/**
Joe Eykholtf211fa52009-08-25 14:01:01 -0700144 * fc_rport_destroy() - free a remote port after last reference is released.
145 * @kref: pointer to kref inside struct fc_rport_priv
146 */
147static void fc_rport_destroy(struct kref *kref)
148{
149 struct fc_rport_priv *rdata;
Joe Eykholtf211fa52009-08-25 14:01:01 -0700150
151 rdata = container_of(kref, struct fc_rport_priv, kref);
Joe Eykholt9e9d0452009-08-25 14:01:18 -0700152 kfree(rdata);
Joe Eykholtf211fa52009-08-25 14:01:01 -0700153}
154
155/**
Robert Love34f42a02009-02-27 10:55:45 -0800156 * fc_rport_state() - return a string for the state the rport is in
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700157 * @rdata: remote port private data
Robert Love42e9a922008-12-09 15:10:17 -0800158 */
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700159static const char *fc_rport_state(struct fc_rport_priv *rdata)
Robert Love42e9a922008-12-09 15:10:17 -0800160{
161 const char *cp;
Robert Love42e9a922008-12-09 15:10:17 -0800162
163 cp = fc_rport_state_names[rdata->rp_state];
164 if (!cp)
165 cp = "Unknown";
166 return cp;
167}
168
169/**
Robert Love34f42a02009-02-27 10:55:45 -0800170 * fc_set_rport_loss_tmo() - Set the remote port loss timeout in seconds.
Robert Love42e9a922008-12-09 15:10:17 -0800171 * @rport: Pointer to Fibre Channel remote port structure
172 * @timeout: timeout in seconds
173 */
174void fc_set_rport_loss_tmo(struct fc_rport *rport, u32 timeout)
175{
176 if (timeout)
177 rport->dev_loss_tmo = timeout + 5;
178 else
179 rport->dev_loss_tmo = 30;
180}
181EXPORT_SYMBOL(fc_set_rport_loss_tmo);
182
183/**
Robert Love34f42a02009-02-27 10:55:45 -0800184 * fc_plogi_get_maxframe() - Get max payload from the common service parameters
Robert Love42e9a922008-12-09 15:10:17 -0800185 * @flp: FLOGI payload structure
186 * @maxval: upper limit, may be less than what is in the service parameters
187 */
Robert Loveb2ab99c2009-02-27 10:55:50 -0800188static unsigned int fc_plogi_get_maxframe(struct fc_els_flogi *flp,
189 unsigned int maxval)
Robert Love42e9a922008-12-09 15:10:17 -0800190{
191 unsigned int mfs;
192
193 /*
194 * Get max payload from the common service parameters and the
195 * class 3 receive data field size.
196 */
197 mfs = ntohs(flp->fl_csp.sp_bb_data) & FC_SP_BB_DATA_MASK;
198 if (mfs >= FC_SP_MIN_MAX_PAYLOAD && mfs < maxval)
199 maxval = mfs;
200 mfs = ntohs(flp->fl_cssp[3 - 1].cp_rdfs);
201 if (mfs >= FC_SP_MIN_MAX_PAYLOAD && mfs < maxval)
202 maxval = mfs;
203 return maxval;
204}
205
206/**
Robert Love34f42a02009-02-27 10:55:45 -0800207 * fc_rport_state_enter() - Change the rport's state
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700208 * @rdata: The rport whose state should change
Robert Love42e9a922008-12-09 15:10:17 -0800209 * @new: The new state of the rport
210 *
211 * Locking Note: Called with the rport lock held
212 */
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700213static void fc_rport_state_enter(struct fc_rport_priv *rdata,
Robert Love42e9a922008-12-09 15:10:17 -0800214 enum fc_rport_state new)
215{
Robert Love42e9a922008-12-09 15:10:17 -0800216 if (rdata->rp_state != new)
217 rdata->retries = 0;
218 rdata->rp_state = new;
219}
220
221static void fc_rport_work(struct work_struct *work)
222{
Abhijeet Joglekar571f8242009-02-27 10:54:41 -0800223 u32 port_id;
Joe Eykholtab28f1f2009-08-25 14:00:34 -0700224 struct fc_rport_priv *rdata =
225 container_of(work, struct fc_rport_priv, event_work);
Joe Eykholt9e9d0452009-08-25 14:01:18 -0700226 struct fc_rport_libfc_priv *rp;
Robert Love42e9a922008-12-09 15:10:17 -0800227 enum fc_rport_event event;
Robert Love42e9a922008-12-09 15:10:17 -0800228 struct fc_lport *lport = rdata->local_port;
229 struct fc_rport_operations *rport_ops;
Joe Eykholt629f4422009-08-25 14:01:06 -0700230 struct fc_rport_identifiers ids;
Joe Eykholtf211fa52009-08-25 14:01:01 -0700231 struct fc_rport *rport;
Robert Love42e9a922008-12-09 15:10:17 -0800232
233 mutex_lock(&rdata->rp_mutex);
234 event = rdata->event;
235 rport_ops = rdata->ops;
Joe Eykholtf211fa52009-08-25 14:01:01 -0700236 rport = rdata->rport;
Robert Love42e9a922008-12-09 15:10:17 -0800237
Joe Eykholt9e9d0452009-08-25 14:01:18 -0700238 FC_RPORT_DBG(rdata, "work event %u\n", event);
239
Joe Eykholt629f4422009-08-25 14:01:06 -0700240 switch (event) {
Joe Eykholt4c0f62b2009-08-25 14:01:12 -0700241 case RPORT_EV_READY:
Joe Eykholtf211fa52009-08-25 14:01:01 -0700242 ids = rdata->ids;
Joe Eykholt5f7ea3b2009-07-29 17:04:49 -0700243 rdata->event = RPORT_EV_NONE;
Joe Eykholt9e9d0452009-08-25 14:01:18 -0700244 kref_get(&rdata->kref);
Robert Love42e9a922008-12-09 15:10:17 -0800245 mutex_unlock(&rdata->rp_mutex);
246
Joe Eykholt9e9d0452009-08-25 14:01:18 -0700247 if (!rport)
248 rport = fc_remote_port_add(lport->host, 0, &ids);
249 if (!rport) {
250 FC_RPORT_DBG(rdata, "Failed to add the rport\n");
251 lport->tt.rport_logoff(rdata);
252 kref_put(&rdata->kref, lport->tt.rport_destroy);
253 return;
Robert Love42e9a922008-12-09 15:10:17 -0800254 }
Joe Eykholt9e9d0452009-08-25 14:01:18 -0700255 mutex_lock(&rdata->rp_mutex);
256 if (rdata->rport)
257 FC_RPORT_DBG(rdata, "rport already allocated\n");
258 rdata->rport = rport;
259 rport->maxframe_size = rdata->maxframe_size;
260 rport->supported_classes = rdata->supported_classes;
261
262 rp = rport->dd_data;
263 rp->local_port = lport;
264 rp->rp_state = rdata->rp_state;
265 rp->flags = rdata->flags;
266 rp->e_d_tov = rdata->e_d_tov;
267 rp->r_a_tov = rdata->r_a_tov;
268 mutex_unlock(&rdata->rp_mutex);
269
Joe Eykholt83455922009-08-25 14:02:01 -0700270 if (rport_ops && rport_ops->event_callback) {
Joe Eykholt9e9d0452009-08-25 14:01:18 -0700271 FC_RPORT_DBG(rdata, "callback ev %d\n", event);
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700272 rport_ops->event_callback(lport, rdata, event);
Joe Eykholt9e9d0452009-08-25 14:01:18 -0700273 }
274 kref_put(&rdata->kref, lport->tt.rport_destroy);
Joe Eykholt629f4422009-08-25 14:01:06 -0700275 break;
276
277 case RPORT_EV_FAILED:
278 case RPORT_EV_LOGO:
279 case RPORT_EV_STOP:
Joe Eykholt9e9d0452009-08-25 14:01:18 -0700280 port_id = rdata->ids.port_id;
Robert Love42e9a922008-12-09 15:10:17 -0800281 mutex_unlock(&rdata->rp_mutex);
Joe Eykholt9e9d0452009-08-25 14:01:18 -0700282
Joe Eykholt48f00902009-08-25 14:01:50 -0700283 if (port_id != FC_FID_DIR_SERV) {
284 mutex_lock(&lport->disc.disc_mutex);
285 list_del(&rdata->peers);
286 mutex_unlock(&lport->disc.disc_mutex);
287 }
288
Joe Eykholt83455922009-08-25 14:02:01 -0700289 if (rport_ops && rport_ops->event_callback) {
Joe Eykholt9e9d0452009-08-25 14:01:18 -0700290 FC_RPORT_DBG(rdata, "callback ev %d\n", event);
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700291 rport_ops->event_callback(lport, rdata, event);
Abhijeet Joglekar571f8242009-02-27 10:54:41 -0800292 }
Joe Eykholt9e9d0452009-08-25 14:01:18 -0700293 cancel_delayed_work_sync(&rdata->retry_work);
294
295 /*
296 * Reset any outstanding exchanges before freeing rport.
297 */
298 lport->tt.exch_mgr_reset(lport, 0, port_id);
299 lport->tt.exch_mgr_reset(lport, port_id, 0);
300
301 if (rport) {
302 rp = rport->dd_data;
303 rp->rp_state = RPORT_ST_DELETE;
304 mutex_lock(&rdata->rp_mutex);
305 rdata->rport = NULL;
306 mutex_unlock(&rdata->rp_mutex);
307 fc_remote_port_delete(rport);
308 }
309 kref_put(&rdata->kref, lport->tt.rport_destroy);
Joe Eykholt629f4422009-08-25 14:01:06 -0700310 break;
311
312 default:
Robert Love42e9a922008-12-09 15:10:17 -0800313 mutex_unlock(&rdata->rp_mutex);
Joe Eykholt629f4422009-08-25 14:01:06 -0700314 break;
315 }
Robert Love42e9a922008-12-09 15:10:17 -0800316}
317
318/**
Robert Love34f42a02009-02-27 10:55:45 -0800319 * fc_rport_login() - Start the remote port login state machine
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700320 * @rdata: private remote port
Robert Love42e9a922008-12-09 15:10:17 -0800321 *
322 * Locking Note: Called without the rport lock held. This
323 * function will hold the rport lock, call an _enter_*
324 * function and then unlock the rport.
325 */
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700326int fc_rport_login(struct fc_rport_priv *rdata)
Robert Love42e9a922008-12-09 15:10:17 -0800327{
Robert Love42e9a922008-12-09 15:10:17 -0800328 mutex_lock(&rdata->rp_mutex);
329
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700330 FC_RPORT_DBG(rdata, "Login to port\n");
Robert Love42e9a922008-12-09 15:10:17 -0800331
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700332 fc_rport_enter_plogi(rdata);
Robert Love42e9a922008-12-09 15:10:17 -0800333
334 mutex_unlock(&rdata->rp_mutex);
335
336 return 0;
337}
338
339/**
Joe Eykholt5f7ea3b2009-07-29 17:04:49 -0700340 * fc_rport_enter_delete() - schedule a remote port to be deleted.
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700341 * @rdata: private remote port
Joe Eykholt5f7ea3b2009-07-29 17:04:49 -0700342 * @event: event to report as the reason for deletion
343 *
344 * Locking Note: Called with the rport lock held.
345 *
346 * Allow state change into DELETE only once.
347 *
348 * Call queue_work only if there's no event already pending.
349 * Set the new event so that the old pending event will not occur.
350 * Since we have the mutex, even if fc_rport_work() is already started,
351 * it'll see the new event.
352 */
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700353static void fc_rport_enter_delete(struct fc_rport_priv *rdata,
Joe Eykholt5f7ea3b2009-07-29 17:04:49 -0700354 enum fc_rport_event event)
355{
Joe Eykholt5f7ea3b2009-07-29 17:04:49 -0700356 if (rdata->rp_state == RPORT_ST_DELETE)
357 return;
358
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700359 FC_RPORT_DBG(rdata, "Delete port\n");
Joe Eykholt5f7ea3b2009-07-29 17:04:49 -0700360
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700361 fc_rport_state_enter(rdata, RPORT_ST_DELETE);
Joe Eykholt5f7ea3b2009-07-29 17:04:49 -0700362
363 if (rdata->event == RPORT_EV_NONE)
364 queue_work(rport_event_queue, &rdata->event_work);
365 rdata->event = event;
366}
367
368/**
Robert Love34f42a02009-02-27 10:55:45 -0800369 * fc_rport_logoff() - Logoff and remove an rport
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700370 * @rdata: private remote port
Robert Love42e9a922008-12-09 15:10:17 -0800371 *
372 * Locking Note: Called without the rport lock held. This
373 * function will hold the rport lock, call an _enter_*
374 * function and then unlock the rport.
375 */
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700376int fc_rport_logoff(struct fc_rport_priv *rdata)
Robert Love42e9a922008-12-09 15:10:17 -0800377{
Robert Love42e9a922008-12-09 15:10:17 -0800378 mutex_lock(&rdata->rp_mutex);
379
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700380 FC_RPORT_DBG(rdata, "Remove port\n");
Robert Love42e9a922008-12-09 15:10:17 -0800381
Joe Eykholt14194052009-07-29 17:04:43 -0700382 if (rdata->rp_state == RPORT_ST_DELETE) {
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700383 FC_RPORT_DBG(rdata, "Port in Delete state, not removing\n");
Abhijeet Joglekarb4c6f542009-04-21 16:27:04 -0700384 mutex_unlock(&rdata->rp_mutex);
385 goto out;
386 }
387
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700388 fc_rport_enter_logo(rdata);
Robert Love42e9a922008-12-09 15:10:17 -0800389
390 /*
Joe Eykholt14194052009-07-29 17:04:43 -0700391 * Change the state to Delete so that we discard
Robert Love42e9a922008-12-09 15:10:17 -0800392 * the response.
393 */
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700394 fc_rport_enter_delete(rdata, RPORT_EV_STOP);
Robert Love42e9a922008-12-09 15:10:17 -0800395 mutex_unlock(&rdata->rp_mutex);
396
Abhijeet Joglekarb4c6f542009-04-21 16:27:04 -0700397out:
Robert Love42e9a922008-12-09 15:10:17 -0800398 return 0;
399}
400
401/**
Robert Love34f42a02009-02-27 10:55:45 -0800402 * fc_rport_enter_ready() - The rport is ready
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700403 * @rdata: private remote port
Robert Love42e9a922008-12-09 15:10:17 -0800404 *
405 * Locking Note: The rport lock is expected to be held before calling
406 * this routine.
407 */
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700408static void fc_rport_enter_ready(struct fc_rport_priv *rdata)
Robert Love42e9a922008-12-09 15:10:17 -0800409{
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700410 fc_rport_state_enter(rdata, RPORT_ST_READY);
Robert Love42e9a922008-12-09 15:10:17 -0800411
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700412 FC_RPORT_DBG(rdata, "Port is Ready\n");
Robert Love42e9a922008-12-09 15:10:17 -0800413
Joe Eykholt5f7ea3b2009-07-29 17:04:49 -0700414 if (rdata->event == RPORT_EV_NONE)
415 queue_work(rport_event_queue, &rdata->event_work);
Joe Eykholt4c0f62b2009-08-25 14:01:12 -0700416 rdata->event = RPORT_EV_READY;
Robert Love42e9a922008-12-09 15:10:17 -0800417}
418
419/**
Robert Love34f42a02009-02-27 10:55:45 -0800420 * fc_rport_timeout() - Handler for the retry_work timer.
Joe Eykholtab28f1f2009-08-25 14:00:34 -0700421 * @work: The work struct of the fc_rport_priv
Robert Love42e9a922008-12-09 15:10:17 -0800422 *
423 * Locking Note: Called without the rport lock held. This
424 * function will hold the rport lock, call an _enter_*
425 * function and then unlock the rport.
426 */
427static void fc_rport_timeout(struct work_struct *work)
428{
Joe Eykholtab28f1f2009-08-25 14:00:34 -0700429 struct fc_rport_priv *rdata =
430 container_of(work, struct fc_rport_priv, retry_work.work);
Robert Love42e9a922008-12-09 15:10:17 -0800431
432 mutex_lock(&rdata->rp_mutex);
433
434 switch (rdata->rp_state) {
435 case RPORT_ST_PLOGI:
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700436 fc_rport_enter_plogi(rdata);
Robert Love42e9a922008-12-09 15:10:17 -0800437 break;
438 case RPORT_ST_PRLI:
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700439 fc_rport_enter_prli(rdata);
Robert Love42e9a922008-12-09 15:10:17 -0800440 break;
441 case RPORT_ST_RTV:
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700442 fc_rport_enter_rtv(rdata);
Robert Love42e9a922008-12-09 15:10:17 -0800443 break;
444 case RPORT_ST_LOGO:
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700445 fc_rport_enter_logo(rdata);
Robert Love42e9a922008-12-09 15:10:17 -0800446 break;
447 case RPORT_ST_READY:
448 case RPORT_ST_INIT:
Joe Eykholt14194052009-07-29 17:04:43 -0700449 case RPORT_ST_DELETE:
Robert Love42e9a922008-12-09 15:10:17 -0800450 break;
451 }
452
453 mutex_unlock(&rdata->rp_mutex);
Robert Love42e9a922008-12-09 15:10:17 -0800454}
455
456/**
Robert Love34f42a02009-02-27 10:55:45 -0800457 * fc_rport_error() - Error handler, called once retries have been exhausted
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700458 * @rdata: private remote port
Robert Love42e9a922008-12-09 15:10:17 -0800459 * @fp: The frame pointer
460 *
Robert Love42e9a922008-12-09 15:10:17 -0800461 * Locking Note: The rport lock is expected to be held before
462 * calling this routine
463 */
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700464static void fc_rport_error(struct fc_rport_priv *rdata, struct fc_frame *fp)
Robert Love42e9a922008-12-09 15:10:17 -0800465{
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700466 FC_RPORT_DBG(rdata, "Error %ld in state %s, retries %d\n",
Joe Eykholtcdbe6df2009-08-25 14:01:39 -0700467 IS_ERR(fp) ? -PTR_ERR(fp) : 0,
468 fc_rport_state(rdata), rdata->retries);
Robert Love42e9a922008-12-09 15:10:17 -0800469
Chris Leech6755db12009-02-27 10:55:02 -0800470 switch (rdata->rp_state) {
471 case RPORT_ST_PLOGI:
472 case RPORT_ST_PRLI:
473 case RPORT_ST_LOGO:
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700474 fc_rport_enter_delete(rdata, RPORT_EV_FAILED);
Chris Leech6755db12009-02-27 10:55:02 -0800475 break;
476 case RPORT_ST_RTV:
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700477 fc_rport_enter_ready(rdata);
Chris Leech6755db12009-02-27 10:55:02 -0800478 break;
Joe Eykholt14194052009-07-29 17:04:43 -0700479 case RPORT_ST_DELETE:
Chris Leech6755db12009-02-27 10:55:02 -0800480 case RPORT_ST_READY:
481 case RPORT_ST_INIT:
482 break;
Robert Love42e9a922008-12-09 15:10:17 -0800483 }
484}
485
486/**
Robert Love34f42a02009-02-27 10:55:45 -0800487 * fc_rport_error_retry() - Error handler when retries are desired
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700488 * @rdata: private remote port data
Chris Leech6755db12009-02-27 10:55:02 -0800489 * @fp: The frame pointer
490 *
491 * If the error was an exchange timeout retry immediately,
492 * otherwise wait for E_D_TOV.
493 *
494 * Locking Note: The rport lock is expected to be held before
495 * calling this routine
496 */
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700497static void fc_rport_error_retry(struct fc_rport_priv *rdata,
498 struct fc_frame *fp)
Chris Leech6755db12009-02-27 10:55:02 -0800499{
Chris Leech6755db12009-02-27 10:55:02 -0800500 unsigned long delay = FC_DEF_E_D_TOV;
501
502 /* make sure this isn't an FC_EX_CLOSED error, never retry those */
503 if (PTR_ERR(fp) == -FC_EX_CLOSED)
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700504 return fc_rport_error(rdata, fp);
Chris Leech6755db12009-02-27 10:55:02 -0800505
Abhijeet Joglekara3666952009-05-01 10:01:26 -0700506 if (rdata->retries < rdata->local_port->max_rport_retry_count) {
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700507 FC_RPORT_DBG(rdata, "Error %ld in state %s, retrying\n",
508 PTR_ERR(fp), fc_rport_state(rdata));
Chris Leech6755db12009-02-27 10:55:02 -0800509 rdata->retries++;
510 /* no additional delay on exchange timeouts */
511 if (PTR_ERR(fp) == -FC_EX_TIMEOUT)
512 delay = 0;
Chris Leech6755db12009-02-27 10:55:02 -0800513 schedule_delayed_work(&rdata->retry_work, delay);
514 return;
515 }
516
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700517 return fc_rport_error(rdata, fp);
Chris Leech6755db12009-02-27 10:55:02 -0800518}
519
520/**
Robert Love34f42a02009-02-27 10:55:45 -0800521 * fc_rport_plogi_recv_resp() - Handle incoming ELS PLOGI response
Robert Love42e9a922008-12-09 15:10:17 -0800522 * @sp: current sequence in the PLOGI exchange
523 * @fp: response frame
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700524 * @rdata_arg: private remote port data
Robert Love42e9a922008-12-09 15:10:17 -0800525 *
526 * Locking Note: This function will be called without the rport lock
527 * held, but it will lock, call an _enter_* function or fc_rport_error
528 * and then unlock the rport.
529 */
530static void fc_rport_plogi_resp(struct fc_seq *sp, struct fc_frame *fp,
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700531 void *rdata_arg)
Robert Love42e9a922008-12-09 15:10:17 -0800532{
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700533 struct fc_rport_priv *rdata = rdata_arg;
Robert Love42e9a922008-12-09 15:10:17 -0800534 struct fc_lport *lport = rdata->local_port;
Robert Lovea29e7642009-04-21 16:27:41 -0700535 struct fc_els_flogi *plp = NULL;
Robert Love42e9a922008-12-09 15:10:17 -0800536 unsigned int tov;
537 u16 csp_seq;
538 u16 cssp_seq;
539 u8 op;
540
541 mutex_lock(&rdata->rp_mutex);
542
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700543 FC_RPORT_DBG(rdata, "Received a PLOGI response\n");
Robert Love42e9a922008-12-09 15:10:17 -0800544
545 if (rdata->rp_state != RPORT_ST_PLOGI) {
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700546 FC_RPORT_DBG(rdata, "Received a PLOGI response, but in state "
547 "%s\n", fc_rport_state(rdata));
Abhijeet Joglekar76f68042009-04-21 16:26:58 -0700548 if (IS_ERR(fp))
549 goto err;
Robert Love42e9a922008-12-09 15:10:17 -0800550 goto out;
551 }
552
Abhijeet Joglekar76f68042009-04-21 16:26:58 -0700553 if (IS_ERR(fp)) {
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700554 fc_rport_error_retry(rdata, fp);
Abhijeet Joglekar76f68042009-04-21 16:26:58 -0700555 goto err;
556 }
557
Robert Love42e9a922008-12-09 15:10:17 -0800558 op = fc_frame_payload_op(fp);
559 if (op == ELS_LS_ACC &&
560 (plp = fc_frame_payload_get(fp, sizeof(*plp))) != NULL) {
Joe Eykholtf211fa52009-08-25 14:01:01 -0700561 rdata->ids.port_name = get_unaligned_be64(&plp->fl_wwpn);
562 rdata->ids.node_name = get_unaligned_be64(&plp->fl_wwnn);
Robert Love42e9a922008-12-09 15:10:17 -0800563
564 tov = ntohl(plp->fl_csp.sp_e_d_tov);
565 if (ntohs(plp->fl_csp.sp_features) & FC_SP_FT_EDTR)
566 tov /= 1000;
567 if (tov > rdata->e_d_tov)
568 rdata->e_d_tov = tov;
569 csp_seq = ntohs(plp->fl_csp.sp_tot_seq);
570 cssp_seq = ntohs(plp->fl_cssp[3 - 1].cp_con_seq);
571 if (cssp_seq < csp_seq)
572 csp_seq = cssp_seq;
573 rdata->max_seq = csp_seq;
Joe Eykholtf211fa52009-08-25 14:01:01 -0700574 rdata->maxframe_size = fc_plogi_get_maxframe(plp, lport->mfs);
Robert Love42e9a922008-12-09 15:10:17 -0800575
576 /*
577 * If the rport is one of the well known addresses
578 * we skip PRLI and RTV and go straight to READY.
579 */
Joe Eykholtf211fa52009-08-25 14:01:01 -0700580 if (rdata->ids.port_id >= FC_FID_DOM_MGR)
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700581 fc_rport_enter_ready(rdata);
Robert Love42e9a922008-12-09 15:10:17 -0800582 else
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700583 fc_rport_enter_prli(rdata);
Robert Love42e9a922008-12-09 15:10:17 -0800584 } else
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700585 fc_rport_error_retry(rdata, fp);
Robert Love42e9a922008-12-09 15:10:17 -0800586
587out:
588 fc_frame_free(fp);
589err:
590 mutex_unlock(&rdata->rp_mutex);
Joe Eykholtf211fa52009-08-25 14:01:01 -0700591 kref_put(&rdata->kref, rdata->local_port->tt.rport_destroy);
Robert Love42e9a922008-12-09 15:10:17 -0800592}
593
594/**
Robert Love34f42a02009-02-27 10:55:45 -0800595 * fc_rport_enter_plogi() - Send Port Login (PLOGI) request to peer
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700596 * @rdata: private remote port data
Robert Love42e9a922008-12-09 15:10:17 -0800597 *
598 * Locking Note: The rport lock is expected to be held before calling
599 * this routine.
600 */
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700601static void fc_rport_enter_plogi(struct fc_rport_priv *rdata)
Robert Love42e9a922008-12-09 15:10:17 -0800602{
Robert Love42e9a922008-12-09 15:10:17 -0800603 struct fc_lport *lport = rdata->local_port;
604 struct fc_frame *fp;
605
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700606 FC_RPORT_DBG(rdata, "Port entered PLOGI state from %s state\n",
607 fc_rport_state(rdata));
Robert Love42e9a922008-12-09 15:10:17 -0800608
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700609 fc_rport_state_enter(rdata, RPORT_ST_PLOGI);
Robert Love42e9a922008-12-09 15:10:17 -0800610
Joe Eykholtf211fa52009-08-25 14:01:01 -0700611 rdata->maxframe_size = FC_MIN_MAX_PAYLOAD;
Robert Love42e9a922008-12-09 15:10:17 -0800612 fp = fc_frame_alloc(lport, sizeof(struct fc_els_flogi));
613 if (!fp) {
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700614 fc_rport_error_retry(rdata, fp);
Robert Love42e9a922008-12-09 15:10:17 -0800615 return;
616 }
617 rdata->e_d_tov = lport->e_d_tov;
618
Joe Eykholtf211fa52009-08-25 14:01:01 -0700619 if (!lport->tt.elsct_send(lport, rdata->ids.port_id, fp, ELS_PLOGI,
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700620 fc_rport_plogi_resp, rdata, lport->e_d_tov))
621 fc_rport_error_retry(rdata, fp);
Robert Love42e9a922008-12-09 15:10:17 -0800622 else
Joe Eykholtf211fa52009-08-25 14:01:01 -0700623 kref_get(&rdata->kref);
Robert Love42e9a922008-12-09 15:10:17 -0800624}
625
626/**
Robert Love34f42a02009-02-27 10:55:45 -0800627 * fc_rport_prli_resp() - Process Login (PRLI) response handler
Robert Love42e9a922008-12-09 15:10:17 -0800628 * @sp: current sequence in the PRLI exchange
629 * @fp: response frame
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700630 * @rdata_arg: private remote port data
Robert Love42e9a922008-12-09 15:10:17 -0800631 *
632 * Locking Note: This function will be called without the rport lock
633 * held, but it will lock, call an _enter_* function or fc_rport_error
634 * and then unlock the rport.
635 */
636static void fc_rport_prli_resp(struct fc_seq *sp, struct fc_frame *fp,
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700637 void *rdata_arg)
Robert Love42e9a922008-12-09 15:10:17 -0800638{
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700639 struct fc_rport_priv *rdata = rdata_arg;
Robert Love42e9a922008-12-09 15:10:17 -0800640 struct {
641 struct fc_els_prli prli;
642 struct fc_els_spp spp;
643 } *pp;
644 u32 roles = FC_RPORT_ROLE_UNKNOWN;
645 u32 fcp_parm = 0;
646 u8 op;
647
648 mutex_lock(&rdata->rp_mutex);
649
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700650 FC_RPORT_DBG(rdata, "Received a PRLI response\n");
Robert Love42e9a922008-12-09 15:10:17 -0800651
652 if (rdata->rp_state != RPORT_ST_PRLI) {
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700653 FC_RPORT_DBG(rdata, "Received a PRLI response, but in state "
654 "%s\n", fc_rport_state(rdata));
Abhijeet Joglekar76f68042009-04-21 16:26:58 -0700655 if (IS_ERR(fp))
656 goto err;
Robert Love42e9a922008-12-09 15:10:17 -0800657 goto out;
658 }
659
Abhijeet Joglekar76f68042009-04-21 16:26:58 -0700660 if (IS_ERR(fp)) {
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700661 fc_rport_error_retry(rdata, fp);
Abhijeet Joglekar76f68042009-04-21 16:26:58 -0700662 goto err;
663 }
664
Robert Love42e9a922008-12-09 15:10:17 -0800665 op = fc_frame_payload_op(fp);
666 if (op == ELS_LS_ACC) {
667 pp = fc_frame_payload_get(fp, sizeof(*pp));
668 if (pp && pp->prli.prli_spp_len >= sizeof(pp->spp)) {
669 fcp_parm = ntohl(pp->spp.spp_params);
670 if (fcp_parm & FCP_SPPF_RETRY)
671 rdata->flags |= FC_RP_FLAGS_RETRY;
672 }
673
Joe Eykholtf211fa52009-08-25 14:01:01 -0700674 rdata->supported_classes = FC_COS_CLASS3;
Robert Love42e9a922008-12-09 15:10:17 -0800675 if (fcp_parm & FCP_SPPF_INIT_FCN)
676 roles |= FC_RPORT_ROLE_FCP_INITIATOR;
677 if (fcp_parm & FCP_SPPF_TARG_FCN)
678 roles |= FC_RPORT_ROLE_FCP_TARGET;
679
Joe Eykholtf211fa52009-08-25 14:01:01 -0700680 rdata->ids.roles = roles;
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700681 fc_rport_enter_rtv(rdata);
Robert Love42e9a922008-12-09 15:10:17 -0800682
683 } else {
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700684 FC_RPORT_DBG(rdata, "Bad ELS response for PRLI command\n");
685 fc_rport_enter_delete(rdata, RPORT_EV_FAILED);
Robert Love42e9a922008-12-09 15:10:17 -0800686 }
687
688out:
689 fc_frame_free(fp);
690err:
691 mutex_unlock(&rdata->rp_mutex);
Joe Eykholtf211fa52009-08-25 14:01:01 -0700692 kref_put(&rdata->kref, rdata->local_port->tt.rport_destroy);
Robert Love42e9a922008-12-09 15:10:17 -0800693}
694
695/**
Robert Love34f42a02009-02-27 10:55:45 -0800696 * fc_rport_logo_resp() - Logout (LOGO) response handler
Robert Love42e9a922008-12-09 15:10:17 -0800697 * @sp: current sequence in the LOGO exchange
698 * @fp: response frame
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700699 * @rdata_arg: private remote port data
Robert Love42e9a922008-12-09 15:10:17 -0800700 *
701 * Locking Note: This function will be called without the rport lock
702 * held, but it will lock, call an _enter_* function or fc_rport_error
703 * and then unlock the rport.
704 */
705static void fc_rport_logo_resp(struct fc_seq *sp, struct fc_frame *fp,
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700706 void *rdata_arg)
Robert Love42e9a922008-12-09 15:10:17 -0800707{
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700708 struct fc_rport_priv *rdata = rdata_arg;
Robert Love42e9a922008-12-09 15:10:17 -0800709 u8 op;
710
711 mutex_lock(&rdata->rp_mutex);
712
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700713 FC_RPORT_DBG(rdata, "Received a LOGO response\n");
Robert Love42e9a922008-12-09 15:10:17 -0800714
Robert Love42e9a922008-12-09 15:10:17 -0800715 if (rdata->rp_state != RPORT_ST_LOGO) {
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700716 FC_RPORT_DBG(rdata, "Received a LOGO response, but in state "
717 "%s\n", fc_rport_state(rdata));
Abhijeet Joglekar76f68042009-04-21 16:26:58 -0700718 if (IS_ERR(fp))
719 goto err;
Robert Love42e9a922008-12-09 15:10:17 -0800720 goto out;
721 }
722
Abhijeet Joglekar76f68042009-04-21 16:26:58 -0700723 if (IS_ERR(fp)) {
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700724 fc_rport_error_retry(rdata, fp);
Abhijeet Joglekar76f68042009-04-21 16:26:58 -0700725 goto err;
726 }
727
Robert Love42e9a922008-12-09 15:10:17 -0800728 op = fc_frame_payload_op(fp);
729 if (op == ELS_LS_ACC) {
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700730 fc_rport_enter_rtv(rdata);
Robert Love42e9a922008-12-09 15:10:17 -0800731 } else {
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700732 FC_RPORT_DBG(rdata, "Bad ELS response for LOGO command\n");
733 fc_rport_enter_delete(rdata, RPORT_EV_LOGO);
Robert Love42e9a922008-12-09 15:10:17 -0800734 }
735
736out:
737 fc_frame_free(fp);
738err:
739 mutex_unlock(&rdata->rp_mutex);
Joe Eykholtf211fa52009-08-25 14:01:01 -0700740 kref_put(&rdata->kref, rdata->local_port->tt.rport_destroy);
Robert Love42e9a922008-12-09 15:10:17 -0800741}
742
743/**
Robert Love34f42a02009-02-27 10:55:45 -0800744 * fc_rport_enter_prli() - Send Process Login (PRLI) request to peer
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700745 * @rdata: private remote port data
Robert Love42e9a922008-12-09 15:10:17 -0800746 *
747 * Locking Note: The rport lock is expected to be held before calling
748 * this routine.
749 */
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700750static void fc_rport_enter_prli(struct fc_rport_priv *rdata)
Robert Love42e9a922008-12-09 15:10:17 -0800751{
Robert Love42e9a922008-12-09 15:10:17 -0800752 struct fc_lport *lport = rdata->local_port;
753 struct {
754 struct fc_els_prli prli;
755 struct fc_els_spp spp;
756 } *pp;
757 struct fc_frame *fp;
758
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700759 FC_RPORT_DBG(rdata, "Port entered PRLI state from %s state\n",
760 fc_rport_state(rdata));
Robert Love42e9a922008-12-09 15:10:17 -0800761
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700762 fc_rport_state_enter(rdata, RPORT_ST_PRLI);
Robert Love42e9a922008-12-09 15:10:17 -0800763
764 fp = fc_frame_alloc(lport, sizeof(*pp));
765 if (!fp) {
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700766 fc_rport_error_retry(rdata, fp);
Robert Love42e9a922008-12-09 15:10:17 -0800767 return;
768 }
769
Joe Eykholtf211fa52009-08-25 14:01:01 -0700770 if (!lport->tt.elsct_send(lport, rdata->ids.port_id, fp, ELS_PRLI,
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700771 fc_rport_prli_resp, rdata, lport->e_d_tov))
772 fc_rport_error_retry(rdata, fp);
Robert Love42e9a922008-12-09 15:10:17 -0800773 else
Joe Eykholtf211fa52009-08-25 14:01:01 -0700774 kref_get(&rdata->kref);
Robert Love42e9a922008-12-09 15:10:17 -0800775}
776
777/**
Robert Love34f42a02009-02-27 10:55:45 -0800778 * fc_rport_els_rtv_resp() - Request Timeout Value response handler
Robert Love42e9a922008-12-09 15:10:17 -0800779 * @sp: current sequence in the RTV exchange
780 * @fp: response frame
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700781 * @rdata_arg: private remote port data
Robert Love42e9a922008-12-09 15:10:17 -0800782 *
783 * Many targets don't seem to support this.
784 *
785 * Locking Note: This function will be called without the rport lock
786 * held, but it will lock, call an _enter_* function or fc_rport_error
787 * and then unlock the rport.
788 */
789static void fc_rport_rtv_resp(struct fc_seq *sp, struct fc_frame *fp,
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700790 void *rdata_arg)
Robert Love42e9a922008-12-09 15:10:17 -0800791{
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700792 struct fc_rport_priv *rdata = rdata_arg;
Robert Love42e9a922008-12-09 15:10:17 -0800793 u8 op;
794
795 mutex_lock(&rdata->rp_mutex);
796
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700797 FC_RPORT_DBG(rdata, "Received a RTV response\n");
Robert Love42e9a922008-12-09 15:10:17 -0800798
799 if (rdata->rp_state != RPORT_ST_RTV) {
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700800 FC_RPORT_DBG(rdata, "Received a RTV response, but in state "
801 "%s\n", fc_rport_state(rdata));
Abhijeet Joglekar76f68042009-04-21 16:26:58 -0700802 if (IS_ERR(fp))
803 goto err;
Robert Love42e9a922008-12-09 15:10:17 -0800804 goto out;
805 }
806
Abhijeet Joglekar76f68042009-04-21 16:26:58 -0700807 if (IS_ERR(fp)) {
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700808 fc_rport_error(rdata, fp);
Abhijeet Joglekar76f68042009-04-21 16:26:58 -0700809 goto err;
810 }
811
Robert Love42e9a922008-12-09 15:10:17 -0800812 op = fc_frame_payload_op(fp);
813 if (op == ELS_LS_ACC) {
814 struct fc_els_rtv_acc *rtv;
815 u32 toq;
816 u32 tov;
817
818 rtv = fc_frame_payload_get(fp, sizeof(*rtv));
819 if (rtv) {
820 toq = ntohl(rtv->rtv_toq);
821 tov = ntohl(rtv->rtv_r_a_tov);
822 if (tov == 0)
823 tov = 1;
824 rdata->r_a_tov = tov;
825 tov = ntohl(rtv->rtv_e_d_tov);
826 if (toq & FC_ELS_RTV_EDRES)
827 tov /= 1000000;
828 if (tov == 0)
829 tov = 1;
830 rdata->e_d_tov = tov;
831 }
832 }
833
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700834 fc_rport_enter_ready(rdata);
Robert Love42e9a922008-12-09 15:10:17 -0800835
836out:
837 fc_frame_free(fp);
838err:
839 mutex_unlock(&rdata->rp_mutex);
Joe Eykholtf211fa52009-08-25 14:01:01 -0700840 kref_put(&rdata->kref, rdata->local_port->tt.rport_destroy);
Robert Love42e9a922008-12-09 15:10:17 -0800841}
842
843/**
Robert Love34f42a02009-02-27 10:55:45 -0800844 * fc_rport_enter_rtv() - Send Request Timeout Value (RTV) request to peer
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700845 * @rdata: private remote port data
Robert Love42e9a922008-12-09 15:10:17 -0800846 *
847 * Locking Note: The rport lock is expected to be held before calling
848 * this routine.
849 */
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700850static void fc_rport_enter_rtv(struct fc_rport_priv *rdata)
Robert Love42e9a922008-12-09 15:10:17 -0800851{
852 struct fc_frame *fp;
Robert Love42e9a922008-12-09 15:10:17 -0800853 struct fc_lport *lport = rdata->local_port;
854
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700855 FC_RPORT_DBG(rdata, "Port entered RTV state from %s state\n",
856 fc_rport_state(rdata));
Robert Love42e9a922008-12-09 15:10:17 -0800857
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700858 fc_rport_state_enter(rdata, RPORT_ST_RTV);
Robert Love42e9a922008-12-09 15:10:17 -0800859
860 fp = fc_frame_alloc(lport, sizeof(struct fc_els_rtv));
861 if (!fp) {
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700862 fc_rport_error_retry(rdata, fp);
Robert Love42e9a922008-12-09 15:10:17 -0800863 return;
864 }
865
Joe Eykholtf211fa52009-08-25 14:01:01 -0700866 if (!lport->tt.elsct_send(lport, rdata->ids.port_id, fp, ELS_RTV,
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700867 fc_rport_rtv_resp, rdata, lport->e_d_tov))
868 fc_rport_error_retry(rdata, fp);
Robert Love42e9a922008-12-09 15:10:17 -0800869 else
Joe Eykholtf211fa52009-08-25 14:01:01 -0700870 kref_get(&rdata->kref);
Robert Love42e9a922008-12-09 15:10:17 -0800871}
872
873/**
Robert Love34f42a02009-02-27 10:55:45 -0800874 * fc_rport_enter_logo() - Send Logout (LOGO) request to peer
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700875 * @rdata: private remote port data
Robert Love42e9a922008-12-09 15:10:17 -0800876 *
877 * Locking Note: The rport lock is expected to be held before calling
878 * this routine.
879 */
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700880static void fc_rport_enter_logo(struct fc_rport_priv *rdata)
Robert Love42e9a922008-12-09 15:10:17 -0800881{
Robert Love42e9a922008-12-09 15:10:17 -0800882 struct fc_lport *lport = rdata->local_port;
883 struct fc_frame *fp;
884
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700885 FC_RPORT_DBG(rdata, "Port entered LOGO state from %s state\n",
886 fc_rport_state(rdata));
Robert Love42e9a922008-12-09 15:10:17 -0800887
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700888 fc_rport_state_enter(rdata, RPORT_ST_LOGO);
Robert Love42e9a922008-12-09 15:10:17 -0800889
890 fp = fc_frame_alloc(lport, sizeof(struct fc_els_logo));
891 if (!fp) {
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700892 fc_rport_error_retry(rdata, fp);
Robert Love42e9a922008-12-09 15:10:17 -0800893 return;
894 }
895
Joe Eykholtf211fa52009-08-25 14:01:01 -0700896 if (!lport->tt.elsct_send(lport, rdata->ids.port_id, fp, ELS_LOGO,
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700897 fc_rport_logo_resp, rdata, lport->e_d_tov))
898 fc_rport_error_retry(rdata, fp);
Robert Love42e9a922008-12-09 15:10:17 -0800899 else
Joe Eykholtf211fa52009-08-25 14:01:01 -0700900 kref_get(&rdata->kref);
Robert Love42e9a922008-12-09 15:10:17 -0800901}
902
903
904/**
Robert Love34f42a02009-02-27 10:55:45 -0800905 * fc_rport_recv_req() - Receive a request from a rport
Robert Love42e9a922008-12-09 15:10:17 -0800906 * @sp: current sequence in the PLOGI exchange
907 * @fp: response frame
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700908 * @rdata_arg: private remote port data
Robert Love42e9a922008-12-09 15:10:17 -0800909 *
910 * Locking Note: Called without the rport lock held. This
911 * function will hold the rport lock, call an _enter_*
912 * function and then unlock the rport.
913 */
914void fc_rport_recv_req(struct fc_seq *sp, struct fc_frame *fp,
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700915 struct fc_rport_priv *rdata)
Robert Love42e9a922008-12-09 15:10:17 -0800916{
Robert Love42e9a922008-12-09 15:10:17 -0800917 struct fc_lport *lport = rdata->local_port;
918
919 struct fc_frame_header *fh;
920 struct fc_seq_els_data els_data;
921 u8 op;
922
923 mutex_lock(&rdata->rp_mutex);
924
925 els_data.fp = NULL;
926 els_data.explan = ELS_EXPL_NONE;
927 els_data.reason = ELS_RJT_NONE;
928
929 fh = fc_frame_header_get(fp);
930
931 if (fh->fh_r_ctl == FC_RCTL_ELS_REQ && fh->fh_type == FC_TYPE_ELS) {
932 op = fc_frame_payload_op(fp);
933 switch (op) {
934 case ELS_PLOGI:
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700935 fc_rport_recv_plogi_req(rdata, sp, fp);
Robert Love42e9a922008-12-09 15:10:17 -0800936 break;
937 case ELS_PRLI:
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700938 fc_rport_recv_prli_req(rdata, sp, fp);
Robert Love42e9a922008-12-09 15:10:17 -0800939 break;
940 case ELS_PRLO:
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700941 fc_rport_recv_prlo_req(rdata, sp, fp);
Robert Love42e9a922008-12-09 15:10:17 -0800942 break;
943 case ELS_LOGO:
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700944 fc_rport_recv_logo_req(rdata, sp, fp);
Robert Love42e9a922008-12-09 15:10:17 -0800945 break;
946 case ELS_RRQ:
947 els_data.fp = fp;
948 lport->tt.seq_els_rsp_send(sp, ELS_RRQ, &els_data);
949 break;
950 case ELS_REC:
951 els_data.fp = fp;
952 lport->tt.seq_els_rsp_send(sp, ELS_REC, &els_data);
953 break;
954 default:
955 els_data.reason = ELS_RJT_UNSUP;
956 lport->tt.seq_els_rsp_send(sp, ELS_LS_RJT, &els_data);
957 break;
958 }
959 }
960
961 mutex_unlock(&rdata->rp_mutex);
962}
963
964/**
Robert Love34f42a02009-02-27 10:55:45 -0800965 * fc_rport_recv_plogi_req() - Handle incoming Port Login (PLOGI) request
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700966 * @rdata: private remote port data
Robert Love42e9a922008-12-09 15:10:17 -0800967 * @sp: current sequence in the PLOGI exchange
968 * @fp: PLOGI request frame
969 *
970 * Locking Note: The rport lock is exected to be held before calling
971 * this function.
972 */
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700973static void fc_rport_recv_plogi_req(struct fc_rport_priv *rdata,
Robert Love42e9a922008-12-09 15:10:17 -0800974 struct fc_seq *sp, struct fc_frame *rx_fp)
975{
Robert Love42e9a922008-12-09 15:10:17 -0800976 struct fc_lport *lport = rdata->local_port;
977 struct fc_frame *fp = rx_fp;
978 struct fc_exch *ep;
979 struct fc_frame_header *fh;
980 struct fc_els_flogi *pl;
981 struct fc_seq_els_data rjt_data;
982 u32 sid;
983 u64 wwpn;
984 u64 wwnn;
985 enum fc_els_rjt_reason reject = 0;
986 u32 f_ctl;
987 rjt_data.fp = NULL;
988
989 fh = fc_frame_header_get(fp);
990
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700991 FC_RPORT_DBG(rdata, "Received PLOGI request while in state %s\n",
992 fc_rport_state(rdata));
Robert Love42e9a922008-12-09 15:10:17 -0800993
994 sid = ntoh24(fh->fh_s_id);
995 pl = fc_frame_payload_get(fp, sizeof(*pl));
996 if (!pl) {
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700997 FC_RPORT_DBG(rdata, "Received PLOGI too short\n");
Robert Love42e9a922008-12-09 15:10:17 -0800998 WARN_ON(1);
999 /* XXX TBD: send reject? */
1000 fc_frame_free(fp);
1001 return;
1002 }
1003 wwpn = get_unaligned_be64(&pl->fl_wwpn);
1004 wwnn = get_unaligned_be64(&pl->fl_wwnn);
1005
1006 /*
1007 * If the session was just created, possibly due to the incoming PLOGI,
1008 * set the state appropriately and accept the PLOGI.
1009 *
1010 * If we had also sent a PLOGI, and if the received PLOGI is from a
1011 * higher WWPN, we accept it, otherwise an LS_RJT is sent with reason
1012 * "command already in progress".
1013 *
1014 * XXX TBD: If the session was ready before, the PLOGI should result in
1015 * all outstanding exchanges being reset.
1016 */
1017 switch (rdata->rp_state) {
1018 case RPORT_ST_INIT:
Joe Eykholt9fb9d322009-08-25 14:00:50 -07001019 FC_RPORT_DBG(rdata, "Received PLOGI, wwpn %llx state INIT "
Robert Love74147052009-06-10 15:31:10 -07001020 "- reject\n", (unsigned long long)wwpn);
Robert Love42e9a922008-12-09 15:10:17 -08001021 reject = ELS_RJT_UNSUP;
1022 break;
1023 case RPORT_ST_PLOGI:
Joe Eykholt9fb9d322009-08-25 14:00:50 -07001024 FC_RPORT_DBG(rdata, "Received PLOGI in PLOGI state %d\n",
Robert Love74147052009-06-10 15:31:10 -07001025 rdata->rp_state);
Robert Love42e9a922008-12-09 15:10:17 -08001026 if (wwpn < lport->wwpn)
1027 reject = ELS_RJT_INPROG;
1028 break;
1029 case RPORT_ST_PRLI:
1030 case RPORT_ST_READY:
Joe Eykholt9fb9d322009-08-25 14:00:50 -07001031 FC_RPORT_DBG(rdata, "Received PLOGI in logged-in state %d "
Robert Love74147052009-06-10 15:31:10 -07001032 "- ignored for now\n", rdata->rp_state);
Robert Love42e9a922008-12-09 15:10:17 -08001033 /* XXX TBD - should reset */
1034 break;
Joe Eykholt14194052009-07-29 17:04:43 -07001035 case RPORT_ST_DELETE:
Robert Love42e9a922008-12-09 15:10:17 -08001036 default:
Joe Eykholt9fb9d322009-08-25 14:00:50 -07001037 FC_RPORT_DBG(rdata, "Received PLOGI in unexpected "
Robert Love74147052009-06-10 15:31:10 -07001038 "state %d\n", rdata->rp_state);
Abhijeet Joglekarb4c6f542009-04-21 16:27:04 -07001039 fc_frame_free(fp);
1040 return;
Robert Love42e9a922008-12-09 15:10:17 -08001041 break;
1042 }
1043
1044 if (reject) {
1045 rjt_data.reason = reject;
1046 rjt_data.explan = ELS_EXPL_NONE;
1047 lport->tt.seq_els_rsp_send(sp, ELS_LS_RJT, &rjt_data);
1048 fc_frame_free(fp);
1049 } else {
1050 fp = fc_frame_alloc(lport, sizeof(*pl));
1051 if (fp == NULL) {
1052 fp = rx_fp;
1053 rjt_data.reason = ELS_RJT_UNAB;
1054 rjt_data.explan = ELS_EXPL_NONE;
1055 lport->tt.seq_els_rsp_send(sp, ELS_LS_RJT, &rjt_data);
1056 fc_frame_free(fp);
1057 } else {
1058 sp = lport->tt.seq_start_next(sp);
1059 WARN_ON(!sp);
Joe Eykholtf211fa52009-08-25 14:01:01 -07001060 rdata->ids.port_name = wwpn;
1061 rdata->ids.node_name = wwnn;
Robert Love42e9a922008-12-09 15:10:17 -08001062
1063 /*
1064 * Get session payload size from incoming PLOGI.
1065 */
Joe Eykholtf211fa52009-08-25 14:01:01 -07001066 rdata->maxframe_size =
Robert Love42e9a922008-12-09 15:10:17 -08001067 fc_plogi_get_maxframe(pl, lport->mfs);
1068 fc_frame_free(rx_fp);
1069 fc_plogi_fill(lport, fp, ELS_LS_ACC);
1070
1071 /*
1072 * Send LS_ACC. If this fails,
1073 * the originator should retry.
1074 */
1075 f_ctl = FC_FC_EX_CTX | FC_FC_LAST_SEQ;
1076 f_ctl |= FC_FC_END_SEQ | FC_FC_SEQ_INIT;
1077 ep = fc_seq_exch(sp);
1078 fc_fill_fc_hdr(fp, FC_RCTL_ELS_REP, ep->did, ep->sid,
1079 FC_TYPE_ELS, f_ctl, 0);
1080 lport->tt.seq_send(lport, sp, fp);
1081 if (rdata->rp_state == RPORT_ST_PLOGI)
Joe Eykholt9fb9d322009-08-25 14:00:50 -07001082 fc_rport_enter_prli(rdata);
Robert Love42e9a922008-12-09 15:10:17 -08001083 }
1084 }
1085}
1086
1087/**
Robert Love34f42a02009-02-27 10:55:45 -08001088 * fc_rport_recv_prli_req() - Handle incoming Process Login (PRLI) request
Joe Eykholt9fb9d322009-08-25 14:00:50 -07001089 * @rdata: private remote port data
Robert Love42e9a922008-12-09 15:10:17 -08001090 * @sp: current sequence in the PRLI exchange
1091 * @fp: PRLI request frame
1092 *
1093 * Locking Note: The rport lock is exected to be held before calling
1094 * this function.
1095 */
Joe Eykholt9fb9d322009-08-25 14:00:50 -07001096static void fc_rport_recv_prli_req(struct fc_rport_priv *rdata,
Robert Love42e9a922008-12-09 15:10:17 -08001097 struct fc_seq *sp, struct fc_frame *rx_fp)
1098{
Robert Love42e9a922008-12-09 15:10:17 -08001099 struct fc_lport *lport = rdata->local_port;
1100 struct fc_exch *ep;
1101 struct fc_frame *fp;
1102 struct fc_frame_header *fh;
1103 struct {
1104 struct fc_els_prli prli;
1105 struct fc_els_spp spp;
1106 } *pp;
1107 struct fc_els_spp *rspp; /* request service param page */
1108 struct fc_els_spp *spp; /* response spp */
1109 unsigned int len;
1110 unsigned int plen;
1111 enum fc_els_rjt_reason reason = ELS_RJT_UNAB;
1112 enum fc_els_rjt_explan explan = ELS_EXPL_NONE;
1113 enum fc_els_spp_resp resp;
1114 struct fc_seq_els_data rjt_data;
1115 u32 f_ctl;
1116 u32 fcp_parm;
1117 u32 roles = FC_RPORT_ROLE_UNKNOWN;
1118 rjt_data.fp = NULL;
1119
1120 fh = fc_frame_header_get(rx_fp);
1121
Joe Eykholt9fb9d322009-08-25 14:00:50 -07001122 FC_RPORT_DBG(rdata, "Received PRLI request while in state %s\n",
1123 fc_rport_state(rdata));
Robert Love42e9a922008-12-09 15:10:17 -08001124
1125 switch (rdata->rp_state) {
1126 case RPORT_ST_PRLI:
1127 case RPORT_ST_READY:
1128 reason = ELS_RJT_NONE;
1129 break;
1130 default:
Abhijeet Joglekarb4c6f542009-04-21 16:27:04 -07001131 fc_frame_free(rx_fp);
1132 return;
Robert Love42e9a922008-12-09 15:10:17 -08001133 break;
1134 }
1135 len = fr_len(rx_fp) - sizeof(*fh);
1136 pp = fc_frame_payload_get(rx_fp, sizeof(*pp));
1137 if (pp == NULL) {
1138 reason = ELS_RJT_PROT;
1139 explan = ELS_EXPL_INV_LEN;
1140 } else {
1141 plen = ntohs(pp->prli.prli_len);
1142 if ((plen % 4) != 0 || plen > len) {
1143 reason = ELS_RJT_PROT;
1144 explan = ELS_EXPL_INV_LEN;
1145 } else if (plen < len) {
1146 len = plen;
1147 }
1148 plen = pp->prli.prli_spp_len;
1149 if ((plen % 4) != 0 || plen < sizeof(*spp) ||
1150 plen > len || len < sizeof(*pp)) {
1151 reason = ELS_RJT_PROT;
1152 explan = ELS_EXPL_INV_LEN;
1153 }
1154 rspp = &pp->spp;
1155 }
1156 if (reason != ELS_RJT_NONE ||
1157 (fp = fc_frame_alloc(lport, len)) == NULL) {
1158 rjt_data.reason = reason;
1159 rjt_data.explan = explan;
1160 lport->tt.seq_els_rsp_send(sp, ELS_LS_RJT, &rjt_data);
1161 } else {
1162 sp = lport->tt.seq_start_next(sp);
1163 WARN_ON(!sp);
1164 pp = fc_frame_payload_get(fp, len);
1165 WARN_ON(!pp);
1166 memset(pp, 0, len);
1167 pp->prli.prli_cmd = ELS_LS_ACC;
1168 pp->prli.prli_spp_len = plen;
1169 pp->prli.prli_len = htons(len);
1170 len -= sizeof(struct fc_els_prli);
1171
1172 /*
1173 * Go through all the service parameter pages and build
1174 * response. If plen indicates longer SPP than standard,
1175 * use that. The entire response has been pre-cleared above.
1176 */
1177 spp = &pp->spp;
1178 while (len >= plen) {
1179 spp->spp_type = rspp->spp_type;
1180 spp->spp_type_ext = rspp->spp_type_ext;
1181 spp->spp_flags = rspp->spp_flags & FC_SPP_EST_IMG_PAIR;
1182 resp = FC_SPP_RESP_ACK;
1183 if (rspp->spp_flags & FC_SPP_RPA_VAL)
1184 resp = FC_SPP_RESP_NO_PA;
1185 switch (rspp->spp_type) {
1186 case 0: /* common to all FC-4 types */
1187 break;
1188 case FC_TYPE_FCP:
1189 fcp_parm = ntohl(rspp->spp_params);
1190 if (fcp_parm * FCP_SPPF_RETRY)
1191 rdata->flags |= FC_RP_FLAGS_RETRY;
Joe Eykholtf211fa52009-08-25 14:01:01 -07001192 rdata->supported_classes = FC_COS_CLASS3;
Robert Love42e9a922008-12-09 15:10:17 -08001193 if (fcp_parm & FCP_SPPF_INIT_FCN)
1194 roles |= FC_RPORT_ROLE_FCP_INITIATOR;
1195 if (fcp_parm & FCP_SPPF_TARG_FCN)
1196 roles |= FC_RPORT_ROLE_FCP_TARGET;
Joe Eykholtf211fa52009-08-25 14:01:01 -07001197 rdata->ids.roles = roles;
Robert Love42e9a922008-12-09 15:10:17 -08001198
1199 spp->spp_params =
1200 htonl(lport->service_params);
1201 break;
1202 default:
1203 resp = FC_SPP_RESP_INVL;
1204 break;
1205 }
1206 spp->spp_flags |= resp;
1207 len -= plen;
1208 rspp = (struct fc_els_spp *)((char *)rspp + plen);
1209 spp = (struct fc_els_spp *)((char *)spp + plen);
1210 }
1211
1212 /*
1213 * Send LS_ACC. If this fails, the originator should retry.
1214 */
1215 f_ctl = FC_FC_EX_CTX | FC_FC_LAST_SEQ;
1216 f_ctl |= FC_FC_END_SEQ | FC_FC_SEQ_INIT;
1217 ep = fc_seq_exch(sp);
1218 fc_fill_fc_hdr(fp, FC_RCTL_ELS_REP, ep->did, ep->sid,
1219 FC_TYPE_ELS, f_ctl, 0);
1220 lport->tt.seq_send(lport, sp, fp);
1221
1222 /*
1223 * Get lock and re-check state.
1224 */
1225 switch (rdata->rp_state) {
1226 case RPORT_ST_PRLI:
Joe Eykholt9fb9d322009-08-25 14:00:50 -07001227 fc_rport_enter_ready(rdata);
Robert Love42e9a922008-12-09 15:10:17 -08001228 break;
1229 case RPORT_ST_READY:
1230 break;
1231 default:
1232 break;
1233 }
1234 }
1235 fc_frame_free(rx_fp);
1236}
1237
1238/**
Robert Love34f42a02009-02-27 10:55:45 -08001239 * fc_rport_recv_prlo_req() - Handle incoming Process Logout (PRLO) request
Joe Eykholt9fb9d322009-08-25 14:00:50 -07001240 * @rdata: private remote port data
Robert Love42e9a922008-12-09 15:10:17 -08001241 * @sp: current sequence in the PRLO exchange
1242 * @fp: PRLO request frame
1243 *
1244 * Locking Note: The rport lock is exected to be held before calling
1245 * this function.
1246 */
Joe Eykholt9fb9d322009-08-25 14:00:50 -07001247static void fc_rport_recv_prlo_req(struct fc_rport_priv *rdata,
1248 struct fc_seq *sp,
Robert Love42e9a922008-12-09 15:10:17 -08001249 struct fc_frame *fp)
1250{
Robert Love42e9a922008-12-09 15:10:17 -08001251 struct fc_lport *lport = rdata->local_port;
1252
1253 struct fc_frame_header *fh;
1254 struct fc_seq_els_data rjt_data;
1255
1256 fh = fc_frame_header_get(fp);
1257
Joe Eykholt9fb9d322009-08-25 14:00:50 -07001258 FC_RPORT_DBG(rdata, "Received PRLO request while in state %s\n",
1259 fc_rport_state(rdata));
Robert Love42e9a922008-12-09 15:10:17 -08001260
Joe Eykholt14194052009-07-29 17:04:43 -07001261 if (rdata->rp_state == RPORT_ST_DELETE) {
Abhijeet Joglekarb4c6f542009-04-21 16:27:04 -07001262 fc_frame_free(fp);
1263 return;
1264 }
1265
Robert Love42e9a922008-12-09 15:10:17 -08001266 rjt_data.fp = NULL;
1267 rjt_data.reason = ELS_RJT_UNAB;
1268 rjt_data.explan = ELS_EXPL_NONE;
1269 lport->tt.seq_els_rsp_send(sp, ELS_LS_RJT, &rjt_data);
1270 fc_frame_free(fp);
1271}
1272
1273/**
Robert Love34f42a02009-02-27 10:55:45 -08001274 * fc_rport_recv_logo_req() - Handle incoming Logout (LOGO) request
Joe Eykholt9fb9d322009-08-25 14:00:50 -07001275 * @rdata: private remote port data
Robert Love42e9a922008-12-09 15:10:17 -08001276 * @sp: current sequence in the LOGO exchange
1277 * @fp: LOGO request frame
1278 *
1279 * Locking Note: The rport lock is exected to be held before calling
1280 * this function.
1281 */
Joe Eykholt9fb9d322009-08-25 14:00:50 -07001282static void fc_rport_recv_logo_req(struct fc_rport_priv *rdata,
1283 struct fc_seq *sp,
Robert Love42e9a922008-12-09 15:10:17 -08001284 struct fc_frame *fp)
1285{
1286 struct fc_frame_header *fh;
Robert Love42e9a922008-12-09 15:10:17 -08001287 struct fc_lport *lport = rdata->local_port;
1288
1289 fh = fc_frame_header_get(fp);
1290
Joe Eykholt9fb9d322009-08-25 14:00:50 -07001291 FC_RPORT_DBG(rdata, "Received LOGO request while in state %s\n",
1292 fc_rport_state(rdata));
Robert Love42e9a922008-12-09 15:10:17 -08001293
Joe Eykholt14194052009-07-29 17:04:43 -07001294 if (rdata->rp_state == RPORT_ST_DELETE) {
Abhijeet Joglekarb4c6f542009-04-21 16:27:04 -07001295 fc_frame_free(fp);
1296 return;
1297 }
1298
Joe Eykholt00fea932009-08-25 14:01:23 -07001299 fc_rport_enter_delete(rdata, RPORT_EV_LOGO);
Robert Love42e9a922008-12-09 15:10:17 -08001300
1301 lport->tt.seq_els_rsp_send(sp, ELS_LS_ACC, NULL);
1302 fc_frame_free(fp);
1303}
1304
1305static void fc_rport_flush_queue(void)
1306{
1307 flush_workqueue(rport_event_queue);
1308}
1309
Robert Love42e9a922008-12-09 15:10:17 -08001310int fc_rport_init(struct fc_lport *lport)
1311{
Joe Eykholt8025b5d2009-08-25 14:02:06 -07001312 if (!lport->tt.rport_lookup)
1313 lport->tt.rport_lookup = fc_rport_lookup;
1314
Robert Love5101ff92009-02-27 10:55:18 -08001315 if (!lport->tt.rport_create)
Joe Eykholt9e9d0452009-08-25 14:01:18 -07001316 lport->tt.rport_create = fc_rport_create;
Robert Love5101ff92009-02-27 10:55:18 -08001317
Robert Love42e9a922008-12-09 15:10:17 -08001318 if (!lport->tt.rport_login)
1319 lport->tt.rport_login = fc_rport_login;
1320
1321 if (!lport->tt.rport_logoff)
1322 lport->tt.rport_logoff = fc_rport_logoff;
1323
1324 if (!lport->tt.rport_recv_req)
1325 lport->tt.rport_recv_req = fc_rport_recv_req;
1326
1327 if (!lport->tt.rport_flush_queue)
1328 lport->tt.rport_flush_queue = fc_rport_flush_queue;
1329
Joe Eykholtf211fa52009-08-25 14:01:01 -07001330 if (!lport->tt.rport_destroy)
1331 lport->tt.rport_destroy = fc_rport_destroy;
1332
Robert Love42e9a922008-12-09 15:10:17 -08001333 return 0;
1334}
1335EXPORT_SYMBOL(fc_rport_init);
1336
Randy Dunlapb0d428a2009-04-27 21:49:31 -07001337int fc_setup_rport(void)
Robert Love42e9a922008-12-09 15:10:17 -08001338{
1339 rport_event_queue = create_singlethread_workqueue("fc_rport_eq");
1340 if (!rport_event_queue)
1341 return -ENOMEM;
1342 return 0;
1343}
1344EXPORT_SYMBOL(fc_setup_rport);
1345
Randy Dunlapb0d428a2009-04-27 21:49:31 -07001346void fc_destroy_rport(void)
Robert Love42e9a922008-12-09 15:10:17 -08001347{
1348 destroy_workqueue(rport_event_queue);
1349}
1350EXPORT_SYMBOL(fc_destroy_rport);
1351
1352void fc_rport_terminate_io(struct fc_rport *rport)
1353{
Joe Eykholtab28f1f2009-08-25 14:00:34 -07001354 struct fc_rport_libfc_priv *rp = rport->dd_data;
1355 struct fc_lport *lport = rp->local_port;
Robert Love42e9a922008-12-09 15:10:17 -08001356
Abhijeet Joglekar1f6ff362009-02-27 10:54:35 -08001357 lport->tt.exch_mgr_reset(lport, 0, rport->port_id);
1358 lport->tt.exch_mgr_reset(lport, rport->port_id, 0);
Robert Love42e9a922008-12-09 15:10:17 -08001359}
1360EXPORT_SYMBOL(fc_rport_terminate_io);