blob: 50959ba0a9a08bf0a22b825cc4641c50c55173bc [file] [log] [blame]
Robert Love42e9a922008-12-09 15:10:17 -08001/*
2 * Copyright(c) 2007 - 2008 Intel Corporation. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms and conditions of the GNU General Public License,
6 * version 2, as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
11 * more details.
12 *
13 * You should have received a copy of the GNU General Public License along with
14 * this program; if not, write to the Free Software Foundation, Inc.,
15 * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
16 *
17 * Maintained at www.Open-FCoE.org
18 */
19
20/*
21 * RPORT GENERAL INFO
22 *
23 * This file contains all processing regarding fc_rports. It contains the
24 * rport state machine and does all rport interaction with the transport class.
25 * There should be no other places in libfc that interact directly with the
26 * transport class in regards to adding and deleting rports.
27 *
28 * fc_rport's represent N_Port's within the fabric.
29 */
30
31/*
32 * RPORT LOCKING
33 *
34 * The rport should never hold the rport mutex and then attempt to acquire
35 * either the lport or disc mutexes. The rport's mutex is considered lesser
36 * than both the lport's mutex and the disc mutex. Refer to fc_lport.c for
37 * more comments on the heirarchy.
38 *
39 * The locking strategy is similar to the lport's strategy. The lock protects
40 * the rport's states and is held and released by the entry points to the rport
41 * block. All _enter_* functions correspond to rport states and expect the rport
42 * mutex to be locked before calling them. This means that rports only handle
43 * one request or response at a time, since they're not critical for the I/O
44 * path this potential over-use of the mutex is acceptable.
45 */
46
47#include <linux/kernel.h>
48#include <linux/spinlock.h>
49#include <linux/interrupt.h>
50#include <linux/rcupdate.h>
51#include <linux/timer.h>
52#include <linux/workqueue.h>
53#include <asm/unaligned.h>
54
55#include <scsi/libfc.h>
56#include <scsi/fc_encode.h>
57
Robert Love42e9a922008-12-09 15:10:17 -080058struct workqueue_struct *rport_event_queue;
59
Joe Eykholt9fb9d322009-08-25 14:00:50 -070060static void fc_rport_enter_plogi(struct fc_rport_priv *);
61static void fc_rport_enter_prli(struct fc_rport_priv *);
62static void fc_rport_enter_rtv(struct fc_rport_priv *);
63static void fc_rport_enter_ready(struct fc_rport_priv *);
64static void fc_rport_enter_logo(struct fc_rport_priv *);
Robert Love42e9a922008-12-09 15:10:17 -080065
Joe Eykholt9fb9d322009-08-25 14:00:50 -070066static void fc_rport_recv_plogi_req(struct fc_rport_priv *,
Robert Love42e9a922008-12-09 15:10:17 -080067 struct fc_seq *, struct fc_frame *);
Joe Eykholt9fb9d322009-08-25 14:00:50 -070068static void fc_rport_recv_prli_req(struct fc_rport_priv *,
Robert Love42e9a922008-12-09 15:10:17 -080069 struct fc_seq *, struct fc_frame *);
Joe Eykholt9fb9d322009-08-25 14:00:50 -070070static void fc_rport_recv_prlo_req(struct fc_rport_priv *,
Robert Love42e9a922008-12-09 15:10:17 -080071 struct fc_seq *, struct fc_frame *);
Joe Eykholt9fb9d322009-08-25 14:00:50 -070072static void fc_rport_recv_logo_req(struct fc_rport_priv *,
Robert Love42e9a922008-12-09 15:10:17 -080073 struct fc_seq *, struct fc_frame *);
74static void fc_rport_timeout(struct work_struct *);
Joe Eykholt9fb9d322009-08-25 14:00:50 -070075static void fc_rport_error(struct fc_rport_priv *, struct fc_frame *);
76static void fc_rport_error_retry(struct fc_rport_priv *, struct fc_frame *);
Robert Love42e9a922008-12-09 15:10:17 -080077static void fc_rport_work(struct work_struct *);
78
79static const char *fc_rport_state_names[] = {
Robert Love42e9a922008-12-09 15:10:17 -080080 [RPORT_ST_INIT] = "Init",
81 [RPORT_ST_PLOGI] = "PLOGI",
82 [RPORT_ST_PRLI] = "PRLI",
83 [RPORT_ST_RTV] = "RTV",
84 [RPORT_ST_READY] = "Ready",
85 [RPORT_ST_LOGO] = "LOGO",
Joe Eykholt14194052009-07-29 17:04:43 -070086 [RPORT_ST_DELETE] = "Delete",
Robert Love42e9a922008-12-09 15:10:17 -080087};
88
89static void fc_rport_rogue_destroy(struct device *dev)
90{
91 struct fc_rport *rport = dev_to_rport(dev);
Joe Eykholt9fb9d322009-08-25 14:00:50 -070092 struct fc_rport_priv *rdata = RPORT_TO_PRIV(rport);
93
94 FC_RPORT_DBG(rdata, "Destroying rogue rport\n");
Robert Love42e9a922008-12-09 15:10:17 -080095 kfree(rport);
96}
97
Joe Eykholt9fb9d322009-08-25 14:00:50 -070098struct fc_rport_priv *fc_rport_rogue_create(struct fc_lport *lport,
99 struct fc_rport_identifiers *ids)
Robert Love42e9a922008-12-09 15:10:17 -0800100{
101 struct fc_rport *rport;
Joe Eykholtab28f1f2009-08-25 14:00:34 -0700102 struct fc_rport_priv *rdata;
Robert Love42e9a922008-12-09 15:10:17 -0800103 rport = kzalloc(sizeof(*rport) + sizeof(*rdata), GFP_KERNEL);
104
105 if (!rport)
106 return NULL;
107
108 rdata = RPORT_TO_PRIV(rport);
109
110 rport->dd_data = rdata;
Joe Eykholt795d86f2009-08-25 14:00:39 -0700111 rport->port_id = ids->port_id;
112 rport->port_name = ids->port_name;
113 rport->node_name = ids->node_name;
114 rport->roles = ids->roles;
Robert Love42e9a922008-12-09 15:10:17 -0800115 rport->maxframe_size = FC_MIN_MAX_PAYLOAD;
116 /*
117 * Note: all this libfc rogue rport code will be removed for
118 * upstream so it fine that this is really ugly and hacky right now.
119 */
120 device_initialize(&rport->dev);
121 rport->dev.release = fc_rport_rogue_destroy;
122
Joe Eykholtf211fa52009-08-25 14:01:01 -0700123 rdata->ids = *ids;
124 kref_init(&rdata->kref);
Robert Love42e9a922008-12-09 15:10:17 -0800125 mutex_init(&rdata->rp_mutex);
Joe Eykholtf211fa52009-08-25 14:01:01 -0700126 rdata->rport = rport;
Joe Eykholt795d86f2009-08-25 14:00:39 -0700127 rdata->local_port = lport;
Robert Love42e9a922008-12-09 15:10:17 -0800128 rdata->trans_state = FC_PORTSTATE_ROGUE;
129 rdata->rp_state = RPORT_ST_INIT;
130 rdata->event = RPORT_EV_NONE;
131 rdata->flags = FC_RP_FLAGS_REC_SUPPORTED;
132 rdata->ops = NULL;
Joe Eykholt795d86f2009-08-25 14:00:39 -0700133 rdata->e_d_tov = lport->e_d_tov;
134 rdata->r_a_tov = lport->r_a_tov;
Joe Eykholtf211fa52009-08-25 14:01:01 -0700135 rdata->maxframe_size = FC_MIN_MAX_PAYLOAD;
Robert Love42e9a922008-12-09 15:10:17 -0800136 INIT_DELAYED_WORK(&rdata->retry_work, fc_rport_timeout);
137 INIT_WORK(&rdata->event_work, fc_rport_work);
138 /*
139 * For good measure, but not necessary as we should only
140 * add REAL rport to the lport list.
141 */
142 INIT_LIST_HEAD(&rdata->peers);
143
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700144 return rdata;
Robert Love42e9a922008-12-09 15:10:17 -0800145}
146
147/**
Joe Eykholtf211fa52009-08-25 14:01:01 -0700148 * fc_rport_destroy() - free a remote port after last reference is released.
149 * @kref: pointer to kref inside struct fc_rport_priv
150 */
151static void fc_rport_destroy(struct kref *kref)
152{
153 struct fc_rport_priv *rdata;
154 struct fc_rport *rport;
155
156 rdata = container_of(kref, struct fc_rport_priv, kref);
157 rport = rdata->rport;
158 put_device(&rport->dev);
159}
160
161/**
Robert Love34f42a02009-02-27 10:55:45 -0800162 * fc_rport_state() - return a string for the state the rport is in
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700163 * @rdata: remote port private data
Robert Love42e9a922008-12-09 15:10:17 -0800164 */
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700165static const char *fc_rport_state(struct fc_rport_priv *rdata)
Robert Love42e9a922008-12-09 15:10:17 -0800166{
167 const char *cp;
Robert Love42e9a922008-12-09 15:10:17 -0800168
169 cp = fc_rport_state_names[rdata->rp_state];
170 if (!cp)
171 cp = "Unknown";
172 return cp;
173}
174
175/**
Robert Love34f42a02009-02-27 10:55:45 -0800176 * fc_set_rport_loss_tmo() - Set the remote port loss timeout in seconds.
Robert Love42e9a922008-12-09 15:10:17 -0800177 * @rport: Pointer to Fibre Channel remote port structure
178 * @timeout: timeout in seconds
179 */
180void fc_set_rport_loss_tmo(struct fc_rport *rport, u32 timeout)
181{
182 if (timeout)
183 rport->dev_loss_tmo = timeout + 5;
184 else
185 rport->dev_loss_tmo = 30;
186}
187EXPORT_SYMBOL(fc_set_rport_loss_tmo);
188
189/**
Robert Love34f42a02009-02-27 10:55:45 -0800190 * fc_plogi_get_maxframe() - Get max payload from the common service parameters
Robert Love42e9a922008-12-09 15:10:17 -0800191 * @flp: FLOGI payload structure
192 * @maxval: upper limit, may be less than what is in the service parameters
193 */
Robert Loveb2ab99c2009-02-27 10:55:50 -0800194static unsigned int fc_plogi_get_maxframe(struct fc_els_flogi *flp,
195 unsigned int maxval)
Robert Love42e9a922008-12-09 15:10:17 -0800196{
197 unsigned int mfs;
198
199 /*
200 * Get max payload from the common service parameters and the
201 * class 3 receive data field size.
202 */
203 mfs = ntohs(flp->fl_csp.sp_bb_data) & FC_SP_BB_DATA_MASK;
204 if (mfs >= FC_SP_MIN_MAX_PAYLOAD && mfs < maxval)
205 maxval = mfs;
206 mfs = ntohs(flp->fl_cssp[3 - 1].cp_rdfs);
207 if (mfs >= FC_SP_MIN_MAX_PAYLOAD && mfs < maxval)
208 maxval = mfs;
209 return maxval;
210}
211
212/**
Robert Love34f42a02009-02-27 10:55:45 -0800213 * fc_rport_state_enter() - Change the rport's state
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700214 * @rdata: The rport whose state should change
Robert Love42e9a922008-12-09 15:10:17 -0800215 * @new: The new state of the rport
216 *
217 * Locking Note: Called with the rport lock held
218 */
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700219static void fc_rport_state_enter(struct fc_rport_priv *rdata,
Robert Love42e9a922008-12-09 15:10:17 -0800220 enum fc_rport_state new)
221{
Robert Love42e9a922008-12-09 15:10:17 -0800222 if (rdata->rp_state != new)
223 rdata->retries = 0;
224 rdata->rp_state = new;
225}
226
227static void fc_rport_work(struct work_struct *work)
228{
Abhijeet Joglekar571f8242009-02-27 10:54:41 -0800229 u32 port_id;
Joe Eykholtab28f1f2009-08-25 14:00:34 -0700230 struct fc_rport_priv *rdata =
231 container_of(work, struct fc_rport_priv, event_work);
Robert Love42e9a922008-12-09 15:10:17 -0800232 enum fc_rport_event event;
233 enum fc_rport_trans_state trans_state;
234 struct fc_lport *lport = rdata->local_port;
235 struct fc_rport_operations *rport_ops;
Joe Eykholt629f4422009-08-25 14:01:06 -0700236 struct fc_rport *new_rport;
237 struct fc_rport_priv *new_rdata;
238 struct fc_rport_identifiers ids;
Joe Eykholtf211fa52009-08-25 14:01:01 -0700239 struct fc_rport *rport;
Robert Love42e9a922008-12-09 15:10:17 -0800240
241 mutex_lock(&rdata->rp_mutex);
242 event = rdata->event;
243 rport_ops = rdata->ops;
Joe Eykholtf211fa52009-08-25 14:01:01 -0700244 rport = rdata->rport;
Robert Love42e9a922008-12-09 15:10:17 -0800245
Joe Eykholt629f4422009-08-25 14:01:06 -0700246 switch (event) {
Joe Eykholt4c0f62b2009-08-25 14:01:12 -0700247 case RPORT_EV_READY:
Joe Eykholtf211fa52009-08-25 14:01:01 -0700248 ids = rdata->ids;
Joe Eykholt5f7ea3b2009-07-29 17:04:49 -0700249 rdata->event = RPORT_EV_NONE;
Robert Love42e9a922008-12-09 15:10:17 -0800250 mutex_unlock(&rdata->rp_mutex);
251
252 new_rport = fc_remote_port_add(lport->host, 0, &ids);
253 if (new_rport) {
254 /*
255 * Switch from the rogue rport to the rport
256 * returned by the FC class.
257 */
Joe Eykholtf211fa52009-08-25 14:01:01 -0700258 new_rport->maxframe_size = rdata->maxframe_size;
Robert Love42e9a922008-12-09 15:10:17 -0800259
260 new_rdata = new_rport->dd_data;
Joe Eykholtf211fa52009-08-25 14:01:01 -0700261 new_rdata->rport = new_rport;
262 new_rdata->ids = ids;
Robert Love42e9a922008-12-09 15:10:17 -0800263 new_rdata->e_d_tov = rdata->e_d_tov;
264 new_rdata->r_a_tov = rdata->r_a_tov;
265 new_rdata->ops = rdata->ops;
266 new_rdata->local_port = rdata->local_port;
267 new_rdata->flags = FC_RP_FLAGS_REC_SUPPORTED;
268 new_rdata->trans_state = FC_PORTSTATE_REAL;
Joe Eykholtf211fa52009-08-25 14:01:01 -0700269 new_rdata->maxframe_size = rdata->maxframe_size;
270 new_rdata->supported_classes = rdata->supported_classes;
271 kref_init(&new_rdata->kref);
Robert Love42e9a922008-12-09 15:10:17 -0800272 mutex_init(&new_rdata->rp_mutex);
273 INIT_DELAYED_WORK(&new_rdata->retry_work,
274 fc_rport_timeout);
275 INIT_LIST_HEAD(&new_rdata->peers);
276 INIT_WORK(&new_rdata->event_work, fc_rport_work);
277
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700278 fc_rport_state_enter(new_rdata, RPORT_ST_READY);
Robert Love42e9a922008-12-09 15:10:17 -0800279 } else {
Robert Love74147052009-06-10 15:31:10 -0700280 printk(KERN_WARNING "libfc: Failed to allocate "
281 " memory for rport (%6x)\n", ids.port_id);
Robert Love42e9a922008-12-09 15:10:17 -0800282 event = RPORT_EV_FAILED;
283 }
Joe Eykholtf211fa52009-08-25 14:01:01 -0700284 if (rdata->ids.port_id != FC_FID_DIR_SERV)
Abhijeet Joglekarb4c6f542009-04-21 16:27:04 -0700285 if (rport_ops->event_callback)
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700286 rport_ops->event_callback(lport, rdata,
Abhijeet Joglekarb4c6f542009-04-21 16:27:04 -0700287 RPORT_EV_FAILED);
Joe Eykholtf211fa52009-08-25 14:01:01 -0700288 kref_put(&rdata->kref, lport->tt.rport_destroy);
Robert Love42e9a922008-12-09 15:10:17 -0800289 rdata = new_rport->dd_data;
290 if (rport_ops->event_callback)
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700291 rport_ops->event_callback(lport, rdata, event);
Joe Eykholt629f4422009-08-25 14:01:06 -0700292 break;
293
294 case RPORT_EV_FAILED:
295 case RPORT_EV_LOGO:
296 case RPORT_EV_STOP:
Robert Love42e9a922008-12-09 15:10:17 -0800297 trans_state = rdata->trans_state;
298 mutex_unlock(&rdata->rp_mutex);
299 if (rport_ops->event_callback)
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700300 rport_ops->event_callback(lport, rdata, event);
Joe Eykholt201e5792009-07-29 17:04:54 -0700301 cancel_delayed_work_sync(&rdata->retry_work);
Robert Love42e9a922008-12-09 15:10:17 -0800302 if (trans_state == FC_PORTSTATE_ROGUE)
Joe Eykholtf211fa52009-08-25 14:01:01 -0700303 kref_put(&rdata->kref, lport->tt.rport_destroy);
Abhijeet Joglekar571f8242009-02-27 10:54:41 -0800304 else {
305 port_id = rport->port_id;
Robert Love42e9a922008-12-09 15:10:17 -0800306 fc_remote_port_delete(rport);
Abhijeet Joglekar571f8242009-02-27 10:54:41 -0800307 lport->tt.exch_mgr_reset(lport, 0, port_id);
308 lport->tt.exch_mgr_reset(lport, port_id, 0);
309 }
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",
467 PTR_ERR(fp), fc_rport_state(rdata), rdata->retries);
Robert Love42e9a922008-12-09 15:10:17 -0800468
Chris Leech6755db12009-02-27 10:55:02 -0800469 switch (rdata->rp_state) {
470 case RPORT_ST_PLOGI:
471 case RPORT_ST_PRLI:
472 case RPORT_ST_LOGO:
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700473 fc_rport_enter_delete(rdata, RPORT_EV_FAILED);
Chris Leech6755db12009-02-27 10:55:02 -0800474 break;
475 case RPORT_ST_RTV:
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700476 fc_rport_enter_ready(rdata);
Chris Leech6755db12009-02-27 10:55:02 -0800477 break;
Joe Eykholt14194052009-07-29 17:04:43 -0700478 case RPORT_ST_DELETE:
Chris Leech6755db12009-02-27 10:55:02 -0800479 case RPORT_ST_READY:
480 case RPORT_ST_INIT:
481 break;
Robert Love42e9a922008-12-09 15:10:17 -0800482 }
483}
484
485/**
Robert Love34f42a02009-02-27 10:55:45 -0800486 * fc_rport_error_retry() - Error handler when retries are desired
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700487 * @rdata: private remote port data
Chris Leech6755db12009-02-27 10:55:02 -0800488 * @fp: The frame pointer
489 *
490 * If the error was an exchange timeout retry immediately,
491 * otherwise wait for E_D_TOV.
492 *
493 * Locking Note: The rport lock is expected to be held before
494 * calling this routine
495 */
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700496static void fc_rport_error_retry(struct fc_rport_priv *rdata,
497 struct fc_frame *fp)
Chris Leech6755db12009-02-27 10:55:02 -0800498{
Chris Leech6755db12009-02-27 10:55:02 -0800499 unsigned long delay = FC_DEF_E_D_TOV;
500
501 /* make sure this isn't an FC_EX_CLOSED error, never retry those */
502 if (PTR_ERR(fp) == -FC_EX_CLOSED)
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700503 return fc_rport_error(rdata, fp);
Chris Leech6755db12009-02-27 10:55:02 -0800504
Abhijeet Joglekara3666952009-05-01 10:01:26 -0700505 if (rdata->retries < rdata->local_port->max_rport_retry_count) {
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700506 FC_RPORT_DBG(rdata, "Error %ld in state %s, retrying\n",
507 PTR_ERR(fp), fc_rport_state(rdata));
Chris Leech6755db12009-02-27 10:55:02 -0800508 rdata->retries++;
509 /* no additional delay on exchange timeouts */
510 if (PTR_ERR(fp) == -FC_EX_TIMEOUT)
511 delay = 0;
Chris Leech6755db12009-02-27 10:55:02 -0800512 schedule_delayed_work(&rdata->retry_work, delay);
513 return;
514 }
515
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700516 return fc_rport_error(rdata, fp);
Chris Leech6755db12009-02-27 10:55:02 -0800517}
518
519/**
Robert Love34f42a02009-02-27 10:55:45 -0800520 * fc_rport_plogi_recv_resp() - Handle incoming ELS PLOGI response
Robert Love42e9a922008-12-09 15:10:17 -0800521 * @sp: current sequence in the PLOGI exchange
522 * @fp: response frame
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700523 * @rdata_arg: private remote port data
Robert Love42e9a922008-12-09 15:10:17 -0800524 *
525 * Locking Note: This function will be called without the rport lock
526 * held, but it will lock, call an _enter_* function or fc_rport_error
527 * and then unlock the rport.
528 */
529static void fc_rport_plogi_resp(struct fc_seq *sp, struct fc_frame *fp,
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700530 void *rdata_arg)
Robert Love42e9a922008-12-09 15:10:17 -0800531{
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700532 struct fc_rport_priv *rdata = rdata_arg;
Robert Love42e9a922008-12-09 15:10:17 -0800533 struct fc_lport *lport = rdata->local_port;
Robert Lovea29e7642009-04-21 16:27:41 -0700534 struct fc_els_flogi *plp = NULL;
Robert Love42e9a922008-12-09 15:10:17 -0800535 unsigned int tov;
536 u16 csp_seq;
537 u16 cssp_seq;
538 u8 op;
539
540 mutex_lock(&rdata->rp_mutex);
541
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700542 FC_RPORT_DBG(rdata, "Received a PLOGI response\n");
Robert Love42e9a922008-12-09 15:10:17 -0800543
544 if (rdata->rp_state != RPORT_ST_PLOGI) {
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700545 FC_RPORT_DBG(rdata, "Received a PLOGI response, but in state "
546 "%s\n", fc_rport_state(rdata));
Abhijeet Joglekar76f68042009-04-21 16:26:58 -0700547 if (IS_ERR(fp))
548 goto err;
Robert Love42e9a922008-12-09 15:10:17 -0800549 goto out;
550 }
551
Abhijeet Joglekar76f68042009-04-21 16:26:58 -0700552 if (IS_ERR(fp)) {
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700553 fc_rport_error_retry(rdata, fp);
Abhijeet Joglekar76f68042009-04-21 16:26:58 -0700554 goto err;
555 }
556
Robert Love42e9a922008-12-09 15:10:17 -0800557 op = fc_frame_payload_op(fp);
558 if (op == ELS_LS_ACC &&
559 (plp = fc_frame_payload_get(fp, sizeof(*plp))) != NULL) {
Joe Eykholtf211fa52009-08-25 14:01:01 -0700560 rdata->ids.port_name = get_unaligned_be64(&plp->fl_wwpn);
561 rdata->ids.node_name = get_unaligned_be64(&plp->fl_wwnn);
Robert Love42e9a922008-12-09 15:10:17 -0800562
563 tov = ntohl(plp->fl_csp.sp_e_d_tov);
564 if (ntohs(plp->fl_csp.sp_features) & FC_SP_FT_EDTR)
565 tov /= 1000;
566 if (tov > rdata->e_d_tov)
567 rdata->e_d_tov = tov;
568 csp_seq = ntohs(plp->fl_csp.sp_tot_seq);
569 cssp_seq = ntohs(plp->fl_cssp[3 - 1].cp_con_seq);
570 if (cssp_seq < csp_seq)
571 csp_seq = cssp_seq;
572 rdata->max_seq = csp_seq;
Joe Eykholtf211fa52009-08-25 14:01:01 -0700573 rdata->maxframe_size = fc_plogi_get_maxframe(plp, lport->mfs);
Robert Love42e9a922008-12-09 15:10:17 -0800574
575 /*
576 * If the rport is one of the well known addresses
577 * we skip PRLI and RTV and go straight to READY.
578 */
Joe Eykholtf211fa52009-08-25 14:01:01 -0700579 if (rdata->ids.port_id >= FC_FID_DOM_MGR)
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700580 fc_rport_enter_ready(rdata);
Robert Love42e9a922008-12-09 15:10:17 -0800581 else
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700582 fc_rport_enter_prli(rdata);
Robert Love42e9a922008-12-09 15:10:17 -0800583 } else
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700584 fc_rport_error_retry(rdata, fp);
Robert Love42e9a922008-12-09 15:10:17 -0800585
586out:
587 fc_frame_free(fp);
588err:
589 mutex_unlock(&rdata->rp_mutex);
Joe Eykholtf211fa52009-08-25 14:01:01 -0700590 kref_put(&rdata->kref, rdata->local_port->tt.rport_destroy);
Robert Love42e9a922008-12-09 15:10:17 -0800591}
592
593/**
Robert Love34f42a02009-02-27 10:55:45 -0800594 * fc_rport_enter_plogi() - Send Port Login (PLOGI) request to peer
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700595 * @rdata: private remote port data
Robert Love42e9a922008-12-09 15:10:17 -0800596 *
597 * Locking Note: The rport lock is expected to be held before calling
598 * this routine.
599 */
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700600static void fc_rport_enter_plogi(struct fc_rport_priv *rdata)
Robert Love42e9a922008-12-09 15:10:17 -0800601{
Robert Love42e9a922008-12-09 15:10:17 -0800602 struct fc_lport *lport = rdata->local_port;
603 struct fc_frame *fp;
604
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700605 FC_RPORT_DBG(rdata, "Port entered PLOGI state from %s state\n",
606 fc_rport_state(rdata));
Robert Love42e9a922008-12-09 15:10:17 -0800607
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700608 fc_rport_state_enter(rdata, RPORT_ST_PLOGI);
Robert Love42e9a922008-12-09 15:10:17 -0800609
Joe Eykholtf211fa52009-08-25 14:01:01 -0700610 rdata->maxframe_size = FC_MIN_MAX_PAYLOAD;
Robert Love42e9a922008-12-09 15:10:17 -0800611 fp = fc_frame_alloc(lport, sizeof(struct fc_els_flogi));
612 if (!fp) {
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700613 fc_rport_error_retry(rdata, fp);
Robert Love42e9a922008-12-09 15:10:17 -0800614 return;
615 }
616 rdata->e_d_tov = lport->e_d_tov;
617
Joe Eykholtf211fa52009-08-25 14:01:01 -0700618 if (!lport->tt.elsct_send(lport, rdata->ids.port_id, fp, ELS_PLOGI,
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700619 fc_rport_plogi_resp, rdata, lport->e_d_tov))
620 fc_rport_error_retry(rdata, fp);
Robert Love42e9a922008-12-09 15:10:17 -0800621 else
Joe Eykholtf211fa52009-08-25 14:01:01 -0700622 kref_get(&rdata->kref);
Robert Love42e9a922008-12-09 15:10:17 -0800623}
624
625/**
Robert Love34f42a02009-02-27 10:55:45 -0800626 * fc_rport_prli_resp() - Process Login (PRLI) response handler
Robert Love42e9a922008-12-09 15:10:17 -0800627 * @sp: current sequence in the PRLI exchange
628 * @fp: response frame
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700629 * @rdata_arg: private remote port data
Robert Love42e9a922008-12-09 15:10:17 -0800630 *
631 * Locking Note: This function will be called without the rport lock
632 * held, but it will lock, call an _enter_* function or fc_rport_error
633 * and then unlock the rport.
634 */
635static void fc_rport_prli_resp(struct fc_seq *sp, struct fc_frame *fp,
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700636 void *rdata_arg)
Robert Love42e9a922008-12-09 15:10:17 -0800637{
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700638 struct fc_rport_priv *rdata = rdata_arg;
Robert Love42e9a922008-12-09 15:10:17 -0800639 struct {
640 struct fc_els_prli prli;
641 struct fc_els_spp spp;
642 } *pp;
643 u32 roles = FC_RPORT_ROLE_UNKNOWN;
644 u32 fcp_parm = 0;
645 u8 op;
646
647 mutex_lock(&rdata->rp_mutex);
648
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700649 FC_RPORT_DBG(rdata, "Received a PRLI response\n");
Robert Love42e9a922008-12-09 15:10:17 -0800650
651 if (rdata->rp_state != RPORT_ST_PRLI) {
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700652 FC_RPORT_DBG(rdata, "Received a PRLI response, but in state "
653 "%s\n", fc_rport_state(rdata));
Abhijeet Joglekar76f68042009-04-21 16:26:58 -0700654 if (IS_ERR(fp))
655 goto err;
Robert Love42e9a922008-12-09 15:10:17 -0800656 goto out;
657 }
658
Abhijeet Joglekar76f68042009-04-21 16:26:58 -0700659 if (IS_ERR(fp)) {
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700660 fc_rport_error_retry(rdata, fp);
Abhijeet Joglekar76f68042009-04-21 16:26:58 -0700661 goto err;
662 }
663
Robert Love42e9a922008-12-09 15:10:17 -0800664 op = fc_frame_payload_op(fp);
665 if (op == ELS_LS_ACC) {
666 pp = fc_frame_payload_get(fp, sizeof(*pp));
667 if (pp && pp->prli.prli_spp_len >= sizeof(pp->spp)) {
668 fcp_parm = ntohl(pp->spp.spp_params);
669 if (fcp_parm & FCP_SPPF_RETRY)
670 rdata->flags |= FC_RP_FLAGS_RETRY;
671 }
672
Joe Eykholtf211fa52009-08-25 14:01:01 -0700673 rdata->supported_classes = FC_COS_CLASS3;
Robert Love42e9a922008-12-09 15:10:17 -0800674 if (fcp_parm & FCP_SPPF_INIT_FCN)
675 roles |= FC_RPORT_ROLE_FCP_INITIATOR;
676 if (fcp_parm & FCP_SPPF_TARG_FCN)
677 roles |= FC_RPORT_ROLE_FCP_TARGET;
678
Joe Eykholtf211fa52009-08-25 14:01:01 -0700679 rdata->ids.roles = roles;
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700680 fc_rport_enter_rtv(rdata);
Robert Love42e9a922008-12-09 15:10:17 -0800681
682 } else {
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700683 FC_RPORT_DBG(rdata, "Bad ELS response for PRLI command\n");
684 fc_rport_enter_delete(rdata, RPORT_EV_FAILED);
Robert Love42e9a922008-12-09 15:10:17 -0800685 }
686
687out:
688 fc_frame_free(fp);
689err:
690 mutex_unlock(&rdata->rp_mutex);
Joe Eykholtf211fa52009-08-25 14:01:01 -0700691 kref_put(&rdata->kref, rdata->local_port->tt.rport_destroy);
Robert Love42e9a922008-12-09 15:10:17 -0800692}
693
694/**
Robert Love34f42a02009-02-27 10:55:45 -0800695 * fc_rport_logo_resp() - Logout (LOGO) response handler
Robert Love42e9a922008-12-09 15:10:17 -0800696 * @sp: current sequence in the LOGO exchange
697 * @fp: response frame
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700698 * @rdata_arg: private remote port data
Robert Love42e9a922008-12-09 15:10:17 -0800699 *
700 * Locking Note: This function will be called without the rport lock
701 * held, but it will lock, call an _enter_* function or fc_rport_error
702 * and then unlock the rport.
703 */
704static void fc_rport_logo_resp(struct fc_seq *sp, struct fc_frame *fp,
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700705 void *rdata_arg)
Robert Love42e9a922008-12-09 15:10:17 -0800706{
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700707 struct fc_rport_priv *rdata = rdata_arg;
Robert Love42e9a922008-12-09 15:10:17 -0800708 u8 op;
709
710 mutex_lock(&rdata->rp_mutex);
711
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700712 FC_RPORT_DBG(rdata, "Received a LOGO response\n");
Robert Love42e9a922008-12-09 15:10:17 -0800713
Robert Love42e9a922008-12-09 15:10:17 -0800714 if (rdata->rp_state != RPORT_ST_LOGO) {
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700715 FC_RPORT_DBG(rdata, "Received a LOGO response, but in state "
716 "%s\n", fc_rport_state(rdata));
Abhijeet Joglekar76f68042009-04-21 16:26:58 -0700717 if (IS_ERR(fp))
718 goto err;
Robert Love42e9a922008-12-09 15:10:17 -0800719 goto out;
720 }
721
Abhijeet Joglekar76f68042009-04-21 16:26:58 -0700722 if (IS_ERR(fp)) {
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700723 fc_rport_error_retry(rdata, fp);
Abhijeet Joglekar76f68042009-04-21 16:26:58 -0700724 goto err;
725 }
726
Robert Love42e9a922008-12-09 15:10:17 -0800727 op = fc_frame_payload_op(fp);
728 if (op == ELS_LS_ACC) {
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700729 fc_rport_enter_rtv(rdata);
Robert Love42e9a922008-12-09 15:10:17 -0800730 } else {
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700731 FC_RPORT_DBG(rdata, "Bad ELS response for LOGO command\n");
732 fc_rport_enter_delete(rdata, RPORT_EV_LOGO);
Robert Love42e9a922008-12-09 15:10:17 -0800733 }
734
735out:
736 fc_frame_free(fp);
737err:
738 mutex_unlock(&rdata->rp_mutex);
Joe Eykholtf211fa52009-08-25 14:01:01 -0700739 kref_put(&rdata->kref, rdata->local_port->tt.rport_destroy);
Robert Love42e9a922008-12-09 15:10:17 -0800740}
741
742/**
Robert Love34f42a02009-02-27 10:55:45 -0800743 * fc_rport_enter_prli() - Send Process Login (PRLI) request to peer
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700744 * @rdata: private remote port data
Robert Love42e9a922008-12-09 15:10:17 -0800745 *
746 * Locking Note: The rport lock is expected to be held before calling
747 * this routine.
748 */
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700749static void fc_rport_enter_prli(struct fc_rport_priv *rdata)
Robert Love42e9a922008-12-09 15:10:17 -0800750{
Robert Love42e9a922008-12-09 15:10:17 -0800751 struct fc_lport *lport = rdata->local_port;
752 struct {
753 struct fc_els_prli prli;
754 struct fc_els_spp spp;
755 } *pp;
756 struct fc_frame *fp;
757
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700758 FC_RPORT_DBG(rdata, "Port entered PRLI state from %s state\n",
759 fc_rport_state(rdata));
Robert Love42e9a922008-12-09 15:10:17 -0800760
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700761 fc_rport_state_enter(rdata, RPORT_ST_PRLI);
Robert Love42e9a922008-12-09 15:10:17 -0800762
763 fp = fc_frame_alloc(lport, sizeof(*pp));
764 if (!fp) {
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700765 fc_rport_error_retry(rdata, fp);
Robert Love42e9a922008-12-09 15:10:17 -0800766 return;
767 }
768
Joe Eykholtf211fa52009-08-25 14:01:01 -0700769 if (!lport->tt.elsct_send(lport, rdata->ids.port_id, fp, ELS_PRLI,
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700770 fc_rport_prli_resp, rdata, lport->e_d_tov))
771 fc_rport_error_retry(rdata, fp);
Robert Love42e9a922008-12-09 15:10:17 -0800772 else
Joe Eykholtf211fa52009-08-25 14:01:01 -0700773 kref_get(&rdata->kref);
Robert Love42e9a922008-12-09 15:10:17 -0800774}
775
776/**
Robert Love34f42a02009-02-27 10:55:45 -0800777 * fc_rport_els_rtv_resp() - Request Timeout Value response handler
Robert Love42e9a922008-12-09 15:10:17 -0800778 * @sp: current sequence in the RTV exchange
779 * @fp: response frame
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700780 * @rdata_arg: private remote port data
Robert Love42e9a922008-12-09 15:10:17 -0800781 *
782 * Many targets don't seem to support this.
783 *
784 * Locking Note: This function will be called without the rport lock
785 * held, but it will lock, call an _enter_* function or fc_rport_error
786 * and then unlock the rport.
787 */
788static void fc_rport_rtv_resp(struct fc_seq *sp, struct fc_frame *fp,
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700789 void *rdata_arg)
Robert Love42e9a922008-12-09 15:10:17 -0800790{
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700791 struct fc_rport_priv *rdata = rdata_arg;
Robert Love42e9a922008-12-09 15:10:17 -0800792 u8 op;
793
794 mutex_lock(&rdata->rp_mutex);
795
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700796 FC_RPORT_DBG(rdata, "Received a RTV response\n");
Robert Love42e9a922008-12-09 15:10:17 -0800797
798 if (rdata->rp_state != RPORT_ST_RTV) {
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700799 FC_RPORT_DBG(rdata, "Received a RTV response, but in state "
800 "%s\n", fc_rport_state(rdata));
Abhijeet Joglekar76f68042009-04-21 16:26:58 -0700801 if (IS_ERR(fp))
802 goto err;
Robert Love42e9a922008-12-09 15:10:17 -0800803 goto out;
804 }
805
Abhijeet Joglekar76f68042009-04-21 16:26:58 -0700806 if (IS_ERR(fp)) {
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700807 fc_rport_error(rdata, fp);
Abhijeet Joglekar76f68042009-04-21 16:26:58 -0700808 goto err;
809 }
810
Robert Love42e9a922008-12-09 15:10:17 -0800811 op = fc_frame_payload_op(fp);
812 if (op == ELS_LS_ACC) {
813 struct fc_els_rtv_acc *rtv;
814 u32 toq;
815 u32 tov;
816
817 rtv = fc_frame_payload_get(fp, sizeof(*rtv));
818 if (rtv) {
819 toq = ntohl(rtv->rtv_toq);
820 tov = ntohl(rtv->rtv_r_a_tov);
821 if (tov == 0)
822 tov = 1;
823 rdata->r_a_tov = tov;
824 tov = ntohl(rtv->rtv_e_d_tov);
825 if (toq & FC_ELS_RTV_EDRES)
826 tov /= 1000000;
827 if (tov == 0)
828 tov = 1;
829 rdata->e_d_tov = tov;
830 }
831 }
832
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700833 fc_rport_enter_ready(rdata);
Robert Love42e9a922008-12-09 15:10:17 -0800834
835out:
836 fc_frame_free(fp);
837err:
838 mutex_unlock(&rdata->rp_mutex);
Joe Eykholtf211fa52009-08-25 14:01:01 -0700839 kref_put(&rdata->kref, rdata->local_port->tt.rport_destroy);
Robert Love42e9a922008-12-09 15:10:17 -0800840}
841
842/**
Robert Love34f42a02009-02-27 10:55:45 -0800843 * fc_rport_enter_rtv() - Send Request Timeout Value (RTV) request to peer
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700844 * @rdata: private remote port data
Robert Love42e9a922008-12-09 15:10:17 -0800845 *
846 * Locking Note: The rport lock is expected to be held before calling
847 * this routine.
848 */
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700849static void fc_rport_enter_rtv(struct fc_rport_priv *rdata)
Robert Love42e9a922008-12-09 15:10:17 -0800850{
851 struct fc_frame *fp;
Robert Love42e9a922008-12-09 15:10:17 -0800852 struct fc_lport *lport = rdata->local_port;
853
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700854 FC_RPORT_DBG(rdata, "Port entered RTV state from %s state\n",
855 fc_rport_state(rdata));
Robert Love42e9a922008-12-09 15:10:17 -0800856
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700857 fc_rport_state_enter(rdata, RPORT_ST_RTV);
Robert Love42e9a922008-12-09 15:10:17 -0800858
859 fp = fc_frame_alloc(lport, sizeof(struct fc_els_rtv));
860 if (!fp) {
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700861 fc_rport_error_retry(rdata, fp);
Robert Love42e9a922008-12-09 15:10:17 -0800862 return;
863 }
864
Joe Eykholtf211fa52009-08-25 14:01:01 -0700865 if (!lport->tt.elsct_send(lport, rdata->ids.port_id, fp, ELS_RTV,
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700866 fc_rport_rtv_resp, rdata, lport->e_d_tov))
867 fc_rport_error_retry(rdata, fp);
Robert Love42e9a922008-12-09 15:10:17 -0800868 else
Joe Eykholtf211fa52009-08-25 14:01:01 -0700869 kref_get(&rdata->kref);
Robert Love42e9a922008-12-09 15:10:17 -0800870}
871
872/**
Robert Love34f42a02009-02-27 10:55:45 -0800873 * fc_rport_enter_logo() - Send Logout (LOGO) request to peer
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700874 * @rdata: private remote port data
Robert Love42e9a922008-12-09 15:10:17 -0800875 *
876 * Locking Note: The rport lock is expected to be held before calling
877 * this routine.
878 */
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700879static void fc_rport_enter_logo(struct fc_rport_priv *rdata)
Robert Love42e9a922008-12-09 15:10:17 -0800880{
Robert Love42e9a922008-12-09 15:10:17 -0800881 struct fc_lport *lport = rdata->local_port;
882 struct fc_frame *fp;
883
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700884 FC_RPORT_DBG(rdata, "Port entered LOGO state from %s state\n",
885 fc_rport_state(rdata));
Robert Love42e9a922008-12-09 15:10:17 -0800886
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700887 fc_rport_state_enter(rdata, RPORT_ST_LOGO);
Robert Love42e9a922008-12-09 15:10:17 -0800888
889 fp = fc_frame_alloc(lport, sizeof(struct fc_els_logo));
890 if (!fp) {
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700891 fc_rport_error_retry(rdata, fp);
Robert Love42e9a922008-12-09 15:10:17 -0800892 return;
893 }
894
Joe Eykholtf211fa52009-08-25 14:01:01 -0700895 if (!lport->tt.elsct_send(lport, rdata->ids.port_id, fp, ELS_LOGO,
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700896 fc_rport_logo_resp, rdata, lport->e_d_tov))
897 fc_rport_error_retry(rdata, fp);
Robert Love42e9a922008-12-09 15:10:17 -0800898 else
Joe Eykholtf211fa52009-08-25 14:01:01 -0700899 kref_get(&rdata->kref);
Robert Love42e9a922008-12-09 15:10:17 -0800900}
901
902
903/**
Robert Love34f42a02009-02-27 10:55:45 -0800904 * fc_rport_recv_req() - Receive a request from a rport
Robert Love42e9a922008-12-09 15:10:17 -0800905 * @sp: current sequence in the PLOGI exchange
906 * @fp: response frame
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700907 * @rdata_arg: private remote port data
Robert Love42e9a922008-12-09 15:10:17 -0800908 *
909 * Locking Note: Called without the rport lock held. This
910 * function will hold the rport lock, call an _enter_*
911 * function and then unlock the rport.
912 */
913void fc_rport_recv_req(struct fc_seq *sp, struct fc_frame *fp,
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700914 struct fc_rport_priv *rdata)
Robert Love42e9a922008-12-09 15:10:17 -0800915{
Robert Love42e9a922008-12-09 15:10:17 -0800916 struct fc_lport *lport = rdata->local_port;
917
918 struct fc_frame_header *fh;
919 struct fc_seq_els_data els_data;
920 u8 op;
921
922 mutex_lock(&rdata->rp_mutex);
923
924 els_data.fp = NULL;
925 els_data.explan = ELS_EXPL_NONE;
926 els_data.reason = ELS_RJT_NONE;
927
928 fh = fc_frame_header_get(fp);
929
930 if (fh->fh_r_ctl == FC_RCTL_ELS_REQ && fh->fh_type == FC_TYPE_ELS) {
931 op = fc_frame_payload_op(fp);
932 switch (op) {
933 case ELS_PLOGI:
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700934 fc_rport_recv_plogi_req(rdata, sp, fp);
Robert Love42e9a922008-12-09 15:10:17 -0800935 break;
936 case ELS_PRLI:
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700937 fc_rport_recv_prli_req(rdata, sp, fp);
Robert Love42e9a922008-12-09 15:10:17 -0800938 break;
939 case ELS_PRLO:
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700940 fc_rport_recv_prlo_req(rdata, sp, fp);
Robert Love42e9a922008-12-09 15:10:17 -0800941 break;
942 case ELS_LOGO:
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700943 fc_rport_recv_logo_req(rdata, sp, fp);
Robert Love42e9a922008-12-09 15:10:17 -0800944 break;
945 case ELS_RRQ:
946 els_data.fp = fp;
947 lport->tt.seq_els_rsp_send(sp, ELS_RRQ, &els_data);
948 break;
949 case ELS_REC:
950 els_data.fp = fp;
951 lport->tt.seq_els_rsp_send(sp, ELS_REC, &els_data);
952 break;
953 default:
954 els_data.reason = ELS_RJT_UNSUP;
955 lport->tt.seq_els_rsp_send(sp, ELS_LS_RJT, &els_data);
956 break;
957 }
958 }
959
960 mutex_unlock(&rdata->rp_mutex);
961}
962
963/**
Robert Love34f42a02009-02-27 10:55:45 -0800964 * fc_rport_recv_plogi_req() - Handle incoming Port Login (PLOGI) request
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700965 * @rdata: private remote port data
Robert Love42e9a922008-12-09 15:10:17 -0800966 * @sp: current sequence in the PLOGI exchange
967 * @fp: PLOGI request frame
968 *
969 * Locking Note: The rport lock is exected to be held before calling
970 * this function.
971 */
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700972static void fc_rport_recv_plogi_req(struct fc_rport_priv *rdata,
Robert Love42e9a922008-12-09 15:10:17 -0800973 struct fc_seq *sp, struct fc_frame *rx_fp)
974{
Robert Love42e9a922008-12-09 15:10:17 -0800975 struct fc_lport *lport = rdata->local_port;
976 struct fc_frame *fp = rx_fp;
977 struct fc_exch *ep;
978 struct fc_frame_header *fh;
979 struct fc_els_flogi *pl;
980 struct fc_seq_els_data rjt_data;
981 u32 sid;
982 u64 wwpn;
983 u64 wwnn;
984 enum fc_els_rjt_reason reject = 0;
985 u32 f_ctl;
986 rjt_data.fp = NULL;
987
988 fh = fc_frame_header_get(fp);
989
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700990 FC_RPORT_DBG(rdata, "Received PLOGI request while in state %s\n",
991 fc_rport_state(rdata));
Robert Love42e9a922008-12-09 15:10:17 -0800992
993 sid = ntoh24(fh->fh_s_id);
994 pl = fc_frame_payload_get(fp, sizeof(*pl));
995 if (!pl) {
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700996 FC_RPORT_DBG(rdata, "Received PLOGI too short\n");
Robert Love42e9a922008-12-09 15:10:17 -0800997 WARN_ON(1);
998 /* XXX TBD: send reject? */
999 fc_frame_free(fp);
1000 return;
1001 }
1002 wwpn = get_unaligned_be64(&pl->fl_wwpn);
1003 wwnn = get_unaligned_be64(&pl->fl_wwnn);
1004
1005 /*
1006 * If the session was just created, possibly due to the incoming PLOGI,
1007 * set the state appropriately and accept the PLOGI.
1008 *
1009 * If we had also sent a PLOGI, and if the received PLOGI is from a
1010 * higher WWPN, we accept it, otherwise an LS_RJT is sent with reason
1011 * "command already in progress".
1012 *
1013 * XXX TBD: If the session was ready before, the PLOGI should result in
1014 * all outstanding exchanges being reset.
1015 */
1016 switch (rdata->rp_state) {
1017 case RPORT_ST_INIT:
Joe Eykholt9fb9d322009-08-25 14:00:50 -07001018 FC_RPORT_DBG(rdata, "Received PLOGI, wwpn %llx state INIT "
Robert Love74147052009-06-10 15:31:10 -07001019 "- reject\n", (unsigned long long)wwpn);
Robert Love42e9a922008-12-09 15:10:17 -08001020 reject = ELS_RJT_UNSUP;
1021 break;
1022 case RPORT_ST_PLOGI:
Joe Eykholt9fb9d322009-08-25 14:00:50 -07001023 FC_RPORT_DBG(rdata, "Received PLOGI in PLOGI state %d\n",
Robert Love74147052009-06-10 15:31:10 -07001024 rdata->rp_state);
Robert Love42e9a922008-12-09 15:10:17 -08001025 if (wwpn < lport->wwpn)
1026 reject = ELS_RJT_INPROG;
1027 break;
1028 case RPORT_ST_PRLI:
1029 case RPORT_ST_READY:
Joe Eykholt9fb9d322009-08-25 14:00:50 -07001030 FC_RPORT_DBG(rdata, "Received PLOGI in logged-in state %d "
Robert Love74147052009-06-10 15:31:10 -07001031 "- ignored for now\n", rdata->rp_state);
Robert Love42e9a922008-12-09 15:10:17 -08001032 /* XXX TBD - should reset */
1033 break;
Joe Eykholt14194052009-07-29 17:04:43 -07001034 case RPORT_ST_DELETE:
Robert Love42e9a922008-12-09 15:10:17 -08001035 default:
Joe Eykholt9fb9d322009-08-25 14:00:50 -07001036 FC_RPORT_DBG(rdata, "Received PLOGI in unexpected "
Robert Love74147052009-06-10 15:31:10 -07001037 "state %d\n", rdata->rp_state);
Abhijeet Joglekarb4c6f542009-04-21 16:27:04 -07001038 fc_frame_free(fp);
1039 return;
Robert Love42e9a922008-12-09 15:10:17 -08001040 break;
1041 }
1042
1043 if (reject) {
1044 rjt_data.reason = reject;
1045 rjt_data.explan = ELS_EXPL_NONE;
1046 lport->tt.seq_els_rsp_send(sp, ELS_LS_RJT, &rjt_data);
1047 fc_frame_free(fp);
1048 } else {
1049 fp = fc_frame_alloc(lport, sizeof(*pl));
1050 if (fp == NULL) {
1051 fp = rx_fp;
1052 rjt_data.reason = ELS_RJT_UNAB;
1053 rjt_data.explan = ELS_EXPL_NONE;
1054 lport->tt.seq_els_rsp_send(sp, ELS_LS_RJT, &rjt_data);
1055 fc_frame_free(fp);
1056 } else {
1057 sp = lport->tt.seq_start_next(sp);
1058 WARN_ON(!sp);
Joe Eykholtf211fa52009-08-25 14:01:01 -07001059 rdata->ids.port_name = wwpn;
1060 rdata->ids.node_name = wwnn;
Robert Love42e9a922008-12-09 15:10:17 -08001061
1062 /*
1063 * Get session payload size from incoming PLOGI.
1064 */
Joe Eykholtf211fa52009-08-25 14:01:01 -07001065 rdata->maxframe_size =
Robert Love42e9a922008-12-09 15:10:17 -08001066 fc_plogi_get_maxframe(pl, lport->mfs);
1067 fc_frame_free(rx_fp);
1068 fc_plogi_fill(lport, fp, ELS_LS_ACC);
1069
1070 /*
1071 * Send LS_ACC. If this fails,
1072 * the originator should retry.
1073 */
1074 f_ctl = FC_FC_EX_CTX | FC_FC_LAST_SEQ;
1075 f_ctl |= FC_FC_END_SEQ | FC_FC_SEQ_INIT;
1076 ep = fc_seq_exch(sp);
1077 fc_fill_fc_hdr(fp, FC_RCTL_ELS_REP, ep->did, ep->sid,
1078 FC_TYPE_ELS, f_ctl, 0);
1079 lport->tt.seq_send(lport, sp, fp);
1080 if (rdata->rp_state == RPORT_ST_PLOGI)
Joe Eykholt9fb9d322009-08-25 14:00:50 -07001081 fc_rport_enter_prli(rdata);
Robert Love42e9a922008-12-09 15:10:17 -08001082 }
1083 }
1084}
1085
1086/**
Robert Love34f42a02009-02-27 10:55:45 -08001087 * fc_rport_recv_prli_req() - Handle incoming Process Login (PRLI) request
Joe Eykholt9fb9d322009-08-25 14:00:50 -07001088 * @rdata: private remote port data
Robert Love42e9a922008-12-09 15:10:17 -08001089 * @sp: current sequence in the PRLI exchange
1090 * @fp: PRLI request frame
1091 *
1092 * Locking Note: The rport lock is exected to be held before calling
1093 * this function.
1094 */
Joe Eykholt9fb9d322009-08-25 14:00:50 -07001095static void fc_rport_recv_prli_req(struct fc_rport_priv *rdata,
Robert Love42e9a922008-12-09 15:10:17 -08001096 struct fc_seq *sp, struct fc_frame *rx_fp)
1097{
Robert Love42e9a922008-12-09 15:10:17 -08001098 struct fc_lport *lport = rdata->local_port;
1099 struct fc_exch *ep;
1100 struct fc_frame *fp;
1101 struct fc_frame_header *fh;
1102 struct {
1103 struct fc_els_prli prli;
1104 struct fc_els_spp spp;
1105 } *pp;
1106 struct fc_els_spp *rspp; /* request service param page */
1107 struct fc_els_spp *spp; /* response spp */
1108 unsigned int len;
1109 unsigned int plen;
1110 enum fc_els_rjt_reason reason = ELS_RJT_UNAB;
1111 enum fc_els_rjt_explan explan = ELS_EXPL_NONE;
1112 enum fc_els_spp_resp resp;
1113 struct fc_seq_els_data rjt_data;
1114 u32 f_ctl;
1115 u32 fcp_parm;
1116 u32 roles = FC_RPORT_ROLE_UNKNOWN;
1117 rjt_data.fp = NULL;
1118
1119 fh = fc_frame_header_get(rx_fp);
1120
Joe Eykholt9fb9d322009-08-25 14:00:50 -07001121 FC_RPORT_DBG(rdata, "Received PRLI request while in state %s\n",
1122 fc_rport_state(rdata));
Robert Love42e9a922008-12-09 15:10:17 -08001123
1124 switch (rdata->rp_state) {
1125 case RPORT_ST_PRLI:
1126 case RPORT_ST_READY:
1127 reason = ELS_RJT_NONE;
1128 break;
1129 default:
Abhijeet Joglekarb4c6f542009-04-21 16:27:04 -07001130 fc_frame_free(rx_fp);
1131 return;
Robert Love42e9a922008-12-09 15:10:17 -08001132 break;
1133 }
1134 len = fr_len(rx_fp) - sizeof(*fh);
1135 pp = fc_frame_payload_get(rx_fp, sizeof(*pp));
1136 if (pp == NULL) {
1137 reason = ELS_RJT_PROT;
1138 explan = ELS_EXPL_INV_LEN;
1139 } else {
1140 plen = ntohs(pp->prli.prli_len);
1141 if ((plen % 4) != 0 || plen > len) {
1142 reason = ELS_RJT_PROT;
1143 explan = ELS_EXPL_INV_LEN;
1144 } else if (plen < len) {
1145 len = plen;
1146 }
1147 plen = pp->prli.prli_spp_len;
1148 if ((plen % 4) != 0 || plen < sizeof(*spp) ||
1149 plen > len || len < sizeof(*pp)) {
1150 reason = ELS_RJT_PROT;
1151 explan = ELS_EXPL_INV_LEN;
1152 }
1153 rspp = &pp->spp;
1154 }
1155 if (reason != ELS_RJT_NONE ||
1156 (fp = fc_frame_alloc(lport, len)) == NULL) {
1157 rjt_data.reason = reason;
1158 rjt_data.explan = explan;
1159 lport->tt.seq_els_rsp_send(sp, ELS_LS_RJT, &rjt_data);
1160 } else {
1161 sp = lport->tt.seq_start_next(sp);
1162 WARN_ON(!sp);
1163 pp = fc_frame_payload_get(fp, len);
1164 WARN_ON(!pp);
1165 memset(pp, 0, len);
1166 pp->prli.prli_cmd = ELS_LS_ACC;
1167 pp->prli.prli_spp_len = plen;
1168 pp->prli.prli_len = htons(len);
1169 len -= sizeof(struct fc_els_prli);
1170
1171 /*
1172 * Go through all the service parameter pages and build
1173 * response. If plen indicates longer SPP than standard,
1174 * use that. The entire response has been pre-cleared above.
1175 */
1176 spp = &pp->spp;
1177 while (len >= plen) {
1178 spp->spp_type = rspp->spp_type;
1179 spp->spp_type_ext = rspp->spp_type_ext;
1180 spp->spp_flags = rspp->spp_flags & FC_SPP_EST_IMG_PAIR;
1181 resp = FC_SPP_RESP_ACK;
1182 if (rspp->spp_flags & FC_SPP_RPA_VAL)
1183 resp = FC_SPP_RESP_NO_PA;
1184 switch (rspp->spp_type) {
1185 case 0: /* common to all FC-4 types */
1186 break;
1187 case FC_TYPE_FCP:
1188 fcp_parm = ntohl(rspp->spp_params);
1189 if (fcp_parm * FCP_SPPF_RETRY)
1190 rdata->flags |= FC_RP_FLAGS_RETRY;
Joe Eykholtf211fa52009-08-25 14:01:01 -07001191 rdata->supported_classes = FC_COS_CLASS3;
Robert Love42e9a922008-12-09 15:10:17 -08001192 if (fcp_parm & FCP_SPPF_INIT_FCN)
1193 roles |= FC_RPORT_ROLE_FCP_INITIATOR;
1194 if (fcp_parm & FCP_SPPF_TARG_FCN)
1195 roles |= FC_RPORT_ROLE_FCP_TARGET;
Joe Eykholtf211fa52009-08-25 14:01:01 -07001196 rdata->ids.roles = roles;
Robert Love42e9a922008-12-09 15:10:17 -08001197
1198 spp->spp_params =
1199 htonl(lport->service_params);
1200 break;
1201 default:
1202 resp = FC_SPP_RESP_INVL;
1203 break;
1204 }
1205 spp->spp_flags |= resp;
1206 len -= plen;
1207 rspp = (struct fc_els_spp *)((char *)rspp + plen);
1208 spp = (struct fc_els_spp *)((char *)spp + plen);
1209 }
1210
1211 /*
1212 * Send LS_ACC. If this fails, the originator should retry.
1213 */
1214 f_ctl = FC_FC_EX_CTX | FC_FC_LAST_SEQ;
1215 f_ctl |= FC_FC_END_SEQ | FC_FC_SEQ_INIT;
1216 ep = fc_seq_exch(sp);
1217 fc_fill_fc_hdr(fp, FC_RCTL_ELS_REP, ep->did, ep->sid,
1218 FC_TYPE_ELS, f_ctl, 0);
1219 lport->tt.seq_send(lport, sp, fp);
1220
1221 /*
1222 * Get lock and re-check state.
1223 */
1224 switch (rdata->rp_state) {
1225 case RPORT_ST_PRLI:
Joe Eykholt9fb9d322009-08-25 14:00:50 -07001226 fc_rport_enter_ready(rdata);
Robert Love42e9a922008-12-09 15:10:17 -08001227 break;
1228 case RPORT_ST_READY:
1229 break;
1230 default:
1231 break;
1232 }
1233 }
1234 fc_frame_free(rx_fp);
1235}
1236
1237/**
Robert Love34f42a02009-02-27 10:55:45 -08001238 * fc_rport_recv_prlo_req() - Handle incoming Process Logout (PRLO) request
Joe Eykholt9fb9d322009-08-25 14:00:50 -07001239 * @rdata: private remote port data
Robert Love42e9a922008-12-09 15:10:17 -08001240 * @sp: current sequence in the PRLO exchange
1241 * @fp: PRLO request frame
1242 *
1243 * Locking Note: The rport lock is exected to be held before calling
1244 * this function.
1245 */
Joe Eykholt9fb9d322009-08-25 14:00:50 -07001246static void fc_rport_recv_prlo_req(struct fc_rport_priv *rdata,
1247 struct fc_seq *sp,
Robert Love42e9a922008-12-09 15:10:17 -08001248 struct fc_frame *fp)
1249{
Robert Love42e9a922008-12-09 15:10:17 -08001250 struct fc_lport *lport = rdata->local_port;
1251
1252 struct fc_frame_header *fh;
1253 struct fc_seq_els_data rjt_data;
1254
1255 fh = fc_frame_header_get(fp);
1256
Joe Eykholt9fb9d322009-08-25 14:00:50 -07001257 FC_RPORT_DBG(rdata, "Received PRLO request while in state %s\n",
1258 fc_rport_state(rdata));
Robert Love42e9a922008-12-09 15:10:17 -08001259
Joe Eykholt14194052009-07-29 17:04:43 -07001260 if (rdata->rp_state == RPORT_ST_DELETE) {
Abhijeet Joglekarb4c6f542009-04-21 16:27:04 -07001261 fc_frame_free(fp);
1262 return;
1263 }
1264
Robert Love42e9a922008-12-09 15:10:17 -08001265 rjt_data.fp = NULL;
1266 rjt_data.reason = ELS_RJT_UNAB;
1267 rjt_data.explan = ELS_EXPL_NONE;
1268 lport->tt.seq_els_rsp_send(sp, ELS_LS_RJT, &rjt_data);
1269 fc_frame_free(fp);
1270}
1271
1272/**
Robert Love34f42a02009-02-27 10:55:45 -08001273 * fc_rport_recv_logo_req() - Handle incoming Logout (LOGO) request
Joe Eykholt9fb9d322009-08-25 14:00:50 -07001274 * @rdata: private remote port data
Robert Love42e9a922008-12-09 15:10:17 -08001275 * @sp: current sequence in the LOGO exchange
1276 * @fp: LOGO request frame
1277 *
1278 * Locking Note: The rport lock is exected to be held before calling
1279 * this function.
1280 */
Joe Eykholt9fb9d322009-08-25 14:00:50 -07001281static void fc_rport_recv_logo_req(struct fc_rport_priv *rdata,
1282 struct fc_seq *sp,
Robert Love42e9a922008-12-09 15:10:17 -08001283 struct fc_frame *fp)
1284{
1285 struct fc_frame_header *fh;
Robert Love42e9a922008-12-09 15:10:17 -08001286 struct fc_lport *lport = rdata->local_port;
1287
1288 fh = fc_frame_header_get(fp);
1289
Joe Eykholt9fb9d322009-08-25 14:00:50 -07001290 FC_RPORT_DBG(rdata, "Received LOGO request while in state %s\n",
1291 fc_rport_state(rdata));
Robert Love42e9a922008-12-09 15:10:17 -08001292
Joe Eykholt14194052009-07-29 17:04:43 -07001293 if (rdata->rp_state == RPORT_ST_DELETE) {
Abhijeet Joglekarb4c6f542009-04-21 16:27:04 -07001294 fc_frame_free(fp);
1295 return;
1296 }
1297
Robert Love42e9a922008-12-09 15:10:17 -08001298 rdata->event = RPORT_EV_LOGO;
Joe Eykholt9fb9d322009-08-25 14:00:50 -07001299 fc_rport_state_enter(rdata, RPORT_ST_DELETE);
Robert Love42e9a922008-12-09 15:10:17 -08001300 queue_work(rport_event_queue, &rdata->event_work);
1301
1302 lport->tt.seq_els_rsp_send(sp, ELS_LS_ACC, NULL);
1303 fc_frame_free(fp);
1304}
1305
1306static void fc_rport_flush_queue(void)
1307{
1308 flush_workqueue(rport_event_queue);
1309}
1310
Robert Love42e9a922008-12-09 15:10:17 -08001311int fc_rport_init(struct fc_lport *lport)
1312{
Robert Love5101ff92009-02-27 10:55:18 -08001313 if (!lport->tt.rport_create)
1314 lport->tt.rport_create = fc_rport_rogue_create;
1315
Robert Love42e9a922008-12-09 15:10:17 -08001316 if (!lport->tt.rport_login)
1317 lport->tt.rport_login = fc_rport_login;
1318
1319 if (!lport->tt.rport_logoff)
1320 lport->tt.rport_logoff = fc_rport_logoff;
1321
1322 if (!lport->tt.rport_recv_req)
1323 lport->tt.rport_recv_req = fc_rport_recv_req;
1324
1325 if (!lport->tt.rport_flush_queue)
1326 lport->tt.rport_flush_queue = fc_rport_flush_queue;
1327
Joe Eykholtf211fa52009-08-25 14:01:01 -07001328 if (!lport->tt.rport_destroy)
1329 lport->tt.rport_destroy = fc_rport_destroy;
1330
Robert Love42e9a922008-12-09 15:10:17 -08001331 return 0;
1332}
1333EXPORT_SYMBOL(fc_rport_init);
1334
Randy Dunlapb0d428a2009-04-27 21:49:31 -07001335int fc_setup_rport(void)
Robert Love42e9a922008-12-09 15:10:17 -08001336{
1337 rport_event_queue = create_singlethread_workqueue("fc_rport_eq");
1338 if (!rport_event_queue)
1339 return -ENOMEM;
1340 return 0;
1341}
1342EXPORT_SYMBOL(fc_setup_rport);
1343
Randy Dunlapb0d428a2009-04-27 21:49:31 -07001344void fc_destroy_rport(void)
Robert Love42e9a922008-12-09 15:10:17 -08001345{
1346 destroy_workqueue(rport_event_queue);
1347}
1348EXPORT_SYMBOL(fc_destroy_rport);
1349
1350void fc_rport_terminate_io(struct fc_rport *rport)
1351{
Joe Eykholtab28f1f2009-08-25 14:00:34 -07001352 struct fc_rport_libfc_priv *rp = rport->dd_data;
1353 struct fc_lport *lport = rp->local_port;
Robert Love42e9a922008-12-09 15:10:17 -08001354
Abhijeet Joglekar1f6ff362009-02-27 10:54:35 -08001355 lport->tt.exch_mgr_reset(lport, 0, rport->port_id);
1356 lport->tt.exch_mgr_reset(lport, rport->port_id, 0);
Robert Love42e9a922008-12-09 15:10:17 -08001357}
1358EXPORT_SYMBOL(fc_rport_terminate_io);