root/drivers/scsi/libfc/fc_disc.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. fc_disc_stop_rports
  2. fc_disc_recv_rscn_req
  3. fc_disc_recv_req
  4. fc_disc_restart
  5. fc_disc_start
  6. fc_disc_done
  7. fc_disc_error
  8. fc_disc_gpn_ft_req
  9. fc_disc_gpn_ft_parse
  10. fc_disc_timeout
  11. fc_disc_gpn_ft_resp
  12. fc_disc_gpn_id_resp
  13. fc_disc_gpn_id_req
  14. fc_disc_single
  15. fc_disc_stop
  16. fc_disc_stop_final
  17. fc_disc_config
  18. fc_disc_init

   1 // SPDX-License-Identifier: GPL-2.0-only
   2 /*
   3  * Copyright(c) 2007 - 2008 Intel Corporation. All rights reserved.
   4  *
   5  * Maintained at www.Open-FCoE.org
   6  */
   7 
   8 /*
   9  * Target Discovery
  10  *
  11  * This block discovers all FC-4 remote ports, including FCP initiators. It
  12  * also handles RSCN events and re-discovery if necessary.
  13  */
  14 
  15 /*
  16  * DISC LOCKING
  17  *
  18  * The disc mutex is can be locked when acquiring rport locks, but may not
  19  * be held when acquiring the lport lock. Refer to fc_lport.c for more
  20  * details.
  21  */
  22 
  23 #include <linux/timer.h>
  24 #include <linux/slab.h>
  25 #include <linux/err.h>
  26 #include <linux/export.h>
  27 #include <linux/rculist.h>
  28 
  29 #include <asm/unaligned.h>
  30 
  31 #include <scsi/fc/fc_gs.h>
  32 
  33 #include <scsi/libfc.h>
  34 
  35 #include "fc_libfc.h"
  36 
  37 #define FC_DISC_RETRY_LIMIT     3       /* max retries */
  38 #define FC_DISC_RETRY_DELAY     500UL   /* (msecs) delay */
  39 
  40 static void fc_disc_gpn_ft_req(struct fc_disc *);
  41 static void fc_disc_gpn_ft_resp(struct fc_seq *, struct fc_frame *, void *);
  42 static void fc_disc_done(struct fc_disc *, enum fc_disc_event);
  43 static void fc_disc_timeout(struct work_struct *);
  44 static int fc_disc_single(struct fc_lport *, struct fc_disc_port *);
  45 static void fc_disc_restart(struct fc_disc *);
  46 
  47 /**
  48  * fc_disc_stop_rports() - Delete all the remote ports associated with the lport
  49  * @disc: The discovery job to stop remote ports on
  50  */
  51 static void fc_disc_stop_rports(struct fc_disc *disc)
  52 {
  53         struct fc_rport_priv *rdata;
  54 
  55         lockdep_assert_held(&disc->disc_mutex);
  56 
  57         list_for_each_entry(rdata, &disc->rports, peers) {
  58                 if (kref_get_unless_zero(&rdata->kref)) {
  59                         fc_rport_logoff(rdata);
  60                         kref_put(&rdata->kref, fc_rport_destroy);
  61                 }
  62         }
  63 }
  64 
  65 /**
  66  * fc_disc_recv_rscn_req() - Handle Registered State Change Notification (RSCN)
  67  * @disc:  The discovery object to which the RSCN applies
  68  * @fp:    The RSCN frame
  69  */
  70 static void fc_disc_recv_rscn_req(struct fc_disc *disc, struct fc_frame *fp)
  71 {
  72         struct fc_lport *lport;
  73         struct fc_els_rscn *rp;
  74         struct fc_els_rscn_page *pp;
  75         struct fc_seq_els_data rjt_data;
  76         unsigned int len;
  77         int redisc = 0;
  78         enum fc_els_rscn_ev_qual ev_qual;
  79         enum fc_els_rscn_addr_fmt fmt;
  80         LIST_HEAD(disc_ports);
  81         struct fc_disc_port *dp, *next;
  82 
  83         lockdep_assert_held(&disc->disc_mutex);
  84 
  85         lport = fc_disc_lport(disc);
  86 
  87         FC_DISC_DBG(disc, "Received an RSCN event\n");
  88 
  89         /* make sure the frame contains an RSCN message */
  90         rp = fc_frame_payload_get(fp, sizeof(*rp));
  91         if (!rp)
  92                 goto reject;
  93         /* make sure the page length is as expected (4 bytes) */
  94         if (rp->rscn_page_len != sizeof(*pp))
  95                 goto reject;
  96         /* get the RSCN payload length */
  97         len = ntohs(rp->rscn_plen);
  98         if (len < sizeof(*rp))
  99                 goto reject;
 100         /* make sure the frame contains the expected payload */
 101         rp = fc_frame_payload_get(fp, len);
 102         if (!rp)
 103                 goto reject;
 104         /* payload must be a multiple of the RSCN page size */
 105         len -= sizeof(*rp);
 106         if (len % sizeof(*pp))
 107                 goto reject;
 108 
 109         for (pp = (void *)(rp + 1); len > 0; len -= sizeof(*pp), pp++) {
 110                 ev_qual = pp->rscn_page_flags >> ELS_RSCN_EV_QUAL_BIT;
 111                 ev_qual &= ELS_RSCN_EV_QUAL_MASK;
 112                 fmt = pp->rscn_page_flags >> ELS_RSCN_ADDR_FMT_BIT;
 113                 fmt &= ELS_RSCN_ADDR_FMT_MASK;
 114                 /*
 115                  * if we get an address format other than port
 116                  * (area, domain, fabric), then do a full discovery
 117                  */
 118                 switch (fmt) {
 119                 case ELS_ADDR_FMT_PORT:
 120                         FC_DISC_DBG(disc, "Port address format for port "
 121                                     "(%6.6x)\n", ntoh24(pp->rscn_fid));
 122                         dp = kzalloc(sizeof(*dp), GFP_KERNEL);
 123                         if (!dp) {
 124                                 redisc = 1;
 125                                 break;
 126                         }
 127                         dp->lp = lport;
 128                         dp->port_id = ntoh24(pp->rscn_fid);
 129                         list_add_tail(&dp->peers, &disc_ports);
 130                         break;
 131                 case ELS_ADDR_FMT_AREA:
 132                 case ELS_ADDR_FMT_DOM:
 133                 case ELS_ADDR_FMT_FAB:
 134                 default:
 135                         FC_DISC_DBG(disc, "Address format is (%d)\n", fmt);
 136                         redisc = 1;
 137                         break;
 138                 }
 139         }
 140         fc_seq_els_rsp_send(fp, ELS_LS_ACC, NULL);
 141 
 142         /*
 143          * If not doing a complete rediscovery, do GPN_ID on
 144          * the individual ports mentioned in the list.
 145          * If any of these get an error, do a full rediscovery.
 146          * In any case, go through the list and free the entries.
 147          */
 148         list_for_each_entry_safe(dp, next, &disc_ports, peers) {
 149                 list_del(&dp->peers);
 150                 if (!redisc)
 151                         redisc = fc_disc_single(lport, dp);
 152                 kfree(dp);
 153         }
 154         if (redisc) {
 155                 FC_DISC_DBG(disc, "RSCN received: rediscovering\n");
 156                 fc_disc_restart(disc);
 157         } else {
 158                 FC_DISC_DBG(disc, "RSCN received: not rediscovering. "
 159                             "redisc %d state %d in_prog %d\n",
 160                             redisc, lport->state, disc->pending);
 161         }
 162         fc_frame_free(fp);
 163         return;
 164 reject:
 165         FC_DISC_DBG(disc, "Received a bad RSCN frame\n");
 166         rjt_data.reason = ELS_RJT_LOGIC;
 167         rjt_data.explan = ELS_EXPL_NONE;
 168         fc_seq_els_rsp_send(fp, ELS_LS_RJT, &rjt_data);
 169         fc_frame_free(fp);
 170 }
 171 
 172 /**
 173  * fc_disc_recv_req() - Handle incoming requests
 174  * @lport: The local port receiving the request
 175  * @fp:    The request frame
 176  *
 177  * Locking Note: This function is called from the EM and will lock
 178  *               the disc_mutex before calling the handler for the
 179  *               request.
 180  */
 181 static void fc_disc_recv_req(struct fc_lport *lport, struct fc_frame *fp)
 182 {
 183         u8 op;
 184         struct fc_disc *disc = &lport->disc;
 185 
 186         op = fc_frame_payload_op(fp);
 187         switch (op) {
 188         case ELS_RSCN:
 189                 mutex_lock(&disc->disc_mutex);
 190                 fc_disc_recv_rscn_req(disc, fp);
 191                 mutex_unlock(&disc->disc_mutex);
 192                 break;
 193         default:
 194                 FC_DISC_DBG(disc, "Received an unsupported request, "
 195                             "the opcode is (%x)\n", op);
 196                 fc_frame_free(fp);
 197                 break;
 198         }
 199 }
 200 
 201 /**
 202  * fc_disc_restart() - Restart discovery
 203  * @disc: The discovery object to be restarted
 204  */
 205 static void fc_disc_restart(struct fc_disc *disc)
 206 {
 207         lockdep_assert_held(&disc->disc_mutex);
 208 
 209         if (!disc->disc_callback)
 210                 return;
 211 
 212         FC_DISC_DBG(disc, "Restarting discovery\n");
 213 
 214         disc->requested = 1;
 215         if (disc->pending)
 216                 return;
 217 
 218         /*
 219          * Advance disc_id.  This is an arbitrary non-zero number that will
 220          * match the value in the fc_rport_priv after discovery for all
 221          * freshly-discovered remote ports.  Avoid wrapping to zero.
 222          */
 223         disc->disc_id = (disc->disc_id + 2) | 1;
 224         disc->retry_count = 0;
 225         fc_disc_gpn_ft_req(disc);
 226 }
 227 
 228 /**
 229  * fc_disc_start() - Start discovery on a local port
 230  * @lport:         The local port to have discovery started on
 231  * @disc_callback: Callback function to be called when discovery is complete
 232  */
 233 static void fc_disc_start(void (*disc_callback)(struct fc_lport *,
 234                                                 enum fc_disc_event),
 235                           struct fc_lport *lport)
 236 {
 237         struct fc_disc *disc = &lport->disc;
 238 
 239         /*
 240          * At this point we may have a new disc job or an existing
 241          * one. Either way, let's lock when we make changes to it
 242          * and send the GPN_FT request.
 243          */
 244         mutex_lock(&disc->disc_mutex);
 245         disc->disc_callback = disc_callback;
 246         fc_disc_restart(disc);
 247         mutex_unlock(&disc->disc_mutex);
 248 }
 249 
 250 /**
 251  * fc_disc_done() - Discovery has been completed
 252  * @disc:  The discovery context
 253  * @event: The discovery completion status
 254  */
 255 static void fc_disc_done(struct fc_disc *disc, enum fc_disc_event event)
 256 {
 257         struct fc_lport *lport = fc_disc_lport(disc);
 258         struct fc_rport_priv *rdata;
 259 
 260         lockdep_assert_held(&disc->disc_mutex);
 261         FC_DISC_DBG(disc, "Discovery complete\n");
 262 
 263         disc->pending = 0;
 264         if (disc->requested) {
 265                 fc_disc_restart(disc);
 266                 return;
 267         }
 268 
 269         /*
 270          * Go through all remote ports.  If they were found in the latest
 271          * discovery, reverify or log them in.  Otherwise, log them out.
 272          * Skip ports which were never discovered.  These are the dNS port
 273          * and ports which were created by PLOGI.
 274          *
 275          * We don't need to use the _rcu variant here as the rport list
 276          * is protected by the disc mutex which is already held on entry.
 277          */
 278         list_for_each_entry(rdata, &disc->rports, peers) {
 279                 if (!kref_get_unless_zero(&rdata->kref))
 280                         continue;
 281                 if (rdata->disc_id) {
 282                         if (rdata->disc_id == disc->disc_id)
 283                                 fc_rport_login(rdata);
 284                         else
 285                                 fc_rport_logoff(rdata);
 286                 }
 287                 kref_put(&rdata->kref, fc_rport_destroy);
 288         }
 289         mutex_unlock(&disc->disc_mutex);
 290         disc->disc_callback(lport, event);
 291         mutex_lock(&disc->disc_mutex);
 292 }
 293 
 294 /**
 295  * fc_disc_error() - Handle error on dNS request
 296  * @disc: The discovery context
 297  * @fp:   The error code encoded as a frame pointer
 298  */
 299 static void fc_disc_error(struct fc_disc *disc, struct fc_frame *fp)
 300 {
 301         struct fc_lport *lport = fc_disc_lport(disc);
 302         unsigned long delay = 0;
 303 
 304         FC_DISC_DBG(disc, "Error %ld, retries %d/%d\n",
 305                     PTR_ERR(fp), disc->retry_count,
 306                     FC_DISC_RETRY_LIMIT);
 307 
 308         if (!fp || PTR_ERR(fp) == -FC_EX_TIMEOUT) {
 309                 /*
 310                  * Memory allocation failure, or the exchange timed out,
 311                  * retry after delay.
 312                  */
 313                 if (disc->retry_count < FC_DISC_RETRY_LIMIT) {
 314                         /* go ahead and retry */
 315                         if (!fp)
 316                                 delay = msecs_to_jiffies(FC_DISC_RETRY_DELAY);
 317                         else {
 318                                 delay = msecs_to_jiffies(lport->e_d_tov);
 319 
 320                                 /* timeout faster first time */
 321                                 if (!disc->retry_count)
 322                                         delay /= 4;
 323                         }
 324                         disc->retry_count++;
 325                         schedule_delayed_work(&disc->disc_work, delay);
 326                 } else
 327                         fc_disc_done(disc, DISC_EV_FAILED);
 328         } else if (PTR_ERR(fp) == -FC_EX_CLOSED) {
 329                 /*
 330                  * if discovery fails due to lport reset, clear
 331                  * pending flag so that subsequent discovery can
 332                  * continue
 333                  */
 334                 disc->pending = 0;
 335         }
 336 }
 337 
 338 /**
 339  * fc_disc_gpn_ft_req() - Send Get Port Names by FC-4 type (GPN_FT) request
 340  * @lport: The discovery context
 341  */
 342 static void fc_disc_gpn_ft_req(struct fc_disc *disc)
 343 {
 344         struct fc_frame *fp;
 345         struct fc_lport *lport = fc_disc_lport(disc);
 346 
 347         lockdep_assert_held(&disc->disc_mutex);
 348 
 349         WARN_ON(!fc_lport_test_ready(lport));
 350 
 351         disc->pending = 1;
 352         disc->requested = 0;
 353 
 354         disc->buf_len = 0;
 355         disc->seq_count = 0;
 356         fp = fc_frame_alloc(lport,
 357                             sizeof(struct fc_ct_hdr) +
 358                             sizeof(struct fc_ns_gid_ft));
 359         if (!fp)
 360                 goto err;
 361 
 362         if (lport->tt.elsct_send(lport, 0, fp,
 363                                  FC_NS_GPN_FT,
 364                                  fc_disc_gpn_ft_resp,
 365                                  disc, 3 * lport->r_a_tov))
 366                 return;
 367 err:
 368         fc_disc_error(disc, NULL);
 369 }
 370 
 371 /**
 372  * fc_disc_gpn_ft_parse() - Parse the body of the dNS GPN_FT response.
 373  * @lport: The local port the GPN_FT was received on
 374  * @buf:   The GPN_FT response buffer
 375  * @len:   The size of response buffer
 376  *
 377  * Goes through the list of IDs and names resulting from a request.
 378  */
 379 static int fc_disc_gpn_ft_parse(struct fc_disc *disc, void *buf, size_t len)
 380 {
 381         struct fc_lport *lport;
 382         struct fc_gpn_ft_resp *np;
 383         char *bp;
 384         size_t plen;
 385         size_t tlen;
 386         int error = 0;
 387         struct fc_rport_identifiers ids;
 388         struct fc_rport_priv *rdata;
 389 
 390         lport = fc_disc_lport(disc);
 391         disc->seq_count++;
 392 
 393         /*
 394          * Handle partial name record left over from previous call.
 395          */
 396         bp = buf;
 397         plen = len;
 398         np = (struct fc_gpn_ft_resp *)bp;
 399         tlen = disc->buf_len;
 400         disc->buf_len = 0;
 401         if (tlen) {
 402                 WARN_ON(tlen >= sizeof(*np));
 403                 plen = sizeof(*np) - tlen;
 404                 WARN_ON(plen <= 0);
 405                 WARN_ON(plen >= sizeof(*np));
 406                 if (plen > len)
 407                         plen = len;
 408                 np = &disc->partial_buf;
 409                 memcpy((char *)np + tlen, bp, plen);
 410 
 411                 /*
 412                  * Set bp so that the loop below will advance it to the
 413                  * first valid full name element.
 414                  */
 415                 bp -= tlen;
 416                 len += tlen;
 417                 plen += tlen;
 418                 disc->buf_len = (unsigned char) plen;
 419                 if (plen == sizeof(*np))
 420                         disc->buf_len = 0;
 421         }
 422 
 423         /*
 424          * Handle full name records, including the one filled from above.
 425          * Normally, np == bp and plen == len, but from the partial case above,
 426          * bp, len describe the overall buffer, and np, plen describe the
 427          * partial buffer, which if would usually be full now.
 428          * After the first time through the loop, things return to "normal".
 429          */
 430         while (plen >= sizeof(*np)) {
 431                 ids.port_id = ntoh24(np->fp_fid);
 432                 ids.port_name = ntohll(np->fp_wwpn);
 433 
 434                 if (ids.port_id != lport->port_id &&
 435                     ids.port_name != lport->wwpn) {
 436                         rdata = fc_rport_create(lport, ids.port_id);
 437                         if (rdata) {
 438                                 rdata->ids.port_name = ids.port_name;
 439                                 rdata->disc_id = disc->disc_id;
 440                         } else {
 441                                 printk(KERN_WARNING "libfc: Failed to allocate "
 442                                        "memory for the newly discovered port "
 443                                        "(%6.6x)\n", ids.port_id);
 444                                 error = -ENOMEM;
 445                         }
 446                 }
 447 
 448                 if (np->fp_flags & FC_NS_FID_LAST) {
 449                         fc_disc_done(disc, DISC_EV_SUCCESS);
 450                         len = 0;
 451                         break;
 452                 }
 453                 len -= sizeof(*np);
 454                 bp += sizeof(*np);
 455                 np = (struct fc_gpn_ft_resp *)bp;
 456                 plen = len;
 457         }
 458 
 459         /*
 460          * Save any partial record at the end of the buffer for next time.
 461          */
 462         if (error == 0 && len > 0 && len < sizeof(*np)) {
 463                 if (np != &disc->partial_buf) {
 464                         FC_DISC_DBG(disc, "Partial buffer remains "
 465                                     "for discovery\n");
 466                         memcpy(&disc->partial_buf, np, len);
 467                 }
 468                 disc->buf_len = (unsigned char) len;
 469         }
 470         return error;
 471 }
 472 
 473 /**
 474  * fc_disc_timeout() - Handler for discovery timeouts
 475  * @work: Structure holding discovery context that needs to retry discovery
 476  */
 477 static void fc_disc_timeout(struct work_struct *work)
 478 {
 479         struct fc_disc *disc = container_of(work,
 480                                             struct fc_disc,
 481                                             disc_work.work);
 482         mutex_lock(&disc->disc_mutex);
 483         fc_disc_gpn_ft_req(disc);
 484         mutex_unlock(&disc->disc_mutex);
 485 }
 486 
 487 /**
 488  * fc_disc_gpn_ft_resp() - Handle a response frame from Get Port Names (GPN_FT)
 489  * @sp:     The sequence that the GPN_FT response was received on
 490  * @fp:     The GPN_FT response frame
 491  * @lp_arg: The discovery context
 492  *
 493  * Locking Note: This function is called without disc mutex held, and
 494  *               should do all its processing with the mutex held
 495  */
 496 static void fc_disc_gpn_ft_resp(struct fc_seq *sp, struct fc_frame *fp,
 497                                 void *disc_arg)
 498 {
 499         struct fc_disc *disc = disc_arg;
 500         struct fc_ct_hdr *cp;
 501         struct fc_frame_header *fh;
 502         enum fc_disc_event event = DISC_EV_NONE;
 503         unsigned int seq_cnt;
 504         unsigned int len;
 505         int error = 0;
 506 
 507         mutex_lock(&disc->disc_mutex);
 508         FC_DISC_DBG(disc, "Received a GPN_FT response\n");
 509 
 510         if (IS_ERR(fp)) {
 511                 fc_disc_error(disc, fp);
 512                 mutex_unlock(&disc->disc_mutex);
 513                 return;
 514         }
 515 
 516         WARN_ON(!fc_frame_is_linear(fp));       /* buffer must be contiguous */
 517         fh = fc_frame_header_get(fp);
 518         len = fr_len(fp) - sizeof(*fh);
 519         seq_cnt = ntohs(fh->fh_seq_cnt);
 520         if (fr_sof(fp) == FC_SOF_I3 && seq_cnt == 0 && disc->seq_count == 0) {
 521                 cp = fc_frame_payload_get(fp, sizeof(*cp));
 522                 if (!cp) {
 523                         FC_DISC_DBG(disc, "GPN_FT response too short, len %d\n",
 524                                     fr_len(fp));
 525                         event = DISC_EV_FAILED;
 526                 } else if (ntohs(cp->ct_cmd) == FC_FS_ACC) {
 527 
 528                         /* Accepted, parse the response. */
 529                         len -= sizeof(*cp);
 530                         error = fc_disc_gpn_ft_parse(disc, cp + 1, len);
 531                 } else if (ntohs(cp->ct_cmd) == FC_FS_RJT) {
 532                         FC_DISC_DBG(disc, "GPN_FT rejected reason %x exp %x "
 533                                     "(check zoning)\n", cp->ct_reason,
 534                                     cp->ct_explan);
 535                         event = DISC_EV_FAILED;
 536                         if (cp->ct_reason == FC_FS_RJT_UNABL &&
 537                             cp->ct_explan == FC_FS_EXP_FTNR)
 538                                 event = DISC_EV_SUCCESS;
 539                 } else {
 540                         FC_DISC_DBG(disc, "GPN_FT unexpected response code "
 541                                     "%x\n", ntohs(cp->ct_cmd));
 542                         event = DISC_EV_FAILED;
 543                 }
 544         } else if (fr_sof(fp) == FC_SOF_N3 && seq_cnt == disc->seq_count) {
 545                 error = fc_disc_gpn_ft_parse(disc, fh + 1, len);
 546         } else {
 547                 FC_DISC_DBG(disc, "GPN_FT unexpected frame - out of sequence? "
 548                             "seq_cnt %x expected %x sof %x eof %x\n",
 549                             seq_cnt, disc->seq_count, fr_sof(fp), fr_eof(fp));
 550                 event = DISC_EV_FAILED;
 551         }
 552         if (error)
 553                 fc_disc_error(disc, ERR_PTR(error));
 554         else if (event != DISC_EV_NONE)
 555                 fc_disc_done(disc, event);
 556         fc_frame_free(fp);
 557         mutex_unlock(&disc->disc_mutex);
 558 }
 559 
 560 /**
 561  * fc_disc_gpn_id_resp() - Handle a response frame from Get Port Names (GPN_ID)
 562  * @sp:        The sequence the GPN_ID is on
 563  * @fp:        The response frame
 564  * @rdata_arg: The remote port that sent the GPN_ID response
 565  *
 566  * Locking Note: This function is called without disc mutex held.
 567  */
 568 static void fc_disc_gpn_id_resp(struct fc_seq *sp, struct fc_frame *fp,
 569                                 void *rdata_arg)
 570 {
 571         struct fc_rport_priv *rdata = rdata_arg;
 572         struct fc_rport_priv *new_rdata;
 573         struct fc_lport *lport;
 574         struct fc_disc *disc;
 575         struct fc_ct_hdr *cp;
 576         struct fc_ns_gid_pn *pn;
 577         u64 port_name;
 578 
 579         lport = rdata->local_port;
 580         disc = &lport->disc;
 581 
 582         if (PTR_ERR(fp) == -FC_EX_CLOSED)
 583                 goto out;
 584         if (IS_ERR(fp))
 585                 goto redisc;
 586 
 587         cp = fc_frame_payload_get(fp, sizeof(*cp));
 588         if (!cp)
 589                 goto redisc;
 590         if (ntohs(cp->ct_cmd) == FC_FS_ACC) {
 591                 if (fr_len(fp) < sizeof(struct fc_frame_header) +
 592                     sizeof(*cp) + sizeof(*pn))
 593                         goto redisc;
 594                 pn = (struct fc_ns_gid_pn *)(cp + 1);
 595                 port_name = get_unaligned_be64(&pn->fn_wwpn);
 596                 mutex_lock(&rdata->rp_mutex);
 597                 if (rdata->ids.port_name == -1)
 598                         rdata->ids.port_name = port_name;
 599                 else if (rdata->ids.port_name != port_name) {
 600                         FC_DISC_DBG(disc, "GPN_ID accepted.  WWPN changed. "
 601                                     "Port-id %6.6x wwpn %16.16llx\n",
 602                                     rdata->ids.port_id, port_name);
 603                         mutex_unlock(&rdata->rp_mutex);
 604                         fc_rport_logoff(rdata);
 605                         mutex_lock(&lport->disc.disc_mutex);
 606                         new_rdata = fc_rport_create(lport, rdata->ids.port_id);
 607                         mutex_unlock(&lport->disc.disc_mutex);
 608                         if (new_rdata) {
 609                                 new_rdata->disc_id = disc->disc_id;
 610                                 fc_rport_login(new_rdata);
 611                         }
 612                         goto out;
 613                 }
 614                 rdata->disc_id = disc->disc_id;
 615                 mutex_unlock(&rdata->rp_mutex);
 616                 fc_rport_login(rdata);
 617         } else if (ntohs(cp->ct_cmd) == FC_FS_RJT) {
 618                 FC_DISC_DBG(disc, "GPN_ID rejected reason %x exp %x\n",
 619                             cp->ct_reason, cp->ct_explan);
 620                 fc_rport_logoff(rdata);
 621         } else {
 622                 FC_DISC_DBG(disc, "GPN_ID unexpected response code %x\n",
 623                             ntohs(cp->ct_cmd));
 624 redisc:
 625                 mutex_lock(&disc->disc_mutex);
 626                 fc_disc_restart(disc);
 627                 mutex_unlock(&disc->disc_mutex);
 628         }
 629 out:
 630         kref_put(&rdata->kref, fc_rport_destroy);
 631         if (!IS_ERR(fp))
 632                 fc_frame_free(fp);
 633 }
 634 
 635 /**
 636  * fc_disc_gpn_id_req() - Send Get Port Names by ID (GPN_ID) request
 637  * @lport: The local port to initiate discovery on
 638  * @rdata: remote port private data
 639  *
 640  * On failure, an error code is returned.
 641  */
 642 static int fc_disc_gpn_id_req(struct fc_lport *lport,
 643                               struct fc_rport_priv *rdata)
 644 {
 645         struct fc_frame *fp;
 646 
 647         lockdep_assert_held(&lport->disc.disc_mutex);
 648         fp = fc_frame_alloc(lport, sizeof(struct fc_ct_hdr) +
 649                             sizeof(struct fc_ns_fid));
 650         if (!fp)
 651                 return -ENOMEM;
 652         if (!lport->tt.elsct_send(lport, rdata->ids.port_id, fp, FC_NS_GPN_ID,
 653                                   fc_disc_gpn_id_resp, rdata,
 654                                   3 * lport->r_a_tov))
 655                 return -ENOMEM;
 656         kref_get(&rdata->kref);
 657         return 0;
 658 }
 659 
 660 /**
 661  * fc_disc_single() - Discover the directory information for a single target
 662  * @lport: The local port the remote port is associated with
 663  * @dp:    The port to rediscover
 664  */
 665 static int fc_disc_single(struct fc_lport *lport, struct fc_disc_port *dp)
 666 {
 667         struct fc_rport_priv *rdata;
 668 
 669         lockdep_assert_held(&lport->disc.disc_mutex);
 670 
 671         rdata = fc_rport_create(lport, dp->port_id);
 672         if (!rdata)
 673                 return -ENOMEM;
 674         rdata->disc_id = 0;
 675         return fc_disc_gpn_id_req(lport, rdata);
 676 }
 677 
 678 /**
 679  * fc_disc_stop() - Stop discovery for a given lport
 680  * @lport: The local port that discovery should stop on
 681  */
 682 static void fc_disc_stop(struct fc_lport *lport)
 683 {
 684         struct fc_disc *disc = &lport->disc;
 685 
 686         if (disc->pending)
 687                 cancel_delayed_work_sync(&disc->disc_work);
 688         mutex_lock(&disc->disc_mutex);
 689         fc_disc_stop_rports(disc);
 690         mutex_unlock(&disc->disc_mutex);
 691 }
 692 
 693 /**
 694  * fc_disc_stop_final() - Stop discovery for a given lport
 695  * @lport: The lport that discovery should stop on
 696  *
 697  * This function will block until discovery has been
 698  * completely stopped and all rports have been deleted.
 699  */
 700 static void fc_disc_stop_final(struct fc_lport *lport)
 701 {
 702         fc_disc_stop(lport);
 703         fc_rport_flush_queue();
 704 }
 705 
 706 /**
 707  * fc_disc_config() - Configure the discovery layer for a local port
 708  * @lport: The local port that needs the discovery layer to be configured
 709  * @priv: Private data structre for users of the discovery layer
 710  */
 711 void fc_disc_config(struct fc_lport *lport, void *priv)
 712 {
 713         struct fc_disc *disc;
 714 
 715         if (!lport->tt.disc_start)
 716                 lport->tt.disc_start = fc_disc_start;
 717 
 718         if (!lport->tt.disc_stop)
 719                 lport->tt.disc_stop = fc_disc_stop;
 720 
 721         if (!lport->tt.disc_stop_final)
 722                 lport->tt.disc_stop_final = fc_disc_stop_final;
 723 
 724         if (!lport->tt.disc_recv_req)
 725                 lport->tt.disc_recv_req = fc_disc_recv_req;
 726 
 727         disc = &lport->disc;
 728 
 729         disc->priv = priv;
 730 }
 731 EXPORT_SYMBOL(fc_disc_config);
 732 
 733 /**
 734  * fc_disc_init() - Initialize the discovery layer for a local port
 735  * @lport: The local port that needs the discovery layer to be initialized
 736  */
 737 void fc_disc_init(struct fc_lport *lport)
 738 {
 739         struct fc_disc *disc = &lport->disc;
 740 
 741         INIT_DELAYED_WORK(&disc->disc_work, fc_disc_timeout);
 742         mutex_init(&disc->disc_mutex);
 743         INIT_LIST_HEAD(&disc->rports);
 744 }
 745 EXPORT_SYMBOL(fc_disc_init);

/* [<][>][^][v][top][bottom][index][help] */