blob: 7162385f52eb9fffe5eb04e80ab85d17760fc086 [file] [log] [blame]
Robert Love42e9a922008-12-09 15:10:17 -08001/*
2 * Copyright(c) 2007 - 2008 Intel Corporation. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms and conditions of the GNU General Public License,
6 * version 2, as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
11 * more details.
12 *
13 * You should have received a copy of the GNU General Public License along with
14 * this program; if not, write to the Free Software Foundation, Inc.,
15 * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
16 *
17 * Maintained at www.Open-FCoE.org
18 */
19
20/*
21 * RPORT GENERAL INFO
22 *
23 * This file contains all processing regarding fc_rports. It contains the
24 * rport state machine and does all rport interaction with the transport class.
25 * There should be no other places in libfc that interact directly with the
26 * transport class in regards to adding and deleting rports.
27 *
28 * fc_rport's represent N_Port's within the fabric.
29 */
30
31/*
32 * RPORT LOCKING
33 *
34 * The rport should never hold the rport mutex and then attempt to acquire
35 * either the lport or disc mutexes. The rport's mutex is considered lesser
36 * than both the lport's mutex and the disc mutex. Refer to fc_lport.c for
37 * more comments on the heirarchy.
38 *
39 * The locking strategy is similar to the lport's strategy. The lock protects
40 * the rport's states and is held and released by the entry points to the rport
41 * block. All _enter_* functions correspond to rport states and expect the rport
42 * mutex to be locked before calling them. This means that rports only handle
43 * one request or response at a time, since they're not critical for the I/O
44 * path this potential over-use of the mutex is acceptable.
45 */
46
47#include <linux/kernel.h>
48#include <linux/spinlock.h>
49#include <linux/interrupt.h>
50#include <linux/rcupdate.h>
51#include <linux/timer.h>
52#include <linux/workqueue.h>
53#include <asm/unaligned.h>
54
55#include <scsi/libfc.h>
56#include <scsi/fc_encode.h>
57
Robert Love42e9a922008-12-09 15:10:17 -080058struct workqueue_struct *rport_event_queue;
59
60static void fc_rport_enter_plogi(struct fc_rport *);
61static void fc_rport_enter_prli(struct fc_rport *);
62static void fc_rport_enter_rtv(struct fc_rport *);
63static void fc_rport_enter_ready(struct fc_rport *);
64static void fc_rport_enter_logo(struct fc_rport *);
65
66static void fc_rport_recv_plogi_req(struct fc_rport *,
67 struct fc_seq *, struct fc_frame *);
68static void fc_rport_recv_prli_req(struct fc_rport *,
69 struct fc_seq *, struct fc_frame *);
70static void fc_rport_recv_prlo_req(struct fc_rport *,
71 struct fc_seq *, struct fc_frame *);
72static void fc_rport_recv_logo_req(struct fc_rport *,
73 struct fc_seq *, struct fc_frame *);
74static void fc_rport_timeout(struct work_struct *);
75static void fc_rport_error(struct fc_rport *, struct fc_frame *);
Chris Leech6755db12009-02-27 10:55:02 -080076static void fc_rport_error_retry(struct fc_rport *, struct fc_frame *);
Robert Love42e9a922008-12-09 15:10:17 -080077static void fc_rport_work(struct work_struct *);
78
79static const char *fc_rport_state_names[] = {
80 [RPORT_ST_NONE] = "None",
81 [RPORT_ST_INIT] = "Init",
82 [RPORT_ST_PLOGI] = "PLOGI",
83 [RPORT_ST_PRLI] = "PRLI",
84 [RPORT_ST_RTV] = "RTV",
85 [RPORT_ST_READY] = "Ready",
86 [RPORT_ST_LOGO] = "LOGO",
87};
88
89static void fc_rport_rogue_destroy(struct device *dev)
90{
91 struct fc_rport *rport = dev_to_rport(dev);
Robert Love74147052009-06-10 15:31:10 -070092 FC_RPORT_DBG(rport, "Destroying rogue rport\n");
Robert Love42e9a922008-12-09 15:10:17 -080093 kfree(rport);
94}
95
96struct fc_rport *fc_rport_rogue_create(struct fc_disc_port *dp)
97{
98 struct fc_rport *rport;
99 struct fc_rport_libfc_priv *rdata;
100 rport = kzalloc(sizeof(*rport) + sizeof(*rdata), GFP_KERNEL);
101
102 if (!rport)
103 return NULL;
104
105 rdata = RPORT_TO_PRIV(rport);
106
107 rport->dd_data = rdata;
108 rport->port_id = dp->ids.port_id;
109 rport->port_name = dp->ids.port_name;
110 rport->node_name = dp->ids.node_name;
111 rport->roles = dp->ids.roles;
112 rport->maxframe_size = FC_MIN_MAX_PAYLOAD;
113 /*
114 * Note: all this libfc rogue rport code will be removed for
115 * upstream so it fine that this is really ugly and hacky right now.
116 */
117 device_initialize(&rport->dev);
118 rport->dev.release = fc_rport_rogue_destroy;
119
120 mutex_init(&rdata->rp_mutex);
121 rdata->local_port = dp->lp;
122 rdata->trans_state = FC_PORTSTATE_ROGUE;
123 rdata->rp_state = RPORT_ST_INIT;
124 rdata->event = RPORT_EV_NONE;
125 rdata->flags = FC_RP_FLAGS_REC_SUPPORTED;
126 rdata->ops = NULL;
127 rdata->e_d_tov = dp->lp->e_d_tov;
128 rdata->r_a_tov = dp->lp->r_a_tov;
129 INIT_DELAYED_WORK(&rdata->retry_work, fc_rport_timeout);
130 INIT_WORK(&rdata->event_work, fc_rport_work);
131 /*
132 * For good measure, but not necessary as we should only
133 * add REAL rport to the lport list.
134 */
135 INIT_LIST_HEAD(&rdata->peers);
136
137 return rport;
138}
139
140/**
Robert Love34f42a02009-02-27 10:55:45 -0800141 * fc_rport_state() - return a string for the state the rport is in
Robert Love42e9a922008-12-09 15:10:17 -0800142 * @rport: The rport whose state we want to get a string for
143 */
144static const char *fc_rport_state(struct fc_rport *rport)
145{
146 const char *cp;
147 struct fc_rport_libfc_priv *rdata = rport->dd_data;
148
149 cp = fc_rport_state_names[rdata->rp_state];
150 if (!cp)
151 cp = "Unknown";
152 return cp;
153}
154
155/**
Robert Love34f42a02009-02-27 10:55:45 -0800156 * fc_set_rport_loss_tmo() - Set the remote port loss timeout in seconds.
Robert Love42e9a922008-12-09 15:10:17 -0800157 * @rport: Pointer to Fibre Channel remote port structure
158 * @timeout: timeout in seconds
159 */
160void fc_set_rport_loss_tmo(struct fc_rport *rport, u32 timeout)
161{
162 if (timeout)
163 rport->dev_loss_tmo = timeout + 5;
164 else
165 rport->dev_loss_tmo = 30;
166}
167EXPORT_SYMBOL(fc_set_rport_loss_tmo);
168
169/**
Robert Love34f42a02009-02-27 10:55:45 -0800170 * fc_plogi_get_maxframe() - Get max payload from the common service parameters
Robert Love42e9a922008-12-09 15:10:17 -0800171 * @flp: FLOGI payload structure
172 * @maxval: upper limit, may be less than what is in the service parameters
173 */
Robert Loveb2ab99c2009-02-27 10:55:50 -0800174static unsigned int fc_plogi_get_maxframe(struct fc_els_flogi *flp,
175 unsigned int maxval)
Robert Love42e9a922008-12-09 15:10:17 -0800176{
177 unsigned int mfs;
178
179 /*
180 * Get max payload from the common service parameters and the
181 * class 3 receive data field size.
182 */
183 mfs = ntohs(flp->fl_csp.sp_bb_data) & FC_SP_BB_DATA_MASK;
184 if (mfs >= FC_SP_MIN_MAX_PAYLOAD && mfs < maxval)
185 maxval = mfs;
186 mfs = ntohs(flp->fl_cssp[3 - 1].cp_rdfs);
187 if (mfs >= FC_SP_MIN_MAX_PAYLOAD && mfs < maxval)
188 maxval = mfs;
189 return maxval;
190}
191
192/**
Robert Love34f42a02009-02-27 10:55:45 -0800193 * fc_rport_state_enter() - Change the rport's state
Robert Love42e9a922008-12-09 15:10:17 -0800194 * @rport: The rport whose state should change
195 * @new: The new state of the rport
196 *
197 * Locking Note: Called with the rport lock held
198 */
199static void fc_rport_state_enter(struct fc_rport *rport,
200 enum fc_rport_state new)
201{
202 struct fc_rport_libfc_priv *rdata = rport->dd_data;
203 if (rdata->rp_state != new)
204 rdata->retries = 0;
205 rdata->rp_state = new;
206}
207
208static void fc_rport_work(struct work_struct *work)
209{
Abhijeet Joglekar571f8242009-02-27 10:54:41 -0800210 u32 port_id;
Robert Love42e9a922008-12-09 15:10:17 -0800211 struct fc_rport_libfc_priv *rdata =
212 container_of(work, struct fc_rport_libfc_priv, event_work);
213 enum fc_rport_event event;
214 enum fc_rport_trans_state trans_state;
215 struct fc_lport *lport = rdata->local_port;
216 struct fc_rport_operations *rport_ops;
217 struct fc_rport *rport = PRIV_TO_RPORT(rdata);
218
219 mutex_lock(&rdata->rp_mutex);
220 event = rdata->event;
221 rport_ops = rdata->ops;
222
223 if (event == RPORT_EV_CREATED) {
224 struct fc_rport *new_rport;
225 struct fc_rport_libfc_priv *new_rdata;
226 struct fc_rport_identifiers ids;
227
228 ids.port_id = rport->port_id;
229 ids.roles = rport->roles;
230 ids.port_name = rport->port_name;
231 ids.node_name = rport->node_name;
232
233 mutex_unlock(&rdata->rp_mutex);
234
235 new_rport = fc_remote_port_add(lport->host, 0, &ids);
236 if (new_rport) {
237 /*
238 * Switch from the rogue rport to the rport
239 * returned by the FC class.
240 */
241 new_rport->maxframe_size = rport->maxframe_size;
242
243 new_rdata = new_rport->dd_data;
244 new_rdata->e_d_tov = rdata->e_d_tov;
245 new_rdata->r_a_tov = rdata->r_a_tov;
246 new_rdata->ops = rdata->ops;
247 new_rdata->local_port = rdata->local_port;
248 new_rdata->flags = FC_RP_FLAGS_REC_SUPPORTED;
249 new_rdata->trans_state = FC_PORTSTATE_REAL;
250 mutex_init(&new_rdata->rp_mutex);
251 INIT_DELAYED_WORK(&new_rdata->retry_work,
252 fc_rport_timeout);
253 INIT_LIST_HEAD(&new_rdata->peers);
254 INIT_WORK(&new_rdata->event_work, fc_rport_work);
255
256 fc_rport_state_enter(new_rport, RPORT_ST_READY);
257 } else {
Robert Love74147052009-06-10 15:31:10 -0700258 printk(KERN_WARNING "libfc: Failed to allocate "
259 " memory for rport (%6x)\n", ids.port_id);
Robert Love42e9a922008-12-09 15:10:17 -0800260 event = RPORT_EV_FAILED;
261 }
Abhijeet Joglekarb4c6f542009-04-21 16:27:04 -0700262 if (rport->port_id != FC_FID_DIR_SERV)
263 if (rport_ops->event_callback)
264 rport_ops->event_callback(lport, rport,
265 RPORT_EV_FAILED);
Robert Love42e9a922008-12-09 15:10:17 -0800266 put_device(&rport->dev);
267 rport = new_rport;
268 rdata = new_rport->dd_data;
269 if (rport_ops->event_callback)
270 rport_ops->event_callback(lport, rport, event);
271 } else if ((event == RPORT_EV_FAILED) ||
272 (event == RPORT_EV_LOGO) ||
273 (event == RPORT_EV_STOP)) {
274 trans_state = rdata->trans_state;
275 mutex_unlock(&rdata->rp_mutex);
276 if (rport_ops->event_callback)
277 rport_ops->event_callback(lport, rport, event);
278 if (trans_state == FC_PORTSTATE_ROGUE)
279 put_device(&rport->dev);
Abhijeet Joglekar571f8242009-02-27 10:54:41 -0800280 else {
281 port_id = rport->port_id;
Robert Love42e9a922008-12-09 15:10:17 -0800282 fc_remote_port_delete(rport);
Abhijeet Joglekar571f8242009-02-27 10:54:41 -0800283 lport->tt.exch_mgr_reset(lport, 0, port_id);
284 lport->tt.exch_mgr_reset(lport, port_id, 0);
285 }
Robert Love42e9a922008-12-09 15:10:17 -0800286 } else
287 mutex_unlock(&rdata->rp_mutex);
288}
289
290/**
Robert Love34f42a02009-02-27 10:55:45 -0800291 * fc_rport_login() - Start the remote port login state machine
Robert Love42e9a922008-12-09 15:10:17 -0800292 * @rport: Fibre Channel remote port
293 *
294 * Locking Note: Called without the rport lock held. This
295 * function will hold the rport lock, call an _enter_*
296 * function and then unlock the rport.
297 */
298int fc_rport_login(struct fc_rport *rport)
299{
300 struct fc_rport_libfc_priv *rdata = rport->dd_data;
301
302 mutex_lock(&rdata->rp_mutex);
303
Robert Love74147052009-06-10 15:31:10 -0700304 FC_RPORT_DBG(rport, "Login to port\n");
Robert Love42e9a922008-12-09 15:10:17 -0800305
306 fc_rport_enter_plogi(rport);
307
308 mutex_unlock(&rdata->rp_mutex);
309
310 return 0;
311}
312
313/**
Robert Love34f42a02009-02-27 10:55:45 -0800314 * fc_rport_logoff() - Logoff and remove an rport
Robert Love42e9a922008-12-09 15:10:17 -0800315 * @rport: Fibre Channel remote port to be removed
316 *
317 * Locking Note: Called without the rport lock held. This
318 * function will hold the rport lock, call an _enter_*
319 * function and then unlock the rport.
320 */
321int fc_rport_logoff(struct fc_rport *rport)
322{
323 struct fc_rport_libfc_priv *rdata = rport->dd_data;
324
325 mutex_lock(&rdata->rp_mutex);
326
Robert Love74147052009-06-10 15:31:10 -0700327 FC_RPORT_DBG(rport, "Remove port\n");
Robert Love42e9a922008-12-09 15:10:17 -0800328
Abhijeet Joglekarb4c6f542009-04-21 16:27:04 -0700329 if (rdata->rp_state == RPORT_ST_NONE) {
Robert Love74147052009-06-10 15:31:10 -0700330 FC_RPORT_DBG(rport, "Port in NONE state, not removing\n");
Abhijeet Joglekarb4c6f542009-04-21 16:27:04 -0700331 mutex_unlock(&rdata->rp_mutex);
332 goto out;
333 }
334
Robert Love42e9a922008-12-09 15:10:17 -0800335 fc_rport_enter_logo(rport);
336
337 /*
338 * Change the state to NONE so that we discard
339 * the response.
340 */
341 fc_rport_state_enter(rport, RPORT_ST_NONE);
342
343 mutex_unlock(&rdata->rp_mutex);
344
345 cancel_delayed_work_sync(&rdata->retry_work);
346
347 mutex_lock(&rdata->rp_mutex);
348
349 rdata->event = RPORT_EV_STOP;
350 queue_work(rport_event_queue, &rdata->event_work);
351
352 mutex_unlock(&rdata->rp_mutex);
353
Abhijeet Joglekarb4c6f542009-04-21 16:27:04 -0700354out:
Robert Love42e9a922008-12-09 15:10:17 -0800355 return 0;
356}
357
358/**
Robert Love34f42a02009-02-27 10:55:45 -0800359 * fc_rport_enter_ready() - The rport is ready
Robert Love42e9a922008-12-09 15:10:17 -0800360 * @rport: Fibre Channel remote port that is ready
361 *
362 * Locking Note: The rport lock is expected to be held before calling
363 * this routine.
364 */
365static void fc_rport_enter_ready(struct fc_rport *rport)
366{
367 struct fc_rport_libfc_priv *rdata = rport->dd_data;
368
369 fc_rport_state_enter(rport, RPORT_ST_READY);
370
Robert Love74147052009-06-10 15:31:10 -0700371 FC_RPORT_DBG(rport, "Port is Ready\n");
Robert Love42e9a922008-12-09 15:10:17 -0800372
373 rdata->event = RPORT_EV_CREATED;
374 queue_work(rport_event_queue, &rdata->event_work);
375}
376
377/**
Robert Love34f42a02009-02-27 10:55:45 -0800378 * fc_rport_timeout() - Handler for the retry_work timer.
Robert Love42e9a922008-12-09 15:10:17 -0800379 * @work: The work struct of the fc_rport_libfc_priv
380 *
381 * Locking Note: Called without the rport lock held. This
382 * function will hold the rport lock, call an _enter_*
383 * function and then unlock the rport.
384 */
385static void fc_rport_timeout(struct work_struct *work)
386{
387 struct fc_rport_libfc_priv *rdata =
388 container_of(work, struct fc_rport_libfc_priv, retry_work.work);
389 struct fc_rport *rport = PRIV_TO_RPORT(rdata);
390
391 mutex_lock(&rdata->rp_mutex);
392
393 switch (rdata->rp_state) {
394 case RPORT_ST_PLOGI:
395 fc_rport_enter_plogi(rport);
396 break;
397 case RPORT_ST_PRLI:
398 fc_rport_enter_prli(rport);
399 break;
400 case RPORT_ST_RTV:
401 fc_rport_enter_rtv(rport);
402 break;
403 case RPORT_ST_LOGO:
404 fc_rport_enter_logo(rport);
405 break;
406 case RPORT_ST_READY:
407 case RPORT_ST_INIT:
408 case RPORT_ST_NONE:
409 break;
410 }
411
412 mutex_unlock(&rdata->rp_mutex);
413 put_device(&rport->dev);
414}
415
416/**
Robert Love34f42a02009-02-27 10:55:45 -0800417 * fc_rport_error() - Error handler, called once retries have been exhausted
Robert Love42e9a922008-12-09 15:10:17 -0800418 * @rport: The fc_rport object
419 * @fp: The frame pointer
420 *
Robert Love42e9a922008-12-09 15:10:17 -0800421 * Locking Note: The rport lock is expected to be held before
422 * calling this routine
423 */
424static void fc_rport_error(struct fc_rport *rport, struct fc_frame *fp)
425{
426 struct fc_rport_libfc_priv *rdata = rport->dd_data;
Robert Love42e9a922008-12-09 15:10:17 -0800427
Robert Love74147052009-06-10 15:31:10 -0700428 FC_RPORT_DBG(rport, "Error %ld in state %s, retries %d\n",
429 PTR_ERR(fp), fc_rport_state(rport), rdata->retries);
Robert Love42e9a922008-12-09 15:10:17 -0800430
Chris Leech6755db12009-02-27 10:55:02 -0800431 switch (rdata->rp_state) {
432 case RPORT_ST_PLOGI:
433 case RPORT_ST_PRLI:
434 case RPORT_ST_LOGO:
435 rdata->event = RPORT_EV_FAILED;
Abhijeet Joglekar55c7a602009-04-21 16:27:19 -0700436 fc_rport_state_enter(rport, RPORT_ST_NONE);
Chris Leech6755db12009-02-27 10:55:02 -0800437 queue_work(rport_event_queue,
438 &rdata->event_work);
439 break;
440 case RPORT_ST_RTV:
441 fc_rport_enter_ready(rport);
442 break;
443 case RPORT_ST_NONE:
444 case RPORT_ST_READY:
445 case RPORT_ST_INIT:
446 break;
Robert Love42e9a922008-12-09 15:10:17 -0800447 }
448}
449
450/**
Robert Love34f42a02009-02-27 10:55:45 -0800451 * fc_rport_error_retry() - Error handler when retries are desired
Chris Leech6755db12009-02-27 10:55:02 -0800452 * @rport: The fc_rport object
453 * @fp: The frame pointer
454 *
455 * If the error was an exchange timeout retry immediately,
456 * otherwise wait for E_D_TOV.
457 *
458 * Locking Note: The rport lock is expected to be held before
459 * calling this routine
460 */
461static void fc_rport_error_retry(struct fc_rport *rport, struct fc_frame *fp)
462{
463 struct fc_rport_libfc_priv *rdata = rport->dd_data;
464 unsigned long delay = FC_DEF_E_D_TOV;
465
466 /* make sure this isn't an FC_EX_CLOSED error, never retry those */
467 if (PTR_ERR(fp) == -FC_EX_CLOSED)
468 return fc_rport_error(rport, fp);
469
Abhijeet Joglekara3666952009-05-01 10:01:26 -0700470 if (rdata->retries < rdata->local_port->max_rport_retry_count) {
Robert Love74147052009-06-10 15:31:10 -0700471 FC_RPORT_DBG(rport, "Error %ld in state %s, retrying\n",
472 PTR_ERR(fp), fc_rport_state(rport));
Chris Leech6755db12009-02-27 10:55:02 -0800473 rdata->retries++;
474 /* no additional delay on exchange timeouts */
475 if (PTR_ERR(fp) == -FC_EX_TIMEOUT)
476 delay = 0;
477 get_device(&rport->dev);
478 schedule_delayed_work(&rdata->retry_work, delay);
479 return;
480 }
481
482 return fc_rport_error(rport, fp);
483}
484
485/**
Robert Love34f42a02009-02-27 10:55:45 -0800486 * fc_rport_plogi_recv_resp() - Handle incoming ELS PLOGI response
Robert Love42e9a922008-12-09 15:10:17 -0800487 * @sp: current sequence in the PLOGI exchange
488 * @fp: response frame
489 * @rp_arg: Fibre Channel remote port
490 *
491 * Locking Note: This function will be called without the rport lock
492 * held, but it will lock, call an _enter_* function or fc_rport_error
493 * and then unlock the rport.
494 */
495static void fc_rport_plogi_resp(struct fc_seq *sp, struct fc_frame *fp,
496 void *rp_arg)
497{
498 struct fc_rport *rport = rp_arg;
499 struct fc_rport_libfc_priv *rdata = rport->dd_data;
500 struct fc_lport *lport = rdata->local_port;
Robert Lovea29e7642009-04-21 16:27:41 -0700501 struct fc_els_flogi *plp = NULL;
Robert Love42e9a922008-12-09 15:10:17 -0800502 unsigned int tov;
503 u16 csp_seq;
504 u16 cssp_seq;
505 u8 op;
506
507 mutex_lock(&rdata->rp_mutex);
508
Robert Love74147052009-06-10 15:31:10 -0700509 FC_RPORT_DBG(rport, "Received a PLOGI response\n");
Robert Love42e9a922008-12-09 15:10:17 -0800510
511 if (rdata->rp_state != RPORT_ST_PLOGI) {
Robert Love74147052009-06-10 15:31:10 -0700512 FC_RPORT_DBG(rport, "Received a PLOGI response, but in state "
513 "%s\n", fc_rport_state(rport));
Abhijeet Joglekar76f68042009-04-21 16:26:58 -0700514 if (IS_ERR(fp))
515 goto err;
Robert Love42e9a922008-12-09 15:10:17 -0800516 goto out;
517 }
518
Abhijeet Joglekar76f68042009-04-21 16:26:58 -0700519 if (IS_ERR(fp)) {
520 fc_rport_error_retry(rport, fp);
521 goto err;
522 }
523
Robert Love42e9a922008-12-09 15:10:17 -0800524 op = fc_frame_payload_op(fp);
525 if (op == ELS_LS_ACC &&
526 (plp = fc_frame_payload_get(fp, sizeof(*plp))) != NULL) {
527 rport->port_name = get_unaligned_be64(&plp->fl_wwpn);
528 rport->node_name = get_unaligned_be64(&plp->fl_wwnn);
529
530 tov = ntohl(plp->fl_csp.sp_e_d_tov);
531 if (ntohs(plp->fl_csp.sp_features) & FC_SP_FT_EDTR)
532 tov /= 1000;
533 if (tov > rdata->e_d_tov)
534 rdata->e_d_tov = tov;
535 csp_seq = ntohs(plp->fl_csp.sp_tot_seq);
536 cssp_seq = ntohs(plp->fl_cssp[3 - 1].cp_con_seq);
537 if (cssp_seq < csp_seq)
538 csp_seq = cssp_seq;
539 rdata->max_seq = csp_seq;
540 rport->maxframe_size =
541 fc_plogi_get_maxframe(plp, lport->mfs);
542
543 /*
544 * If the rport is one of the well known addresses
545 * we skip PRLI and RTV and go straight to READY.
546 */
547 if (rport->port_id >= FC_FID_DOM_MGR)
548 fc_rport_enter_ready(rport);
549 else
550 fc_rport_enter_prli(rport);
551 } else
Chris Leech6755db12009-02-27 10:55:02 -0800552 fc_rport_error_retry(rport, fp);
Robert Love42e9a922008-12-09 15:10:17 -0800553
554out:
555 fc_frame_free(fp);
556err:
557 mutex_unlock(&rdata->rp_mutex);
558 put_device(&rport->dev);
559}
560
561/**
Robert Love34f42a02009-02-27 10:55:45 -0800562 * fc_rport_enter_plogi() - Send Port Login (PLOGI) request to peer
Robert Love42e9a922008-12-09 15:10:17 -0800563 * @rport: Fibre Channel remote port to send PLOGI to
564 *
565 * Locking Note: The rport lock is expected to be held before calling
566 * this routine.
567 */
568static void fc_rport_enter_plogi(struct fc_rport *rport)
569{
570 struct fc_rport_libfc_priv *rdata = rport->dd_data;
571 struct fc_lport *lport = rdata->local_port;
572 struct fc_frame *fp;
573
Robert Love74147052009-06-10 15:31:10 -0700574 FC_RPORT_DBG(rport, "Port entered PLOGI state from %s state\n",
575 fc_rport_state(rport));
Robert Love42e9a922008-12-09 15:10:17 -0800576
577 fc_rport_state_enter(rport, RPORT_ST_PLOGI);
578
579 rport->maxframe_size = FC_MIN_MAX_PAYLOAD;
580 fp = fc_frame_alloc(lport, sizeof(struct fc_els_flogi));
581 if (!fp) {
Chris Leech6755db12009-02-27 10:55:02 -0800582 fc_rport_error_retry(rport, fp);
Robert Love42e9a922008-12-09 15:10:17 -0800583 return;
584 }
585 rdata->e_d_tov = lport->e_d_tov;
586
587 if (!lport->tt.elsct_send(lport, rport, fp, ELS_PLOGI,
588 fc_rport_plogi_resp, rport, lport->e_d_tov))
Chris Leech6755db12009-02-27 10:55:02 -0800589 fc_rport_error_retry(rport, fp);
Robert Love42e9a922008-12-09 15:10:17 -0800590 else
591 get_device(&rport->dev);
592}
593
594/**
Robert Love34f42a02009-02-27 10:55:45 -0800595 * fc_rport_prli_resp() - Process Login (PRLI) response handler
Robert Love42e9a922008-12-09 15:10:17 -0800596 * @sp: current sequence in the PRLI exchange
597 * @fp: response frame
598 * @rp_arg: Fibre Channel remote port
599 *
600 * Locking Note: This function will be called without the rport lock
601 * held, but it will lock, call an _enter_* function or fc_rport_error
602 * and then unlock the rport.
603 */
604static void fc_rport_prli_resp(struct fc_seq *sp, struct fc_frame *fp,
605 void *rp_arg)
606{
607 struct fc_rport *rport = rp_arg;
608 struct fc_rport_libfc_priv *rdata = rport->dd_data;
609 struct {
610 struct fc_els_prli prli;
611 struct fc_els_spp spp;
612 } *pp;
613 u32 roles = FC_RPORT_ROLE_UNKNOWN;
614 u32 fcp_parm = 0;
615 u8 op;
616
617 mutex_lock(&rdata->rp_mutex);
618
Robert Love74147052009-06-10 15:31:10 -0700619 FC_RPORT_DBG(rport, "Received a PRLI response\n");
Robert Love42e9a922008-12-09 15:10:17 -0800620
621 if (rdata->rp_state != RPORT_ST_PRLI) {
Robert Love74147052009-06-10 15:31:10 -0700622 FC_RPORT_DBG(rport, "Received a PRLI response, but in state "
623 "%s\n", fc_rport_state(rport));
Abhijeet Joglekar76f68042009-04-21 16:26:58 -0700624 if (IS_ERR(fp))
625 goto err;
Robert Love42e9a922008-12-09 15:10:17 -0800626 goto out;
627 }
628
Abhijeet Joglekar76f68042009-04-21 16:26:58 -0700629 if (IS_ERR(fp)) {
630 fc_rport_error_retry(rport, fp);
631 goto err;
632 }
633
Robert Love42e9a922008-12-09 15:10:17 -0800634 op = fc_frame_payload_op(fp);
635 if (op == ELS_LS_ACC) {
636 pp = fc_frame_payload_get(fp, sizeof(*pp));
637 if (pp && pp->prli.prli_spp_len >= sizeof(pp->spp)) {
638 fcp_parm = ntohl(pp->spp.spp_params);
639 if (fcp_parm & FCP_SPPF_RETRY)
640 rdata->flags |= FC_RP_FLAGS_RETRY;
641 }
642
643 rport->supported_classes = FC_COS_CLASS3;
644 if (fcp_parm & FCP_SPPF_INIT_FCN)
645 roles |= FC_RPORT_ROLE_FCP_INITIATOR;
646 if (fcp_parm & FCP_SPPF_TARG_FCN)
647 roles |= FC_RPORT_ROLE_FCP_TARGET;
648
649 rport->roles = roles;
650 fc_rport_enter_rtv(rport);
651
652 } else {
Robert Love74147052009-06-10 15:31:10 -0700653 FC_RPORT_DBG(rport, "Bad ELS response for PRLI command\n");
Robert Love42e9a922008-12-09 15:10:17 -0800654 rdata->event = RPORT_EV_FAILED;
Abhijeet Joglekar55c7a602009-04-21 16:27:19 -0700655 fc_rport_state_enter(rport, RPORT_ST_NONE);
Robert Love42e9a922008-12-09 15:10:17 -0800656 queue_work(rport_event_queue, &rdata->event_work);
657 }
658
659out:
660 fc_frame_free(fp);
661err:
662 mutex_unlock(&rdata->rp_mutex);
663 put_device(&rport->dev);
664}
665
666/**
Robert Love34f42a02009-02-27 10:55:45 -0800667 * fc_rport_logo_resp() - Logout (LOGO) response handler
Robert Love42e9a922008-12-09 15:10:17 -0800668 * @sp: current sequence in the LOGO exchange
669 * @fp: response frame
670 * @rp_arg: Fibre Channel remote port
671 *
672 * Locking Note: This function will be called without the rport lock
673 * held, but it will lock, call an _enter_* function or fc_rport_error
674 * and then unlock the rport.
675 */
676static void fc_rport_logo_resp(struct fc_seq *sp, struct fc_frame *fp,
677 void *rp_arg)
678{
679 struct fc_rport *rport = rp_arg;
680 struct fc_rport_libfc_priv *rdata = rport->dd_data;
681 u8 op;
682
683 mutex_lock(&rdata->rp_mutex);
684
Robert Love74147052009-06-10 15:31:10 -0700685 FC_RPORT_DBG(rport, "Received a LOGO response\n");
Robert Love42e9a922008-12-09 15:10:17 -0800686
Robert Love42e9a922008-12-09 15:10:17 -0800687 if (rdata->rp_state != RPORT_ST_LOGO) {
Robert Love74147052009-06-10 15:31:10 -0700688 FC_RPORT_DBG(rport, "Received a LOGO response, but in state "
689 "%s\n", fc_rport_state(rport));
Abhijeet Joglekar76f68042009-04-21 16:26:58 -0700690 if (IS_ERR(fp))
691 goto err;
Robert Love42e9a922008-12-09 15:10:17 -0800692 goto out;
693 }
694
Abhijeet Joglekar76f68042009-04-21 16:26:58 -0700695 if (IS_ERR(fp)) {
696 fc_rport_error_retry(rport, fp);
697 goto err;
698 }
699
Robert Love42e9a922008-12-09 15:10:17 -0800700 op = fc_frame_payload_op(fp);
701 if (op == ELS_LS_ACC) {
702 fc_rport_enter_rtv(rport);
703 } else {
Robert Love74147052009-06-10 15:31:10 -0700704 FC_RPORT_DBG(rport, "Bad ELS response for LOGO command\n");
Robert Love42e9a922008-12-09 15:10:17 -0800705 rdata->event = RPORT_EV_LOGO;
Abhijeet Joglekar55c7a602009-04-21 16:27:19 -0700706 fc_rport_state_enter(rport, RPORT_ST_NONE);
Robert Love42e9a922008-12-09 15:10:17 -0800707 queue_work(rport_event_queue, &rdata->event_work);
708 }
709
710out:
711 fc_frame_free(fp);
712err:
713 mutex_unlock(&rdata->rp_mutex);
714 put_device(&rport->dev);
715}
716
717/**
Robert Love34f42a02009-02-27 10:55:45 -0800718 * fc_rport_enter_prli() - Send Process Login (PRLI) request to peer
Robert Love42e9a922008-12-09 15:10:17 -0800719 * @rport: Fibre Channel remote port to send PRLI to
720 *
721 * Locking Note: The rport lock is expected to be held before calling
722 * this routine.
723 */
724static void fc_rport_enter_prli(struct fc_rport *rport)
725{
726 struct fc_rport_libfc_priv *rdata = rport->dd_data;
727 struct fc_lport *lport = rdata->local_port;
728 struct {
729 struct fc_els_prli prli;
730 struct fc_els_spp spp;
731 } *pp;
732 struct fc_frame *fp;
733
Robert Love74147052009-06-10 15:31:10 -0700734 FC_RPORT_DBG(rport, "Port entered PRLI state from %s state\n",
735 fc_rport_state(rport));
Robert Love42e9a922008-12-09 15:10:17 -0800736
737 fc_rport_state_enter(rport, RPORT_ST_PRLI);
738
739 fp = fc_frame_alloc(lport, sizeof(*pp));
740 if (!fp) {
Chris Leech6755db12009-02-27 10:55:02 -0800741 fc_rport_error_retry(rport, fp);
Robert Love42e9a922008-12-09 15:10:17 -0800742 return;
743 }
744
745 if (!lport->tt.elsct_send(lport, rport, fp, ELS_PRLI,
746 fc_rport_prli_resp, rport, lport->e_d_tov))
Chris Leech6755db12009-02-27 10:55:02 -0800747 fc_rport_error_retry(rport, fp);
Robert Love42e9a922008-12-09 15:10:17 -0800748 else
749 get_device(&rport->dev);
750}
751
752/**
Robert Love34f42a02009-02-27 10:55:45 -0800753 * fc_rport_els_rtv_resp() - Request Timeout Value response handler
Robert Love42e9a922008-12-09 15:10:17 -0800754 * @sp: current sequence in the RTV exchange
755 * @fp: response frame
756 * @rp_arg: Fibre Channel remote port
757 *
758 * Many targets don't seem to support this.
759 *
760 * Locking Note: This function will be called without the rport lock
761 * held, but it will lock, call an _enter_* function or fc_rport_error
762 * and then unlock the rport.
763 */
764static void fc_rport_rtv_resp(struct fc_seq *sp, struct fc_frame *fp,
765 void *rp_arg)
766{
767 struct fc_rport *rport = rp_arg;
768 struct fc_rport_libfc_priv *rdata = rport->dd_data;
769 u8 op;
770
771 mutex_lock(&rdata->rp_mutex);
772
Robert Love74147052009-06-10 15:31:10 -0700773 FC_RPORT_DBG(rport, "Received a RTV response\n");
Robert Love42e9a922008-12-09 15:10:17 -0800774
775 if (rdata->rp_state != RPORT_ST_RTV) {
Robert Love74147052009-06-10 15:31:10 -0700776 FC_RPORT_DBG(rport, "Received a RTV response, but in state "
777 "%s\n", fc_rport_state(rport));
Abhijeet Joglekar76f68042009-04-21 16:26:58 -0700778 if (IS_ERR(fp))
779 goto err;
Robert Love42e9a922008-12-09 15:10:17 -0800780 goto out;
781 }
782
Abhijeet Joglekar76f68042009-04-21 16:26:58 -0700783 if (IS_ERR(fp)) {
784 fc_rport_error(rport, fp);
785 goto err;
786 }
787
Robert Love42e9a922008-12-09 15:10:17 -0800788 op = fc_frame_payload_op(fp);
789 if (op == ELS_LS_ACC) {
790 struct fc_els_rtv_acc *rtv;
791 u32 toq;
792 u32 tov;
793
794 rtv = fc_frame_payload_get(fp, sizeof(*rtv));
795 if (rtv) {
796 toq = ntohl(rtv->rtv_toq);
797 tov = ntohl(rtv->rtv_r_a_tov);
798 if (tov == 0)
799 tov = 1;
800 rdata->r_a_tov = tov;
801 tov = ntohl(rtv->rtv_e_d_tov);
802 if (toq & FC_ELS_RTV_EDRES)
803 tov /= 1000000;
804 if (tov == 0)
805 tov = 1;
806 rdata->e_d_tov = tov;
807 }
808 }
809
810 fc_rport_enter_ready(rport);
811
812out:
813 fc_frame_free(fp);
814err:
815 mutex_unlock(&rdata->rp_mutex);
816 put_device(&rport->dev);
817}
818
819/**
Robert Love34f42a02009-02-27 10:55:45 -0800820 * fc_rport_enter_rtv() - Send Request Timeout Value (RTV) request to peer
Robert Love42e9a922008-12-09 15:10:17 -0800821 * @rport: Fibre Channel remote port to send RTV to
822 *
823 * Locking Note: The rport lock is expected to be held before calling
824 * this routine.
825 */
826static void fc_rport_enter_rtv(struct fc_rport *rport)
827{
828 struct fc_frame *fp;
829 struct fc_rport_libfc_priv *rdata = rport->dd_data;
830 struct fc_lport *lport = rdata->local_port;
831
Robert Love74147052009-06-10 15:31:10 -0700832 FC_RPORT_DBG(rport, "Port entered RTV state from %s state\n",
833 fc_rport_state(rport));
Robert Love42e9a922008-12-09 15:10:17 -0800834
835 fc_rport_state_enter(rport, RPORT_ST_RTV);
836
837 fp = fc_frame_alloc(lport, sizeof(struct fc_els_rtv));
838 if (!fp) {
Chris Leech6755db12009-02-27 10:55:02 -0800839 fc_rport_error_retry(rport, fp);
Robert Love42e9a922008-12-09 15:10:17 -0800840 return;
841 }
842
843 if (!lport->tt.elsct_send(lport, rport, fp, ELS_RTV,
844 fc_rport_rtv_resp, rport, lport->e_d_tov))
Chris Leech6755db12009-02-27 10:55:02 -0800845 fc_rport_error_retry(rport, fp);
Robert Love42e9a922008-12-09 15:10:17 -0800846 else
847 get_device(&rport->dev);
848}
849
850/**
Robert Love34f42a02009-02-27 10:55:45 -0800851 * fc_rport_enter_logo() - Send Logout (LOGO) request to peer
Robert Love42e9a922008-12-09 15:10:17 -0800852 * @rport: Fibre Channel remote port to send LOGO to
853 *
854 * Locking Note: The rport lock is expected to be held before calling
855 * this routine.
856 */
857static void fc_rport_enter_logo(struct fc_rport *rport)
858{
859 struct fc_rport_libfc_priv *rdata = rport->dd_data;
860 struct fc_lport *lport = rdata->local_port;
861 struct fc_frame *fp;
862
Robert Love74147052009-06-10 15:31:10 -0700863 FC_RPORT_DBG(rport, "Port entered LOGO state from %s state\n",
864 fc_rport_state(rport));
Robert Love42e9a922008-12-09 15:10:17 -0800865
866 fc_rport_state_enter(rport, RPORT_ST_LOGO);
867
868 fp = fc_frame_alloc(lport, sizeof(struct fc_els_logo));
869 if (!fp) {
Chris Leech6755db12009-02-27 10:55:02 -0800870 fc_rport_error_retry(rport, fp);
Robert Love42e9a922008-12-09 15:10:17 -0800871 return;
872 }
873
874 if (!lport->tt.elsct_send(lport, rport, fp, ELS_LOGO,
875 fc_rport_logo_resp, rport, lport->e_d_tov))
Chris Leech6755db12009-02-27 10:55:02 -0800876 fc_rport_error_retry(rport, fp);
Robert Love42e9a922008-12-09 15:10:17 -0800877 else
878 get_device(&rport->dev);
879}
880
881
882/**
Robert Love34f42a02009-02-27 10:55:45 -0800883 * fc_rport_recv_req() - Receive a request from a rport
Robert Love42e9a922008-12-09 15:10:17 -0800884 * @sp: current sequence in the PLOGI exchange
885 * @fp: response frame
886 * @rp_arg: Fibre Channel remote port
887 *
888 * Locking Note: Called without the rport lock held. This
889 * function will hold the rport lock, call an _enter_*
890 * function and then unlock the rport.
891 */
892void fc_rport_recv_req(struct fc_seq *sp, struct fc_frame *fp,
893 struct fc_rport *rport)
894{
895 struct fc_rport_libfc_priv *rdata = rport->dd_data;
896 struct fc_lport *lport = rdata->local_port;
897
898 struct fc_frame_header *fh;
899 struct fc_seq_els_data els_data;
900 u8 op;
901
902 mutex_lock(&rdata->rp_mutex);
903
904 els_data.fp = NULL;
905 els_data.explan = ELS_EXPL_NONE;
906 els_data.reason = ELS_RJT_NONE;
907
908 fh = fc_frame_header_get(fp);
909
910 if (fh->fh_r_ctl == FC_RCTL_ELS_REQ && fh->fh_type == FC_TYPE_ELS) {
911 op = fc_frame_payload_op(fp);
912 switch (op) {
913 case ELS_PLOGI:
914 fc_rport_recv_plogi_req(rport, sp, fp);
915 break;
916 case ELS_PRLI:
917 fc_rport_recv_prli_req(rport, sp, fp);
918 break;
919 case ELS_PRLO:
920 fc_rport_recv_prlo_req(rport, sp, fp);
921 break;
922 case ELS_LOGO:
923 fc_rport_recv_logo_req(rport, sp, fp);
924 break;
925 case ELS_RRQ:
926 els_data.fp = fp;
927 lport->tt.seq_els_rsp_send(sp, ELS_RRQ, &els_data);
928 break;
929 case ELS_REC:
930 els_data.fp = fp;
931 lport->tt.seq_els_rsp_send(sp, ELS_REC, &els_data);
932 break;
933 default:
934 els_data.reason = ELS_RJT_UNSUP;
935 lport->tt.seq_els_rsp_send(sp, ELS_LS_RJT, &els_data);
936 break;
937 }
938 }
939
940 mutex_unlock(&rdata->rp_mutex);
941}
942
943/**
Robert Love34f42a02009-02-27 10:55:45 -0800944 * fc_rport_recv_plogi_req() - Handle incoming Port Login (PLOGI) request
Robert Love42e9a922008-12-09 15:10:17 -0800945 * @rport: Fibre Channel remote port that initiated PLOGI
946 * @sp: current sequence in the PLOGI exchange
947 * @fp: PLOGI request frame
948 *
949 * Locking Note: The rport lock is exected to be held before calling
950 * this function.
951 */
952static void fc_rport_recv_plogi_req(struct fc_rport *rport,
953 struct fc_seq *sp, struct fc_frame *rx_fp)
954{
955 struct fc_rport_libfc_priv *rdata = rport->dd_data;
956 struct fc_lport *lport = rdata->local_port;
957 struct fc_frame *fp = rx_fp;
958 struct fc_exch *ep;
959 struct fc_frame_header *fh;
960 struct fc_els_flogi *pl;
961 struct fc_seq_els_data rjt_data;
962 u32 sid;
963 u64 wwpn;
964 u64 wwnn;
965 enum fc_els_rjt_reason reject = 0;
966 u32 f_ctl;
967 rjt_data.fp = NULL;
968
969 fh = fc_frame_header_get(fp);
970
Robert Love74147052009-06-10 15:31:10 -0700971 FC_RPORT_DBG(rport, "Received PLOGI request while in state %s\n",
972 fc_rport_state(rport));
Robert Love42e9a922008-12-09 15:10:17 -0800973
974 sid = ntoh24(fh->fh_s_id);
975 pl = fc_frame_payload_get(fp, sizeof(*pl));
976 if (!pl) {
Robert Love74147052009-06-10 15:31:10 -0700977 FC_RPORT_DBG(rport, "Received PLOGI too short\n");
Robert Love42e9a922008-12-09 15:10:17 -0800978 WARN_ON(1);
979 /* XXX TBD: send reject? */
980 fc_frame_free(fp);
981 return;
982 }
983 wwpn = get_unaligned_be64(&pl->fl_wwpn);
984 wwnn = get_unaligned_be64(&pl->fl_wwnn);
985
986 /*
987 * If the session was just created, possibly due to the incoming PLOGI,
988 * set the state appropriately and accept the PLOGI.
989 *
990 * If we had also sent a PLOGI, and if the received PLOGI is from a
991 * higher WWPN, we accept it, otherwise an LS_RJT is sent with reason
992 * "command already in progress".
993 *
994 * XXX TBD: If the session was ready before, the PLOGI should result in
995 * all outstanding exchanges being reset.
996 */
997 switch (rdata->rp_state) {
998 case RPORT_ST_INIT:
Robert Love74147052009-06-10 15:31:10 -0700999 FC_RPORT_DBG(rport, "Received PLOGI, wwpn %llx state INIT "
1000 "- reject\n", (unsigned long long)wwpn);
Robert Love42e9a922008-12-09 15:10:17 -08001001 reject = ELS_RJT_UNSUP;
1002 break;
1003 case RPORT_ST_PLOGI:
Robert Love74147052009-06-10 15:31:10 -07001004 FC_RPORT_DBG(rport, "Received PLOGI in PLOGI state %d\n",
1005 rdata->rp_state);
Robert Love42e9a922008-12-09 15:10:17 -08001006 if (wwpn < lport->wwpn)
1007 reject = ELS_RJT_INPROG;
1008 break;
1009 case RPORT_ST_PRLI:
1010 case RPORT_ST_READY:
Robert Love74147052009-06-10 15:31:10 -07001011 FC_RPORT_DBG(rport, "Received PLOGI in logged-in state %d "
1012 "- ignored for now\n", rdata->rp_state);
Robert Love42e9a922008-12-09 15:10:17 -08001013 /* XXX TBD - should reset */
1014 break;
1015 case RPORT_ST_NONE:
1016 default:
Robert Love74147052009-06-10 15:31:10 -07001017 FC_RPORT_DBG(rport, "Received PLOGI in unexpected "
1018 "state %d\n", rdata->rp_state);
Abhijeet Joglekarb4c6f542009-04-21 16:27:04 -07001019 fc_frame_free(fp);
1020 return;
Robert Love42e9a922008-12-09 15:10:17 -08001021 break;
1022 }
1023
1024 if (reject) {
1025 rjt_data.reason = reject;
1026 rjt_data.explan = ELS_EXPL_NONE;
1027 lport->tt.seq_els_rsp_send(sp, ELS_LS_RJT, &rjt_data);
1028 fc_frame_free(fp);
1029 } else {
1030 fp = fc_frame_alloc(lport, sizeof(*pl));
1031 if (fp == NULL) {
1032 fp = rx_fp;
1033 rjt_data.reason = ELS_RJT_UNAB;
1034 rjt_data.explan = ELS_EXPL_NONE;
1035 lport->tt.seq_els_rsp_send(sp, ELS_LS_RJT, &rjt_data);
1036 fc_frame_free(fp);
1037 } else {
1038 sp = lport->tt.seq_start_next(sp);
1039 WARN_ON(!sp);
1040 fc_rport_set_name(rport, wwpn, wwnn);
1041
1042 /*
1043 * Get session payload size from incoming PLOGI.
1044 */
1045 rport->maxframe_size =
1046 fc_plogi_get_maxframe(pl, lport->mfs);
1047 fc_frame_free(rx_fp);
1048 fc_plogi_fill(lport, fp, ELS_LS_ACC);
1049
1050 /*
1051 * Send LS_ACC. If this fails,
1052 * the originator should retry.
1053 */
1054 f_ctl = FC_FC_EX_CTX | FC_FC_LAST_SEQ;
1055 f_ctl |= FC_FC_END_SEQ | FC_FC_SEQ_INIT;
1056 ep = fc_seq_exch(sp);
1057 fc_fill_fc_hdr(fp, FC_RCTL_ELS_REP, ep->did, ep->sid,
1058 FC_TYPE_ELS, f_ctl, 0);
1059 lport->tt.seq_send(lport, sp, fp);
1060 if (rdata->rp_state == RPORT_ST_PLOGI)
1061 fc_rport_enter_prli(rport);
1062 }
1063 }
1064}
1065
1066/**
Robert Love34f42a02009-02-27 10:55:45 -08001067 * fc_rport_recv_prli_req() - Handle incoming Process Login (PRLI) request
Robert Love42e9a922008-12-09 15:10:17 -08001068 * @rport: Fibre Channel remote port that initiated PRLI
1069 * @sp: current sequence in the PRLI exchange
1070 * @fp: PRLI request frame
1071 *
1072 * Locking Note: The rport lock is exected to be held before calling
1073 * this function.
1074 */
1075static void fc_rport_recv_prli_req(struct fc_rport *rport,
1076 struct fc_seq *sp, struct fc_frame *rx_fp)
1077{
1078 struct fc_rport_libfc_priv *rdata = rport->dd_data;
1079 struct fc_lport *lport = rdata->local_port;
1080 struct fc_exch *ep;
1081 struct fc_frame *fp;
1082 struct fc_frame_header *fh;
1083 struct {
1084 struct fc_els_prli prli;
1085 struct fc_els_spp spp;
1086 } *pp;
1087 struct fc_els_spp *rspp; /* request service param page */
1088 struct fc_els_spp *spp; /* response spp */
1089 unsigned int len;
1090 unsigned int plen;
1091 enum fc_els_rjt_reason reason = ELS_RJT_UNAB;
1092 enum fc_els_rjt_explan explan = ELS_EXPL_NONE;
1093 enum fc_els_spp_resp resp;
1094 struct fc_seq_els_data rjt_data;
1095 u32 f_ctl;
1096 u32 fcp_parm;
1097 u32 roles = FC_RPORT_ROLE_UNKNOWN;
1098 rjt_data.fp = NULL;
1099
1100 fh = fc_frame_header_get(rx_fp);
1101
Robert Love74147052009-06-10 15:31:10 -07001102 FC_RPORT_DBG(rport, "Received PRLI request while in state %s\n",
1103 fc_rport_state(rport));
Robert Love42e9a922008-12-09 15:10:17 -08001104
1105 switch (rdata->rp_state) {
1106 case RPORT_ST_PRLI:
1107 case RPORT_ST_READY:
1108 reason = ELS_RJT_NONE;
1109 break;
1110 default:
Abhijeet Joglekarb4c6f542009-04-21 16:27:04 -07001111 fc_frame_free(rx_fp);
1112 return;
Robert Love42e9a922008-12-09 15:10:17 -08001113 break;
1114 }
1115 len = fr_len(rx_fp) - sizeof(*fh);
1116 pp = fc_frame_payload_get(rx_fp, sizeof(*pp));
1117 if (pp == NULL) {
1118 reason = ELS_RJT_PROT;
1119 explan = ELS_EXPL_INV_LEN;
1120 } else {
1121 plen = ntohs(pp->prli.prli_len);
1122 if ((plen % 4) != 0 || plen > len) {
1123 reason = ELS_RJT_PROT;
1124 explan = ELS_EXPL_INV_LEN;
1125 } else if (plen < len) {
1126 len = plen;
1127 }
1128 plen = pp->prli.prli_spp_len;
1129 if ((plen % 4) != 0 || plen < sizeof(*spp) ||
1130 plen > len || len < sizeof(*pp)) {
1131 reason = ELS_RJT_PROT;
1132 explan = ELS_EXPL_INV_LEN;
1133 }
1134 rspp = &pp->spp;
1135 }
1136 if (reason != ELS_RJT_NONE ||
1137 (fp = fc_frame_alloc(lport, len)) == NULL) {
1138 rjt_data.reason = reason;
1139 rjt_data.explan = explan;
1140 lport->tt.seq_els_rsp_send(sp, ELS_LS_RJT, &rjt_data);
1141 } else {
1142 sp = lport->tt.seq_start_next(sp);
1143 WARN_ON(!sp);
1144 pp = fc_frame_payload_get(fp, len);
1145 WARN_ON(!pp);
1146 memset(pp, 0, len);
1147 pp->prli.prli_cmd = ELS_LS_ACC;
1148 pp->prli.prli_spp_len = plen;
1149 pp->prli.prli_len = htons(len);
1150 len -= sizeof(struct fc_els_prli);
1151
1152 /*
1153 * Go through all the service parameter pages and build
1154 * response. If plen indicates longer SPP than standard,
1155 * use that. The entire response has been pre-cleared above.
1156 */
1157 spp = &pp->spp;
1158 while (len >= plen) {
1159 spp->spp_type = rspp->spp_type;
1160 spp->spp_type_ext = rspp->spp_type_ext;
1161 spp->spp_flags = rspp->spp_flags & FC_SPP_EST_IMG_PAIR;
1162 resp = FC_SPP_RESP_ACK;
1163 if (rspp->spp_flags & FC_SPP_RPA_VAL)
1164 resp = FC_SPP_RESP_NO_PA;
1165 switch (rspp->spp_type) {
1166 case 0: /* common to all FC-4 types */
1167 break;
1168 case FC_TYPE_FCP:
1169 fcp_parm = ntohl(rspp->spp_params);
1170 if (fcp_parm * FCP_SPPF_RETRY)
1171 rdata->flags |= FC_RP_FLAGS_RETRY;
1172 rport->supported_classes = FC_COS_CLASS3;
1173 if (fcp_parm & FCP_SPPF_INIT_FCN)
1174 roles |= FC_RPORT_ROLE_FCP_INITIATOR;
1175 if (fcp_parm & FCP_SPPF_TARG_FCN)
1176 roles |= FC_RPORT_ROLE_FCP_TARGET;
1177 rport->roles = roles;
1178
1179 spp->spp_params =
1180 htonl(lport->service_params);
1181 break;
1182 default:
1183 resp = FC_SPP_RESP_INVL;
1184 break;
1185 }
1186 spp->spp_flags |= resp;
1187 len -= plen;
1188 rspp = (struct fc_els_spp *)((char *)rspp + plen);
1189 spp = (struct fc_els_spp *)((char *)spp + plen);
1190 }
1191
1192 /*
1193 * Send LS_ACC. If this fails, the originator should retry.
1194 */
1195 f_ctl = FC_FC_EX_CTX | FC_FC_LAST_SEQ;
1196 f_ctl |= FC_FC_END_SEQ | FC_FC_SEQ_INIT;
1197 ep = fc_seq_exch(sp);
1198 fc_fill_fc_hdr(fp, FC_RCTL_ELS_REP, ep->did, ep->sid,
1199 FC_TYPE_ELS, f_ctl, 0);
1200 lport->tt.seq_send(lport, sp, fp);
1201
1202 /*
1203 * Get lock and re-check state.
1204 */
1205 switch (rdata->rp_state) {
1206 case RPORT_ST_PRLI:
1207 fc_rport_enter_ready(rport);
1208 break;
1209 case RPORT_ST_READY:
1210 break;
1211 default:
1212 break;
1213 }
1214 }
1215 fc_frame_free(rx_fp);
1216}
1217
1218/**
Robert Love34f42a02009-02-27 10:55:45 -08001219 * fc_rport_recv_prlo_req() - Handle incoming Process Logout (PRLO) request
Robert Love42e9a922008-12-09 15:10:17 -08001220 * @rport: Fibre Channel remote port that initiated PRLO
1221 * @sp: current sequence in the PRLO exchange
1222 * @fp: PRLO request frame
1223 *
1224 * Locking Note: The rport lock is exected to be held before calling
1225 * this function.
1226 */
1227static void fc_rport_recv_prlo_req(struct fc_rport *rport, struct fc_seq *sp,
1228 struct fc_frame *fp)
1229{
1230 struct fc_rport_libfc_priv *rdata = rport->dd_data;
1231 struct fc_lport *lport = rdata->local_port;
1232
1233 struct fc_frame_header *fh;
1234 struct fc_seq_els_data rjt_data;
1235
1236 fh = fc_frame_header_get(fp);
1237
Robert Love74147052009-06-10 15:31:10 -07001238 FC_RPORT_DBG(rport, "Received PRLO request while in state %s\n",
1239 fc_rport_state(rport));
Robert Love42e9a922008-12-09 15:10:17 -08001240
Abhijeet Joglekarb4c6f542009-04-21 16:27:04 -07001241 if (rdata->rp_state == RPORT_ST_NONE) {
1242 fc_frame_free(fp);
1243 return;
1244 }
1245
Robert Love42e9a922008-12-09 15:10:17 -08001246 rjt_data.fp = NULL;
1247 rjt_data.reason = ELS_RJT_UNAB;
1248 rjt_data.explan = ELS_EXPL_NONE;
1249 lport->tt.seq_els_rsp_send(sp, ELS_LS_RJT, &rjt_data);
1250 fc_frame_free(fp);
1251}
1252
1253/**
Robert Love34f42a02009-02-27 10:55:45 -08001254 * fc_rport_recv_logo_req() - Handle incoming Logout (LOGO) request
Robert Love42e9a922008-12-09 15:10:17 -08001255 * @rport: Fibre Channel remote port that initiated LOGO
1256 * @sp: current sequence in the LOGO exchange
1257 * @fp: LOGO request frame
1258 *
1259 * Locking Note: The rport lock is exected to be held before calling
1260 * this function.
1261 */
1262static void fc_rport_recv_logo_req(struct fc_rport *rport, struct fc_seq *sp,
1263 struct fc_frame *fp)
1264{
1265 struct fc_frame_header *fh;
1266 struct fc_rport_libfc_priv *rdata = rport->dd_data;
1267 struct fc_lport *lport = rdata->local_port;
1268
1269 fh = fc_frame_header_get(fp);
1270
Robert Love74147052009-06-10 15:31:10 -07001271 FC_RPORT_DBG(rport, "Received LOGO request while in state %s\n",
1272 fc_rport_state(rport));
Robert Love42e9a922008-12-09 15:10:17 -08001273
Abhijeet Joglekarb4c6f542009-04-21 16:27:04 -07001274 if (rdata->rp_state == RPORT_ST_NONE) {
1275 fc_frame_free(fp);
1276 return;
1277 }
1278
Robert Love42e9a922008-12-09 15:10:17 -08001279 rdata->event = RPORT_EV_LOGO;
Abhijeet Joglekar55c7a602009-04-21 16:27:19 -07001280 fc_rport_state_enter(rport, RPORT_ST_NONE);
Robert Love42e9a922008-12-09 15:10:17 -08001281 queue_work(rport_event_queue, &rdata->event_work);
1282
1283 lport->tt.seq_els_rsp_send(sp, ELS_LS_ACC, NULL);
1284 fc_frame_free(fp);
1285}
1286
1287static void fc_rport_flush_queue(void)
1288{
1289 flush_workqueue(rport_event_queue);
1290}
1291
Robert Love42e9a922008-12-09 15:10:17 -08001292int fc_rport_init(struct fc_lport *lport)
1293{
Robert Love5101ff92009-02-27 10:55:18 -08001294 if (!lport->tt.rport_create)
1295 lport->tt.rport_create = fc_rport_rogue_create;
1296
Robert Love42e9a922008-12-09 15:10:17 -08001297 if (!lport->tt.rport_login)
1298 lport->tt.rport_login = fc_rport_login;
1299
1300 if (!lport->tt.rport_logoff)
1301 lport->tt.rport_logoff = fc_rport_logoff;
1302
1303 if (!lport->tt.rport_recv_req)
1304 lport->tt.rport_recv_req = fc_rport_recv_req;
1305
1306 if (!lport->tt.rport_flush_queue)
1307 lport->tt.rport_flush_queue = fc_rport_flush_queue;
1308
1309 return 0;
1310}
1311EXPORT_SYMBOL(fc_rport_init);
1312
Randy Dunlapb0d428a2009-04-27 21:49:31 -07001313int fc_setup_rport(void)
Robert Love42e9a922008-12-09 15:10:17 -08001314{
1315 rport_event_queue = create_singlethread_workqueue("fc_rport_eq");
1316 if (!rport_event_queue)
1317 return -ENOMEM;
1318 return 0;
1319}
1320EXPORT_SYMBOL(fc_setup_rport);
1321
Randy Dunlapb0d428a2009-04-27 21:49:31 -07001322void fc_destroy_rport(void)
Robert Love42e9a922008-12-09 15:10:17 -08001323{
1324 destroy_workqueue(rport_event_queue);
1325}
1326EXPORT_SYMBOL(fc_destroy_rport);
1327
1328void fc_rport_terminate_io(struct fc_rport *rport)
1329{
1330 struct fc_rport_libfc_priv *rdata = rport->dd_data;
1331 struct fc_lport *lport = rdata->local_port;
1332
Abhijeet Joglekar1f6ff362009-02-27 10:54:35 -08001333 lport->tt.exch_mgr_reset(lport, 0, rport->port_id);
1334 lport->tt.exch_mgr_reset(lport, rport->port_id, 0);
Robert Love42e9a922008-12-09 15:10:17 -08001335}
1336EXPORT_SYMBOL(fc_rport_terminate_io);