0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023 #include <linux/timer.h>
0024 #include <linux/slab.h>
0025 #include <linux/err.h>
0026 #include <linux/export.h>
0027 #include <linux/rculist.h>
0028
0029 #include <asm/unaligned.h>
0030
0031 #include <scsi/fc/fc_gs.h>
0032
0033 #include <scsi/libfc.h>
0034
0035 #include "fc_libfc.h"
0036
0037 #define FC_DISC_RETRY_LIMIT 3
0038 #define FC_DISC_RETRY_DELAY 500UL
0039
0040 static void fc_disc_gpn_ft_req(struct fc_disc *);
0041 static void fc_disc_gpn_ft_resp(struct fc_seq *, struct fc_frame *, void *);
0042 static void fc_disc_done(struct fc_disc *, enum fc_disc_event);
0043 static void fc_disc_timeout(struct work_struct *);
0044 static int fc_disc_single(struct fc_lport *, struct fc_disc_port *);
0045 static void fc_disc_restart(struct fc_disc *);
0046
0047
0048
0049
0050
0051 static void fc_disc_stop_rports(struct fc_disc *disc)
0052 {
0053 struct fc_rport_priv *rdata;
0054
0055 lockdep_assert_held(&disc->disc_mutex);
0056
0057 list_for_each_entry(rdata, &disc->rports, peers) {
0058 if (kref_get_unless_zero(&rdata->kref)) {
0059 fc_rport_logoff(rdata);
0060 kref_put(&rdata->kref, fc_rport_destroy);
0061 }
0062 }
0063 }
0064
0065
0066
0067
0068
0069
0070 static void fc_disc_recv_rscn_req(struct fc_disc *disc, struct fc_frame *fp)
0071 {
0072 struct fc_lport *lport;
0073 struct fc_els_rscn *rp;
0074 struct fc_els_rscn_page *pp;
0075 struct fc_seq_els_data rjt_data;
0076 unsigned int len;
0077 int redisc = 0;
0078 enum fc_els_rscn_ev_qual ev_qual;
0079 enum fc_els_rscn_addr_fmt fmt;
0080 LIST_HEAD(disc_ports);
0081 struct fc_disc_port *dp, *next;
0082
0083 lockdep_assert_held(&disc->disc_mutex);
0084
0085 lport = fc_disc_lport(disc);
0086
0087 FC_DISC_DBG(disc, "Received an RSCN event\n");
0088
0089
0090 rp = fc_frame_payload_get(fp, sizeof(*rp));
0091 if (!rp)
0092 goto reject;
0093
0094 if (rp->rscn_page_len != sizeof(*pp))
0095 goto reject;
0096
0097 len = ntohs(rp->rscn_plen);
0098 if (len < sizeof(*rp))
0099 goto reject;
0100
0101 rp = fc_frame_payload_get(fp, len);
0102 if (!rp)
0103 goto reject;
0104
0105 len -= sizeof(*rp);
0106 if (len % sizeof(*pp))
0107 goto reject;
0108
0109 for (pp = (void *)(rp + 1); len > 0; len -= sizeof(*pp), pp++) {
0110 ev_qual = pp->rscn_page_flags >> ELS_RSCN_EV_QUAL_BIT;
0111 ev_qual &= ELS_RSCN_EV_QUAL_MASK;
0112 fmt = pp->rscn_page_flags >> ELS_RSCN_ADDR_FMT_BIT;
0113 fmt &= ELS_RSCN_ADDR_FMT_MASK;
0114
0115
0116
0117
0118 switch (fmt) {
0119 case ELS_ADDR_FMT_PORT:
0120 FC_DISC_DBG(disc, "Port address format for port "
0121 "(%6.6x)\n", ntoh24(pp->rscn_fid));
0122 dp = kzalloc(sizeof(*dp), GFP_KERNEL);
0123 if (!dp) {
0124 redisc = 1;
0125 break;
0126 }
0127 dp->lp = lport;
0128 dp->port_id = ntoh24(pp->rscn_fid);
0129 list_add_tail(&dp->peers, &disc_ports);
0130 break;
0131 case ELS_ADDR_FMT_AREA:
0132 case ELS_ADDR_FMT_DOM:
0133 case ELS_ADDR_FMT_FAB:
0134 default:
0135 FC_DISC_DBG(disc, "Address format is (%d)\n", fmt);
0136 redisc = 1;
0137 break;
0138 }
0139 }
0140 fc_seq_els_rsp_send(fp, ELS_LS_ACC, NULL);
0141
0142
0143
0144
0145
0146
0147
0148 list_for_each_entry_safe(dp, next, &disc_ports, peers) {
0149 list_del(&dp->peers);
0150 if (!redisc)
0151 redisc = fc_disc_single(lport, dp);
0152 kfree(dp);
0153 }
0154 if (redisc) {
0155 FC_DISC_DBG(disc, "RSCN received: rediscovering\n");
0156 fc_disc_restart(disc);
0157 } else {
0158 FC_DISC_DBG(disc, "RSCN received: not rediscovering. "
0159 "redisc %d state %d in_prog %d\n",
0160 redisc, lport->state, disc->pending);
0161 }
0162 fc_frame_free(fp);
0163 return;
0164 reject:
0165 FC_DISC_DBG(disc, "Received a bad RSCN frame\n");
0166 rjt_data.reason = ELS_RJT_LOGIC;
0167 rjt_data.explan = ELS_EXPL_NONE;
0168 fc_seq_els_rsp_send(fp, ELS_LS_RJT, &rjt_data);
0169 fc_frame_free(fp);
0170 }
0171
0172
0173
0174
0175
0176
0177
0178
0179
0180
0181 static void fc_disc_recv_req(struct fc_lport *lport, struct fc_frame *fp)
0182 {
0183 u8 op;
0184 struct fc_disc *disc = &lport->disc;
0185
0186 op = fc_frame_payload_op(fp);
0187 switch (op) {
0188 case ELS_RSCN:
0189 mutex_lock(&disc->disc_mutex);
0190 fc_disc_recv_rscn_req(disc, fp);
0191 mutex_unlock(&disc->disc_mutex);
0192 break;
0193 default:
0194 FC_DISC_DBG(disc, "Received an unsupported request, "
0195 "the opcode is (%x)\n", op);
0196 fc_frame_free(fp);
0197 break;
0198 }
0199 }
0200
0201
0202
0203
0204
0205 static void fc_disc_restart(struct fc_disc *disc)
0206 {
0207 lockdep_assert_held(&disc->disc_mutex);
0208
0209 if (!disc->disc_callback)
0210 return;
0211
0212 FC_DISC_DBG(disc, "Restarting discovery\n");
0213
0214 disc->requested = 1;
0215 if (disc->pending)
0216 return;
0217
0218
0219
0220
0221
0222
0223 disc->disc_id = (disc->disc_id + 2) | 1;
0224 disc->retry_count = 0;
0225 fc_disc_gpn_ft_req(disc);
0226 }
0227
0228
0229
0230
0231
0232
0233 static void fc_disc_start(void (*disc_callback)(struct fc_lport *,
0234 enum fc_disc_event),
0235 struct fc_lport *lport)
0236 {
0237 struct fc_disc *disc = &lport->disc;
0238
0239
0240
0241
0242
0243
0244 mutex_lock(&disc->disc_mutex);
0245 disc->disc_callback = disc_callback;
0246 fc_disc_restart(disc);
0247 mutex_unlock(&disc->disc_mutex);
0248 }
0249
0250
0251
0252
0253
0254
0255 static void fc_disc_done(struct fc_disc *disc, enum fc_disc_event event)
0256 {
0257 struct fc_lport *lport = fc_disc_lport(disc);
0258 struct fc_rport_priv *rdata;
0259
0260 lockdep_assert_held(&disc->disc_mutex);
0261 FC_DISC_DBG(disc, "Discovery complete\n");
0262
0263 disc->pending = 0;
0264 if (disc->requested) {
0265 fc_disc_restart(disc);
0266 return;
0267 }
0268
0269
0270
0271
0272
0273
0274
0275
0276
0277
0278 list_for_each_entry(rdata, &disc->rports, peers) {
0279 if (!kref_get_unless_zero(&rdata->kref))
0280 continue;
0281 if (rdata->disc_id) {
0282 if (rdata->disc_id == disc->disc_id)
0283 fc_rport_login(rdata);
0284 else
0285 fc_rport_logoff(rdata);
0286 }
0287 kref_put(&rdata->kref, fc_rport_destroy);
0288 }
0289 mutex_unlock(&disc->disc_mutex);
0290 disc->disc_callback(lport, event);
0291 mutex_lock(&disc->disc_mutex);
0292 }
0293
0294
0295
0296
0297
0298
0299 static void fc_disc_error(struct fc_disc *disc, struct fc_frame *fp)
0300 {
0301 struct fc_lport *lport = fc_disc_lport(disc);
0302 unsigned long delay = 0;
0303
0304 FC_DISC_DBG(disc, "Error %d, retries %d/%d\n",
0305 PTR_ERR_OR_ZERO(fp), disc->retry_count,
0306 FC_DISC_RETRY_LIMIT);
0307
0308 if (!fp || PTR_ERR(fp) == -FC_EX_TIMEOUT) {
0309
0310
0311
0312
0313 if (disc->retry_count < FC_DISC_RETRY_LIMIT) {
0314
0315 if (!fp)
0316 delay = msecs_to_jiffies(FC_DISC_RETRY_DELAY);
0317 else {
0318 delay = msecs_to_jiffies(lport->e_d_tov);
0319
0320
0321 if (!disc->retry_count)
0322 delay /= 4;
0323 }
0324 disc->retry_count++;
0325 schedule_delayed_work(&disc->disc_work, delay);
0326 } else
0327 fc_disc_done(disc, DISC_EV_FAILED);
0328 } else if (PTR_ERR(fp) == -FC_EX_CLOSED) {
0329
0330
0331
0332
0333
0334 disc->pending = 0;
0335 }
0336 }
0337
0338
0339
0340
0341
0342 static void fc_disc_gpn_ft_req(struct fc_disc *disc)
0343 {
0344 struct fc_frame *fp;
0345 struct fc_lport *lport = fc_disc_lport(disc);
0346
0347 lockdep_assert_held(&disc->disc_mutex);
0348
0349 WARN_ON(!fc_lport_test_ready(lport));
0350
0351 disc->pending = 1;
0352 disc->requested = 0;
0353
0354 disc->buf_len = 0;
0355 disc->seq_count = 0;
0356 fp = fc_frame_alloc(lport,
0357 sizeof(struct fc_ct_hdr) +
0358 sizeof(struct fc_ns_gid_ft));
0359 if (!fp)
0360 goto err;
0361
0362 if (lport->tt.elsct_send(lport, 0, fp,
0363 FC_NS_GPN_FT,
0364 fc_disc_gpn_ft_resp,
0365 disc, 3 * lport->r_a_tov))
0366 return;
0367 err:
0368 fc_disc_error(disc, NULL);
0369 }
0370
0371
0372
0373
0374
0375
0376
0377
0378
0379 static int fc_disc_gpn_ft_parse(struct fc_disc *disc, void *buf, size_t len)
0380 {
0381 struct fc_lport *lport;
0382 struct fc_gpn_ft_resp *np;
0383 char *bp;
0384 size_t plen;
0385 size_t tlen;
0386 int error = 0;
0387 struct fc_rport_identifiers ids;
0388 struct fc_rport_priv *rdata;
0389
0390 lport = fc_disc_lport(disc);
0391 disc->seq_count++;
0392
0393
0394
0395
0396 bp = buf;
0397 plen = len;
0398 np = (struct fc_gpn_ft_resp *)bp;
0399 tlen = disc->buf_len;
0400 disc->buf_len = 0;
0401 if (tlen) {
0402 WARN_ON(tlen >= sizeof(*np));
0403 plen = sizeof(*np) - tlen;
0404 WARN_ON(plen <= 0);
0405 WARN_ON(plen >= sizeof(*np));
0406 if (plen > len)
0407 plen = len;
0408 np = &disc->partial_buf;
0409 memcpy((char *)np + tlen, bp, plen);
0410
0411
0412
0413
0414
0415 bp -= tlen;
0416 len += tlen;
0417 plen += tlen;
0418 disc->buf_len = (unsigned char) plen;
0419 if (plen == sizeof(*np))
0420 disc->buf_len = 0;
0421 }
0422
0423
0424
0425
0426
0427
0428
0429
0430 while (plen >= sizeof(*np)) {
0431 ids.port_id = ntoh24(np->fp_fid);
0432 ids.port_name = ntohll(np->fp_wwpn);
0433
0434 if (ids.port_id != lport->port_id &&
0435 ids.port_name != lport->wwpn) {
0436 rdata = fc_rport_create(lport, ids.port_id);
0437 if (rdata) {
0438 rdata->ids.port_name = ids.port_name;
0439 rdata->disc_id = disc->disc_id;
0440 } else {
0441 printk(KERN_WARNING "libfc: Failed to allocate "
0442 "memory for the newly discovered port "
0443 "(%6.6x)\n", ids.port_id);
0444 error = -ENOMEM;
0445 }
0446 }
0447
0448 if (np->fp_flags & FC_NS_FID_LAST) {
0449 fc_disc_done(disc, DISC_EV_SUCCESS);
0450 len = 0;
0451 break;
0452 }
0453 len -= sizeof(*np);
0454 bp += sizeof(*np);
0455 np = (struct fc_gpn_ft_resp *)bp;
0456 plen = len;
0457 }
0458
0459
0460
0461
0462 if (error == 0 && len > 0 && len < sizeof(*np)) {
0463 if (np != &disc->partial_buf) {
0464 FC_DISC_DBG(disc, "Partial buffer remains "
0465 "for discovery\n");
0466 memcpy(&disc->partial_buf, np, len);
0467 }
0468 disc->buf_len = (unsigned char) len;
0469 }
0470 return error;
0471 }
0472
0473
0474
0475
0476
0477 static void fc_disc_timeout(struct work_struct *work)
0478 {
0479 struct fc_disc *disc = container_of(work,
0480 struct fc_disc,
0481 disc_work.work);
0482 mutex_lock(&disc->disc_mutex);
0483 fc_disc_gpn_ft_req(disc);
0484 mutex_unlock(&disc->disc_mutex);
0485 }
0486
0487
0488
0489
0490
0491
0492
0493
0494
0495
0496 static void fc_disc_gpn_ft_resp(struct fc_seq *sp, struct fc_frame *fp,
0497 void *disc_arg)
0498 {
0499 struct fc_disc *disc = disc_arg;
0500 struct fc_ct_hdr *cp;
0501 struct fc_frame_header *fh;
0502 enum fc_disc_event event = DISC_EV_NONE;
0503 unsigned int seq_cnt;
0504 unsigned int len;
0505 int error = 0;
0506
0507 mutex_lock(&disc->disc_mutex);
0508 FC_DISC_DBG(disc, "Received a GPN_FT response\n");
0509
0510 if (IS_ERR(fp)) {
0511 fc_disc_error(disc, fp);
0512 mutex_unlock(&disc->disc_mutex);
0513 return;
0514 }
0515
0516 WARN_ON(!fc_frame_is_linear(fp));
0517 fh = fc_frame_header_get(fp);
0518 len = fr_len(fp) - sizeof(*fh);
0519 seq_cnt = ntohs(fh->fh_seq_cnt);
0520 if (fr_sof(fp) == FC_SOF_I3 && seq_cnt == 0 && disc->seq_count == 0) {
0521 cp = fc_frame_payload_get(fp, sizeof(*cp));
0522 if (!cp) {
0523 FC_DISC_DBG(disc, "GPN_FT response too short, len %d\n",
0524 fr_len(fp));
0525 event = DISC_EV_FAILED;
0526 } else if (ntohs(cp->ct_cmd) == FC_FS_ACC) {
0527
0528
0529 len -= sizeof(*cp);
0530 error = fc_disc_gpn_ft_parse(disc, cp + 1, len);
0531 } else if (ntohs(cp->ct_cmd) == FC_FS_RJT) {
0532 FC_DISC_DBG(disc, "GPN_FT rejected reason %x exp %x "
0533 "(check zoning)\n", cp->ct_reason,
0534 cp->ct_explan);
0535 event = DISC_EV_FAILED;
0536 if (cp->ct_reason == FC_FS_RJT_UNABL &&
0537 cp->ct_explan == FC_FS_EXP_FTNR)
0538 event = DISC_EV_SUCCESS;
0539 } else {
0540 FC_DISC_DBG(disc, "GPN_FT unexpected response code "
0541 "%x\n", ntohs(cp->ct_cmd));
0542 event = DISC_EV_FAILED;
0543 }
0544 } else if (fr_sof(fp) == FC_SOF_N3 && seq_cnt == disc->seq_count) {
0545 error = fc_disc_gpn_ft_parse(disc, fh + 1, len);
0546 } else {
0547 FC_DISC_DBG(disc, "GPN_FT unexpected frame - out of sequence? "
0548 "seq_cnt %x expected %x sof %x eof %x\n",
0549 seq_cnt, disc->seq_count, fr_sof(fp), fr_eof(fp));
0550 event = DISC_EV_FAILED;
0551 }
0552 if (error)
0553 fc_disc_error(disc, ERR_PTR(error));
0554 else if (event != DISC_EV_NONE)
0555 fc_disc_done(disc, event);
0556 fc_frame_free(fp);
0557 mutex_unlock(&disc->disc_mutex);
0558 }
0559
0560
0561
0562
0563
0564
0565
0566
0567
0568 static void fc_disc_gpn_id_resp(struct fc_seq *sp, struct fc_frame *fp,
0569 void *rdata_arg)
0570 {
0571 struct fc_rport_priv *rdata = rdata_arg;
0572 struct fc_rport_priv *new_rdata;
0573 struct fc_lport *lport;
0574 struct fc_disc *disc;
0575 struct fc_ct_hdr *cp;
0576 struct fc_ns_gid_pn *pn;
0577 u64 port_name;
0578
0579 lport = rdata->local_port;
0580 disc = &lport->disc;
0581
0582 if (PTR_ERR(fp) == -FC_EX_CLOSED)
0583 goto out;
0584 if (IS_ERR(fp)) {
0585 mutex_lock(&disc->disc_mutex);
0586 fc_disc_restart(disc);
0587 mutex_unlock(&disc->disc_mutex);
0588 goto out;
0589 }
0590
0591 cp = fc_frame_payload_get(fp, sizeof(*cp));
0592 if (!cp)
0593 goto redisc;
0594 if (ntohs(cp->ct_cmd) == FC_FS_ACC) {
0595 if (fr_len(fp) < sizeof(struct fc_frame_header) +
0596 sizeof(*cp) + sizeof(*pn))
0597 goto redisc;
0598 pn = (struct fc_ns_gid_pn *)(cp + 1);
0599 port_name = get_unaligned_be64(&pn->fn_wwpn);
0600 mutex_lock(&rdata->rp_mutex);
0601 if (rdata->ids.port_name == -1)
0602 rdata->ids.port_name = port_name;
0603 else if (rdata->ids.port_name != port_name) {
0604 FC_DISC_DBG(disc, "GPN_ID accepted. WWPN changed. "
0605 "Port-id %6.6x wwpn %16.16llx\n",
0606 rdata->ids.port_id, port_name);
0607 mutex_unlock(&rdata->rp_mutex);
0608 fc_rport_logoff(rdata);
0609 mutex_lock(&lport->disc.disc_mutex);
0610 new_rdata = fc_rport_create(lport, rdata->ids.port_id);
0611 mutex_unlock(&lport->disc.disc_mutex);
0612 if (new_rdata) {
0613 new_rdata->disc_id = disc->disc_id;
0614 fc_rport_login(new_rdata);
0615 }
0616 goto free_fp;
0617 }
0618 rdata->disc_id = disc->disc_id;
0619 mutex_unlock(&rdata->rp_mutex);
0620 fc_rport_login(rdata);
0621 } else if (ntohs(cp->ct_cmd) == FC_FS_RJT) {
0622 FC_DISC_DBG(disc, "GPN_ID rejected reason %x exp %x\n",
0623 cp->ct_reason, cp->ct_explan);
0624 fc_rport_logoff(rdata);
0625 } else {
0626 FC_DISC_DBG(disc, "GPN_ID unexpected response code %x\n",
0627 ntohs(cp->ct_cmd));
0628 redisc:
0629 mutex_lock(&disc->disc_mutex);
0630 fc_disc_restart(disc);
0631 mutex_unlock(&disc->disc_mutex);
0632 }
0633 free_fp:
0634 fc_frame_free(fp);
0635 out:
0636 kref_put(&rdata->kref, fc_rport_destroy);
0637 }
0638
0639
0640
0641
0642
0643
0644
0645
0646 static int fc_disc_gpn_id_req(struct fc_lport *lport,
0647 struct fc_rport_priv *rdata)
0648 {
0649 struct fc_frame *fp;
0650
0651 lockdep_assert_held(&lport->disc.disc_mutex);
0652 fp = fc_frame_alloc(lport, sizeof(struct fc_ct_hdr) +
0653 sizeof(struct fc_ns_fid));
0654 if (!fp)
0655 return -ENOMEM;
0656 if (!lport->tt.elsct_send(lport, rdata->ids.port_id, fp, FC_NS_GPN_ID,
0657 fc_disc_gpn_id_resp, rdata,
0658 3 * lport->r_a_tov))
0659 return -ENOMEM;
0660 kref_get(&rdata->kref);
0661 return 0;
0662 }
0663
0664
0665
0666
0667
0668
0669 static int fc_disc_single(struct fc_lport *lport, struct fc_disc_port *dp)
0670 {
0671 struct fc_rport_priv *rdata;
0672
0673 lockdep_assert_held(&lport->disc.disc_mutex);
0674
0675 rdata = fc_rport_create(lport, dp->port_id);
0676 if (!rdata)
0677 return -ENOMEM;
0678 rdata->disc_id = 0;
0679 return fc_disc_gpn_id_req(lport, rdata);
0680 }
0681
0682
0683
0684
0685
0686 static void fc_disc_stop(struct fc_lport *lport)
0687 {
0688 struct fc_disc *disc = &lport->disc;
0689
0690 if (disc->pending)
0691 cancel_delayed_work_sync(&disc->disc_work);
0692 mutex_lock(&disc->disc_mutex);
0693 fc_disc_stop_rports(disc);
0694 mutex_unlock(&disc->disc_mutex);
0695 }
0696
0697
0698
0699
0700
0701
0702
0703
0704 static void fc_disc_stop_final(struct fc_lport *lport)
0705 {
0706 fc_disc_stop(lport);
0707 fc_rport_flush_queue();
0708 }
0709
0710
0711
0712
0713
0714
0715 void fc_disc_config(struct fc_lport *lport, void *priv)
0716 {
0717 struct fc_disc *disc;
0718
0719 if (!lport->tt.disc_start)
0720 lport->tt.disc_start = fc_disc_start;
0721
0722 if (!lport->tt.disc_stop)
0723 lport->tt.disc_stop = fc_disc_stop;
0724
0725 if (!lport->tt.disc_stop_final)
0726 lport->tt.disc_stop_final = fc_disc_stop_final;
0727
0728 if (!lport->tt.disc_recv_req)
0729 lport->tt.disc_recv_req = fc_disc_recv_req;
0730
0731 disc = &lport->disc;
0732
0733 disc->priv = priv;
0734 }
0735 EXPORT_SYMBOL(fc_disc_config);
0736
0737
0738
0739
0740
0741 void fc_disc_init(struct fc_lport *lport)
0742 {
0743 struct fc_disc *disc = &lport->disc;
0744
0745 INIT_DELAYED_WORK(&disc->disc_work, fc_disc_timeout);
0746 mutex_init(&disc->disc_mutex);
0747 INIT_LIST_HEAD(&disc->rports);
0748 }
0749 EXPORT_SYMBOL(fc_disc_init);