1 /* 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 * Target Discovery 22 * 23 * This block discovers all FC-4 remote ports, including FCP initiators. It 24 * also handles RSCN events and re-discovery if necessary. 25 */ 26 27 /* 28 * DISC LOCKING 29 * 30 * The disc mutex is can be locked when acquiring rport locks, but may not 31 * be held when acquiring the lport lock. Refer to fc_lport.c for more 32 * details. 33 */ 34 35 #include <linux/timer.h> 36 #include <linux/err.h> 37 #include <asm/unaligned.h> 38 39 #include <scsi/fc/fc_gs.h> 40 41 #include <scsi/libfc.h> 42 43 #define FC_DISC_RETRY_LIMIT 3 /* max retries */ 44 #define FC_DISC_RETRY_DELAY 500UL /* (msecs) delay */ 45 46 #define FC_DISC_DELAY 3 47 48 static int fc_disc_debug; 49 50 #define FC_DEBUG_DISC(fmt...) \ 51 do { \ 52 if (fc_disc_debug) \ 53 FC_DBG(fmt); \ 54 } while (0) 55 56 static void fc_disc_gpn_ft_req(struct fc_disc *); 57 static void fc_disc_gpn_ft_resp(struct fc_seq *, struct fc_frame *, void *); 58 static int fc_disc_new_target(struct fc_disc *, struct fc_rport *, 59 struct fc_rport_identifiers *); 60 static void fc_disc_del_target(struct fc_disc *, struct fc_rport *); 61 static void fc_disc_done(struct fc_disc *); 62 static void fc_disc_timeout(struct work_struct *); 63 static void fc_disc_single(struct fc_disc *, struct fc_disc_port *); 64 static void fc_disc_restart(struct fc_disc *); 65 66 /** 67 * fc_disc_lookup_rport() - lookup a remote port by port_id 68 * @lport: Fibre Channel host port instance 69 * @port_id: remote port port_id to match 70 */ 71 struct fc_rport *fc_disc_lookup_rport(const struct fc_lport *lport, 72 u32 port_id) 73 { 74 const struct fc_disc *disc = &lport->disc; 75 struct fc_rport *rport, *found = NULL; 76 struct fc_rport_libfc_priv *rdata; 77 int disc_found = 0; 78 79 list_for_each_entry(rdata, &disc->rports, peers) { 80 rport = PRIV_TO_RPORT(rdata); 81 if (rport->port_id == port_id) { 82 disc_found = 1; 83 found = rport; 84 break; 85 } 86 } 87 88 if (!disc_found) 89 found = NULL; 90 91 return found; 92 } 93 94 /** 95 * fc_disc_stop_rports() - delete all the remote ports associated with the lport 96 * @disc: The discovery job to stop rports on 97 * 98 * Locking Note: This function expects that the lport mutex is locked before 99 * calling it. 100 */ 101 void fc_disc_stop_rports(struct fc_disc *disc) 102 { 103 struct fc_lport *lport; 104 struct fc_rport *rport; 105 struct fc_rport_libfc_priv *rdata, *next; 106 107 lport = disc->lport; 108 109 mutex_lock(&disc->disc_mutex); 110 list_for_each_entry_safe(rdata, next, &disc->rports, peers) { 111 rport = PRIV_TO_RPORT(rdata); 112 list_del(&rdata->peers); 113 lport->tt.rport_logoff(rport); 114 } 115 116 mutex_unlock(&disc->disc_mutex); 117 } 118 119 /** 120 * fc_disc_rport_callback() - Event handler for rport events 121 * @lport: The lport which is receiving the event 122 * @rport: The rport which the event has occured on 123 * @event: The event that occured 124 * 125 * Locking Note: The rport lock should not be held when calling 126 * this function. 127 */ 128 static void fc_disc_rport_callback(struct fc_lport *lport, 129 struct fc_rport *rport, 130 enum fc_rport_event event) 131 { 132 struct fc_rport_libfc_priv *rdata = rport->dd_data; 133 struct fc_disc *disc = &lport->disc; 134 int found = 0; 135 136 FC_DEBUG_DISC("Received a %d event for port (%6x)\n", event, 137 rport->port_id); 138 139 if (event == RPORT_EV_CREATED) { 140 if (disc) { 141 found = 1; 142 mutex_lock(&disc->disc_mutex); 143 list_add_tail(&rdata->peers, &disc->rports); 144 mutex_unlock(&disc->disc_mutex); 145 } 146 } 147 148 if (!found) 149 FC_DEBUG_DISC("The rport (%6x) is not maintained " 150 "by the discovery layer\n", rport->port_id); 151 } 152 153 /** 154 * fc_disc_recv_rscn_req() - Handle Registered State Change Notification (RSCN) 155 * @sp: Current sequence of the RSCN exchange 156 * @fp: RSCN Frame 157 * @lport: Fibre Channel host port instance 158 * 159 * Locking Note: This function expects that the disc_mutex is locked 160 * before it is called. 161 */ 162 static void fc_disc_recv_rscn_req(struct fc_seq *sp, struct fc_frame *fp, 163 struct fc_disc *disc) 164 { 165 struct fc_lport *lport; 166 struct fc_rport *rport; 167 struct fc_rport_libfc_priv *rdata; 168 struct fc_els_rscn *rp; 169 struct fc_els_rscn_page *pp; 170 struct fc_seq_els_data rjt_data; 171 unsigned int len; 172 int redisc = 0; 173 enum fc_els_rscn_ev_qual ev_qual; 174 enum fc_els_rscn_addr_fmt fmt; 175 LIST_HEAD(disc_ports); 176 struct fc_disc_port *dp, *next; 177 178 lport = disc->lport; 179 180 FC_DEBUG_DISC("Received an RSCN event on port (%6x)\n", 181 fc_host_port_id(lport->host)); 182 183 /* make sure the frame contains an RSCN message */ 184 rp = fc_frame_payload_get(fp, sizeof(*rp)); 185 if (!rp) 186 goto reject; 187 /* make sure the page length is as expected (4 bytes) */ 188 if (rp->rscn_page_len != sizeof(*pp)) 189 goto reject; 190 /* get the RSCN payload length */ 191 len = ntohs(rp->rscn_plen); 192 if (len < sizeof(*rp)) 193 goto reject; 194 /* make sure the frame contains the expected payload */ 195 rp = fc_frame_payload_get(fp, len); 196 if (!rp) 197 goto reject; 198 /* payload must be a multiple of the RSCN page size */ 199 len -= sizeof(*rp); 200 if (len % sizeof(*pp)) 201 goto reject; 202 203 for (pp = (void *)(rp + 1); len > 0; len -= sizeof(*pp), pp++) { 204 ev_qual = pp->rscn_page_flags >> ELS_RSCN_EV_QUAL_BIT; 205 ev_qual &= ELS_RSCN_EV_QUAL_MASK; 206 fmt = pp->rscn_page_flags >> ELS_RSCN_ADDR_FMT_BIT; 207 fmt &= ELS_RSCN_ADDR_FMT_MASK; 208 /* 209 * if we get an address format other than port 210 * (area, domain, fabric), then do a full discovery 211 */ 212 switch (fmt) { 213 case ELS_ADDR_FMT_PORT: 214 FC_DEBUG_DISC("Port address format for port (%6x)\n", 215 ntoh24(pp->rscn_fid)); 216 dp = kzalloc(sizeof(*dp), GFP_KERNEL); 217 if (!dp) { 218 redisc = 1; 219 break; 220 } 221 dp->lp = lport; 222 dp->ids.port_id = ntoh24(pp->rscn_fid); 223 dp->ids.port_name = -1; 224 dp->ids.node_name = -1; 225 dp->ids.roles = FC_RPORT_ROLE_UNKNOWN; 226 list_add_tail(&dp->peers, &disc_ports); 227 break; 228 case ELS_ADDR_FMT_AREA: 229 case ELS_ADDR_FMT_DOM: 230 case ELS_ADDR_FMT_FAB: 231 default: 232 FC_DEBUG_DISC("Address format is (%d)\n", fmt); 233 redisc = 1; 234 break; 235 } 236 } 237 lport->tt.seq_els_rsp_send(sp, ELS_LS_ACC, NULL); 238 if (redisc) { 239 FC_DEBUG_DISC("RSCN received: rediscovering\n"); 240 fc_disc_restart(disc); 241 } else { 242 FC_DEBUG_DISC("RSCN received: not rediscovering. " 243 "redisc %d state %d in_prog %d\n", 244 redisc, lport->state, disc->pending); 245 list_for_each_entry_safe(dp, next, &disc_ports, peers) { 246 list_del(&dp->peers); 247 rport = lport->tt.rport_lookup(lport, dp->ids.port_id); 248 if (rport) { 249 rdata = rport->dd_data; 250 list_del(&rdata->peers); 251 lport->tt.rport_logoff(rport); 252 } 253 fc_disc_single(disc, dp); 254 } 255 } 256 fc_frame_free(fp); 257 return; 258 reject: 259 FC_DEBUG_DISC("Received a bad RSCN frame\n"); 260 rjt_data.fp = NULL; 261 rjt_data.reason = ELS_RJT_LOGIC; 262 rjt_data.explan = ELS_EXPL_NONE; 263 lport->tt.seq_els_rsp_send(sp, ELS_LS_RJT, &rjt_data); 264 fc_frame_free(fp); 265 } 266 267 /** 268 * fc_disc_recv_req() - Handle incoming requests 269 * @sp: Current sequence of the request exchange 270 * @fp: The frame 271 * @lport: The FC local port 272 * 273 * Locking Note: This function is called from the EM and will lock 274 * the disc_mutex before calling the handler for the 275 * request. 276 */ 277 static void fc_disc_recv_req(struct fc_seq *sp, struct fc_frame *fp, 278 struct fc_lport *lport) 279 { 280 u8 op; 281 struct fc_disc *disc = &lport->disc; 282 283 op = fc_frame_payload_op(fp); 284 switch (op) { 285 case ELS_RSCN: 286 mutex_lock(&disc->disc_mutex); 287 fc_disc_recv_rscn_req(sp, fp, disc); 288 mutex_unlock(&disc->disc_mutex); 289 break; 290 default: 291 FC_DBG("Received an unsupported request. opcode (%x)\n", op); 292 break; 293 } 294 } 295 296 /** 297 * fc_disc_restart() - Restart discovery 298 * @lport: FC discovery context 299 * 300 * Locking Note: This function expects that the disc mutex 301 * is already locked. 302 */ 303 static void fc_disc_restart(struct fc_disc *disc) 304 { 305 struct fc_rport *rport; 306 struct fc_rport_libfc_priv *rdata, *next; 307 struct fc_lport *lport = disc->lport; 308 309 FC_DEBUG_DISC("Restarting discovery for port (%6x)\n", 310 fc_host_port_id(lport->host)); 311 312 list_for_each_entry_safe(rdata, next, &disc->rports, peers) { 313 rport = PRIV_TO_RPORT(rdata); 314 FC_DEBUG_DISC("list_del(%6x)\n", rport->port_id); 315 list_del(&rdata->peers); 316 lport->tt.rport_logoff(rport); 317 } 318 319 disc->requested = 1; 320 if (!disc->pending) 321 fc_disc_gpn_ft_req(disc); 322 } 323 324 /** 325 * fc_disc_start() - Fibre Channel Target discovery 326 * @lport: FC local port 327 * 328 * Returns non-zero if discovery cannot be started. 329 */ 330 static void fc_disc_start(void (*disc_callback)(struct fc_lport *, 331 enum fc_disc_event), 332 struct fc_lport *lport) 333 { 334 struct fc_rport *rport; 335 struct fc_rport_identifiers ids; 336 struct fc_disc *disc = &lport->disc; 337 338 /* 339 * At this point we may have a new disc job or an existing 340 * one. Either way, let's lock when we make changes to it 341 * and send the GPN_FT request. 342 */ 343 mutex_lock(&disc->disc_mutex); 344 345 disc->disc_callback = disc_callback; 346 347 /* 348 * If not ready, or already running discovery, just set request flag. 349 */ 350 disc->requested = 1; 351 352 if (disc->pending) { 353 mutex_unlock(&disc->disc_mutex); 354 return; 355 } 356 357 /* 358 * Handle point-to-point mode as a simple discovery 359 * of the remote port. Yucky, yucky, yuck, yuck! 360 */ 361 rport = disc->lport->ptp_rp; 362 if (rport) { 363 ids.port_id = rport->port_id; 364 ids.port_name = rport->port_name; 365 ids.node_name = rport->node_name; 366 ids.roles = FC_RPORT_ROLE_UNKNOWN; 367 get_device(&rport->dev); 368 369 if (!fc_disc_new_target(disc, rport, &ids)) { 370 disc->event = DISC_EV_SUCCESS; 371 fc_disc_done(disc); 372 } 373 put_device(&rport->dev); 374 } else { 375 fc_disc_gpn_ft_req(disc); /* get ports by FC-4 type */ 376 } 377 378 mutex_unlock(&disc->disc_mutex); 379 } 380 381 static struct fc_rport_operations fc_disc_rport_ops = { 382 .event_callback = fc_disc_rport_callback, 383 }; 384 385 /** 386 * fc_disc_new_target() - Handle new target found by discovery 387 * @lport: FC local port 388 * @rport: The previous FC remote port (NULL if new remote port) 389 * @ids: Identifiers for the new FC remote port 390 * 391 * Locking Note: This function expects that the disc_mutex is locked 392 * before it is called. 393 */ 394 static int fc_disc_new_target(struct fc_disc *disc, 395 struct fc_rport *rport, 396 struct fc_rport_identifiers *ids) 397 { 398 struct fc_lport *lport = disc->lport; 399 struct fc_rport_libfc_priv *rdata; 400 int error = 0; 401 402 if (rport && ids->port_name) { 403 if (rport->port_name == -1) { 404 /* 405 * Set WWN and fall through to notify of create. 406 */ 407 fc_rport_set_name(rport, ids->port_name, 408 rport->node_name); 409 } else if (rport->port_name != ids->port_name) { 410 /* 411 * This is a new port with the same FCID as 412 * a previously-discovered port. Presumably the old 413 * port logged out and a new port logged in and was 414 * assigned the same FCID. This should be rare. 415 * Delete the old one and fall thru to re-create. 416 */ 417 fc_disc_del_target(disc, rport); 418 rport = NULL; 419 } 420 } 421 if (((ids->port_name != -1) || (ids->port_id != -1)) && 422 ids->port_id != fc_host_port_id(lport->host) && 423 ids->port_name != lport->wwpn) { 424 if (!rport) { 425 rport = lport->tt.rport_lookup(lport, ids->port_id); 426 if (!rport) { 427 struct fc_disc_port dp; 428 dp.lp = lport; 429 dp.ids.port_id = ids->port_id; 430 dp.ids.port_name = ids->port_name; 431 dp.ids.node_name = ids->node_name; 432 dp.ids.roles = ids->roles; 433 rport = lport->tt.rport_create(&dp); 434 } 435 if (!rport) 436 error = -ENOMEM; 437 } 438 if (rport) { 439 rdata = rport->dd_data; 440 rdata->ops = &fc_disc_rport_ops; 441 rdata->rp_state = RPORT_ST_INIT; 442 lport->tt.rport_login(rport); 443 } 444 } 445 return error; 446 } 447 448 /** 449 * fc_disc_del_target() - Delete a target 450 * @disc: FC discovery context 451 * @rport: The remote port to be removed 452 */ 453 static void fc_disc_del_target(struct fc_disc *disc, struct fc_rport *rport) 454 { 455 struct fc_lport *lport = disc->lport; 456 struct fc_rport_libfc_priv *rdata = rport->dd_data; 457 list_del(&rdata->peers); 458 lport->tt.rport_logoff(rport); 459 } 460 461 /** 462 * fc_disc_done() - Discovery has been completed 463 * @disc: FC discovery context 464 */ 465 static void fc_disc_done(struct fc_disc *disc) 466 { 467 struct fc_lport *lport = disc->lport; 468 469 FC_DEBUG_DISC("Discovery complete for port (%6x)\n", 470 fc_host_port_id(lport->host)); 471 472 disc->disc_callback(lport, disc->event); 473 disc->event = DISC_EV_NONE; 474 475 if (disc->requested) 476 fc_disc_gpn_ft_req(disc); 477 else 478 disc->pending = 0; 479 } 480 481 /** 482 * fc_disc_error() - Handle error on dNS request 483 * @disc: FC discovery context 484 * @fp: The frame pointer 485 */ 486 static void fc_disc_error(struct fc_disc *disc, struct fc_frame *fp) 487 { 488 struct fc_lport *lport = disc->lport; 489 unsigned long delay = 0; 490 if (fc_disc_debug) 491 FC_DBG("Error %ld, retries %d/%d\n", 492 PTR_ERR(fp), disc->retry_count, 493 FC_DISC_RETRY_LIMIT); 494 495 if (!fp || PTR_ERR(fp) == -FC_EX_TIMEOUT) { 496 /* 497 * Memory allocation failure, or the exchange timed out, 498 * retry after delay. 499 */ 500 if (disc->retry_count < FC_DISC_RETRY_LIMIT) { 501 /* go ahead and retry */ 502 if (!fp) 503 delay = msecs_to_jiffies(FC_DISC_RETRY_DELAY); 504 else { 505 delay = msecs_to_jiffies(lport->e_d_tov); 506 507 /* timeout faster first time */ 508 if (!disc->retry_count) 509 delay /= 4; 510 } 511 disc->retry_count++; 512 schedule_delayed_work(&disc->disc_work, delay); 513 } else { 514 /* exceeded retries */ 515 disc->event = DISC_EV_FAILED; 516 fc_disc_done(disc); 517 } 518 } 519 } 520 521 /** 522 * fc_disc_gpn_ft_req() - Send Get Port Names by FC-4 type (GPN_FT) request 523 * @lport: FC discovery context 524 * 525 * Locking Note: This function expects that the disc_mutex is locked 526 * before it is called. 527 */ 528 static void fc_disc_gpn_ft_req(struct fc_disc *disc) 529 { 530 struct fc_frame *fp; 531 struct fc_lport *lport = disc->lport; 532 533 WARN_ON(!fc_lport_test_ready(lport)); 534 535 disc->pending = 1; 536 disc->requested = 0; 537 538 disc->buf_len = 0; 539 disc->seq_count = 0; 540 fp = fc_frame_alloc(lport, 541 sizeof(struct fc_ct_hdr) + 542 sizeof(struct fc_ns_gid_ft)); 543 if (!fp) 544 goto err; 545 546 if (lport->tt.elsct_send(lport, NULL, fp, 547 FC_NS_GPN_FT, 548 fc_disc_gpn_ft_resp, 549 disc, lport->e_d_tov)) 550 return; 551 err: 552 fc_disc_error(disc, fp); 553 } 554 555 /** 556 * fc_disc_gpn_ft_parse() - Parse the list of IDs and names resulting from a request 557 * @lport: Fibre Channel host port instance 558 * @buf: GPN_FT response buffer 559 * @len: size of response buffer 560 */ 561 static int fc_disc_gpn_ft_parse(struct fc_disc *disc, void *buf, size_t len) 562 { 563 struct fc_lport *lport; 564 struct fc_gpn_ft_resp *np; 565 char *bp; 566 size_t plen; 567 size_t tlen; 568 int error = 0; 569 struct fc_disc_port dp; 570 struct fc_rport *rport; 571 struct fc_rport_libfc_priv *rdata; 572 573 lport = disc->lport; 574 575 /* 576 * Handle partial name record left over from previous call. 577 */ 578 bp = buf; 579 plen = len; 580 np = (struct fc_gpn_ft_resp *)bp; 581 tlen = disc->buf_len; 582 if (tlen) { 583 WARN_ON(tlen >= sizeof(*np)); 584 plen = sizeof(*np) - tlen; 585 WARN_ON(plen <= 0); 586 WARN_ON(plen >= sizeof(*np)); 587 if (plen > len) 588 plen = len; 589 np = &disc->partial_buf; 590 memcpy((char *)np + tlen, bp, plen); 591 592 /* 593 * Set bp so that the loop below will advance it to the 594 * first valid full name element. 595 */ 596 bp -= tlen; 597 len += tlen; 598 plen += tlen; 599 disc->buf_len = (unsigned char) plen; 600 if (plen == sizeof(*np)) 601 disc->buf_len = 0; 602 } 603 604 /* 605 * Handle full name records, including the one filled from above. 606 * Normally, np == bp and plen == len, but from the partial case above, 607 * bp, len describe the overall buffer, and np, plen describe the 608 * partial buffer, which if would usually be full now. 609 * After the first time through the loop, things return to "normal". 610 */ 611 while (plen >= sizeof(*np)) { 612 dp.lp = lport; 613 dp.ids.port_id = ntoh24(np->fp_fid); 614 dp.ids.port_name = ntohll(np->fp_wwpn); 615 dp.ids.node_name = -1; 616 dp.ids.roles = FC_RPORT_ROLE_UNKNOWN; 617 618 if ((dp.ids.port_id != fc_host_port_id(lport->host)) && 619 (dp.ids.port_name != lport->wwpn)) { 620 rport = lport->tt.rport_create(&dp); 621 if (rport) { 622 rdata = rport->dd_data; 623 rdata->ops = &fc_disc_rport_ops; 624 rdata->local_port = lport; 625 lport->tt.rport_login(rport); 626 } else 627 FC_DBG("Failed to allocate memory for " 628 "the newly discovered port (%6x)\n", 629 dp.ids.port_id); 630 } 631 632 if (np->fp_flags & FC_NS_FID_LAST) { 633 disc->event = DISC_EV_SUCCESS; 634 fc_disc_done(disc); 635 len = 0; 636 break; 637 } 638 len -= sizeof(*np); 639 bp += sizeof(*np); 640 np = (struct fc_gpn_ft_resp *)bp; 641 plen = len; 642 } 643 644 /* 645 * Save any partial record at the end of the buffer for next time. 646 */ 647 if (error == 0 && len > 0 && len < sizeof(*np)) { 648 if (np != &disc->partial_buf) { 649 FC_DEBUG_DISC("Partial buffer remains " 650 "for discovery by (%6x)\n", 651 fc_host_port_id(lport->host)); 652 memcpy(&disc->partial_buf, np, len); 653 } 654 disc->buf_len = (unsigned char) len; 655 } else { 656 disc->buf_len = 0; 657 } 658 return error; 659 } 660 661 /** 662 * fc_disc_timeout() - Retry handler for the disc component 663 * @work: Structure holding disc obj that needs retry discovery 664 * 665 * Handle retry of memory allocation for remote ports. 666 */ 667 static void fc_disc_timeout(struct work_struct *work) 668 { 669 struct fc_disc *disc = container_of(work, 670 struct fc_disc, 671 disc_work.work); 672 mutex_lock(&disc->disc_mutex); 673 if (disc->requested && !disc->pending) 674 fc_disc_gpn_ft_req(disc); 675 mutex_unlock(&disc->disc_mutex); 676 } 677 678 /** 679 * fc_disc_gpn_ft_resp() - Handle a response frame from Get Port Names (GPN_FT) 680 * @sp: Current sequence of GPN_FT exchange 681 * @fp: response frame 682 * @lp_arg: Fibre Channel host port instance 683 * 684 * Locking Note: This function expects that the disc_mutex is locked 685 * before it is called. 686 */ 687 static void fc_disc_gpn_ft_resp(struct fc_seq *sp, struct fc_frame *fp, 688 void *disc_arg) 689 { 690 struct fc_disc *disc = disc_arg; 691 struct fc_ct_hdr *cp; 692 struct fc_frame_header *fh; 693 unsigned int seq_cnt; 694 void *buf = NULL; 695 unsigned int len; 696 int error; 697 698 FC_DEBUG_DISC("Received a GPN_FT response on port (%6x)\n", 699 fc_host_port_id(disc->lport->host)); 700 701 if (IS_ERR(fp)) { 702 fc_disc_error(disc, fp); 703 return; 704 } 705 706 WARN_ON(!fc_frame_is_linear(fp)); /* buffer must be contiguous */ 707 fh = fc_frame_header_get(fp); 708 len = fr_len(fp) - sizeof(*fh); 709 seq_cnt = ntohs(fh->fh_seq_cnt); 710 if (fr_sof(fp) == FC_SOF_I3 && seq_cnt == 0 && 711 disc->seq_count == 0) { 712 cp = fc_frame_payload_get(fp, sizeof(*cp)); 713 if (!cp) { 714 FC_DBG("GPN_FT response too short, len %d\n", 715 fr_len(fp)); 716 } else if (ntohs(cp->ct_cmd) == FC_FS_ACC) { 717 718 /* Accepted, parse the response. */ 719 buf = cp + 1; 720 len -= sizeof(*cp); 721 } else if (ntohs(cp->ct_cmd) == FC_FS_RJT) { 722 FC_DBG("GPN_FT rejected reason %x exp %x " 723 "(check zoning)\n", cp->ct_reason, 724 cp->ct_explan); 725 disc->event = DISC_EV_FAILED; 726 fc_disc_done(disc); 727 } else { 728 FC_DBG("GPN_FT unexpected response code %x\n", 729 ntohs(cp->ct_cmd)); 730 } 731 } else if (fr_sof(fp) == FC_SOF_N3 && 732 seq_cnt == disc->seq_count) { 733 buf = fh + 1; 734 } else { 735 FC_DBG("GPN_FT unexpected frame - out of sequence? " 736 "seq_cnt %x expected %x sof %x eof %x\n", 737 seq_cnt, disc->seq_count, fr_sof(fp), fr_eof(fp)); 738 } 739 if (buf) { 740 error = fc_disc_gpn_ft_parse(disc, buf, len); 741 if (error) 742 fc_disc_error(disc, fp); 743 else 744 disc->seq_count++; 745 } 746 fc_frame_free(fp); 747 } 748 749 /** 750 * fc_disc_single() - Discover the directory information for a single target 751 * @lport: FC local port 752 * @dp: The port to rediscover 753 * 754 * Locking Note: This function expects that the disc_mutex is locked 755 * before it is called. 756 */ 757 static void fc_disc_single(struct fc_disc *disc, struct fc_disc_port *dp) 758 { 759 struct fc_lport *lport; 760 struct fc_rport *rport; 761 struct fc_rport *new_rport; 762 struct fc_rport_libfc_priv *rdata; 763 764 lport = disc->lport; 765 766 if (dp->ids.port_id == fc_host_port_id(lport->host)) 767 goto out; 768 769 rport = lport->tt.rport_lookup(lport, dp->ids.port_id); 770 if (rport) 771 fc_disc_del_target(disc, rport); 772 773 new_rport = lport->tt.rport_create(dp); 774 if (new_rport) { 775 rdata = new_rport->dd_data; 776 rdata->ops = &fc_disc_rport_ops; 777 kfree(dp); 778 lport->tt.rport_login(new_rport); 779 } 780 return; 781 out: 782 kfree(dp); 783 } 784 785 /** 786 * fc_disc_stop() - Stop discovery for a given lport 787 * @lport: The lport that discovery should stop for 788 */ 789 void fc_disc_stop(struct fc_lport *lport) 790 { 791 struct fc_disc *disc = &lport->disc; 792 793 if (disc) { 794 cancel_delayed_work_sync(&disc->disc_work); 795 fc_disc_stop_rports(disc); 796 } 797 } 798 799 /** 800 * fc_disc_stop_final() - Stop discovery for a given lport 801 * @lport: The lport that discovery should stop for 802 * 803 * This function will block until discovery has been 804 * completely stopped and all rports have been deleted. 805 */ 806 void fc_disc_stop_final(struct fc_lport *lport) 807 { 808 fc_disc_stop(lport); 809 lport->tt.rport_flush_queue(); 810 } 811 812 /** 813 * fc_disc_init() - Initialize the discovery block 814 * @lport: FC local port 815 */ 816 int fc_disc_init(struct fc_lport *lport) 817 { 818 struct fc_disc *disc; 819 820 if (!lport->tt.disc_start) 821 lport->tt.disc_start = fc_disc_start; 822 823 if (!lport->tt.disc_stop) 824 lport->tt.disc_stop = fc_disc_stop; 825 826 if (!lport->tt.disc_stop_final) 827 lport->tt.disc_stop_final = fc_disc_stop_final; 828 829 if (!lport->tt.disc_recv_req) 830 lport->tt.disc_recv_req = fc_disc_recv_req; 831 832 if (!lport->tt.rport_lookup) 833 lport->tt.rport_lookup = fc_disc_lookup_rport; 834 835 disc = &lport->disc; 836 INIT_DELAYED_WORK(&disc->disc_work, fc_disc_timeout); 837 mutex_init(&disc->disc_mutex); 838 INIT_LIST_HEAD(&disc->rports); 839 840 disc->lport = lport; 841 disc->delay = FC_DISC_DELAY; 842 disc->event = DISC_EV_NONE; 843 844 return 0; 845 } 846 EXPORT_SYMBOL(fc_disc_init); 847