diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2016-12-14 21:49:33 +0300 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2016-12-14 21:49:33 +0300 |
commit | a829a8445f09036404060f4d6489cb13433f4304 (patch) | |
tree | 60067e1425239a9f372c10100ede39691c3d612b /drivers/scsi/fcoe/fcoe_ctlr.c | |
parent | 84b6079134420f4635f23c2088a3892057b23bb0 (diff) | |
parent | f5b893c947151d424a4ab55ea3a8544b81974b31 (diff) | |
download | linux-a829a8445f09036404060f4d6489cb13433f4304.tar.xz |
Merge tag 'scsi-misc' of git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi
Pull SCSI updates from James Bottomley:
"This update includes the usual round of major driver updates (ncr5380,
lpfc, hisi_sas, megaraid_sas, ufs, ibmvscsis, mpt3sas).
There's also an assortment of minor fixes, mostly in error legs or
other not very user visible stuff. The major change is the
pci_alloc_irq_vectors replacement for the old pci_msix_.. calls; this
effectively makes IRQ mapping generic for the drivers and allows
blk_mq to use the information"
* tag 'scsi-misc' of git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi: (256 commits)
scsi: qla4xxx: switch to pci_alloc_irq_vectors
scsi: hisi_sas: support deferred probe for v2 hw
scsi: megaraid_sas: switch to pci_alloc_irq_vectors
scsi: scsi_devinfo: remove synchronous ALUA for NETAPP devices
scsi: be2iscsi: set errno on error path
scsi: be2iscsi: set errno on error path
scsi: hpsa: fallback to use legacy REPORT PHYS command
scsi: scsi_dh_alua: Fix RCU annotations
scsi: hpsa: use %phN for short hex dumps
scsi: hisi_sas: fix free'ing in probe and remove
scsi: isci: switch to pci_alloc_irq_vectors
scsi: ipr: Fix runaway IRQs when falling back from MSI to LSI
scsi: dpt_i2o: double free on error path
scsi: cxlflash: Migrate scsi command pointer to AFU command
scsi: cxlflash: Migrate IOARRIN specific routines to function pointers
scsi: cxlflash: Cleanup queuecommand()
scsi: cxlflash: Cleanup send_tmf()
scsi: cxlflash: Remove AFU command lock
scsi: cxlflash: Wait for active AFU commands to timeout upon tear down
scsi: cxlflash: Remove private command pool
...
Diffstat (limited to 'drivers/scsi/fcoe/fcoe_ctlr.c')
-rw-r--r-- | drivers/scsi/fcoe/fcoe_ctlr.c | 157 |
1 files changed, 128 insertions, 29 deletions
diff --git a/drivers/scsi/fcoe/fcoe_ctlr.c b/drivers/scsi/fcoe/fcoe_ctlr.c index dcf36537a767..cea57e27e713 100644 --- a/drivers/scsi/fcoe/fcoe_ctlr.c +++ b/drivers/scsi/fcoe/fcoe_ctlr.c @@ -801,6 +801,8 @@ int fcoe_ctlr_els_send(struct fcoe_ctlr *fip, struct fc_lport *lport, return -EINPROGRESS; drop: kfree_skb(skb); + LIBFCOE_FIP_DBG(fip, "drop els_send op %u d_id %x\n", + op, ntoh24(fh->fh_d_id)); return -EINVAL; } EXPORT_SYMBOL(fcoe_ctlr_els_send); @@ -1316,7 +1318,7 @@ drop: * The overall length has already been checked. */ static void fcoe_ctlr_recv_clr_vlink(struct fcoe_ctlr *fip, - struct fip_header *fh) + struct sk_buff *skb) { struct fip_desc *desc; struct fip_mac_desc *mp; @@ -1331,14 +1333,18 @@ static void fcoe_ctlr_recv_clr_vlink(struct fcoe_ctlr *fip, int num_vlink_desc; int reset_phys_port = 0; struct fip_vn_desc **vlink_desc_arr = NULL; + struct fip_header *fh = (struct fip_header *)skb->data; + struct ethhdr *eh = eth_hdr(skb); LIBFCOE_FIP_DBG(fip, "Clear Virtual Link received\n"); - if (!fcf || !lport->port_id) { + if (!fcf) { /* * We are yet to select best FCF, but we got CVL in the * meantime. reset the ctlr and let it rediscover the FCF */ + LIBFCOE_FIP_DBG(fip, "Resetting fcoe_ctlr as FCF has not been " + "selected yet\n"); mutex_lock(&fip->ctlr_mutex); fcoe_ctlr_reset(fip); mutex_unlock(&fip->ctlr_mutex); @@ -1346,6 +1352,31 @@ static void fcoe_ctlr_recv_clr_vlink(struct fcoe_ctlr *fip, } /* + * If we've selected an FCF check that the CVL is from there to avoid + * processing CVLs from an unexpected source. If it is from an + * unexpected source drop it on the floor. + */ + if (!ether_addr_equal(eh->h_source, fcf->fcf_mac)) { + LIBFCOE_FIP_DBG(fip, "Dropping CVL due to source address " + "mismatch with FCF src=%pM\n", eh->h_source); + return; + } + + /* + * If we haven't logged into the fabric but receive a CVL we should + * reset everything and go back to solicitation. + */ + if (!lport->port_id) { + LIBFCOE_FIP_DBG(fip, "lport not logged in, resoliciting\n"); + mutex_lock(&fip->ctlr_mutex); + fcoe_ctlr_reset(fip); + mutex_unlock(&fip->ctlr_mutex); + fc_lport_reset(fip->lp); + fcoe_ctlr_solicit(fip, NULL); + return; + } + + /* * mask of required descriptors. Validating each one clears its bit. */ desc_mask = BIT(FIP_DT_MAC) | BIT(FIP_DT_NAME); @@ -1576,7 +1607,7 @@ static int fcoe_ctlr_recv_handler(struct fcoe_ctlr *fip, struct sk_buff *skb) if (op == FIP_OP_DISC && sub == FIP_SC_ADV) fcoe_ctlr_recv_adv(fip, skb); else if (op == FIP_OP_CTRL && sub == FIP_SC_CLR_VLINK) - fcoe_ctlr_recv_clr_vlink(fip, fiph); + fcoe_ctlr_recv_clr_vlink(fip, skb); kfree_skb(skb); return 0; drop: @@ -2122,7 +2153,7 @@ static void fcoe_ctlr_vn_rport_callback(struct fc_lport *lport, LIBFCOE_FIP_DBG(fip, "rport FLOGI limited port_id %6.6x\n", rdata->ids.port_id); - lport->tt.rport_logoff(rdata); + fc_rport_logoff(rdata); } break; default: @@ -2145,9 +2176,15 @@ static void fcoe_ctlr_disc_stop_locked(struct fc_lport *lport) { struct fc_rport_priv *rdata; + rcu_read_lock(); + list_for_each_entry_rcu(rdata, &lport->disc.rports, peers) { + if (kref_get_unless_zero(&rdata->kref)) { + fc_rport_logoff(rdata); + kref_put(&rdata->kref, fc_rport_destroy); + } + } + rcu_read_unlock(); mutex_lock(&lport->disc.disc_mutex); - list_for_each_entry_rcu(rdata, &lport->disc.rports, peers) - lport->tt.rport_logoff(rdata); lport->disc.disc_callback = NULL; mutex_unlock(&lport->disc.disc_mutex); } @@ -2178,7 +2215,7 @@ static void fcoe_ctlr_disc_stop(struct fc_lport *lport) static void fcoe_ctlr_disc_stop_final(struct fc_lport *lport) { fcoe_ctlr_disc_stop(lport); - lport->tt.rport_flush_queue(); + fc_rport_flush_queue(); synchronize_rcu(); } @@ -2393,6 +2430,8 @@ static void fcoe_ctlr_vn_probe_req(struct fcoe_ctlr *fip, switch (fip->state) { case FIP_ST_VNMP_CLAIM: case FIP_ST_VNMP_UP: + LIBFCOE_FIP_DBG(fip, "vn_probe_req: send reply, state %x\n", + fip->state); fcoe_ctlr_vn_send(fip, FIP_SC_VN_PROBE_REP, frport->enode_mac, 0); break; @@ -2407,15 +2446,21 @@ static void fcoe_ctlr_vn_probe_req(struct fcoe_ctlr *fip, */ if (fip->lp->wwpn > rdata->ids.port_name && !(frport->flags & FIP_FL_REC_OR_P2P)) { + LIBFCOE_FIP_DBG(fip, "vn_probe_req: " + "port_id collision\n"); fcoe_ctlr_vn_send(fip, FIP_SC_VN_PROBE_REP, frport->enode_mac, 0); break; } /* fall through */ case FIP_ST_VNMP_START: + LIBFCOE_FIP_DBG(fip, "vn_probe_req: " + "restart VN2VN negotiation\n"); fcoe_ctlr_vn_restart(fip); break; default: + LIBFCOE_FIP_DBG(fip, "vn_probe_req: ignore state %x\n", + fip->state); break; } } @@ -2437,9 +2482,12 @@ static void fcoe_ctlr_vn_probe_reply(struct fcoe_ctlr *fip, case FIP_ST_VNMP_PROBE1: case FIP_ST_VNMP_PROBE2: case FIP_ST_VNMP_CLAIM: + LIBFCOE_FIP_DBG(fip, "vn_probe_reply: restart state %x\n", + fip->state); fcoe_ctlr_vn_restart(fip); break; case FIP_ST_VNMP_UP: + LIBFCOE_FIP_DBG(fip, "vn_probe_reply: send claim notify\n"); fcoe_ctlr_vn_send_claim(fip); break; default: @@ -2467,26 +2515,33 @@ static void fcoe_ctlr_vn_add(struct fcoe_ctlr *fip, struct fc_rport_priv *new) return; mutex_lock(&lport->disc.disc_mutex); - rdata = lport->tt.rport_create(lport, port_id); + rdata = fc_rport_create(lport, port_id); if (!rdata) { mutex_unlock(&lport->disc.disc_mutex); return; } + mutex_lock(&rdata->rp_mutex); + mutex_unlock(&lport->disc.disc_mutex); rdata->ops = &fcoe_ctlr_vn_rport_ops; rdata->disc_id = lport->disc.disc_id; ids = &rdata->ids; if ((ids->port_name != -1 && ids->port_name != new->ids.port_name) || - (ids->node_name != -1 && ids->node_name != new->ids.node_name)) - lport->tt.rport_logoff(rdata); + (ids->node_name != -1 && ids->node_name != new->ids.node_name)) { + mutex_unlock(&rdata->rp_mutex); + LIBFCOE_FIP_DBG(fip, "vn_add rport logoff %6.6x\n", port_id); + fc_rport_logoff(rdata); + mutex_lock(&rdata->rp_mutex); + } ids->port_name = new->ids.port_name; ids->node_name = new->ids.node_name; - mutex_unlock(&lport->disc.disc_mutex); + mutex_unlock(&rdata->rp_mutex); frport = fcoe_ctlr_rport(rdata); - LIBFCOE_FIP_DBG(fip, "vn_add rport %6.6x %s\n", - port_id, frport->fcoe_len ? "old" : "new"); + LIBFCOE_FIP_DBG(fip, "vn_add rport %6.6x %s state %d\n", + port_id, frport->fcoe_len ? "old" : "new", + rdata->rp_state); *frport = *fcoe_ctlr_rport(new); frport->time = 0; } @@ -2506,12 +2561,12 @@ static int fcoe_ctlr_vn_lookup(struct fcoe_ctlr *fip, u32 port_id, u8 *mac) struct fcoe_rport *frport; int ret = -1; - rdata = lport->tt.rport_lookup(lport, port_id); + rdata = fc_rport_lookup(lport, port_id); if (rdata) { frport = fcoe_ctlr_rport(rdata); memcpy(mac, frport->enode_mac, ETH_ALEN); ret = 0; - kref_put(&rdata->kref, lport->tt.rport_destroy); + kref_put(&rdata->kref, fc_rport_destroy); } return ret; } @@ -2529,6 +2584,7 @@ static void fcoe_ctlr_vn_claim_notify(struct fcoe_ctlr *fip, struct fcoe_rport *frport = fcoe_ctlr_rport(new); if (frport->flags & FIP_FL_REC_OR_P2P) { + LIBFCOE_FIP_DBG(fip, "send probe req for P2P/REC\n"); fcoe_ctlr_vn_send(fip, FIP_SC_VN_PROBE_REQ, fcoe_all_vn2vn, 0); return; } @@ -2536,25 +2592,37 @@ static void fcoe_ctlr_vn_claim_notify(struct fcoe_ctlr *fip, case FIP_ST_VNMP_START: case FIP_ST_VNMP_PROBE1: case FIP_ST_VNMP_PROBE2: - if (new->ids.port_id == fip->port_id) + if (new->ids.port_id == fip->port_id) { + LIBFCOE_FIP_DBG(fip, "vn_claim_notify: " + "restart, state %d\n", + fip->state); fcoe_ctlr_vn_restart(fip); + } break; case FIP_ST_VNMP_CLAIM: case FIP_ST_VNMP_UP: if (new->ids.port_id == fip->port_id) { if (new->ids.port_name > fip->lp->wwpn) { + LIBFCOE_FIP_DBG(fip, "vn_claim_notify: " + "restart, port_id collision\n"); fcoe_ctlr_vn_restart(fip); break; } + LIBFCOE_FIP_DBG(fip, "vn_claim_notify: " + "send claim notify\n"); fcoe_ctlr_vn_send_claim(fip); break; } + LIBFCOE_FIP_DBG(fip, "vn_claim_notify: send reply to %x\n", + new->ids.port_id); fcoe_ctlr_vn_send(fip, FIP_SC_VN_CLAIM_REP, frport->enode_mac, min((u32)frport->fcoe_len, fcoe_ctlr_fcoe_size(fip))); fcoe_ctlr_vn_add(fip, new); break; default: + LIBFCOE_FIP_DBG(fip, "vn_claim_notify: " + "ignoring claim from %x\n", new->ids.port_id); break; } } @@ -2591,19 +2659,26 @@ static void fcoe_ctlr_vn_beacon(struct fcoe_ctlr *fip, frport = fcoe_ctlr_rport(new); if (frport->flags & FIP_FL_REC_OR_P2P) { + LIBFCOE_FIP_DBG(fip, "p2p beacon while in vn2vn mode\n"); fcoe_ctlr_vn_send(fip, FIP_SC_VN_PROBE_REQ, fcoe_all_vn2vn, 0); return; } - rdata = lport->tt.rport_lookup(lport, new->ids.port_id); + rdata = fc_rport_lookup(lport, new->ids.port_id); if (rdata) { if (rdata->ids.node_name == new->ids.node_name && rdata->ids.port_name == new->ids.port_name) { frport = fcoe_ctlr_rport(rdata); - if (!frport->time && fip->state == FIP_ST_VNMP_UP) - lport->tt.rport_login(rdata); + LIBFCOE_FIP_DBG(fip, "beacon from rport %x\n", + rdata->ids.port_id); + if (!frport->time && fip->state == FIP_ST_VNMP_UP) { + LIBFCOE_FIP_DBG(fip, "beacon expired " + "for rport %x\n", + rdata->ids.port_id); + fc_rport_login(rdata); + } frport->time = jiffies; } - kref_put(&rdata->kref, lport->tt.rport_destroy); + kref_put(&rdata->kref, fc_rport_destroy); return; } if (fip->state != FIP_ST_VNMP_UP) @@ -2638,11 +2713,15 @@ static unsigned long fcoe_ctlr_vn_age(struct fcoe_ctlr *fip) unsigned long deadline; next_time = jiffies + msecs_to_jiffies(FIP_VN_BEACON_INT * 10); - mutex_lock(&lport->disc.disc_mutex); + rcu_read_lock(); list_for_each_entry_rcu(rdata, &lport->disc.rports, peers) { + if (!kref_get_unless_zero(&rdata->kref)) + continue; frport = fcoe_ctlr_rport(rdata); - if (!frport->time) + if (!frport->time) { + kref_put(&rdata->kref, fc_rport_destroy); continue; + } deadline = frport->time + msecs_to_jiffies(FIP_VN_BEACON_INT * 25 / 10); if (time_after_eq(jiffies, deadline)) { @@ -2650,11 +2729,12 @@ static unsigned long fcoe_ctlr_vn_age(struct fcoe_ctlr *fip) LIBFCOE_FIP_DBG(fip, "port %16.16llx fc_id %6.6x beacon expired\n", rdata->ids.port_name, rdata->ids.port_id); - lport->tt.rport_logoff(rdata); + fc_rport_logoff(rdata); } else if (time_before(deadline, next_time)) next_time = deadline; + kref_put(&rdata->kref, fc_rport_destroy); } - mutex_unlock(&lport->disc.disc_mutex); + rcu_read_unlock(); return next_time; } @@ -2674,11 +2754,21 @@ static int fcoe_ctlr_vn_recv(struct fcoe_ctlr *fip, struct sk_buff *skb) struct fc_rport_priv rdata; struct fcoe_rport frport; } buf; - int rc; + int rc, vlan_id = 0; fiph = (struct fip_header *)skb->data; sub = fiph->fip_subcode; + if (fip->lp->vlan) + vlan_id = skb_vlan_tag_get_id(skb); + + if (vlan_id && vlan_id != fip->lp->vlan) { + LIBFCOE_FIP_DBG(fip, "vn_recv drop frame sub %x vlan %d\n", + sub, vlan_id); + rc = -EAGAIN; + goto drop; + } + rc = fcoe_ctlr_vn_parse(fip, skb, &buf.rdata); if (rc) { LIBFCOE_FIP_DBG(fip, "vn_recv vn_parse error %d\n", rc); @@ -2941,7 +3031,7 @@ static void fcoe_ctlr_disc_recv(struct fc_lport *lport, struct fc_frame *fp) rjt_data.reason = ELS_RJT_UNSUP; rjt_data.explan = ELS_EXPL_NONE; - lport->tt.seq_els_rsp_send(fp, ELS_LS_RJT, &rjt_data); + fc_seq_els_rsp_send(fp, ELS_LS_RJT, &rjt_data); fc_frame_free(fp); } @@ -2991,12 +3081,17 @@ static void fcoe_ctlr_vn_disc(struct fcoe_ctlr *fip) mutex_lock(&disc->disc_mutex); callback = disc->pending ? disc->disc_callback : NULL; disc->pending = 0; + mutex_unlock(&disc->disc_mutex); + rcu_read_lock(); list_for_each_entry_rcu(rdata, &disc->rports, peers) { + if (!kref_get_unless_zero(&rdata->kref)) + continue; frport = fcoe_ctlr_rport(rdata); if (frport->time) - lport->tt.rport_login(rdata); + fc_rport_login(rdata); + kref_put(&rdata->kref, fc_rport_destroy); } - mutex_unlock(&disc->disc_mutex); + rcu_read_unlock(); if (callback) callback(lport, DISC_EV_SUCCESS); } @@ -3015,11 +3110,13 @@ static void fcoe_ctlr_vn_timeout(struct fcoe_ctlr *fip) switch (fip->state) { case FIP_ST_VNMP_START: fcoe_ctlr_set_state(fip, FIP_ST_VNMP_PROBE1); + LIBFCOE_FIP_DBG(fip, "vn_timeout: send 1st probe request\n"); fcoe_ctlr_vn_send(fip, FIP_SC_VN_PROBE_REQ, fcoe_all_vn2vn, 0); next_time = jiffies + msecs_to_jiffies(FIP_VN_PROBE_WAIT); break; case FIP_ST_VNMP_PROBE1: fcoe_ctlr_set_state(fip, FIP_ST_VNMP_PROBE2); + LIBFCOE_FIP_DBG(fip, "vn_timeout: send 2nd probe request\n"); fcoe_ctlr_vn_send(fip, FIP_SC_VN_PROBE_REQ, fcoe_all_vn2vn, 0); next_time = jiffies + msecs_to_jiffies(FIP_VN_ANN_WAIT); break; @@ -3030,6 +3127,7 @@ static void fcoe_ctlr_vn_timeout(struct fcoe_ctlr *fip) hton24(mac + 3, new_port_id); fcoe_ctlr_map_dest(fip); fip->update_mac(fip->lp, mac); + LIBFCOE_FIP_DBG(fip, "vn_timeout: send claim notify\n"); fcoe_ctlr_vn_send_claim(fip); next_time = jiffies + msecs_to_jiffies(FIP_VN_ANN_WAIT); break; @@ -3041,6 +3139,7 @@ static void fcoe_ctlr_vn_timeout(struct fcoe_ctlr *fip) next_time = fip->sol_time + msecs_to_jiffies(FIP_VN_ANN_WAIT); if (time_after_eq(jiffies, next_time)) { fcoe_ctlr_set_state(fip, FIP_ST_VNMP_UP); + LIBFCOE_FIP_DBG(fip, "vn_timeout: send vn2vn beacon\n"); fcoe_ctlr_vn_send(fip, FIP_SC_VN_BEACON, fcoe_all_vn2vn, 0); next_time = jiffies + msecs_to_jiffies(FIP_VN_ANN_WAIT); @@ -3051,6 +3150,7 @@ static void fcoe_ctlr_vn_timeout(struct fcoe_ctlr *fip) case FIP_ST_VNMP_UP: next_time = fcoe_ctlr_vn_age(fip); if (time_after_eq(jiffies, fip->port_ka_time)) { + LIBFCOE_FIP_DBG(fip, "vn_timeout: send vn2vn beacon\n"); fcoe_ctlr_vn_send(fip, FIP_SC_VN_BEACON, fcoe_all_vn2vn, 0); fip->port_ka_time = jiffies + @@ -3135,7 +3235,6 @@ int fcoe_libfc_config(struct fc_lport *lport, struct fcoe_ctlr *fip, fc_exch_init(lport); fc_elsct_init(lport); fc_lport_init(lport); - fc_rport_init(lport); fc_disc_init(lport); fcoe_ctlr_mode_set(lport, fip, fip->mode); return 0; |