diff options
-rw-r--r-- | drivers/scsi/lpfc/lpfc.h | 3 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_attr.c | 84 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_hbadisc.c | 2 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_init.c | 2 |
4 files changed, 80 insertions, 11 deletions
diff --git a/drivers/scsi/lpfc/lpfc.h b/drivers/scsi/lpfc/lpfc.h index 1ec9cf0e374a..a7de0bca5bdd 100644 --- a/drivers/scsi/lpfc/lpfc.h +++ b/drivers/scsi/lpfc/lpfc.h @@ -306,6 +306,7 @@ struct lpfc_hba { uint32_t cfg_use_msi; uint32_t cfg_sg_seg_cnt; uint32_t cfg_sg_dma_buf_size; + uint64_t cfg_soft_wwnn; uint64_t cfg_soft_wwpn; uint32_t dev_loss_tmo_changed; @@ -358,7 +359,7 @@ struct lpfc_hba { #define VPD_PORT 0x8 /* valid vpd port data */ #define VPD_MASK 0xf /* mask for any vpd data */ - uint8_t soft_wwpn_enable; + uint8_t soft_wwn_enable; struct timer_list fcp_poll_timer; struct timer_list els_tmofunc; diff --git a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c index e2ac7ba3d8ad..f247e786af99 100644 --- a/drivers/scsi/lpfc/lpfc_attr.c +++ b/drivers/scsi/lpfc/lpfc_attr.c @@ -552,10 +552,10 @@ static CLASS_DEVICE_ATTR(board_mode, S_IRUGO | S_IWUSR, static CLASS_DEVICE_ATTR(issue_reset, S_IWUSR, NULL, lpfc_issue_reset); -static char *lpfc_soft_wwpn_key = "C99G71SL8032A"; +static char *lpfc_soft_wwn_key = "C99G71SL8032A"; static ssize_t -lpfc_soft_wwpn_enable_store(struct class_device *cdev, const char *buf, +lpfc_soft_wwn_enable_store(struct class_device *cdev, const char *buf, size_t count) { struct Scsi_Host *host = class_to_shost(cdev); @@ -579,15 +579,15 @@ lpfc_soft_wwpn_enable_store(struct class_device *cdev, const char *buf, if (buf[cnt-1] == '\n') cnt--; - if ((cnt != strlen(lpfc_soft_wwpn_key)) || - (strncmp(buf, lpfc_soft_wwpn_key, strlen(lpfc_soft_wwpn_key)) != 0)) + if ((cnt != strlen(lpfc_soft_wwn_key)) || + (strncmp(buf, lpfc_soft_wwn_key, strlen(lpfc_soft_wwn_key)) != 0)) return -EINVAL; - phba->soft_wwpn_enable = 1; + phba->soft_wwn_enable = 1; return count; } -static CLASS_DEVICE_ATTR(lpfc_soft_wwpn_enable, S_IWUSR, NULL, - lpfc_soft_wwpn_enable_store); +static CLASS_DEVICE_ATTR(lpfc_soft_wwn_enable, S_IWUSR, NULL, + lpfc_soft_wwn_enable_store); static ssize_t lpfc_soft_wwpn_show(struct class_device *cdev, char *buf) @@ -613,12 +613,12 @@ lpfc_soft_wwpn_store(struct class_device *cdev, const char *buf, size_t count) if (buf[cnt-1] == '\n') cnt--; - if (!phba->soft_wwpn_enable || (cnt < 16) || (cnt > 18) || + if (!phba->soft_wwn_enable || (cnt < 16) || (cnt > 18) || ((cnt == 17) && (*buf++ != 'x')) || ((cnt == 18) && ((*buf++ != '0') || (*buf++ != 'x')))) return -EINVAL; - phba->soft_wwpn_enable = 0; + phba->soft_wwn_enable = 0; memset(wwpn, 0, sizeof(wwpn)); @@ -639,6 +639,8 @@ lpfc_soft_wwpn_store(struct class_device *cdev, const char *buf, size_t count) } phba->cfg_soft_wwpn = wwn_to_u64(wwpn); fc_host_port_name(host) = phba->cfg_soft_wwpn; + if (phba->cfg_soft_wwnn) + fc_host_node_name(host) = phba->cfg_soft_wwnn; dev_printk(KERN_NOTICE, &phba->pcidev->dev, "lpfc%d: Reinitializing to use soft_wwpn\n", phba->brd_no); @@ -664,6 +666,66 @@ lpfc_soft_wwpn_store(struct class_device *cdev, const char *buf, size_t count) static CLASS_DEVICE_ATTR(lpfc_soft_wwpn, S_IRUGO | S_IWUSR,\ lpfc_soft_wwpn_show, lpfc_soft_wwpn_store); +static ssize_t +lpfc_soft_wwnn_show(struct class_device *cdev, char *buf) +{ + struct Scsi_Host *host = class_to_shost(cdev); + struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata; + return snprintf(buf, PAGE_SIZE, "0x%llx\n", + (unsigned long long)phba->cfg_soft_wwnn); +} + + +static ssize_t +lpfc_soft_wwnn_store(struct class_device *cdev, const char *buf, size_t count) +{ + struct Scsi_Host *host = class_to_shost(cdev); + struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata; + unsigned int i, j, cnt=count; + u8 wwnn[8]; + + /* count may include a LF at end of string */ + if (buf[cnt-1] == '\n') + cnt--; + + if (!phba->soft_wwn_enable || (cnt < 16) || (cnt > 18) || + ((cnt == 17) && (*buf++ != 'x')) || + ((cnt == 18) && ((*buf++ != '0') || (*buf++ != 'x')))) + return -EINVAL; + + /* + * Allow wwnn to be set many times, as long as the enable is set. + * However, once the wwpn is set, everything locks. + */ + + memset(wwnn, 0, sizeof(wwnn)); + + /* Validate and store the new name */ + for (i=0, j=0; i < 16; i++) { + if ((*buf >= 'a') && (*buf <= 'f')) + j = ((j << 4) | ((*buf++ -'a') + 10)); + else if ((*buf >= 'A') && (*buf <= 'F')) + j = ((j << 4) | ((*buf++ -'A') + 10)); + else if ((*buf >= '0') && (*buf <= '9')) + j = ((j << 4) | (*buf++ -'0')); + else + return -EINVAL; + if (i % 2) { + wwnn[i/2] = j & 0xff; + j = 0; + } + } + phba->cfg_soft_wwnn = wwn_to_u64(wwnn); + + dev_printk(KERN_NOTICE, &phba->pcidev->dev, + "lpfc%d: soft_wwnn set. Value will take effect upon " + "setting of the soft_wwpn\n", phba->brd_no); + + return count; +} +static CLASS_DEVICE_ATTR(lpfc_soft_wwnn, S_IRUGO | S_IWUSR,\ + lpfc_soft_wwnn_show, lpfc_soft_wwnn_store); + static int lpfc_poll = 0; module_param(lpfc_poll, int, 0); @@ -1009,8 +1071,9 @@ struct class_device_attribute *lpfc_host_attrs[] = { &class_device_attr_lpfc_poll, &class_device_attr_lpfc_poll_tmo, &class_device_attr_lpfc_use_msi, + &class_device_attr_lpfc_soft_wwnn, &class_device_attr_lpfc_soft_wwpn, - &class_device_attr_lpfc_soft_wwpn_enable, + &class_device_attr_lpfc_soft_wwn_enable, NULL, }; @@ -1815,6 +1878,7 @@ lpfc_get_cfgparam(struct lpfc_hba *phba) lpfc_devloss_tmo_init(phba, lpfc_devloss_tmo); lpfc_nodev_tmo_init(phba, lpfc_nodev_tmo); phba->cfg_poll = lpfc_poll; + phba->cfg_soft_wwnn = 0L; phba->cfg_soft_wwpn = 0L; /* diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c index 1118b6d49fcc..c39564e85e94 100644 --- a/drivers/scsi/lpfc/lpfc_hbadisc.c +++ b/drivers/scsi/lpfc/lpfc_hbadisc.c @@ -672,6 +672,8 @@ lpfc_mbx_cmpl_read_sparam(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb) memcpy((uint8_t *) & phba->fc_sparam, (uint8_t *) mp->virt, sizeof (struct serv_parm)); + if (phba->cfg_soft_wwnn) + u64_to_wwn(phba->cfg_soft_wwnn, phba->fc_sparam.nodeName.u.wwn); if (phba->cfg_soft_wwpn) u64_to_wwn(phba->cfg_soft_wwpn, phba->fc_sparam.portName.u.wwn); memcpy((uint8_t *) & phba->fc_nodename, diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index b872519e2ced..cf9081c262d7 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c @@ -268,6 +268,8 @@ lpfc_config_port_post(struct lpfc_hba * phba) kfree(mp); pmb->context1 = NULL; + if (phba->cfg_soft_wwnn) + u64_to_wwn(phba->cfg_soft_wwnn, phba->fc_sparam.nodeName.u.wwn); if (phba->cfg_soft_wwpn) u64_to_wwn(phba->cfg_soft_wwpn, phba->fc_sparam.portName.u.wwn); memcpy(&phba->fc_nodename, &phba->fc_sparam.nodeName, |