blob: 97aeaddd600d42c03feb79f3fa11bf6a80ce3229 [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
Uwe Kleine-König732bee72010-06-11 12:16:59 +020037 * more comments on the hierarchy.
Robert Love42e9a922008-12-09 15:10:17 -080038 *
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>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090050#include <linux/slab.h>
Robert Love42e9a922008-12-09 15:10:17 -080051#include <linux/rcupdate.h>
52#include <linux/timer.h>
53#include <linux/workqueue.h>
Paul Gortmaker09703662011-05-27 09:37:25 -040054#include <linux/export.h>
Robert Love42e9a922008-12-09 15:10:17 -080055#include <asm/unaligned.h>
56
57#include <scsi/libfc.h>
58#include <scsi/fc_encode.h>
59
Robert Love8866a5d2009-11-03 11:45:58 -080060#include "fc_libfc.h"
61
Randy Dunlap55204902011-01-28 16:03:57 -080062static struct workqueue_struct *rport_event_queue;
Robert Love42e9a922008-12-09 15:10:17 -080063
Joe Eykholta7b12a22010-07-20 15:20:08 -070064static void fc_rport_enter_flogi(struct fc_rport_priv *);
Joe Eykholt9fb9d322009-08-25 14:00:50 -070065static void fc_rport_enter_plogi(struct fc_rport_priv *);
66static void fc_rport_enter_prli(struct fc_rport_priv *);
67static void fc_rport_enter_rtv(struct fc_rport_priv *);
68static void fc_rport_enter_ready(struct fc_rport_priv *);
69static void fc_rport_enter_logo(struct fc_rport_priv *);
Joe Eykholt370c3bd2009-08-25 14:03:47 -070070static void fc_rport_enter_adisc(struct fc_rport_priv *);
Robert Love42e9a922008-12-09 15:10:17 -080071
Joe Eykholt922611562010-07-20 15:21:12 -070072static void fc_rport_recv_plogi_req(struct fc_lport *, struct fc_frame *);
73static void fc_rport_recv_prli_req(struct fc_rport_priv *, struct fc_frame *);
74static void fc_rport_recv_prlo_req(struct fc_rport_priv *, struct fc_frame *);
75static void fc_rport_recv_logo_req(struct fc_lport *, struct fc_frame *);
Robert Love42e9a922008-12-09 15:10:17 -080076static void fc_rport_timeout(struct work_struct *);
Joe Eykholt9fb9d322009-08-25 14:00:50 -070077static void fc_rport_error(struct fc_rport_priv *, struct fc_frame *);
78static void fc_rport_error_retry(struct fc_rport_priv *, struct fc_frame *);
Robert Love42e9a922008-12-09 15:10:17 -080079static void fc_rport_work(struct work_struct *);
80
81static const char *fc_rport_state_names[] = {
Robert Love42e9a922008-12-09 15:10:17 -080082 [RPORT_ST_INIT] = "Init",
Joe Eykholta7b12a22010-07-20 15:20:08 -070083 [RPORT_ST_FLOGI] = "FLOGI",
84 [RPORT_ST_PLOGI_WAIT] = "PLOGI_WAIT",
Robert Love42e9a922008-12-09 15:10:17 -080085 [RPORT_ST_PLOGI] = "PLOGI",
86 [RPORT_ST_PRLI] = "PRLI",
87 [RPORT_ST_RTV] = "RTV",
88 [RPORT_ST_READY] = "Ready",
Joe Eykholt370c3bd2009-08-25 14:03:47 -070089 [RPORT_ST_ADISC] = "ADISC",
Joe Eykholt14194052009-07-29 17:04:43 -070090 [RPORT_ST_DELETE] = "Delete",
Robert Love42e9a922008-12-09 15:10:17 -080091};
92
Joe Eykholt9e9d0452009-08-25 14:01:18 -070093/**
Robert Love3a3b42b2009-11-03 11:47:39 -080094 * fc_rport_lookup() - Lookup a remote port by port_id
95 * @lport: The local port to lookup the remote port on
96 * @port_id: The remote port ID to look up
Joe Eykholt42e90412010-07-20 15:19:37 -070097 *
Hannes Reineckebaa67192016-05-24 08:11:58 +020098 * The reference count of the fc_rport_priv structure is
99 * increased by one.
Joe Eykholt8025b5d2009-08-25 14:02:06 -0700100 */
101static struct fc_rport_priv *fc_rport_lookup(const struct fc_lport *lport,
102 u32 port_id)
103{
Hannes Reineckebaa67192016-05-24 08:11:58 +0200104 struct fc_rport_priv *rdata = NULL, *tmp_rdata;
Joe Eykholt8025b5d2009-08-25 14:02:06 -0700105
Hannes Reineckebaa67192016-05-24 08:11:58 +0200106 rcu_read_lock();
107 list_for_each_entry_rcu(tmp_rdata, &lport->disc.rports, peers)
108 if (tmp_rdata->ids.port_id == port_id &&
109 kref_get_unless_zero(&tmp_rdata->kref)) {
110 rdata = tmp_rdata;
111 break;
112 }
113 rcu_read_unlock();
114 return rdata;
Joe Eykholt8025b5d2009-08-25 14:02:06 -0700115}
116
117/**
Robert Love9737e6a2009-08-25 14:02:59 -0700118 * fc_rport_create() - Create a new remote port
Robert Love3a3b42b2009-11-03 11:47:39 -0800119 * @lport: The local port this remote port will be associated with
120 * @ids: The identifiers for the new remote port
121 *
122 * The remote port will start in the INIT state.
Joe Eykholt9e9d0452009-08-25 14:01:18 -0700123 *
Joe Eykholt48f00902009-08-25 14:01:50 -0700124 * Locking note: must be called with the disc_mutex held.
Joe Eykholt9e9d0452009-08-25 14:01:18 -0700125 */
126static struct fc_rport_priv *fc_rport_create(struct fc_lport *lport,
Robert Love9737e6a2009-08-25 14:02:59 -0700127 u32 port_id)
Robert Love42e9a922008-12-09 15:10:17 -0800128{
Joe Eykholtab28f1f2009-08-25 14:00:34 -0700129 struct fc_rport_priv *rdata;
Robert Love42e9a922008-12-09 15:10:17 -0800130
Robert Love9737e6a2009-08-25 14:02:59 -0700131 rdata = lport->tt.rport_lookup(lport, port_id);
Joe Eykholt19f97e32009-08-25 14:01:55 -0700132 if (rdata)
133 return rdata;
134
Joe Eykholtf90377a2010-07-20 15:19:42 -0700135 rdata = kzalloc(sizeof(*rdata) + lport->rport_priv_size, GFP_KERNEL);
Joe Eykholt9e9d0452009-08-25 14:01:18 -0700136 if (!rdata)
Robert Love42e9a922008-12-09 15:10:17 -0800137 return NULL;
138
Robert Love9737e6a2009-08-25 14:02:59 -0700139 rdata->ids.node_name = -1;
140 rdata->ids.port_name = -1;
141 rdata->ids.port_id = port_id;
142 rdata->ids.roles = FC_RPORT_ROLE_UNKNOWN;
143
Joe Eykholtf211fa52009-08-25 14:01:01 -0700144 kref_init(&rdata->kref);
Robert Love42e9a922008-12-09 15:10:17 -0800145 mutex_init(&rdata->rp_mutex);
Joe Eykholt795d86f2009-08-25 14:00:39 -0700146 rdata->local_port = lport;
Robert Love42e9a922008-12-09 15:10:17 -0800147 rdata->rp_state = RPORT_ST_INIT;
148 rdata->event = RPORT_EV_NONE;
149 rdata->flags = FC_RP_FLAGS_REC_SUPPORTED;
Joe Eykholt795d86f2009-08-25 14:00:39 -0700150 rdata->e_d_tov = lport->e_d_tov;
151 rdata->r_a_tov = lport->r_a_tov;
Joe Eykholtf211fa52009-08-25 14:01:01 -0700152 rdata->maxframe_size = FC_MIN_MAX_PAYLOAD;
Robert Love42e9a922008-12-09 15:10:17 -0800153 INIT_DELAYED_WORK(&rdata->retry_work, fc_rport_timeout);
154 INIT_WORK(&rdata->event_work, fc_rport_work);
Bhanu Prakash Gollapudi75a27922011-01-28 16:05:27 -0800155 if (port_id != FC_FID_DIR_SERV) {
156 rdata->lld_event_callback = lport->tt.rport_event_callback;
Joe Eykholt42e90412010-07-20 15:19:37 -0700157 list_add_rcu(&rdata->peers, &lport->disc.rports);
Bhanu Prakash Gollapudi75a27922011-01-28 16:05:27 -0800158 }
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700159 return rdata;
Robert Love42e9a922008-12-09 15:10:17 -0800160}
161
162/**
Robert Love3a3b42b2009-11-03 11:47:39 -0800163 * fc_rport_destroy() - Free a remote port after last reference is released
164 * @kref: The remote port's kref
Joe Eykholtf211fa52009-08-25 14:01:01 -0700165 */
166static void fc_rport_destroy(struct kref *kref)
167{
168 struct fc_rport_priv *rdata;
Joe Eykholtf211fa52009-08-25 14:01:01 -0700169
170 rdata = container_of(kref, struct fc_rport_priv, kref);
Lai Jiangshan8497a242011-03-18 11:41:14 +0800171 kfree_rcu(rdata, rcu);
Joe Eykholtf211fa52009-08-25 14:01:01 -0700172}
173
174/**
Robert Love3a3b42b2009-11-03 11:47:39 -0800175 * fc_rport_state() - Return a string identifying the remote port's state
176 * @rdata: The remote port
Robert Love42e9a922008-12-09 15:10:17 -0800177 */
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700178static const char *fc_rport_state(struct fc_rport_priv *rdata)
Robert Love42e9a922008-12-09 15:10:17 -0800179{
180 const char *cp;
Robert Love42e9a922008-12-09 15:10:17 -0800181
182 cp = fc_rport_state_names[rdata->rp_state];
183 if (!cp)
184 cp = "Unknown";
185 return cp;
186}
187
188/**
Robert Love3a3b42b2009-11-03 11:47:39 -0800189 * fc_set_rport_loss_tmo() - Set the remote port loss timeout
190 * @rport: The remote port that gets a new timeout value
191 * @timeout: The new timeout value (in seconds)
Robert Love42e9a922008-12-09 15:10:17 -0800192 */
193void fc_set_rport_loss_tmo(struct fc_rport *rport, u32 timeout)
194{
195 if (timeout)
Mike Christie73b43762010-10-08 17:12:10 -0700196 rport->dev_loss_tmo = timeout;
Robert Love42e9a922008-12-09 15:10:17 -0800197 else
Mike Christie73b43762010-10-08 17:12:10 -0700198 rport->dev_loss_tmo = 1;
Robert Love42e9a922008-12-09 15:10:17 -0800199}
200EXPORT_SYMBOL(fc_set_rport_loss_tmo);
201
202/**
Robert Love3a3b42b2009-11-03 11:47:39 -0800203 * fc_plogi_get_maxframe() - Get the maximum payload from the common service
204 * parameters in a FLOGI frame
Joe Eykholta7b12a22010-07-20 15:20:08 -0700205 * @flp: The FLOGI or PLOGI payload
Robert Love3a3b42b2009-11-03 11:47:39 -0800206 * @maxval: The maximum frame size upper limit; this may be less than what
207 * is in the service parameters
Robert Love42e9a922008-12-09 15:10:17 -0800208 */
Robert Loveb2ab99c2009-02-27 10:55:50 -0800209static unsigned int fc_plogi_get_maxframe(struct fc_els_flogi *flp,
210 unsigned int maxval)
Robert Love42e9a922008-12-09 15:10:17 -0800211{
212 unsigned int mfs;
213
214 /*
215 * Get max payload from the common service parameters and the
216 * class 3 receive data field size.
217 */
218 mfs = ntohs(flp->fl_csp.sp_bb_data) & FC_SP_BB_DATA_MASK;
219 if (mfs >= FC_SP_MIN_MAX_PAYLOAD && mfs < maxval)
220 maxval = mfs;
221 mfs = ntohs(flp->fl_cssp[3 - 1].cp_rdfs);
222 if (mfs >= FC_SP_MIN_MAX_PAYLOAD && mfs < maxval)
223 maxval = mfs;
224 return maxval;
225}
226
227/**
Robert Love3a3b42b2009-11-03 11:47:39 -0800228 * fc_rport_state_enter() - Change the state of a remote port
229 * @rdata: The remote port whose state should change
230 * @new: The new state
Robert Love42e9a922008-12-09 15:10:17 -0800231 *
232 * Locking Note: Called with the rport lock held
233 */
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700234static void fc_rport_state_enter(struct fc_rport_priv *rdata,
Robert Love42e9a922008-12-09 15:10:17 -0800235 enum fc_rport_state new)
236{
Robert Love42e9a922008-12-09 15:10:17 -0800237 if (rdata->rp_state != new)
238 rdata->retries = 0;
239 rdata->rp_state = new;
240}
241
Robert Love3a3b42b2009-11-03 11:47:39 -0800242/**
243 * fc_rport_work() - Handler for remote port events in the rport_event_queue
244 * @work: Handle to the remote port being dequeued
245 */
Robert Love42e9a922008-12-09 15:10:17 -0800246static void fc_rport_work(struct work_struct *work)
247{
Abhijeet Joglekar571f8242009-02-27 10:54:41 -0800248 u32 port_id;
Joe Eykholtab28f1f2009-08-25 14:00:34 -0700249 struct fc_rport_priv *rdata =
250 container_of(work, struct fc_rport_priv, event_work);
Robert Love3a3b42b2009-11-03 11:47:39 -0800251 struct fc_rport_libfc_priv *rpriv;
Robert Love42e9a922008-12-09 15:10:17 -0800252 enum fc_rport_event event;
Robert Love42e9a922008-12-09 15:10:17 -0800253 struct fc_lport *lport = rdata->local_port;
254 struct fc_rport_operations *rport_ops;
Joe Eykholt629f4422009-08-25 14:01:06 -0700255 struct fc_rport_identifiers ids;
Joe Eykholtf211fa52009-08-25 14:01:01 -0700256 struct fc_rport *rport;
Joe Eykholt96ad8462011-01-28 16:04:02 -0800257 struct fc4_prov *prov;
258 u8 type;
Robert Love42e9a922008-12-09 15:10:17 -0800259
260 mutex_lock(&rdata->rp_mutex);
261 event = rdata->event;
262 rport_ops = rdata->ops;
Joe Eykholtf211fa52009-08-25 14:01:01 -0700263 rport = rdata->rport;
Robert Love42e9a922008-12-09 15:10:17 -0800264
Joe Eykholt9e9d0452009-08-25 14:01:18 -0700265 FC_RPORT_DBG(rdata, "work event %u\n", event);
266
Joe Eykholt629f4422009-08-25 14:01:06 -0700267 switch (event) {
Joe Eykholt4c0f62b2009-08-25 14:01:12 -0700268 case RPORT_EV_READY:
Joe Eykholtf211fa52009-08-25 14:01:01 -0700269 ids = rdata->ids;
Joe Eykholt5f7ea3b2009-07-29 17:04:49 -0700270 rdata->event = RPORT_EV_NONE;
Joe Eykholtf0342602010-06-11 16:44:57 -0700271 rdata->major_retries = 0;
Joe Eykholt9e9d0452009-08-25 14:01:18 -0700272 kref_get(&rdata->kref);
Robert Love42e9a922008-12-09 15:10:17 -0800273 mutex_unlock(&rdata->rp_mutex);
274
Joe Eykholt9e9d0452009-08-25 14:01:18 -0700275 if (!rport)
276 rport = fc_remote_port_add(lport->host, 0, &ids);
277 if (!rport) {
278 FC_RPORT_DBG(rdata, "Failed to add the rport\n");
279 lport->tt.rport_logoff(rdata);
280 kref_put(&rdata->kref, lport->tt.rport_destroy);
281 return;
Robert Love42e9a922008-12-09 15:10:17 -0800282 }
Joe Eykholt9e9d0452009-08-25 14:01:18 -0700283 mutex_lock(&rdata->rp_mutex);
284 if (rdata->rport)
285 FC_RPORT_DBG(rdata, "rport already allocated\n");
286 rdata->rport = rport;
287 rport->maxframe_size = rdata->maxframe_size;
288 rport->supported_classes = rdata->supported_classes;
289
Robert Love3a3b42b2009-11-03 11:47:39 -0800290 rpriv = rport->dd_data;
291 rpriv->local_port = lport;
292 rpriv->rp_state = rdata->rp_state;
293 rpriv->flags = rdata->flags;
294 rpriv->e_d_tov = rdata->e_d_tov;
295 rpriv->r_a_tov = rdata->r_a_tov;
Joe Eykholt9e9d0452009-08-25 14:01:18 -0700296 mutex_unlock(&rdata->rp_mutex);
297
Joe Eykholt83455922009-08-25 14:02:01 -0700298 if (rport_ops && rport_ops->event_callback) {
Joe Eykholt9e9d0452009-08-25 14:01:18 -0700299 FC_RPORT_DBG(rdata, "callback ev %d\n", event);
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700300 rport_ops->event_callback(lport, rdata, event);
Joe Eykholt9e9d0452009-08-25 14:01:18 -0700301 }
Bhanu Prakash Gollapudi75a27922011-01-28 16:05:27 -0800302 if (rdata->lld_event_callback) {
303 FC_RPORT_DBG(rdata, "lld callback ev %d\n", event);
304 rdata->lld_event_callback(lport, rdata, event);
305 }
Joe Eykholt9e9d0452009-08-25 14:01:18 -0700306 kref_put(&rdata->kref, lport->tt.rport_destroy);
Joe Eykholt629f4422009-08-25 14:01:06 -0700307 break;
308
309 case RPORT_EV_FAILED:
310 case RPORT_EV_LOGO:
311 case RPORT_EV_STOP:
Joe Eykholt96ad8462011-01-28 16:04:02 -0800312 if (rdata->prli_count) {
313 mutex_lock(&fc_prov_mutex);
314 for (type = 1; type < FC_FC4_PROV_SIZE; type++) {
315 prov = fc_passive_prov[type];
316 if (prov && prov->prlo)
317 prov->prlo(rdata);
318 }
319 mutex_unlock(&fc_prov_mutex);
320 }
Joe Eykholt9e9d0452009-08-25 14:01:18 -0700321 port_id = rdata->ids.port_id;
Robert Love42e9a922008-12-09 15:10:17 -0800322 mutex_unlock(&rdata->rp_mutex);
Joe Eykholt9e9d0452009-08-25 14:01:18 -0700323
Joe Eykholt83455922009-08-25 14:02:01 -0700324 if (rport_ops && rport_ops->event_callback) {
Joe Eykholt9e9d0452009-08-25 14:01:18 -0700325 FC_RPORT_DBG(rdata, "callback ev %d\n", event);
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700326 rport_ops->event_callback(lport, rdata, event);
Abhijeet Joglekar571f8242009-02-27 10:54:41 -0800327 }
Bhanu Prakash Gollapudi75a27922011-01-28 16:05:27 -0800328 if (rdata->lld_event_callback) {
329 FC_RPORT_DBG(rdata, "lld callback ev %d\n", event);
330 rdata->lld_event_callback(lport, rdata, event);
331 }
Joe Eykholt9e9d0452009-08-25 14:01:18 -0700332 cancel_delayed_work_sync(&rdata->retry_work);
333
334 /*
335 * Reset any outstanding exchanges before freeing rport.
336 */
337 lport->tt.exch_mgr_reset(lport, 0, port_id);
338 lport->tt.exch_mgr_reset(lport, port_id, 0);
339
340 if (rport) {
Robert Love3a3b42b2009-11-03 11:47:39 -0800341 rpriv = rport->dd_data;
342 rpriv->rp_state = RPORT_ST_DELETE;
Joe Eykholt9e9d0452009-08-25 14:01:18 -0700343 mutex_lock(&rdata->rp_mutex);
344 rdata->rport = NULL;
345 mutex_unlock(&rdata->rp_mutex);
346 fc_remote_port_delete(rport);
347 }
Joe Eykholt4b2164d2010-06-11 16:44:51 -0700348
Joe Eykholt4b2164d2010-06-11 16:44:51 -0700349 mutex_lock(&rdata->rp_mutex);
350 if (rdata->rp_state == RPORT_ST_DELETE) {
351 if (port_id == FC_FID_DIR_SERV) {
352 rdata->event = RPORT_EV_NONE;
353 mutex_unlock(&rdata->rp_mutex);
Parikh, Neeravfe5e3f12011-02-25 15:02:51 -0800354 kref_put(&rdata->kref, lport->tt.rport_destroy);
Joe Eykholtf0342602010-06-11 16:44:57 -0700355 } else if ((rdata->flags & FC_RP_STARTED) &&
356 rdata->major_retries <
357 lport->max_rport_retry_count) {
358 rdata->major_retries++;
Joe Eykholt4b2164d2010-06-11 16:44:51 -0700359 rdata->event = RPORT_EV_NONE;
360 FC_RPORT_DBG(rdata, "work restart\n");
Joe Eykholta7b12a22010-07-20 15:20:08 -0700361 fc_rport_enter_flogi(rdata);
Joe Eykholt4b2164d2010-06-11 16:44:51 -0700362 mutex_unlock(&rdata->rp_mutex);
363 } else {
364 FC_RPORT_DBG(rdata, "work delete\n");
Joe Eykholt42e90412010-07-20 15:19:37 -0700365 list_del_rcu(&rdata->peers);
Joe Eykholt4b2164d2010-06-11 16:44:51 -0700366 mutex_unlock(&rdata->rp_mutex);
367 kref_put(&rdata->kref, lport->tt.rport_destroy);
368 }
369 } else {
370 /*
371 * Re-open for events. Reissue READY event if ready.
372 */
373 rdata->event = RPORT_EV_NONE;
374 if (rdata->rp_state == RPORT_ST_READY)
375 fc_rport_enter_ready(rdata);
Joe Eykholtb4a9c7e2009-10-21 16:28:30 -0700376 mutex_unlock(&rdata->rp_mutex);
Joe Eykholt4b2164d2010-06-11 16:44:51 -0700377 }
Joe Eykholt629f4422009-08-25 14:01:06 -0700378 break;
379
380 default:
Robert Love42e9a922008-12-09 15:10:17 -0800381 mutex_unlock(&rdata->rp_mutex);
Joe Eykholt629f4422009-08-25 14:01:06 -0700382 break;
383 }
Robert Love42e9a922008-12-09 15:10:17 -0800384}
385
386/**
Robert Love34f42a02009-02-27 10:55:45 -0800387 * fc_rport_login() - Start the remote port login state machine
Robert Love3a3b42b2009-11-03 11:47:39 -0800388 * @rdata: The remote port to be logged in to
Robert Love42e9a922008-12-09 15:10:17 -0800389 *
390 * Locking Note: Called without the rport lock held. This
391 * function will hold the rport lock, call an _enter_*
392 * function and then unlock the rport.
Joe Eykholt370c3bd2009-08-25 14:03:47 -0700393 *
394 * This indicates the intent to be logged into the remote port.
395 * If it appears we are already logged in, ADISC is used to verify
396 * the setup.
Robert Love42e9a922008-12-09 15:10:17 -0800397 */
Bart Van Asschec6b21c92012-01-13 17:26:20 -0800398static int fc_rport_login(struct fc_rport_priv *rdata)
Robert Love42e9a922008-12-09 15:10:17 -0800399{
Robert Love42e9a922008-12-09 15:10:17 -0800400 mutex_lock(&rdata->rp_mutex);
401
Joe Eykholt4b2164d2010-06-11 16:44:51 -0700402 rdata->flags |= FC_RP_STARTED;
Joe Eykholt370c3bd2009-08-25 14:03:47 -0700403 switch (rdata->rp_state) {
404 case RPORT_ST_READY:
405 FC_RPORT_DBG(rdata, "ADISC port\n");
406 fc_rport_enter_adisc(rdata);
407 break;
Joe Eykholtb4a9c7e2009-10-21 16:28:30 -0700408 case RPORT_ST_DELETE:
409 FC_RPORT_DBG(rdata, "Restart deleted port\n");
Joe Eykholtb4a9c7e2009-10-21 16:28:30 -0700410 break;
Joe Eykholt370c3bd2009-08-25 14:03:47 -0700411 default:
412 FC_RPORT_DBG(rdata, "Login to port\n");
Joe Eykholta7b12a22010-07-20 15:20:08 -0700413 fc_rport_enter_flogi(rdata);
Joe Eykholt370c3bd2009-08-25 14:03:47 -0700414 break;
415 }
Robert Love42e9a922008-12-09 15:10:17 -0800416 mutex_unlock(&rdata->rp_mutex);
417
418 return 0;
419}
420
421/**
Robert Love3a3b42b2009-11-03 11:47:39 -0800422 * fc_rport_enter_delete() - Schedule a remote port to be deleted
423 * @rdata: The remote port to be deleted
424 * @event: The event to report as the reason for deletion
Joe Eykholt5f7ea3b2009-07-29 17:04:49 -0700425 *
426 * Locking Note: Called with the rport lock held.
427 *
428 * Allow state change into DELETE only once.
429 *
430 * Call queue_work only if there's no event already pending.
431 * Set the new event so that the old pending event will not occur.
432 * Since we have the mutex, even if fc_rport_work() is already started,
433 * it'll see the new event.
434 */
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700435static void fc_rport_enter_delete(struct fc_rport_priv *rdata,
Joe Eykholt5f7ea3b2009-07-29 17:04:49 -0700436 enum fc_rport_event event)
437{
Joe Eykholt5f7ea3b2009-07-29 17:04:49 -0700438 if (rdata->rp_state == RPORT_ST_DELETE)
439 return;
440
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700441 FC_RPORT_DBG(rdata, "Delete port\n");
Joe Eykholt5f7ea3b2009-07-29 17:04:49 -0700442
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700443 fc_rport_state_enter(rdata, RPORT_ST_DELETE);
Joe Eykholt5f7ea3b2009-07-29 17:04:49 -0700444
445 if (rdata->event == RPORT_EV_NONE)
446 queue_work(rport_event_queue, &rdata->event_work);
447 rdata->event = event;
448}
449
450/**
Robert Love3a3b42b2009-11-03 11:47:39 -0800451 * fc_rport_logoff() - Logoff and remove a remote port
452 * @rdata: The remote port to be logged off of
Robert Love42e9a922008-12-09 15:10:17 -0800453 *
454 * Locking Note: Called without the rport lock held. This
455 * function will hold the rport lock, call an _enter_*
456 * function and then unlock the rport.
457 */
Bart Van Asschec6b21c92012-01-13 17:26:20 -0800458static int fc_rport_logoff(struct fc_rport_priv *rdata)
Robert Love42e9a922008-12-09 15:10:17 -0800459{
Hannes Reinecke649eb862016-08-05 14:55:02 +0200460 struct fc_lport *lport = rdata->local_port;
461 u32 port_id = rdata->ids.port_id;
462
Robert Love42e9a922008-12-09 15:10:17 -0800463 mutex_lock(&rdata->rp_mutex);
464
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700465 FC_RPORT_DBG(rdata, "Remove port\n");
Robert Love42e9a922008-12-09 15:10:17 -0800466
Joe Eykholt4b2164d2010-06-11 16:44:51 -0700467 rdata->flags &= ~FC_RP_STARTED;
Joe Eykholt14194052009-07-29 17:04:43 -0700468 if (rdata->rp_state == RPORT_ST_DELETE) {
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700469 FC_RPORT_DBG(rdata, "Port in Delete state, not removing\n");
Abhijeet Joglekarb4c6f542009-04-21 16:27:04 -0700470 goto out;
471 }
Hannes Reinecke649eb862016-08-05 14:55:02 +0200472 /*
473 * FC-LS states:
474 * To explicitly Logout, the initiating Nx_Port shall terminate
475 * other open Sequences that it initiated with the destination
476 * Nx_Port prior to performing Logout.
477 */
478 lport->tt.exch_mgr_reset(lport, 0, port_id);
479 lport->tt.exch_mgr_reset(lport, port_id, 0);
480
Joe Eykholt4b2164d2010-06-11 16:44:51 -0700481 fc_rport_enter_logo(rdata);
Robert Love42e9a922008-12-09 15:10:17 -0800482
483 /*
Joe Eykholt14194052009-07-29 17:04:43 -0700484 * Change the state to Delete so that we discard
Robert Love42e9a922008-12-09 15:10:17 -0800485 * the response.
486 */
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700487 fc_rport_enter_delete(rdata, RPORT_EV_STOP);
Abhijeet Joglekarb4c6f542009-04-21 16:27:04 -0700488out:
Joe Eykholtb4a9c7e2009-10-21 16:28:30 -0700489 mutex_unlock(&rdata->rp_mutex);
Robert Love42e9a922008-12-09 15:10:17 -0800490 return 0;
491}
492
493/**
Robert Love3a3b42b2009-11-03 11:47:39 -0800494 * fc_rport_enter_ready() - Transition to the RPORT_ST_READY state
495 * @rdata: The remote port that is ready
Robert Love42e9a922008-12-09 15:10:17 -0800496 *
497 * Locking Note: The rport lock is expected to be held before calling
498 * this routine.
499 */
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700500static void fc_rport_enter_ready(struct fc_rport_priv *rdata)
Robert Love42e9a922008-12-09 15:10:17 -0800501{
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700502 fc_rport_state_enter(rdata, RPORT_ST_READY);
Robert Love42e9a922008-12-09 15:10:17 -0800503
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700504 FC_RPORT_DBG(rdata, "Port is Ready\n");
Robert Love42e9a922008-12-09 15:10:17 -0800505
Joe Eykholt5f7ea3b2009-07-29 17:04:49 -0700506 if (rdata->event == RPORT_EV_NONE)
507 queue_work(rport_event_queue, &rdata->event_work);
Joe Eykholt4c0f62b2009-08-25 14:01:12 -0700508 rdata->event = RPORT_EV_READY;
Robert Love42e9a922008-12-09 15:10:17 -0800509}
510
511/**
Robert Love3a3b42b2009-11-03 11:47:39 -0800512 * fc_rport_timeout() - Handler for the retry_work timer
513 * @work: Handle to the remote port that has timed out
Robert Love42e9a922008-12-09 15:10:17 -0800514 *
515 * Locking Note: Called without the rport lock held. This
516 * function will hold the rport lock, call an _enter_*
517 * function and then unlock the rport.
518 */
519static void fc_rport_timeout(struct work_struct *work)
520{
Joe Eykholtab28f1f2009-08-25 14:00:34 -0700521 struct fc_rport_priv *rdata =
522 container_of(work, struct fc_rport_priv, retry_work.work);
Robert Love42e9a922008-12-09 15:10:17 -0800523
524 mutex_lock(&rdata->rp_mutex);
525
526 switch (rdata->rp_state) {
Joe Eykholta7b12a22010-07-20 15:20:08 -0700527 case RPORT_ST_FLOGI:
528 fc_rport_enter_flogi(rdata);
529 break;
Robert Love42e9a922008-12-09 15:10:17 -0800530 case RPORT_ST_PLOGI:
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700531 fc_rport_enter_plogi(rdata);
Robert Love42e9a922008-12-09 15:10:17 -0800532 break;
533 case RPORT_ST_PRLI:
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700534 fc_rport_enter_prli(rdata);
Robert Love42e9a922008-12-09 15:10:17 -0800535 break;
536 case RPORT_ST_RTV:
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700537 fc_rport_enter_rtv(rdata);
Robert Love42e9a922008-12-09 15:10:17 -0800538 break;
Joe Eykholt370c3bd2009-08-25 14:03:47 -0700539 case RPORT_ST_ADISC:
540 fc_rport_enter_adisc(rdata);
541 break;
Joe Eykholta7b12a22010-07-20 15:20:08 -0700542 case RPORT_ST_PLOGI_WAIT:
Robert Love42e9a922008-12-09 15:10:17 -0800543 case RPORT_ST_READY:
544 case RPORT_ST_INIT:
Joe Eykholt14194052009-07-29 17:04:43 -0700545 case RPORT_ST_DELETE:
Robert Love42e9a922008-12-09 15:10:17 -0800546 break;
547 }
548
549 mutex_unlock(&rdata->rp_mutex);
Robert Love42e9a922008-12-09 15:10:17 -0800550}
551
552/**
Robert Love34f42a02009-02-27 10:55:45 -0800553 * fc_rport_error() - Error handler, called once retries have been exhausted
Robert Love3a3b42b2009-11-03 11:47:39 -0800554 * @rdata: The remote port the error is happened on
555 * @fp: The error code encapsulated in a frame pointer
Robert Love42e9a922008-12-09 15:10:17 -0800556 *
Robert Love42e9a922008-12-09 15:10:17 -0800557 * Locking Note: The rport lock is expected to be held before
558 * calling this routine
559 */
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700560static void fc_rport_error(struct fc_rport_priv *rdata, struct fc_frame *fp)
Robert Love42e9a922008-12-09 15:10:17 -0800561{
Hannes Reinecked3919662016-08-05 14:55:01 +0200562 struct fc_lport *lport = rdata->local_port;
563
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700564 FC_RPORT_DBG(rdata, "Error %ld in state %s, retries %d\n",
Joe Eykholtcdbe6df2009-08-25 14:01:39 -0700565 IS_ERR(fp) ? -PTR_ERR(fp) : 0,
566 fc_rport_state(rdata), rdata->retries);
Robert Love42e9a922008-12-09 15:10:17 -0800567
Chris Leech6755db12009-02-27 10:55:02 -0800568 switch (rdata->rp_state) {
Joe Eykholta7b12a22010-07-20 15:20:08 -0700569 case RPORT_ST_FLOGI:
Joe Eykholt4b2164d2010-06-11 16:44:51 -0700570 rdata->flags &= ~FC_RP_STARTED;
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700571 fc_rport_enter_delete(rdata, RPORT_EV_FAILED);
Chris Leech6755db12009-02-27 10:55:02 -0800572 break;
Hannes Reinecked3919662016-08-05 14:55:01 +0200573 case RPORT_ST_PLOGI:
574 if (lport->point_to_multipoint) {
575 rdata->flags &= ~FC_RP_STARTED;
576 fc_rport_enter_delete(rdata, RPORT_EV_FAILED);
577 } else
578 fc_rport_enter_logo(rdata);
579 break;
Chris Leech6755db12009-02-27 10:55:02 -0800580 case RPORT_ST_RTV:
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700581 fc_rport_enter_ready(rdata);
Chris Leech6755db12009-02-27 10:55:02 -0800582 break;
Joe Eykholt370c3bd2009-08-25 14:03:47 -0700583 case RPORT_ST_PRLI:
584 case RPORT_ST_ADISC:
585 fc_rport_enter_logo(rdata);
586 break;
Joe Eykholta7b12a22010-07-20 15:20:08 -0700587 case RPORT_ST_PLOGI_WAIT:
Joe Eykholt14194052009-07-29 17:04:43 -0700588 case RPORT_ST_DELETE:
Chris Leech6755db12009-02-27 10:55:02 -0800589 case RPORT_ST_READY:
590 case RPORT_ST_INIT:
591 break;
Robert Love42e9a922008-12-09 15:10:17 -0800592 }
593}
594
595/**
Robert Love3a3b42b2009-11-03 11:47:39 -0800596 * fc_rport_error_retry() - Handler for remote port state retries
597 * @rdata: The remote port whose state is to be retried
598 * @fp: The error code encapsulated in a frame pointer
Chris Leech6755db12009-02-27 10:55:02 -0800599 *
600 * If the error was an exchange timeout retry immediately,
601 * otherwise wait for E_D_TOV.
602 *
603 * Locking Note: The rport lock is expected to be held before
604 * calling this routine
605 */
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700606static void fc_rport_error_retry(struct fc_rport_priv *rdata,
607 struct fc_frame *fp)
Chris Leech6755db12009-02-27 10:55:02 -0800608{
Krishna Mohana5860692013-02-13 16:33:04 -0800609 unsigned long delay = msecs_to_jiffies(FC_DEF_E_D_TOV);
Chris Leech6755db12009-02-27 10:55:02 -0800610
611 /* make sure this isn't an FC_EX_CLOSED error, never retry those */
612 if (PTR_ERR(fp) == -FC_EX_CLOSED)
Hillf Danton28a4af12011-01-28 16:03:26 -0800613 goto out;
Chris Leech6755db12009-02-27 10:55:02 -0800614
Abhijeet Joglekara3666952009-05-01 10:01:26 -0700615 if (rdata->retries < rdata->local_port->max_rport_retry_count) {
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700616 FC_RPORT_DBG(rdata, "Error %ld in state %s, retrying\n",
617 PTR_ERR(fp), fc_rport_state(rdata));
Chris Leech6755db12009-02-27 10:55:02 -0800618 rdata->retries++;
619 /* no additional delay on exchange timeouts */
620 if (PTR_ERR(fp) == -FC_EX_TIMEOUT)
621 delay = 0;
Chris Leech6755db12009-02-27 10:55:02 -0800622 schedule_delayed_work(&rdata->retry_work, delay);
623 return;
624 }
625
Hillf Danton28a4af12011-01-28 16:03:26 -0800626out:
627 fc_rport_error(rdata, fp);
Chris Leech6755db12009-02-27 10:55:02 -0800628}
629
630/**
Joe Eykholta7b12a22010-07-20 15:20:08 -0700631 * fc_rport_login_complete() - Handle parameters and completion of p-mp login.
632 * @rdata: The remote port which we logged into or which logged into us.
633 * @fp: The FLOGI or PLOGI request or response frame
634 *
635 * Returns non-zero error if a problem is detected with the frame.
636 * Does not free the frame.
637 *
638 * This is only used in point-to-multipoint mode for FIP currently.
639 */
640static int fc_rport_login_complete(struct fc_rport_priv *rdata,
641 struct fc_frame *fp)
642{
643 struct fc_lport *lport = rdata->local_port;
644 struct fc_els_flogi *flogi;
645 unsigned int e_d_tov;
646 u16 csp_flags;
647
648 flogi = fc_frame_payload_get(fp, sizeof(*flogi));
649 if (!flogi)
650 return -EINVAL;
651
652 csp_flags = ntohs(flogi->fl_csp.sp_features);
653
654 if (fc_frame_payload_op(fp) == ELS_FLOGI) {
655 if (csp_flags & FC_SP_FT_FPORT) {
656 FC_RPORT_DBG(rdata, "Fabric bit set in FLOGI\n");
657 return -EINVAL;
658 }
659 } else {
660
661 /*
662 * E_D_TOV is not valid on an incoming FLOGI request.
663 */
664 e_d_tov = ntohl(flogi->fl_csp.sp_e_d_tov);
665 if (csp_flags & FC_SP_FT_EDTR)
666 e_d_tov /= 1000000;
667 if (e_d_tov > rdata->e_d_tov)
668 rdata->e_d_tov = e_d_tov;
669 }
670 rdata->maxframe_size = fc_plogi_get_maxframe(flogi, lport->mfs);
671 return 0;
672}
673
674/**
675 * fc_rport_flogi_resp() - Handle response to FLOGI request for p-mp mode
676 * @sp: The sequence that the FLOGI was on
677 * @fp: The FLOGI response frame
678 * @rp_arg: The remote port that received the FLOGI response
679 */
Bart Van Asschec6b21c92012-01-13 17:26:20 -0800680static void fc_rport_flogi_resp(struct fc_seq *sp, struct fc_frame *fp,
681 void *rp_arg)
Joe Eykholta7b12a22010-07-20 15:20:08 -0700682{
683 struct fc_rport_priv *rdata = rp_arg;
684 struct fc_lport *lport = rdata->local_port;
685 struct fc_els_flogi *flogi;
686 unsigned int r_a_tov;
687
688 FC_RPORT_DBG(rdata, "Received a FLOGI %s\n", fc_els_resp_type(fp));
689
690 if (fp == ERR_PTR(-FC_EX_CLOSED))
Hillf Danton0e9e3d32010-11-30 16:19:04 -0800691 goto put;
Joe Eykholta7b12a22010-07-20 15:20:08 -0700692
693 mutex_lock(&rdata->rp_mutex);
694
695 if (rdata->rp_state != RPORT_ST_FLOGI) {
696 FC_RPORT_DBG(rdata, "Received a FLOGI response, but in state "
697 "%s\n", fc_rport_state(rdata));
698 if (IS_ERR(fp))
699 goto err;
700 goto out;
701 }
702
703 if (IS_ERR(fp)) {
704 fc_rport_error(rdata, fp);
705 goto err;
706 }
707
708 if (fc_frame_payload_op(fp) != ELS_LS_ACC)
709 goto bad;
710 if (fc_rport_login_complete(rdata, fp))
711 goto bad;
712
713 flogi = fc_frame_payload_get(fp, sizeof(*flogi));
714 if (!flogi)
715 goto bad;
716 r_a_tov = ntohl(flogi->fl_csp.sp_r_a_tov);
717 if (r_a_tov > rdata->r_a_tov)
718 rdata->r_a_tov = r_a_tov;
719
720 if (rdata->ids.port_name < lport->wwpn)
721 fc_rport_enter_plogi(rdata);
722 else
723 fc_rport_state_enter(rdata, RPORT_ST_PLOGI_WAIT);
724out:
725 fc_frame_free(fp);
726err:
727 mutex_unlock(&rdata->rp_mutex);
Hillf Danton0e9e3d32010-11-30 16:19:04 -0800728put:
Hannes Reineckebaa67192016-05-24 08:11:58 +0200729 kref_put(&rdata->kref, lport->tt.rport_destroy);
Joe Eykholta7b12a22010-07-20 15:20:08 -0700730 return;
731bad:
732 FC_RPORT_DBG(rdata, "Bad FLOGI response\n");
733 fc_rport_error_retry(rdata, fp);
734 goto out;
735}
736
737/**
738 * fc_rport_enter_flogi() - Send a FLOGI request to the remote port for p-mp
739 * @rdata: The remote port to send a FLOGI to
740 *
741 * Locking Note: The rport lock is expected to be held before calling
742 * this routine.
743 */
744static void fc_rport_enter_flogi(struct fc_rport_priv *rdata)
745{
746 struct fc_lport *lport = rdata->local_port;
747 struct fc_frame *fp;
748
749 if (!lport->point_to_multipoint)
750 return fc_rport_enter_plogi(rdata);
751
752 FC_RPORT_DBG(rdata, "Entered FLOGI state from %s state\n",
753 fc_rport_state(rdata));
754
755 fc_rport_state_enter(rdata, RPORT_ST_FLOGI);
756
757 fp = fc_frame_alloc(lport, sizeof(struct fc_els_flogi));
758 if (!fp)
759 return fc_rport_error_retry(rdata, fp);
760
761 if (!lport->tt.elsct_send(lport, rdata->ids.port_id, fp, ELS_FLOGI,
762 fc_rport_flogi_resp, rdata,
763 2 * lport->r_a_tov))
764 fc_rport_error_retry(rdata, NULL);
765 else
766 kref_get(&rdata->kref);
767}
768
769/**
770 * fc_rport_recv_flogi_req() - Handle Fabric Login (FLOGI) request in p-mp mode
771 * @lport: The local port that received the PLOGI request
Joe Eykholta7b12a22010-07-20 15:20:08 -0700772 * @rx_fp: The PLOGI request frame
773 */
774static void fc_rport_recv_flogi_req(struct fc_lport *lport,
Joe Eykholt922611562010-07-20 15:21:12 -0700775 struct fc_frame *rx_fp)
Joe Eykholta7b12a22010-07-20 15:20:08 -0700776{
777 struct fc_disc *disc;
778 struct fc_els_flogi *flp;
779 struct fc_rport_priv *rdata;
780 struct fc_frame *fp = rx_fp;
Joe Eykholta7b12a22010-07-20 15:20:08 -0700781 struct fc_seq_els_data rjt_data;
Joe Eykholt24f089e2010-07-20 15:21:01 -0700782 u32 sid;
Joe Eykholta7b12a22010-07-20 15:20:08 -0700783
Joe Eykholt251748a2010-07-20 15:20:56 -0700784 sid = fc_frame_sid(fp);
Joe Eykholta7b12a22010-07-20 15:20:08 -0700785
786 FC_RPORT_ID_DBG(lport, sid, "Received FLOGI request\n");
787
788 disc = &lport->disc;
Joe Eykholta7b12a22010-07-20 15:20:08 -0700789 if (!lport->point_to_multipoint) {
790 rjt_data.reason = ELS_RJT_UNSUP;
791 rjt_data.explan = ELS_EXPL_NONE;
792 goto reject;
793 }
794
795 flp = fc_frame_payload_get(fp, sizeof(*flp));
796 if (!flp) {
797 rjt_data.reason = ELS_RJT_LOGIC;
798 rjt_data.explan = ELS_EXPL_INV_LEN;
799 goto reject;
800 }
801
802 rdata = lport->tt.rport_lookup(lport, sid);
803 if (!rdata) {
804 rjt_data.reason = ELS_RJT_FIP;
805 rjt_data.explan = ELS_EXPL_NOT_NEIGHBOR;
806 goto reject;
807 }
808 mutex_lock(&rdata->rp_mutex);
809
810 FC_RPORT_DBG(rdata, "Received FLOGI in %s state\n",
811 fc_rport_state(rdata));
812
813 switch (rdata->rp_state) {
814 case RPORT_ST_INIT:
Kiran Patil48058482011-06-20 16:58:59 -0700815 /*
816 * If received the FLOGI request on RPORT which is INIT state
817 * (means not transition to FLOGI either fc_rport timeout
818 * function didn;t trigger or this end hasn;t received
819 * beacon yet from other end. In that case only, allow RPORT
820 * state machine to continue, otherwise fall through which
821 * causes the code to send reject response.
822 * NOTE; Not checking for FIP->state such as VNMP_UP or
823 * VNMP_CLAIM because if FIP state is not one of those,
824 * RPORT wouldn;t have created and 'rport_lookup' would have
825 * failed anyway in that case.
826 */
827 if (lport->point_to_multipoint)
828 break;
Joe Eykholta7b12a22010-07-20 15:20:08 -0700829 case RPORT_ST_DELETE:
830 mutex_unlock(&rdata->rp_mutex);
831 rjt_data.reason = ELS_RJT_FIP;
832 rjt_data.explan = ELS_EXPL_NOT_NEIGHBOR;
Hannes Reineckebaa67192016-05-24 08:11:58 +0200833 goto reject_put;
Joe Eykholta7b12a22010-07-20 15:20:08 -0700834 case RPORT_ST_FLOGI:
835 case RPORT_ST_PLOGI_WAIT:
836 case RPORT_ST_PLOGI:
837 break;
838 case RPORT_ST_PRLI:
839 case RPORT_ST_RTV:
840 case RPORT_ST_READY:
841 case RPORT_ST_ADISC:
842 /*
843 * Set the remote port to be deleted and to then restart.
844 * This queues work to be sure exchanges are reset.
845 */
846 fc_rport_enter_delete(rdata, RPORT_EV_LOGO);
847 mutex_unlock(&rdata->rp_mutex);
848 rjt_data.reason = ELS_RJT_BUSY;
849 rjt_data.explan = ELS_EXPL_NONE;
Hannes Reineckebaa67192016-05-24 08:11:58 +0200850 goto reject_put;
Joe Eykholta7b12a22010-07-20 15:20:08 -0700851 }
852 if (fc_rport_login_complete(rdata, fp)) {
853 mutex_unlock(&rdata->rp_mutex);
854 rjt_data.reason = ELS_RJT_LOGIC;
855 rjt_data.explan = ELS_EXPL_NONE;
Hannes Reineckebaa67192016-05-24 08:11:58 +0200856 goto reject_put;
Joe Eykholta7b12a22010-07-20 15:20:08 -0700857 }
Joe Eykholta7b12a22010-07-20 15:20:08 -0700858
859 fp = fc_frame_alloc(lport, sizeof(*flp));
860 if (!fp)
861 goto out;
862
Joe Eykholta7b12a22010-07-20 15:20:08 -0700863 fc_flogi_fill(lport, fp);
864 flp = fc_frame_payload_get(fp, sizeof(*flp));
865 flp->fl_cmd = ELS_LS_ACC;
866
Joe Eykholt24f089e2010-07-20 15:21:01 -0700867 fc_fill_reply_hdr(fp, rx_fp, FC_RCTL_ELS_REP, 0);
868 lport->tt.frame_send(lport, fp);
Joe Eykholta7b12a22010-07-20 15:20:08 -0700869
870 if (rdata->ids.port_name < lport->wwpn)
871 fc_rport_enter_plogi(rdata);
872 else
873 fc_rport_state_enter(rdata, RPORT_ST_PLOGI_WAIT);
874out:
875 mutex_unlock(&rdata->rp_mutex);
Hannes Reineckebaa67192016-05-24 08:11:58 +0200876 kref_put(&rdata->kref, lport->tt.rport_destroy);
Joe Eykholt24f089e2010-07-20 15:21:01 -0700877 fc_frame_free(rx_fp);
Joe Eykholta7b12a22010-07-20 15:20:08 -0700878 return;
879
Hannes Reineckebaa67192016-05-24 08:11:58 +0200880reject_put:
881 kref_put(&rdata->kref, lport->tt.rport_destroy);
Joe Eykholta7b12a22010-07-20 15:20:08 -0700882reject:
Joe Eykholt922611562010-07-20 15:21:12 -0700883 lport->tt.seq_els_rsp_send(rx_fp, ELS_LS_RJT, &rjt_data);
Joe Eykholt24f089e2010-07-20 15:21:01 -0700884 fc_frame_free(rx_fp);
Joe Eykholta7b12a22010-07-20 15:20:08 -0700885}
886
887/**
888 * fc_rport_plogi_resp() - Handler for ELS PLOGI responses
Robert Love3a3b42b2009-11-03 11:47:39 -0800889 * @sp: The sequence the PLOGI is on
890 * @fp: The PLOGI response frame
891 * @rdata_arg: The remote port that sent the PLOGI response
Robert Love42e9a922008-12-09 15:10:17 -0800892 *
893 * Locking Note: This function will be called without the rport lock
894 * held, but it will lock, call an _enter_* function or fc_rport_error
895 * and then unlock the rport.
896 */
897static void fc_rport_plogi_resp(struct fc_seq *sp, struct fc_frame *fp,
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700898 void *rdata_arg)
Robert Love42e9a922008-12-09 15:10:17 -0800899{
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700900 struct fc_rport_priv *rdata = rdata_arg;
Robert Love42e9a922008-12-09 15:10:17 -0800901 struct fc_lport *lport = rdata->local_port;
Robert Lovea29e7642009-04-21 16:27:41 -0700902 struct fc_els_flogi *plp = NULL;
Robert Love42e9a922008-12-09 15:10:17 -0800903 u16 csp_seq;
904 u16 cssp_seq;
905 u8 op;
906
907 mutex_lock(&rdata->rp_mutex);
908
Joe Eykholtf657d292009-08-25 14:03:21 -0700909 FC_RPORT_DBG(rdata, "Received a PLOGI %s\n", fc_els_resp_type(fp));
Robert Love42e9a922008-12-09 15:10:17 -0800910
911 if (rdata->rp_state != RPORT_ST_PLOGI) {
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700912 FC_RPORT_DBG(rdata, "Received a PLOGI response, but in state "
913 "%s\n", fc_rport_state(rdata));
Abhijeet Joglekar76f68042009-04-21 16:26:58 -0700914 if (IS_ERR(fp))
915 goto err;
Robert Love42e9a922008-12-09 15:10:17 -0800916 goto out;
917 }
918
Abhijeet Joglekar76f68042009-04-21 16:26:58 -0700919 if (IS_ERR(fp)) {
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700920 fc_rport_error_retry(rdata, fp);
Abhijeet Joglekar76f68042009-04-21 16:26:58 -0700921 goto err;
922 }
923
Robert Love42e9a922008-12-09 15:10:17 -0800924 op = fc_frame_payload_op(fp);
925 if (op == ELS_LS_ACC &&
926 (plp = fc_frame_payload_get(fp, sizeof(*plp))) != NULL) {
Joe Eykholtf211fa52009-08-25 14:01:01 -0700927 rdata->ids.port_name = get_unaligned_be64(&plp->fl_wwpn);
928 rdata->ids.node_name = get_unaligned_be64(&plp->fl_wwnn);
Robert Love42e9a922008-12-09 15:10:17 -0800929
Bhanu Prakash Gollapudi75a27922011-01-28 16:05:27 -0800930 /* save plogi response sp_features for further reference */
931 rdata->sp_features = ntohs(plp->fl_csp.sp_features);
932
Joe Eykholta7b12a22010-07-20 15:20:08 -0700933 if (lport->point_to_multipoint)
934 fc_rport_login_complete(rdata, fp);
Robert Love42e9a922008-12-09 15:10:17 -0800935 csp_seq = ntohs(plp->fl_csp.sp_tot_seq);
936 cssp_seq = ntohs(plp->fl_cssp[3 - 1].cp_con_seq);
937 if (cssp_seq < csp_seq)
938 csp_seq = cssp_seq;
939 rdata->max_seq = csp_seq;
Joe Eykholtf211fa52009-08-25 14:01:01 -0700940 rdata->maxframe_size = fc_plogi_get_maxframe(plp, lport->mfs);
Joe Eykholt3ac6f982009-08-25 14:03:26 -0700941 fc_rport_enter_prli(rdata);
Robert Love42e9a922008-12-09 15:10:17 -0800942 } else
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700943 fc_rport_error_retry(rdata, fp);
Robert Love42e9a922008-12-09 15:10:17 -0800944
945out:
946 fc_frame_free(fp);
947err:
948 mutex_unlock(&rdata->rp_mutex);
Hannes Reineckebaa67192016-05-24 08:11:58 +0200949 kref_put(&rdata->kref, lport->tt.rport_destroy);
Robert Love42e9a922008-12-09 15:10:17 -0800950}
951
Mark Rustade0335f62013-05-18 04:01:36 +0000952static bool
953fc_rport_compatible_roles(struct fc_lport *lport, struct fc_rport_priv *rdata)
954{
955 if (rdata->ids.roles == FC_PORT_ROLE_UNKNOWN)
956 return true;
957 if ((rdata->ids.roles & FC_PORT_ROLE_FCP_TARGET) &&
958 (lport->service_params & FCP_SPPF_INIT_FCN))
959 return true;
960 if ((rdata->ids.roles & FC_PORT_ROLE_FCP_INITIATOR) &&
961 (lport->service_params & FCP_SPPF_TARG_FCN))
962 return true;
963 return false;
964}
965
Robert Love42e9a922008-12-09 15:10:17 -0800966/**
Robert Love3a3b42b2009-11-03 11:47:39 -0800967 * fc_rport_enter_plogi() - Send Port Login (PLOGI) request
968 * @rdata: The remote port to send a PLOGI to
Robert Love42e9a922008-12-09 15:10:17 -0800969 *
970 * Locking Note: The rport lock is expected to be held before calling
971 * this routine.
972 */
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700973static void fc_rport_enter_plogi(struct fc_rport_priv *rdata)
Robert Love42e9a922008-12-09 15:10:17 -0800974{
Robert Love42e9a922008-12-09 15:10:17 -0800975 struct fc_lport *lport = rdata->local_port;
976 struct fc_frame *fp;
977
Mark Rustade0335f62013-05-18 04:01:36 +0000978 if (!fc_rport_compatible_roles(lport, rdata)) {
979 FC_RPORT_DBG(rdata, "PLOGI suppressed for incompatible role\n");
980 fc_rport_state_enter(rdata, RPORT_ST_PLOGI_WAIT);
981 return;
982 }
983
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700984 FC_RPORT_DBG(rdata, "Port entered PLOGI state from %s state\n",
985 fc_rport_state(rdata));
Robert Love42e9a922008-12-09 15:10:17 -0800986
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700987 fc_rport_state_enter(rdata, RPORT_ST_PLOGI);
Robert Love42e9a922008-12-09 15:10:17 -0800988
Joe Eykholtf211fa52009-08-25 14:01:01 -0700989 rdata->maxframe_size = FC_MIN_MAX_PAYLOAD;
Robert Love42e9a922008-12-09 15:10:17 -0800990 fp = fc_frame_alloc(lport, sizeof(struct fc_els_flogi));
991 if (!fp) {
Joe Eykholta7b12a22010-07-20 15:20:08 -0700992 FC_RPORT_DBG(rdata, "%s frame alloc failed\n", __func__);
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700993 fc_rport_error_retry(rdata, fp);
Robert Love42e9a922008-12-09 15:10:17 -0800994 return;
995 }
996 rdata->e_d_tov = lport->e_d_tov;
997
Joe Eykholtf211fa52009-08-25 14:01:01 -0700998 if (!lport->tt.elsct_send(lport, rdata->ids.port_id, fp, ELS_PLOGI,
Joe Eykholtb94f8952009-11-03 11:50:21 -0800999 fc_rport_plogi_resp, rdata,
1000 2 * lport->r_a_tov))
Chris Leech8f550f92009-10-21 16:28:09 -07001001 fc_rport_error_retry(rdata, NULL);
Robert Love42e9a922008-12-09 15:10:17 -08001002 else
Joe Eykholtf211fa52009-08-25 14:01:01 -07001003 kref_get(&rdata->kref);
Robert Love42e9a922008-12-09 15:10:17 -08001004}
1005
1006/**
Robert Love34f42a02009-02-27 10:55:45 -08001007 * fc_rport_prli_resp() - Process Login (PRLI) response handler
Robert Love3a3b42b2009-11-03 11:47:39 -08001008 * @sp: The sequence the PRLI response was on
1009 * @fp: The PRLI response frame
1010 * @rdata_arg: The remote port that sent the PRLI response
Robert Love42e9a922008-12-09 15:10:17 -08001011 *
1012 * Locking Note: This function will be called without the rport lock
1013 * held, but it will lock, call an _enter_* function or fc_rport_error
1014 * and then unlock the rport.
1015 */
1016static void fc_rport_prli_resp(struct fc_seq *sp, struct fc_frame *fp,
Joe Eykholt9fb9d322009-08-25 14:00:50 -07001017 void *rdata_arg)
Robert Love42e9a922008-12-09 15:10:17 -08001018{
Joe Eykholt9fb9d322009-08-25 14:00:50 -07001019 struct fc_rport_priv *rdata = rdata_arg;
Robert Love42e9a922008-12-09 15:10:17 -08001020 struct {
1021 struct fc_els_prli prli;
1022 struct fc_els_spp spp;
1023 } *pp;
Joe Eykholt925ceda2011-01-28 16:04:23 -08001024 struct fc_els_spp temp_spp;
1025 struct fc4_prov *prov;
Robert Love42e9a922008-12-09 15:10:17 -08001026 u32 roles = FC_RPORT_ROLE_UNKNOWN;
1027 u32 fcp_parm = 0;
1028 u8 op;
Bhanu Prakash Gollapudi618461c2010-06-11 16:43:54 -07001029 u8 resp_code = 0;
Robert Love42e9a922008-12-09 15:10:17 -08001030
1031 mutex_lock(&rdata->rp_mutex);
1032
Joe Eykholtf657d292009-08-25 14:03:21 -07001033 FC_RPORT_DBG(rdata, "Received a PRLI %s\n", fc_els_resp_type(fp));
Robert Love42e9a922008-12-09 15:10:17 -08001034
1035 if (rdata->rp_state != RPORT_ST_PRLI) {
Joe Eykholt9fb9d322009-08-25 14:00:50 -07001036 FC_RPORT_DBG(rdata, "Received a PRLI response, but in state "
1037 "%s\n", fc_rport_state(rdata));
Abhijeet Joglekar76f68042009-04-21 16:26:58 -07001038 if (IS_ERR(fp))
1039 goto err;
Robert Love42e9a922008-12-09 15:10:17 -08001040 goto out;
1041 }
1042
Abhijeet Joglekar76f68042009-04-21 16:26:58 -07001043 if (IS_ERR(fp)) {
Joe Eykholt9fb9d322009-08-25 14:00:50 -07001044 fc_rport_error_retry(rdata, fp);
Abhijeet Joglekar76f68042009-04-21 16:26:58 -07001045 goto err;
1046 }
1047
Robert Love6bd054c2009-08-25 14:03:04 -07001048 /* reinitialize remote port roles */
1049 rdata->ids.roles = FC_RPORT_ROLE_UNKNOWN;
1050
Robert Love42e9a922008-12-09 15:10:17 -08001051 op = fc_frame_payload_op(fp);
1052 if (op == ELS_LS_ACC) {
1053 pp = fc_frame_payload_get(fp, sizeof(*pp));
Bhanu Prakash Gollapudi618461c2010-06-11 16:43:54 -07001054 if (!pp)
1055 goto out;
1056
1057 resp_code = (pp->spp.spp_flags & FC_SPP_RESP_MASK);
1058 FC_RPORT_DBG(rdata, "PRLI spp_flags = 0x%x\n",
1059 pp->spp.spp_flags);
Bhanu Prakash Gollapudi75a27922011-01-28 16:05:27 -08001060 rdata->spp_type = pp->spp.spp_type;
Bhanu Prakash Gollapudi618461c2010-06-11 16:43:54 -07001061 if (resp_code != FC_SPP_RESP_ACK) {
1062 if (resp_code == FC_SPP_RESP_CONF)
1063 fc_rport_error(rdata, fp);
1064 else
1065 fc_rport_error_retry(rdata, fp);
1066 goto out;
Robert Love42e9a922008-12-09 15:10:17 -08001067 }
Bhanu Prakash Gollapudi618461c2010-06-11 16:43:54 -07001068 if (pp->prli.prli_spp_len < sizeof(pp->spp))
1069 goto out;
1070
1071 fcp_parm = ntohl(pp->spp.spp_params);
1072 if (fcp_parm & FCP_SPPF_RETRY)
1073 rdata->flags |= FC_RP_FLAGS_RETRY;
Bhanu Prakash Gollapudi75a27922011-01-28 16:05:27 -08001074 if (fcp_parm & FCP_SPPF_CONF_COMPL)
1075 rdata->flags |= FC_RP_FLAGS_CONF_REQ;
Robert Love42e9a922008-12-09 15:10:17 -08001076
Joe Eykholt925ceda2011-01-28 16:04:23 -08001077 prov = fc_passive_prov[FC_TYPE_FCP];
1078 if (prov) {
1079 memset(&temp_spp, 0, sizeof(temp_spp));
1080 prov->prli(rdata, pp->prli.prli_spp_len,
1081 &pp->spp, &temp_spp);
1082 }
1083
Joe Eykholtf211fa52009-08-25 14:01:01 -07001084 rdata->supported_classes = FC_COS_CLASS3;
Robert Love42e9a922008-12-09 15:10:17 -08001085 if (fcp_parm & FCP_SPPF_INIT_FCN)
1086 roles |= FC_RPORT_ROLE_FCP_INITIATOR;
1087 if (fcp_parm & FCP_SPPF_TARG_FCN)
1088 roles |= FC_RPORT_ROLE_FCP_TARGET;
1089
Joe Eykholtf211fa52009-08-25 14:01:01 -07001090 rdata->ids.roles = roles;
Joe Eykholt9fb9d322009-08-25 14:00:50 -07001091 fc_rport_enter_rtv(rdata);
Robert Love42e9a922008-12-09 15:10:17 -08001092
1093 } else {
Joe Eykholt9fb9d322009-08-25 14:00:50 -07001094 FC_RPORT_DBG(rdata, "Bad ELS response for PRLI command\n");
Bhanu Prakash Gollapudi292e40b2010-06-11 16:43:49 -07001095 fc_rport_error_retry(rdata, fp);
Robert Love42e9a922008-12-09 15:10:17 -08001096 }
1097
1098out:
1099 fc_frame_free(fp);
1100err:
1101 mutex_unlock(&rdata->rp_mutex);
Joe Eykholtf211fa52009-08-25 14:01:01 -07001102 kref_put(&rdata->kref, rdata->local_port->tt.rport_destroy);
Robert Love42e9a922008-12-09 15:10:17 -08001103}
1104
1105/**
Robert Love3a3b42b2009-11-03 11:47:39 -08001106 * fc_rport_enter_prli() - Send Process Login (PRLI) request
1107 * @rdata: The remote port to send the PRLI request to
Robert Love42e9a922008-12-09 15:10:17 -08001108 *
1109 * Locking Note: The rport lock is expected to be held before calling
1110 * this routine.
1111 */
Joe Eykholt9fb9d322009-08-25 14:00:50 -07001112static void fc_rport_enter_prli(struct fc_rport_priv *rdata)
Robert Love42e9a922008-12-09 15:10:17 -08001113{
Robert Love42e9a922008-12-09 15:10:17 -08001114 struct fc_lport *lport = rdata->local_port;
1115 struct {
1116 struct fc_els_prli prli;
1117 struct fc_els_spp spp;
1118 } *pp;
1119 struct fc_frame *fp;
Joe Eykholt925ceda2011-01-28 16:04:23 -08001120 struct fc4_prov *prov;
Robert Love42e9a922008-12-09 15:10:17 -08001121
Joe Eykholt3ac6f982009-08-25 14:03:26 -07001122 /*
1123 * If the rport is one of the well known addresses
1124 * we skip PRLI and RTV and go straight to READY.
1125 */
1126 if (rdata->ids.port_id >= FC_FID_DOM_MGR) {
1127 fc_rport_enter_ready(rdata);
1128 return;
1129 }
1130
Joe Eykholt9fb9d322009-08-25 14:00:50 -07001131 FC_RPORT_DBG(rdata, "Port entered PRLI state from %s state\n",
1132 fc_rport_state(rdata));
Robert Love42e9a922008-12-09 15:10:17 -08001133
Joe Eykholt9fb9d322009-08-25 14:00:50 -07001134 fc_rport_state_enter(rdata, RPORT_ST_PRLI);
Robert Love42e9a922008-12-09 15:10:17 -08001135
1136 fp = fc_frame_alloc(lport, sizeof(*pp));
1137 if (!fp) {
Joe Eykholt9fb9d322009-08-25 14:00:50 -07001138 fc_rport_error_retry(rdata, fp);
Robert Love42e9a922008-12-09 15:10:17 -08001139 return;
1140 }
1141
Joe Eykholt925ceda2011-01-28 16:04:23 -08001142 fc_prli_fill(lport, fp);
1143
1144 prov = fc_passive_prov[FC_TYPE_FCP];
1145 if (prov) {
1146 pp = fc_frame_payload_get(fp, sizeof(*pp));
1147 prov->prli(rdata, sizeof(pp->spp), NULL, &pp->spp);
1148 }
1149
1150 fc_fill_fc_hdr(fp, FC_RCTL_ELS_REQ, rdata->ids.port_id,
1151 fc_host_port_id(lport->host), FC_TYPE_ELS,
1152 FC_FC_FIRST_SEQ | FC_FC_END_SEQ | FC_FC_SEQ_INIT, 0);
1153
1154 if (!lport->tt.exch_seq_send(lport, fp, fc_rport_prli_resp,
1155 NULL, rdata, 2 * lport->r_a_tov))
Chris Leech8f550f92009-10-21 16:28:09 -07001156 fc_rport_error_retry(rdata, NULL);
Robert Love42e9a922008-12-09 15:10:17 -08001157 else
Joe Eykholtf211fa52009-08-25 14:01:01 -07001158 kref_get(&rdata->kref);
Robert Love42e9a922008-12-09 15:10:17 -08001159}
1160
1161/**
Robert Love3a3b42b2009-11-03 11:47:39 -08001162 * fc_rport_els_rtv_resp() - Handler for Request Timeout Value (RTV) responses
1163 * @sp: The sequence the RTV was on
1164 * @fp: The RTV response frame
1165 * @rdata_arg: The remote port that sent the RTV response
Robert Love42e9a922008-12-09 15:10:17 -08001166 *
1167 * Many targets don't seem to support this.
1168 *
1169 * Locking Note: This function will be called without the rport lock
1170 * held, but it will lock, call an _enter_* function or fc_rport_error
1171 * and then unlock the rport.
1172 */
1173static void fc_rport_rtv_resp(struct fc_seq *sp, struct fc_frame *fp,
Joe Eykholt9fb9d322009-08-25 14:00:50 -07001174 void *rdata_arg)
Robert Love42e9a922008-12-09 15:10:17 -08001175{
Joe Eykholt9fb9d322009-08-25 14:00:50 -07001176 struct fc_rport_priv *rdata = rdata_arg;
Robert Love42e9a922008-12-09 15:10:17 -08001177 u8 op;
1178
1179 mutex_lock(&rdata->rp_mutex);
1180
Joe Eykholtf657d292009-08-25 14:03:21 -07001181 FC_RPORT_DBG(rdata, "Received a RTV %s\n", fc_els_resp_type(fp));
Robert Love42e9a922008-12-09 15:10:17 -08001182
1183 if (rdata->rp_state != RPORT_ST_RTV) {
Joe Eykholt9fb9d322009-08-25 14:00:50 -07001184 FC_RPORT_DBG(rdata, "Received a RTV response, but in state "
1185 "%s\n", fc_rport_state(rdata));
Abhijeet Joglekar76f68042009-04-21 16:26:58 -07001186 if (IS_ERR(fp))
1187 goto err;
Robert Love42e9a922008-12-09 15:10:17 -08001188 goto out;
1189 }
1190
Abhijeet Joglekar76f68042009-04-21 16:26:58 -07001191 if (IS_ERR(fp)) {
Joe Eykholt9fb9d322009-08-25 14:00:50 -07001192 fc_rport_error(rdata, fp);
Abhijeet Joglekar76f68042009-04-21 16:26:58 -07001193 goto err;
1194 }
1195
Robert Love42e9a922008-12-09 15:10:17 -08001196 op = fc_frame_payload_op(fp);
1197 if (op == ELS_LS_ACC) {
1198 struct fc_els_rtv_acc *rtv;
1199 u32 toq;
1200 u32 tov;
1201
1202 rtv = fc_frame_payload_get(fp, sizeof(*rtv));
1203 if (rtv) {
1204 toq = ntohl(rtv->rtv_toq);
1205 tov = ntohl(rtv->rtv_r_a_tov);
1206 if (tov == 0)
1207 tov = 1;
1208 rdata->r_a_tov = tov;
1209 tov = ntohl(rtv->rtv_e_d_tov);
1210 if (toq & FC_ELS_RTV_EDRES)
1211 tov /= 1000000;
1212 if (tov == 0)
1213 tov = 1;
1214 rdata->e_d_tov = tov;
1215 }
1216 }
1217
Joe Eykholt9fb9d322009-08-25 14:00:50 -07001218 fc_rport_enter_ready(rdata);
Robert Love42e9a922008-12-09 15:10:17 -08001219
1220out:
1221 fc_frame_free(fp);
1222err:
1223 mutex_unlock(&rdata->rp_mutex);
Joe Eykholtf211fa52009-08-25 14:01:01 -07001224 kref_put(&rdata->kref, rdata->local_port->tt.rport_destroy);
Robert Love42e9a922008-12-09 15:10:17 -08001225}
1226
1227/**
Robert Love3a3b42b2009-11-03 11:47:39 -08001228 * fc_rport_enter_rtv() - Send Request Timeout Value (RTV) request
1229 * @rdata: The remote port to send the RTV request to
Robert Love42e9a922008-12-09 15:10:17 -08001230 *
1231 * Locking Note: The rport lock is expected to be held before calling
1232 * this routine.
1233 */
Joe Eykholt9fb9d322009-08-25 14:00:50 -07001234static void fc_rport_enter_rtv(struct fc_rport_priv *rdata)
Robert Love42e9a922008-12-09 15:10:17 -08001235{
1236 struct fc_frame *fp;
Robert Love42e9a922008-12-09 15:10:17 -08001237 struct fc_lport *lport = rdata->local_port;
1238
Joe Eykholt9fb9d322009-08-25 14:00:50 -07001239 FC_RPORT_DBG(rdata, "Port entered RTV state from %s state\n",
1240 fc_rport_state(rdata));
Robert Love42e9a922008-12-09 15:10:17 -08001241
Joe Eykholt9fb9d322009-08-25 14:00:50 -07001242 fc_rport_state_enter(rdata, RPORT_ST_RTV);
Robert Love42e9a922008-12-09 15:10:17 -08001243
1244 fp = fc_frame_alloc(lport, sizeof(struct fc_els_rtv));
1245 if (!fp) {
Joe Eykholt9fb9d322009-08-25 14:00:50 -07001246 fc_rport_error_retry(rdata, fp);
Robert Love42e9a922008-12-09 15:10:17 -08001247 return;
1248 }
1249
Joe Eykholtf211fa52009-08-25 14:01:01 -07001250 if (!lport->tt.elsct_send(lport, rdata->ids.port_id, fp, ELS_RTV,
Joe Eykholtb94f8952009-11-03 11:50:21 -08001251 fc_rport_rtv_resp, rdata,
1252 2 * lport->r_a_tov))
Chris Leech8f550f92009-10-21 16:28:09 -07001253 fc_rport_error_retry(rdata, NULL);
Robert Love42e9a922008-12-09 15:10:17 -08001254 else
Joe Eykholtf211fa52009-08-25 14:01:01 -07001255 kref_get(&rdata->kref);
Robert Love42e9a922008-12-09 15:10:17 -08001256}
1257
1258/**
Joe Eykholt079ecd82010-07-20 15:20:51 -07001259 * fc_rport_logo_resp() - Handler for logout (LOGO) responses
1260 * @sp: The sequence the LOGO was on
1261 * @fp: The LOGO response frame
1262 * @lport_arg: The local port
1263 */
1264static void fc_rport_logo_resp(struct fc_seq *sp, struct fc_frame *fp,
1265 void *lport_arg)
1266{
1267 struct fc_lport *lport = lport_arg;
1268
1269 FC_RPORT_ID_DBG(lport, fc_seq_exch(sp)->did,
1270 "Received a LOGO %s\n", fc_els_resp_type(fp));
1271 if (IS_ERR(fp))
1272 return;
1273 fc_frame_free(fp);
1274}
1275
1276/**
Robert Love3a3b42b2009-11-03 11:47:39 -08001277 * fc_rport_enter_logo() - Send a logout (LOGO) request
1278 * @rdata: The remote port to send the LOGO request to
Robert Love42e9a922008-12-09 15:10:17 -08001279 *
1280 * Locking Note: The rport lock is expected to be held before calling
1281 * this routine.
1282 */
Joe Eykholt9fb9d322009-08-25 14:00:50 -07001283static void fc_rport_enter_logo(struct fc_rport_priv *rdata)
Robert Love42e9a922008-12-09 15:10:17 -08001284{
Robert Love42e9a922008-12-09 15:10:17 -08001285 struct fc_lport *lport = rdata->local_port;
1286 struct fc_frame *fp;
1287
Joe Eykholt079ecd82010-07-20 15:20:51 -07001288 FC_RPORT_DBG(rdata, "Port sending LOGO from %s state\n",
Joe Eykholt9fb9d322009-08-25 14:00:50 -07001289 fc_rport_state(rdata));
Robert Love42e9a922008-12-09 15:10:17 -08001290
Robert Love42e9a922008-12-09 15:10:17 -08001291 fp = fc_frame_alloc(lport, sizeof(struct fc_els_logo));
Joe Eykholt079ecd82010-07-20 15:20:51 -07001292 if (!fp)
Robert Love42e9a922008-12-09 15:10:17 -08001293 return;
Joe Eykholt079ecd82010-07-20 15:20:51 -07001294 (void)lport->tt.elsct_send(lport, rdata->ids.port_id, fp, ELS_LOGO,
1295 fc_rport_logo_resp, lport, 0);
Robert Love42e9a922008-12-09 15:10:17 -08001296}
1297
Robert Love42e9a922008-12-09 15:10:17 -08001298/**
Robert Love3a3b42b2009-11-03 11:47:39 -08001299 * fc_rport_els_adisc_resp() - Handler for Address Discovery (ADISC) responses
1300 * @sp: The sequence the ADISC response was on
1301 * @fp: The ADISC response frame
1302 * @rdata_arg: The remote port that sent the ADISC response
Joe Eykholt370c3bd2009-08-25 14:03:47 -07001303 *
1304 * Locking Note: This function will be called without the rport lock
1305 * held, but it will lock, call an _enter_* function or fc_rport_error
1306 * and then unlock the rport.
1307 */
1308static void fc_rport_adisc_resp(struct fc_seq *sp, struct fc_frame *fp,
Robert Love3a3b42b2009-11-03 11:47:39 -08001309 void *rdata_arg)
Joe Eykholt370c3bd2009-08-25 14:03:47 -07001310{
1311 struct fc_rport_priv *rdata = rdata_arg;
1312 struct fc_els_adisc *adisc;
1313 u8 op;
1314
1315 mutex_lock(&rdata->rp_mutex);
1316
1317 FC_RPORT_DBG(rdata, "Received a ADISC response\n");
1318
1319 if (rdata->rp_state != RPORT_ST_ADISC) {
1320 FC_RPORT_DBG(rdata, "Received a ADISC resp but in state %s\n",
1321 fc_rport_state(rdata));
1322 if (IS_ERR(fp))
1323 goto err;
1324 goto out;
1325 }
1326
1327 if (IS_ERR(fp)) {
1328 fc_rport_error(rdata, fp);
1329 goto err;
1330 }
1331
1332 /*
1333 * If address verification failed. Consider us logged out of the rport.
1334 * Since the rport is still in discovery, we want to be
1335 * logged in, so go to PLOGI state. Otherwise, go back to READY.
1336 */
1337 op = fc_frame_payload_op(fp);
1338 adisc = fc_frame_payload_get(fp, sizeof(*adisc));
1339 if (op != ELS_LS_ACC || !adisc ||
1340 ntoh24(adisc->adisc_port_id) != rdata->ids.port_id ||
1341 get_unaligned_be64(&adisc->adisc_wwpn) != rdata->ids.port_name ||
1342 get_unaligned_be64(&adisc->adisc_wwnn) != rdata->ids.node_name) {
1343 FC_RPORT_DBG(rdata, "ADISC error or mismatch\n");
Joe Eykholta7b12a22010-07-20 15:20:08 -07001344 fc_rport_enter_flogi(rdata);
Joe Eykholt370c3bd2009-08-25 14:03:47 -07001345 } else {
1346 FC_RPORT_DBG(rdata, "ADISC OK\n");
1347 fc_rport_enter_ready(rdata);
1348 }
1349out:
1350 fc_frame_free(fp);
1351err:
1352 mutex_unlock(&rdata->rp_mutex);
1353 kref_put(&rdata->kref, rdata->local_port->tt.rport_destroy);
1354}
1355
1356/**
Robert Love3a3b42b2009-11-03 11:47:39 -08001357 * fc_rport_enter_adisc() - Send Address Discover (ADISC) request
1358 * @rdata: The remote port to send the ADISC request to
Joe Eykholt370c3bd2009-08-25 14:03:47 -07001359 *
1360 * Locking Note: The rport lock is expected to be held before calling
1361 * this routine.
1362 */
1363static void fc_rport_enter_adisc(struct fc_rport_priv *rdata)
1364{
1365 struct fc_lport *lport = rdata->local_port;
1366 struct fc_frame *fp;
1367
1368 FC_RPORT_DBG(rdata, "sending ADISC from %s state\n",
1369 fc_rport_state(rdata));
1370
1371 fc_rport_state_enter(rdata, RPORT_ST_ADISC);
1372
1373 fp = fc_frame_alloc(lport, sizeof(struct fc_els_adisc));
1374 if (!fp) {
1375 fc_rport_error_retry(rdata, fp);
1376 return;
1377 }
1378 if (!lport->tt.elsct_send(lport, rdata->ids.port_id, fp, ELS_ADISC,
Joe Eykholtb94f8952009-11-03 11:50:21 -08001379 fc_rport_adisc_resp, rdata,
1380 2 * lport->r_a_tov))
Chris Leech8f550f92009-10-21 16:28:09 -07001381 fc_rport_error_retry(rdata, NULL);
Joe Eykholt370c3bd2009-08-25 14:03:47 -07001382 else
1383 kref_get(&rdata->kref);
1384}
1385
1386/**
Robert Love3a3b42b2009-11-03 11:47:39 -08001387 * fc_rport_recv_adisc_req() - Handler for Address Discovery (ADISC) requests
1388 * @rdata: The remote port that sent the ADISC request
Robert Love3a3b42b2009-11-03 11:47:39 -08001389 * @in_fp: The ADISC request frame
Joe Eykholt8abbe3a2009-08-25 14:03:52 -07001390 *
1391 * Locking Note: Called with the lport and rport locks held.
1392 */
1393static void fc_rport_recv_adisc_req(struct fc_rport_priv *rdata,
Joe Eykholt922611562010-07-20 15:21:12 -07001394 struct fc_frame *in_fp)
Joe Eykholt8abbe3a2009-08-25 14:03:52 -07001395{
1396 struct fc_lport *lport = rdata->local_port;
1397 struct fc_frame *fp;
Joe Eykholt8abbe3a2009-08-25 14:03:52 -07001398 struct fc_els_adisc *adisc;
1399 struct fc_seq_els_data rjt_data;
Joe Eykholt8abbe3a2009-08-25 14:03:52 -07001400
1401 FC_RPORT_DBG(rdata, "Received ADISC request\n");
1402
1403 adisc = fc_frame_payload_get(in_fp, sizeof(*adisc));
1404 if (!adisc) {
Joe Eykholt8abbe3a2009-08-25 14:03:52 -07001405 rjt_data.reason = ELS_RJT_PROT;
1406 rjt_data.explan = ELS_EXPL_INV_LEN;
Joe Eykholt922611562010-07-20 15:21:12 -07001407 lport->tt.seq_els_rsp_send(in_fp, ELS_LS_RJT, &rjt_data);
Joe Eykholt8abbe3a2009-08-25 14:03:52 -07001408 goto drop;
1409 }
1410
1411 fp = fc_frame_alloc(lport, sizeof(*adisc));
1412 if (!fp)
1413 goto drop;
1414 fc_adisc_fill(lport, fp);
1415 adisc = fc_frame_payload_get(fp, sizeof(*adisc));
1416 adisc->adisc_cmd = ELS_LS_ACC;
Joe Eykholt24f089e2010-07-20 15:21:01 -07001417 fc_fill_reply_hdr(fp, in_fp, FC_RCTL_ELS_REP, 0);
1418 lport->tt.frame_send(lport, fp);
Joe Eykholt8abbe3a2009-08-25 14:03:52 -07001419drop:
1420 fc_frame_free(in_fp);
1421}
1422
1423/**
Yi Zou63e27fb2009-11-20 14:55:24 -08001424 * fc_rport_recv_rls_req() - Handle received Read Link Status request
1425 * @rdata: The remote port that sent the RLS request
Yi Zou63e27fb2009-11-20 14:55:24 -08001426 * @rx_fp: The PRLI request frame
1427 *
1428 * Locking Note: The rport lock is expected to be held before calling
1429 * this function.
1430 */
1431static void fc_rport_recv_rls_req(struct fc_rport_priv *rdata,
Joe Eykholt922611562010-07-20 15:21:12 -07001432 struct fc_frame *rx_fp)
Yi Zou63e27fb2009-11-20 14:55:24 -08001433
1434{
1435 struct fc_lport *lport = rdata->local_port;
1436 struct fc_frame *fp;
Yi Zou63e27fb2009-11-20 14:55:24 -08001437 struct fc_els_rls *rls;
1438 struct fc_els_rls_resp *rsp;
1439 struct fc_els_lesb *lesb;
1440 struct fc_seq_els_data rjt_data;
1441 struct fc_host_statistics *hst;
Yi Zou63e27fb2009-11-20 14:55:24 -08001442
1443 FC_RPORT_DBG(rdata, "Received RLS request while in state %s\n",
1444 fc_rport_state(rdata));
1445
1446 rls = fc_frame_payload_get(rx_fp, sizeof(*rls));
1447 if (!rls) {
1448 rjt_data.reason = ELS_RJT_PROT;
1449 rjt_data.explan = ELS_EXPL_INV_LEN;
1450 goto out_rjt;
1451 }
1452
1453 fp = fc_frame_alloc(lport, sizeof(*rsp));
1454 if (!fp) {
1455 rjt_data.reason = ELS_RJT_UNAB;
1456 rjt_data.explan = ELS_EXPL_INSUF_RES;
1457 goto out_rjt;
1458 }
1459
1460 rsp = fc_frame_payload_get(fp, sizeof(*rsp));
1461 memset(rsp, 0, sizeof(*rsp));
1462 rsp->rls_cmd = ELS_LS_ACC;
1463 lesb = &rsp->rls_lesb;
1464 if (lport->tt.get_lesb) {
1465 /* get LESB from LLD if it supports it */
1466 lport->tt.get_lesb(lport, lesb);
1467 } else {
1468 fc_get_host_stats(lport->host);
1469 hst = &lport->host_stats;
1470 lesb->lesb_link_fail = htonl(hst->link_failure_count);
1471 lesb->lesb_sync_loss = htonl(hst->loss_of_sync_count);
1472 lesb->lesb_sig_loss = htonl(hst->loss_of_signal_count);
1473 lesb->lesb_prim_err = htonl(hst->prim_seq_protocol_err_count);
1474 lesb->lesb_inv_word = htonl(hst->invalid_tx_word_count);
1475 lesb->lesb_inv_crc = htonl(hst->invalid_crc_count);
1476 }
1477
Joe Eykholt24f089e2010-07-20 15:21:01 -07001478 fc_fill_reply_hdr(fp, rx_fp, FC_RCTL_ELS_REP, 0);
1479 lport->tt.frame_send(lport, fp);
Yi Zou63e27fb2009-11-20 14:55:24 -08001480 goto out;
1481
1482out_rjt:
Joe Eykholt922611562010-07-20 15:21:12 -07001483 lport->tt.seq_els_rsp_send(rx_fp, ELS_LS_RJT, &rjt_data);
Yi Zou63e27fb2009-11-20 14:55:24 -08001484out:
1485 fc_frame_free(rx_fp);
1486}
1487
1488/**
Robert Love3a3b42b2009-11-03 11:47:39 -08001489 * fc_rport_recv_els_req() - Handler for validated ELS requests
1490 * @lport: The local port that received the ELS request
Robert Love3a3b42b2009-11-03 11:47:39 -08001491 * @fp: The ELS request frame
Joe Eykholt83fe6a92009-08-25 14:03:31 -07001492 *
1493 * Handle incoming ELS requests that require port login.
1494 * The ELS opcode has already been validated by the caller.
Robert Love42e9a922008-12-09 15:10:17 -08001495 *
Joe Eykholt131203a2009-08-25 14:03:10 -07001496 * Locking Note: Called with the lport lock held.
Robert Love42e9a922008-12-09 15:10:17 -08001497 */
Joe Eykholt922611562010-07-20 15:21:12 -07001498static void fc_rport_recv_els_req(struct fc_lport *lport, struct fc_frame *fp)
Robert Love42e9a922008-12-09 15:10:17 -08001499{
Joe Eykholt131203a2009-08-25 14:03:10 -07001500 struct fc_rport_priv *rdata;
Robert Love42e9a922008-12-09 15:10:17 -08001501 struct fc_seq_els_data els_data;
Robert Love42e9a922008-12-09 15:10:17 -08001502
Joe Eykholt251748a2010-07-20 15:20:56 -07001503 rdata = lport->tt.rport_lookup(lport, fc_frame_sid(fp));
Hannes Reineckebaa67192016-05-24 08:11:58 +02001504 if (!rdata)
Joe Eykholt83fe6a92009-08-25 14:03:31 -07001505 goto reject;
Hannes Reineckebaa67192016-05-24 08:11:58 +02001506
Joe Eykholt131203a2009-08-25 14:03:10 -07001507 mutex_lock(&rdata->rp_mutex);
1508
Joe Eykholt83fe6a92009-08-25 14:03:31 -07001509 switch (rdata->rp_state) {
1510 case RPORT_ST_PRLI:
1511 case RPORT_ST_RTV:
1512 case RPORT_ST_READY:
Joe Eykholt370c3bd2009-08-25 14:03:47 -07001513 case RPORT_ST_ADISC:
Joe Eykholt83fe6a92009-08-25 14:03:31 -07001514 break;
1515 default:
1516 mutex_unlock(&rdata->rp_mutex);
Hannes Reineckebaa67192016-05-24 08:11:58 +02001517 kref_put(&rdata->kref, lport->tt.rport_destroy);
Joe Eykholt83fe6a92009-08-25 14:03:31 -07001518 goto reject;
1519 }
1520
1521 switch (fc_frame_payload_op(fp)) {
Joe Eykholt131203a2009-08-25 14:03:10 -07001522 case ELS_PRLI:
Joe Eykholt922611562010-07-20 15:21:12 -07001523 fc_rport_recv_prli_req(rdata, fp);
Joe Eykholt131203a2009-08-25 14:03:10 -07001524 break;
1525 case ELS_PRLO:
Joe Eykholt922611562010-07-20 15:21:12 -07001526 fc_rport_recv_prlo_req(rdata, fp);
Joe Eykholt131203a2009-08-25 14:03:10 -07001527 break;
Joe Eykholt8abbe3a2009-08-25 14:03:52 -07001528 case ELS_ADISC:
Joe Eykholt922611562010-07-20 15:21:12 -07001529 fc_rport_recv_adisc_req(rdata, fp);
Joe Eykholt8abbe3a2009-08-25 14:03:52 -07001530 break;
Joe Eykholt131203a2009-08-25 14:03:10 -07001531 case ELS_RRQ:
Joe Eykholt922611562010-07-20 15:21:12 -07001532 lport->tt.seq_els_rsp_send(fp, ELS_RRQ, NULL);
1533 fc_frame_free(fp);
Joe Eykholt131203a2009-08-25 14:03:10 -07001534 break;
1535 case ELS_REC:
Joe Eykholt922611562010-07-20 15:21:12 -07001536 lport->tt.seq_els_rsp_send(fp, ELS_REC, NULL);
1537 fc_frame_free(fp);
Joe Eykholt131203a2009-08-25 14:03:10 -07001538 break;
Yi Zou63e27fb2009-11-20 14:55:24 -08001539 case ELS_RLS:
Joe Eykholt922611562010-07-20 15:21:12 -07001540 fc_rport_recv_rls_req(rdata, fp);
Yi Zou63e27fb2009-11-20 14:55:24 -08001541 break;
Joe Eykholt131203a2009-08-25 14:03:10 -07001542 default:
Joe Eykholt83fe6a92009-08-25 14:03:31 -07001543 fc_frame_free(fp); /* can't happen */
Joe Eykholt131203a2009-08-25 14:03:10 -07001544 break;
Robert Love42e9a922008-12-09 15:10:17 -08001545 }
1546
1547 mutex_unlock(&rdata->rp_mutex);
Hannes Reineckebaa67192016-05-24 08:11:58 +02001548 kref_put(&rdata->kref, rdata->local_port->tt.rport_destroy);
Joe Eykholt83fe6a92009-08-25 14:03:31 -07001549 return;
1550
1551reject:
Joe Eykholt922611562010-07-20 15:21:12 -07001552 els_data.reason = ELS_RJT_UNAB;
1553 els_data.explan = ELS_EXPL_PLOGI_REQD;
1554 lport->tt.seq_els_rsp_send(fp, ELS_LS_RJT, &els_data);
Joe Eykholt83fe6a92009-08-25 14:03:31 -07001555 fc_frame_free(fp);
1556}
1557
1558/**
Robert Love3a3b42b2009-11-03 11:47:39 -08001559 * fc_rport_recv_req() - Handler for requests
Robert Love3a3b42b2009-11-03 11:47:39 -08001560 * @lport: The local port that received the request
Joe Eykholt922611562010-07-20 15:21:12 -07001561 * @fp: The request frame
Joe Eykholt83fe6a92009-08-25 14:03:31 -07001562 *
1563 * Locking Note: Called with the lport lock held.
1564 */
Bart Van Asschec6b21c92012-01-13 17:26:20 -08001565static void fc_rport_recv_req(struct fc_lport *lport, struct fc_frame *fp)
Joe Eykholt83fe6a92009-08-25 14:03:31 -07001566{
1567 struct fc_seq_els_data els_data;
1568
1569 /*
Joe Eykholta7b12a22010-07-20 15:20:08 -07001570 * Handle FLOGI, PLOGI and LOGO requests separately, since they
Joe Eykholt83fe6a92009-08-25 14:03:31 -07001571 * don't require prior login.
1572 * Check for unsupported opcodes first and reject them.
1573 * For some ops, it would be incorrect to reject with "PLOGI required".
1574 */
1575 switch (fc_frame_payload_op(fp)) {
Joe Eykholta7b12a22010-07-20 15:20:08 -07001576 case ELS_FLOGI:
Joe Eykholt922611562010-07-20 15:21:12 -07001577 fc_rport_recv_flogi_req(lport, fp);
Joe Eykholta7b12a22010-07-20 15:20:08 -07001578 break;
Joe Eykholt83fe6a92009-08-25 14:03:31 -07001579 case ELS_PLOGI:
Joe Eykholt922611562010-07-20 15:21:12 -07001580 fc_rport_recv_plogi_req(lport, fp);
Joe Eykholt83fe6a92009-08-25 14:03:31 -07001581 break;
1582 case ELS_LOGO:
Joe Eykholt922611562010-07-20 15:21:12 -07001583 fc_rport_recv_logo_req(lport, fp);
Joe Eykholt83fe6a92009-08-25 14:03:31 -07001584 break;
1585 case ELS_PRLI:
1586 case ELS_PRLO:
Joe Eykholt8abbe3a2009-08-25 14:03:52 -07001587 case ELS_ADISC:
Joe Eykholt83fe6a92009-08-25 14:03:31 -07001588 case ELS_RRQ:
1589 case ELS_REC:
Yi Zou63e27fb2009-11-20 14:55:24 -08001590 case ELS_RLS:
Joe Eykholt922611562010-07-20 15:21:12 -07001591 fc_rport_recv_els_req(lport, fp);
Joe Eykholt83fe6a92009-08-25 14:03:31 -07001592 break;
1593 default:
Joe Eykholt83fe6a92009-08-25 14:03:31 -07001594 els_data.reason = ELS_RJT_UNSUP;
1595 els_data.explan = ELS_EXPL_NONE;
Joe Eykholt922611562010-07-20 15:21:12 -07001596 lport->tt.seq_els_rsp_send(fp, ELS_LS_RJT, &els_data);
1597 fc_frame_free(fp);
Joe Eykholt83fe6a92009-08-25 14:03:31 -07001598 break;
1599 }
Robert Love42e9a922008-12-09 15:10:17 -08001600}
1601
1602/**
Robert Love3a3b42b2009-11-03 11:47:39 -08001603 * fc_rport_recv_plogi_req() - Handler for Port Login (PLOGI) requests
1604 * @lport: The local port that received the PLOGI request
Robert Love3a3b42b2009-11-03 11:47:39 -08001605 * @rx_fp: The PLOGI request frame
Robert Love42e9a922008-12-09 15:10:17 -08001606 *
Joe Eykholt3ac6f982009-08-25 14:03:26 -07001607 * Locking Note: The rport lock is held before calling this function.
Robert Love42e9a922008-12-09 15:10:17 -08001608 */
Joe Eykholt3ac6f982009-08-25 14:03:26 -07001609static void fc_rport_recv_plogi_req(struct fc_lport *lport,
Joe Eykholt922611562010-07-20 15:21:12 -07001610 struct fc_frame *rx_fp)
Robert Love42e9a922008-12-09 15:10:17 -08001611{
Joe Eykholt3ac6f982009-08-25 14:03:26 -07001612 struct fc_disc *disc;
1613 struct fc_rport_priv *rdata;
Robert Love42e9a922008-12-09 15:10:17 -08001614 struct fc_frame *fp = rx_fp;
Robert Love42e9a922008-12-09 15:10:17 -08001615 struct fc_els_flogi *pl;
1616 struct fc_seq_els_data rjt_data;
Joe Eykholt24f089e2010-07-20 15:21:01 -07001617 u32 sid;
Joe Eykholt3ac6f982009-08-25 14:03:26 -07001618
Joe Eykholt251748a2010-07-20 15:20:56 -07001619 sid = fc_frame_sid(fp);
Joe Eykholt3ac6f982009-08-25 14:03:26 -07001620
1621 FC_RPORT_ID_DBG(lport, sid, "Received PLOGI request\n");
1622
Robert Love42e9a922008-12-09 15:10:17 -08001623 pl = fc_frame_payload_get(fp, sizeof(*pl));
1624 if (!pl) {
Joe Eykholt3ac6f982009-08-25 14:03:26 -07001625 FC_RPORT_ID_DBG(lport, sid, "Received PLOGI too short\n");
1626 rjt_data.reason = ELS_RJT_PROT;
1627 rjt_data.explan = ELS_EXPL_INV_LEN;
1628 goto reject;
Robert Love42e9a922008-12-09 15:10:17 -08001629 }
Joe Eykholt3ac6f982009-08-25 14:03:26 -07001630
1631 disc = &lport->disc;
1632 mutex_lock(&disc->disc_mutex);
1633 rdata = lport->tt.rport_create(lport, sid);
1634 if (!rdata) {
1635 mutex_unlock(&disc->disc_mutex);
1636 rjt_data.reason = ELS_RJT_UNAB;
1637 rjt_data.explan = ELS_EXPL_INSUF_RES;
1638 goto reject;
1639 }
1640
1641 mutex_lock(&rdata->rp_mutex);
1642 mutex_unlock(&disc->disc_mutex);
1643
1644 rdata->ids.port_name = get_unaligned_be64(&pl->fl_wwpn);
1645 rdata->ids.node_name = get_unaligned_be64(&pl->fl_wwnn);
Robert Love42e9a922008-12-09 15:10:17 -08001646
1647 /*
Joe Eykholt3ac6f982009-08-25 14:03:26 -07001648 * If the rport was just created, possibly due to the incoming PLOGI,
Robert Love42e9a922008-12-09 15:10:17 -08001649 * set the state appropriately and accept the PLOGI.
1650 *
1651 * If we had also sent a PLOGI, and if the received PLOGI is from a
1652 * higher WWPN, we accept it, otherwise an LS_RJT is sent with reason
1653 * "command already in progress".
1654 *
1655 * XXX TBD: If the session was ready before, the PLOGI should result in
1656 * all outstanding exchanges being reset.
1657 */
1658 switch (rdata->rp_state) {
1659 case RPORT_ST_INIT:
Joe Eykholt3ac6f982009-08-25 14:03:26 -07001660 FC_RPORT_DBG(rdata, "Received PLOGI in INIT state\n");
Robert Love42e9a922008-12-09 15:10:17 -08001661 break;
Joe Eykholta7b12a22010-07-20 15:20:08 -07001662 case RPORT_ST_PLOGI_WAIT:
1663 FC_RPORT_DBG(rdata, "Received PLOGI in PLOGI_WAIT state\n");
1664 break;
Robert Love42e9a922008-12-09 15:10:17 -08001665 case RPORT_ST_PLOGI:
Joe Eykholt3ac6f982009-08-25 14:03:26 -07001666 FC_RPORT_DBG(rdata, "Received PLOGI in PLOGI state\n");
1667 if (rdata->ids.port_name < lport->wwpn) {
1668 mutex_unlock(&rdata->rp_mutex);
1669 rjt_data.reason = ELS_RJT_INPROG;
1670 rjt_data.explan = ELS_EXPL_NONE;
1671 goto reject;
1672 }
Robert Love42e9a922008-12-09 15:10:17 -08001673 break;
1674 case RPORT_ST_PRLI:
Joe Eykholtb4a9c7e2009-10-21 16:28:30 -07001675 case RPORT_ST_RTV:
Robert Love42e9a922008-12-09 15:10:17 -08001676 case RPORT_ST_READY:
Joe Eykholt370c3bd2009-08-25 14:03:47 -07001677 case RPORT_ST_ADISC:
1678 FC_RPORT_DBG(rdata, "Received PLOGI in logged-in state %d "
1679 "- ignored for now\n", rdata->rp_state);
1680 /* XXX TBD - should reset */
Robert Love42e9a922008-12-09 15:10:17 -08001681 break;
Joe Eykholta7b12a22010-07-20 15:20:08 -07001682 case RPORT_ST_FLOGI:
Joe Eykholt14194052009-07-29 17:04:43 -07001683 case RPORT_ST_DELETE:
Joe Eykholtb4a9c7e2009-10-21 16:28:30 -07001684 FC_RPORT_DBG(rdata, "Received PLOGI in state %s - send busy\n",
1685 fc_rport_state(rdata));
1686 mutex_unlock(&rdata->rp_mutex);
1687 rjt_data.reason = ELS_RJT_BUSY;
1688 rjt_data.explan = ELS_EXPL_NONE;
1689 goto reject;
Robert Love42e9a922008-12-09 15:10:17 -08001690 }
Mark Rustade0335f62013-05-18 04:01:36 +00001691 if (!fc_rport_compatible_roles(lport, rdata)) {
1692 FC_RPORT_DBG(rdata, "Received PLOGI for incompatible role\n");
1693 mutex_unlock(&rdata->rp_mutex);
1694 rjt_data.reason = ELS_RJT_LOGIC;
1695 rjt_data.explan = ELS_EXPL_NONE;
1696 goto reject;
1697 }
Robert Love42e9a922008-12-09 15:10:17 -08001698
Joe Eykholt3ac6f982009-08-25 14:03:26 -07001699 /*
1700 * Get session payload size from incoming PLOGI.
1701 */
1702 rdata->maxframe_size = fc_plogi_get_maxframe(pl, lport->mfs);
Robert Love42e9a922008-12-09 15:10:17 -08001703
Joe Eykholt3ac6f982009-08-25 14:03:26 -07001704 /*
1705 * Send LS_ACC. If this fails, the originator should retry.
1706 */
Joe Eykholt3ac6f982009-08-25 14:03:26 -07001707 fp = fc_frame_alloc(lport, sizeof(*pl));
1708 if (!fp)
1709 goto out;
Robert Love42e9a922008-12-09 15:10:17 -08001710
Joe Eykholt3ac6f982009-08-25 14:03:26 -07001711 fc_plogi_fill(lport, fp, ELS_LS_ACC);
Joe Eykholt24f089e2010-07-20 15:21:01 -07001712 fc_fill_reply_hdr(fp, rx_fp, FC_RCTL_ELS_REP, 0);
1713 lport->tt.frame_send(lport, fp);
Joe Eykholt3ac6f982009-08-25 14:03:26 -07001714 fc_rport_enter_prli(rdata);
1715out:
1716 mutex_unlock(&rdata->rp_mutex);
Joe Eykholt24f089e2010-07-20 15:21:01 -07001717 fc_frame_free(rx_fp);
Joe Eykholt3ac6f982009-08-25 14:03:26 -07001718 return;
1719
1720reject:
Joe Eykholt922611562010-07-20 15:21:12 -07001721 lport->tt.seq_els_rsp_send(fp, ELS_LS_RJT, &rjt_data);
Joe Eykholt3ac6f982009-08-25 14:03:26 -07001722 fc_frame_free(fp);
Robert Love42e9a922008-12-09 15:10:17 -08001723}
1724
1725/**
Robert Love3a3b42b2009-11-03 11:47:39 -08001726 * fc_rport_recv_prli_req() - Handler for process login (PRLI) requests
1727 * @rdata: The remote port that sent the PRLI request
Robert Love3a3b42b2009-11-03 11:47:39 -08001728 * @rx_fp: The PRLI request frame
Robert Love42e9a922008-12-09 15:10:17 -08001729 *
Bart Van Asschec1d45422013-08-14 15:31:52 +00001730 * Locking Note: The rport lock is expected to be held before calling
Robert Love42e9a922008-12-09 15:10:17 -08001731 * this function.
1732 */
Joe Eykholt9fb9d322009-08-25 14:00:50 -07001733static void fc_rport_recv_prli_req(struct fc_rport_priv *rdata,
Joe Eykholt922611562010-07-20 15:21:12 -07001734 struct fc_frame *rx_fp)
Robert Love42e9a922008-12-09 15:10:17 -08001735{
Robert Love42e9a922008-12-09 15:10:17 -08001736 struct fc_lport *lport = rdata->local_port;
Robert Love42e9a922008-12-09 15:10:17 -08001737 struct fc_frame *fp;
Robert Love42e9a922008-12-09 15:10:17 -08001738 struct {
1739 struct fc_els_prli prli;
1740 struct fc_els_spp spp;
1741 } *pp;
1742 struct fc_els_spp *rspp; /* request service param page */
1743 struct fc_els_spp *spp; /* response spp */
1744 unsigned int len;
1745 unsigned int plen;
Robert Love42e9a922008-12-09 15:10:17 -08001746 enum fc_els_spp_resp resp;
Joe Eykholt96ad8462011-01-28 16:04:02 -08001747 enum fc_els_spp_resp passive;
Robert Love42e9a922008-12-09 15:10:17 -08001748 struct fc_seq_els_data rjt_data;
Joe Eykholt96ad8462011-01-28 16:04:02 -08001749 struct fc4_prov *prov;
Robert Love42e9a922008-12-09 15:10:17 -08001750
Joe Eykholt9fb9d322009-08-25 14:00:50 -07001751 FC_RPORT_DBG(rdata, "Received PRLI request while in state %s\n",
1752 fc_rport_state(rdata));
Robert Love42e9a922008-12-09 15:10:17 -08001753
Joe Eykholt251748a2010-07-20 15:20:56 -07001754 len = fr_len(rx_fp) - sizeof(struct fc_frame_header);
Robert Love42e9a922008-12-09 15:10:17 -08001755 pp = fc_frame_payload_get(rx_fp, sizeof(*pp));
Joe Eykholta2f6a022010-03-12 16:07:36 -08001756 if (!pp)
1757 goto reject_len;
1758 plen = ntohs(pp->prli.prli_len);
1759 if ((plen % 4) != 0 || plen > len || plen < 16)
1760 goto reject_len;
1761 if (plen < len)
1762 len = plen;
1763 plen = pp->prli.prli_spp_len;
1764 if ((plen % 4) != 0 || plen < sizeof(*spp) ||
1765 plen > len || len < sizeof(*pp) || plen < 12)
1766 goto reject_len;
1767 rspp = &pp->spp;
1768
1769 fp = fc_frame_alloc(lport, len);
1770 if (!fp) {
1771 rjt_data.reason = ELS_RJT_UNAB;
1772 rjt_data.explan = ELS_EXPL_INSUF_RES;
1773 goto reject;
Robert Love42e9a922008-12-09 15:10:17 -08001774 }
Joe Eykholta2f6a022010-03-12 16:07:36 -08001775 pp = fc_frame_payload_get(fp, len);
1776 WARN_ON(!pp);
1777 memset(pp, 0, len);
1778 pp->prli.prli_cmd = ELS_LS_ACC;
1779 pp->prli.prli_spp_len = plen;
1780 pp->prli.prli_len = htons(len);
1781 len -= sizeof(struct fc_els_prli);
Robert Love42e9a922008-12-09 15:10:17 -08001782
Joe Eykholta2f6a022010-03-12 16:07:36 -08001783 /*
1784 * Go through all the service parameter pages and build
1785 * response. If plen indicates longer SPP than standard,
1786 * use that. The entire response has been pre-cleared above.
1787 */
1788 spp = &pp->spp;
Joe Eykholt96ad8462011-01-28 16:04:02 -08001789 mutex_lock(&fc_prov_mutex);
Joe Eykholta2f6a022010-03-12 16:07:36 -08001790 while (len >= plen) {
Bhanu Prakash Gollapudi75a27922011-01-28 16:05:27 -08001791 rdata->spp_type = rspp->spp_type;
Joe Eykholta2f6a022010-03-12 16:07:36 -08001792 spp->spp_type = rspp->spp_type;
1793 spp->spp_type_ext = rspp->spp_type_ext;
Joe Eykholt96ad8462011-01-28 16:04:02 -08001794 resp = 0;
Robert Love42e9a922008-12-09 15:10:17 -08001795
Joe Eykholt96ad8462011-01-28 16:04:02 -08001796 if (rspp->spp_type < FC_FC4_PROV_SIZE) {
1797 prov = fc_active_prov[rspp->spp_type];
1798 if (prov)
1799 resp = prov->prli(rdata, plen, rspp, spp);
1800 prov = fc_passive_prov[rspp->spp_type];
1801 if (prov) {
1802 passive = prov->prli(rdata, plen, rspp, spp);
1803 if (!resp || passive == FC_SPP_RESP_ACK)
1804 resp = passive;
1805 }
1806 }
1807 if (!resp) {
1808 if (spp->spp_flags & FC_SPP_EST_IMG_PAIR)
1809 resp |= FC_SPP_RESP_CONF;
1810 else
1811 resp |= FC_SPP_RESP_INVL;
Robert Love42e9a922008-12-09 15:10:17 -08001812 }
Joe Eykholta2f6a022010-03-12 16:07:36 -08001813 spp->spp_flags |= resp;
1814 len -= plen;
1815 rspp = (struct fc_els_spp *)((char *)rspp + plen);
1816 spp = (struct fc_els_spp *)((char *)spp + plen);
Robert Love42e9a922008-12-09 15:10:17 -08001817 }
Joe Eykholt96ad8462011-01-28 16:04:02 -08001818 mutex_unlock(&fc_prov_mutex);
Joe Eykholta2f6a022010-03-12 16:07:36 -08001819
1820 /*
1821 * Send LS_ACC. If this fails, the originator should retry.
1822 */
Joe Eykholt24f089e2010-07-20 15:21:01 -07001823 fc_fill_reply_hdr(fp, rx_fp, FC_RCTL_ELS_REP, 0);
1824 lport->tt.frame_send(lport, fp);
Joe Eykholta2f6a022010-03-12 16:07:36 -08001825
1826 switch (rdata->rp_state) {
1827 case RPORT_ST_PRLI:
1828 fc_rport_enter_ready(rdata);
1829 break;
1830 default:
1831 break;
1832 }
1833 goto drop;
1834
1835reject_len:
1836 rjt_data.reason = ELS_RJT_PROT;
1837 rjt_data.explan = ELS_EXPL_INV_LEN;
1838reject:
Joe Eykholt922611562010-07-20 15:21:12 -07001839 lport->tt.seq_els_rsp_send(rx_fp, ELS_LS_RJT, &rjt_data);
Joe Eykholta2f6a022010-03-12 16:07:36 -08001840drop:
Robert Love42e9a922008-12-09 15:10:17 -08001841 fc_frame_free(rx_fp);
1842}
1843
1844/**
Robert Love3a3b42b2009-11-03 11:47:39 -08001845 * fc_rport_recv_prlo_req() - Handler for process logout (PRLO) requests
1846 * @rdata: The remote port that sent the PRLO request
Bhanu Prakash Gollapudif8fc6c22010-06-11 16:44:04 -07001847 * @rx_fp: The PRLO request frame
Robert Love42e9a922008-12-09 15:10:17 -08001848 *
Bart Van Asschec1d45422013-08-14 15:31:52 +00001849 * Locking Note: The rport lock is expected to be held before calling
Robert Love42e9a922008-12-09 15:10:17 -08001850 * this function.
1851 */
Joe Eykholt9fb9d322009-08-25 14:00:50 -07001852static void fc_rport_recv_prlo_req(struct fc_rport_priv *rdata,
Bhanu Prakash Gollapudif8fc6c22010-06-11 16:44:04 -07001853 struct fc_frame *rx_fp)
Robert Love42e9a922008-12-09 15:10:17 -08001854{
Robert Love42e9a922008-12-09 15:10:17 -08001855 struct fc_lport *lport = rdata->local_port;
Bhanu Prakash Gollapudif8fc6c22010-06-11 16:44:04 -07001856 struct fc_frame *fp;
1857 struct {
1858 struct fc_els_prlo prlo;
1859 struct fc_els_spp spp;
1860 } *pp;
1861 struct fc_els_spp *rspp; /* request service param page */
1862 struct fc_els_spp *spp; /* response spp */
1863 unsigned int len;
1864 unsigned int plen;
Robert Love42e9a922008-12-09 15:10:17 -08001865 struct fc_seq_els_data rjt_data;
1866
Joe Eykholt9fb9d322009-08-25 14:00:50 -07001867 FC_RPORT_DBG(rdata, "Received PRLO request while in state %s\n",
1868 fc_rport_state(rdata));
Robert Love42e9a922008-12-09 15:10:17 -08001869
Joe Eykholt251748a2010-07-20 15:20:56 -07001870 len = fr_len(rx_fp) - sizeof(struct fc_frame_header);
Bhanu Prakash Gollapudif8fc6c22010-06-11 16:44:04 -07001871 pp = fc_frame_payload_get(rx_fp, sizeof(*pp));
1872 if (!pp)
1873 goto reject_len;
1874 plen = ntohs(pp->prlo.prlo_len);
1875 if (plen != 20)
1876 goto reject_len;
1877 if (plen < len)
1878 len = plen;
1879
1880 rspp = &pp->spp;
1881
1882 fp = fc_frame_alloc(lport, len);
1883 if (!fp) {
1884 rjt_data.reason = ELS_RJT_UNAB;
1885 rjt_data.explan = ELS_EXPL_INSUF_RES;
1886 goto reject;
1887 }
1888
Bhanu Prakash Gollapudif8fc6c22010-06-11 16:44:04 -07001889 pp = fc_frame_payload_get(fp, len);
1890 WARN_ON(!pp);
1891 memset(pp, 0, len);
1892 pp->prlo.prlo_cmd = ELS_LS_ACC;
1893 pp->prlo.prlo_obs = 0x10;
1894 pp->prlo.prlo_len = htons(len);
1895 spp = &pp->spp;
1896 spp->spp_type = rspp->spp_type;
1897 spp->spp_type_ext = rspp->spp_type_ext;
1898 spp->spp_flags = FC_SPP_RESP_ACK;
1899
Hannes Reinecke166f3102016-08-05 14:55:00 +02001900 fc_rport_enter_prli(rdata);
Bhanu Prakash Gollapudif8fc6c22010-06-11 16:44:04 -07001901
Joe Eykholt922611562010-07-20 15:21:12 -07001902 fc_fill_reply_hdr(fp, rx_fp, FC_RCTL_ELS_REP, 0);
1903 lport->tt.frame_send(lport, fp);
Bhanu Prakash Gollapudif8fc6c22010-06-11 16:44:04 -07001904 goto drop;
1905
1906reject_len:
1907 rjt_data.reason = ELS_RJT_PROT;
1908 rjt_data.explan = ELS_EXPL_INV_LEN;
1909reject:
Joe Eykholt922611562010-07-20 15:21:12 -07001910 lport->tt.seq_els_rsp_send(rx_fp, ELS_LS_RJT, &rjt_data);
Bhanu Prakash Gollapudif8fc6c22010-06-11 16:44:04 -07001911drop:
1912 fc_frame_free(rx_fp);
Robert Love42e9a922008-12-09 15:10:17 -08001913}
1914
1915/**
Robert Love3a3b42b2009-11-03 11:47:39 -08001916 * fc_rport_recv_logo_req() - Handler for logout (LOGO) requests
1917 * @lport: The local port that received the LOGO request
Robert Love3a3b42b2009-11-03 11:47:39 -08001918 * @fp: The LOGO request frame
Robert Love42e9a922008-12-09 15:10:17 -08001919 *
Bart Van Asschec1d45422013-08-14 15:31:52 +00001920 * Locking Note: The rport lock is expected to be held before calling
Robert Love42e9a922008-12-09 15:10:17 -08001921 * this function.
1922 */
Joe Eykholt922611562010-07-20 15:21:12 -07001923static void fc_rport_recv_logo_req(struct fc_lport *lport, struct fc_frame *fp)
Robert Love42e9a922008-12-09 15:10:17 -08001924{
Joe Eykholt83fe6a92009-08-25 14:03:31 -07001925 struct fc_rport_priv *rdata;
1926 u32 sid;
Robert Love42e9a922008-12-09 15:10:17 -08001927
Joe Eykholt922611562010-07-20 15:21:12 -07001928 lport->tt.seq_els_rsp_send(fp, ELS_LS_ACC, NULL);
Joe Eykholtfeab4ae2009-08-25 14:03:36 -07001929
Joe Eykholt251748a2010-07-20 15:20:56 -07001930 sid = fc_frame_sid(fp);
Robert Love42e9a922008-12-09 15:10:17 -08001931
Joe Eykholt83fe6a92009-08-25 14:03:31 -07001932 rdata = lport->tt.rport_lookup(lport, sid);
1933 if (rdata) {
1934 mutex_lock(&rdata->rp_mutex);
1935 FC_RPORT_DBG(rdata, "Received LOGO request while in state %s\n",
1936 fc_rport_state(rdata));
Joe Eykholtfeab4ae2009-08-25 14:03:36 -07001937
Hannes Reinecke649eb862016-08-05 14:55:02 +02001938 fc_rport_enter_delete(rdata, RPORT_EV_STOP);
Joe Eykholt83fe6a92009-08-25 14:03:31 -07001939 mutex_unlock(&rdata->rp_mutex);
Hannes Reineckebaa67192016-05-24 08:11:58 +02001940 kref_put(&rdata->kref, rdata->local_port->tt.rport_destroy);
Joe Eykholt83fe6a92009-08-25 14:03:31 -07001941 } else
1942 FC_RPORT_ID_DBG(lport, sid,
1943 "Received LOGO from non-logged-in port\n");
Robert Love42e9a922008-12-09 15:10:17 -08001944 fc_frame_free(fp);
1945}
1946
Robert Love3a3b42b2009-11-03 11:47:39 -08001947/**
1948 * fc_rport_flush_queue() - Flush the rport_event_queue
1949 */
Robert Love42e9a922008-12-09 15:10:17 -08001950static void fc_rport_flush_queue(void)
1951{
1952 flush_workqueue(rport_event_queue);
1953}
1954
Robert Love3a3b42b2009-11-03 11:47:39 -08001955/**
1956 * fc_rport_init() - Initialize the remote port layer for a local port
1957 * @lport: The local port to initialize the remote port layer for
1958 */
Robert Love42e9a922008-12-09 15:10:17 -08001959int fc_rport_init(struct fc_lport *lport)
1960{
Joe Eykholt8025b5d2009-08-25 14:02:06 -07001961 if (!lport->tt.rport_lookup)
1962 lport->tt.rport_lookup = fc_rport_lookup;
1963
Robert Love5101ff92009-02-27 10:55:18 -08001964 if (!lport->tt.rport_create)
Joe Eykholt9e9d0452009-08-25 14:01:18 -07001965 lport->tt.rport_create = fc_rport_create;
Robert Love5101ff92009-02-27 10:55:18 -08001966
Robert Love42e9a922008-12-09 15:10:17 -08001967 if (!lport->tt.rport_login)
1968 lport->tt.rport_login = fc_rport_login;
1969
1970 if (!lport->tt.rport_logoff)
1971 lport->tt.rport_logoff = fc_rport_logoff;
1972
1973 if (!lport->tt.rport_recv_req)
1974 lport->tt.rport_recv_req = fc_rport_recv_req;
1975
1976 if (!lport->tt.rport_flush_queue)
1977 lport->tt.rport_flush_queue = fc_rport_flush_queue;
1978
Joe Eykholtf211fa52009-08-25 14:01:01 -07001979 if (!lport->tt.rport_destroy)
1980 lport->tt.rport_destroy = fc_rport_destroy;
1981
Robert Love42e9a922008-12-09 15:10:17 -08001982 return 0;
1983}
1984EXPORT_SYMBOL(fc_rport_init);
1985
Robert Love3a3b42b2009-11-03 11:47:39 -08001986/**
Joe Eykholt96ad8462011-01-28 16:04:02 -08001987 * fc_rport_fcp_prli() - Handle incoming PRLI for the FCP initiator.
1988 * @rdata: remote port private
1989 * @spp_len: service parameter page length
1990 * @rspp: received service parameter page
1991 * @spp: response service parameter page
1992 *
1993 * Returns the value for the response code to be placed in spp_flags;
1994 * Returns 0 if not an initiator.
1995 */
1996static int fc_rport_fcp_prli(struct fc_rport_priv *rdata, u32 spp_len,
1997 const struct fc_els_spp *rspp,
1998 struct fc_els_spp *spp)
1999{
2000 struct fc_lport *lport = rdata->local_port;
2001 u32 fcp_parm;
2002
2003 fcp_parm = ntohl(rspp->spp_params);
2004 rdata->ids.roles = FC_RPORT_ROLE_UNKNOWN;
2005 if (fcp_parm & FCP_SPPF_INIT_FCN)
2006 rdata->ids.roles |= FC_RPORT_ROLE_FCP_INITIATOR;
2007 if (fcp_parm & FCP_SPPF_TARG_FCN)
2008 rdata->ids.roles |= FC_RPORT_ROLE_FCP_TARGET;
2009 if (fcp_parm & FCP_SPPF_RETRY)
2010 rdata->flags |= FC_RP_FLAGS_RETRY;
2011 rdata->supported_classes = FC_COS_CLASS3;
2012
Mark Rustad732bdb92013-03-20 07:17:55 +00002013 if (!(lport->service_params & FCP_SPPF_INIT_FCN))
Joe Eykholt96ad8462011-01-28 16:04:02 -08002014 return 0;
2015
2016 spp->spp_flags |= rspp->spp_flags & FC_SPP_EST_IMG_PAIR;
2017
2018 /*
2019 * OR in our service parameters with other providers (target), if any.
2020 */
2021 fcp_parm = ntohl(spp->spp_params);
2022 spp->spp_params = htonl(fcp_parm | lport->service_params);
2023 return FC_SPP_RESP_ACK;
2024}
2025
2026/*
2027 * FC-4 provider ops for FCP initiator.
2028 */
2029struct fc4_prov fc_rport_fcp_init = {
2030 .prli = fc_rport_fcp_prli,
2031};
2032
2033/**
2034 * fc_rport_t0_prli() - Handle incoming PRLI parameters for type 0
2035 * @rdata: remote port private
2036 * @spp_len: service parameter page length
2037 * @rspp: received service parameter page
2038 * @spp: response service parameter page
2039 */
2040static int fc_rport_t0_prli(struct fc_rport_priv *rdata, u32 spp_len,
2041 const struct fc_els_spp *rspp,
2042 struct fc_els_spp *spp)
2043{
2044 if (rspp->spp_flags & FC_SPP_EST_IMG_PAIR)
2045 return FC_SPP_RESP_INVL;
2046 return FC_SPP_RESP_ACK;
2047}
2048
2049/*
2050 * FC-4 provider ops for type 0 service parameters.
2051 *
2052 * This handles the special case of type 0 which is always successful
2053 * but doesn't do anything otherwise.
2054 */
2055struct fc4_prov fc_rport_t0_prov = {
2056 .prli = fc_rport_t0_prli,
2057};
2058
2059/**
Robert Love3a3b42b2009-11-03 11:47:39 -08002060 * fc_setup_rport() - Initialize the rport_event_queue
2061 */
Randy Dunlap55204902011-01-28 16:03:57 -08002062int fc_setup_rport(void)
Robert Love42e9a922008-12-09 15:10:17 -08002063{
2064 rport_event_queue = create_singlethread_workqueue("fc_rport_eq");
2065 if (!rport_event_queue)
2066 return -ENOMEM;
2067 return 0;
2068}
Robert Love42e9a922008-12-09 15:10:17 -08002069
Robert Love3a3b42b2009-11-03 11:47:39 -08002070/**
2071 * fc_destroy_rport() - Destroy the rport_event_queue
2072 */
Randy Dunlap55204902011-01-28 16:03:57 -08002073void fc_destroy_rport(void)
Robert Love42e9a922008-12-09 15:10:17 -08002074{
2075 destroy_workqueue(rport_event_queue);
2076}
Robert Love42e9a922008-12-09 15:10:17 -08002077
Robert Love3a3b42b2009-11-03 11:47:39 -08002078/**
2079 * fc_rport_terminate_io() - Stop all outstanding I/O on a remote port
2080 * @rport: The remote port whose I/O should be terminated
2081 */
Robert Love42e9a922008-12-09 15:10:17 -08002082void fc_rport_terminate_io(struct fc_rport *rport)
2083{
Robert Love3a3b42b2009-11-03 11:47:39 -08002084 struct fc_rport_libfc_priv *rpriv = rport->dd_data;
2085 struct fc_lport *lport = rpriv->local_port;
Robert Love42e9a922008-12-09 15:10:17 -08002086
Abhijeet Joglekar1f6ff362009-02-27 10:54:35 -08002087 lport->tt.exch_mgr_reset(lport, 0, rport->port_id);
2088 lport->tt.exch_mgr_reset(lport, rport->port_id, 0);
Robert Love42e9a922008-12-09 15:10:17 -08002089}
2090EXPORT_SYMBOL(fc_rport_terminate_io);