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 | |
| 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>
| -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_ */ |
