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