diff options
author | Neerav Parikh <Neerav.Parikh@intel.com> | 2011-05-16 19:45:29 -0400 |
---|---|---|
committer | James Bottomley <jbottomley@parallels.com> | 2011-05-24 12:36:29 -0400 |
commit | bdf252183e58654fcceedbf3fdcfd878b9e4f2d6 (patch) | |
tree | b02db1a5baab6cde3fb77f2e9c7c1c302e996ce1 /drivers/scsi/fcoe | |
parent | c051ad2e57e379e07e4ec28b2a54eeb0d04c5d59 (diff) |
[SCSI] fcoe: Prevent creation of an NPIV port with duplicate WWPN
This patch adds a validation step before allowing creation of a new NPIV port.
It checks whether the WWPN passed for the new NPIV port to be created is unique
for the given physical port.
Signed-off-by: Neerav Parikh <Neerav.Parikh@intel.com>
Tested-by: Ross Brattain <ross.b.brattain@intel.com>
Signed-off-by: Robert Love <robert.w.love@intel.com>
Signed-off-by: James Bottomley <jbottomley@parallels.com>
Diffstat (limited to 'drivers/scsi/fcoe')
-rw-r--r-- | drivers/scsi/fcoe/fcoe.c | 58 | ||||
-rw-r--r-- | drivers/scsi/fcoe/fcoe.h | 10 |
2 files changed, 68 insertions, 0 deletions
diff --git a/drivers/scsi/fcoe/fcoe.c b/drivers/scsi/fcoe/fcoe.c index cc23bd9480b2..155d7b9bdeae 100644 --- a/drivers/scsi/fcoe/fcoe.c +++ b/drivers/scsi/fcoe/fcoe.c | |||
@@ -137,6 +137,7 @@ static int fcoe_vport_create(struct fc_vport *, bool disabled); | |||
137 | static int fcoe_vport_disable(struct fc_vport *, bool disable); | 137 | static int fcoe_vport_disable(struct fc_vport *, bool disable); |
138 | static void fcoe_set_vport_symbolic_name(struct fc_vport *); | 138 | static void fcoe_set_vport_symbolic_name(struct fc_vport *); |
139 | static void fcoe_set_port_id(struct fc_lport *, u32, struct fc_frame *); | 139 | static void fcoe_set_port_id(struct fc_lport *, u32, struct fc_frame *); |
140 | static int fcoe_validate_vport_create(struct fc_vport *); | ||
140 | 141 | ||
141 | static struct libfc_function_template fcoe_libfc_fcn_templ = { | 142 | static struct libfc_function_template fcoe_libfc_fcn_templ = { |
142 | .frame_send = fcoe_xmit, | 143 | .frame_send = fcoe_xmit, |
@@ -2351,6 +2352,17 @@ static int fcoe_vport_create(struct fc_vport *vport, bool disabled) | |||
2351 | struct fcoe_interface *fcoe = port->priv; | 2352 | struct fcoe_interface *fcoe = port->priv; |
2352 | struct net_device *netdev = fcoe->netdev; | 2353 | struct net_device *netdev = fcoe->netdev; |
2353 | struct fc_lport *vn_port; | 2354 | struct fc_lport *vn_port; |
2355 | int rc; | ||
2356 | char buf[32]; | ||
2357 | |||
2358 | rc = fcoe_validate_vport_create(vport); | ||
2359 | if (rc) { | ||
2360 | wwn_to_str(vport->port_name, buf, sizeof(buf)); | ||
2361 | printk(KERN_ERR "fcoe: Failed to create vport, " | ||
2362 | "WWPN (0x%s) already exists\n", | ||
2363 | buf); | ||
2364 | return rc; | ||
2365 | } | ||
2354 | 2366 | ||
2355 | mutex_lock(&fcoe_config_mutex); | 2367 | mutex_lock(&fcoe_config_mutex); |
2356 | vn_port = fcoe_if_create(fcoe, &vport->dev, 1); | 2368 | vn_port = fcoe_if_create(fcoe, &vport->dev, 1); |
@@ -2497,3 +2509,49 @@ static void fcoe_set_port_id(struct fc_lport *lport, | |||
2497 | if (fp && fc_frame_payload_op(fp) == ELS_FLOGI) | 2509 | if (fp && fc_frame_payload_op(fp) == ELS_FLOGI) |
2498 | fcoe_ctlr_recv_flogi(&fcoe->ctlr, lport, fp); | 2510 | fcoe_ctlr_recv_flogi(&fcoe->ctlr, lport, fp); |
2499 | } | 2511 | } |
2512 | |||
2513 | /** | ||
2514 | * fcoe_validate_vport_create() - Validate a vport before creating it | ||
2515 | * @vport: NPIV port to be created | ||
2516 | * | ||
2517 | * This routine is meant to add validation for a vport before creating it | ||
2518 | * via fcoe_vport_create(). | ||
2519 | * Current validations are: | ||
2520 | * - WWPN supplied is unique for given lport | ||
2521 | * | ||
2522 | * | ||
2523 | */ | ||
2524 | static int fcoe_validate_vport_create(struct fc_vport *vport) | ||
2525 | { | ||
2526 | struct Scsi_Host *shost = vport_to_shost(vport); | ||
2527 | struct fc_lport *n_port = shost_priv(shost); | ||
2528 | struct fc_lport *vn_port; | ||
2529 | int rc = 0; | ||
2530 | char buf[32]; | ||
2531 | |||
2532 | mutex_lock(&n_port->lp_mutex); | ||
2533 | |||
2534 | wwn_to_str(vport->port_name, buf, sizeof(buf)); | ||
2535 | /* Check if the wwpn is not same as that of the lport */ | ||
2536 | if (!memcmp(&n_port->wwpn, &vport->port_name, sizeof(u64))) { | ||
2537 | FCOE_DBG("vport WWPN 0x%s is same as that of the " | ||
2538 | "base port WWPN\n", buf); | ||
2539 | rc = -EINVAL; | ||
2540 | goto out; | ||
2541 | } | ||
2542 | |||
2543 | /* Check if there is any existing vport with same wwpn */ | ||
2544 | list_for_each_entry(vn_port, &n_port->vports, list) { | ||
2545 | if (!memcmp(&vn_port->wwpn, &vport->port_name, sizeof(u64))) { | ||
2546 | FCOE_DBG("vport with given WWPN 0x%s already " | ||
2547 | "exists\n", buf); | ||
2548 | rc = -EINVAL; | ||
2549 | break; | ||
2550 | } | ||
2551 | } | ||
2552 | |||
2553 | out: | ||
2554 | mutex_unlock(&n_port->lp_mutex); | ||
2555 | |||
2556 | return rc; | ||
2557 | } | ||
diff --git a/drivers/scsi/fcoe/fcoe.h b/drivers/scsi/fcoe/fcoe.h index 408a6fd78fb4..c4a93993c0cf 100644 --- a/drivers/scsi/fcoe/fcoe.h +++ b/drivers/scsi/fcoe/fcoe.h | |||
@@ -99,4 +99,14 @@ static inline struct net_device *fcoe_netdev(const struct fc_lport *lport) | |||
99 | ((struct fcoe_port *)lport_priv(lport))->priv)->netdev; | 99 | ((struct fcoe_port *)lport_priv(lport))->priv)->netdev; |
100 | } | 100 | } |
101 | 101 | ||
102 | static inline void wwn_to_str(u64 wwn, char *buf, int len) | ||
103 | { | ||
104 | u8 wwpn[8]; | ||
105 | |||
106 | u64_to_wwn(wwn, wwpn); | ||
107 | snprintf(buf, len, "%02x%02x%02x%02x%02x%02x%02x%02x", | ||
108 | wwpn[0], wwpn[1], wwpn[2], wwpn[3], | ||
109 | wwpn[4], wwpn[5], wwpn[6], wwpn[7]); | ||
110 | } | ||
111 | |||
102 | #endif /* _FCOE_H_ */ | 112 | #endif /* _FCOE_H_ */ |