diff options
author | James Smart <james.smart@emulex.com> | 2011-12-13 22:20:45 +0400 |
---|---|---|
committer | James Bottomley <JBottomley@Parallels.com> | 2011-12-15 10:57:43 +0400 |
commit | 026abb87a5586c838a47aca7198d78e356b6351e (patch) | |
tree | 39c99398f8aab41fd7623f1d9a79197565a8f2e2 /drivers/scsi/lpfc/lpfc_attr.c | |
parent | 2cb6fc8c014b9b00c4487a79b8f6ed0da4121f45 (diff) | |
download | linux-026abb87a5586c838a47aca7198d78e356b6351e.tar.xz |
[SCSI] lpfc 8.3.28: Miscellaneous fixes in sysfs and mgmt interfaces
Miscellaneous fixes in sysfs and mgmt interfaces:
- Added SLI4 INTF_TYPE and SLI_FAMILY as sub-field to the fwrev sysfs
attribute (CR 124103)
- Added a sysfs attribute "protocol" to report SLI4 port link protocol
type (CR 124102)
- Increment mix-and-match minor number by 1 for added "protocol" sysfs
attribute. (124102)
- Move the link speed check into the generic sli3/sli4 code
path. (CR 124185, 124122)
- Deleted check for inExtWLen (CR 122523)
- Add the word "offline" to message 2889 (CR 124385)
- Conditionalize the firmware upgrade/downgrade so that it is only
attempted for SLI4 type 2 boards (CR 124406)
- Return an error if the mbox sysfs is called. (CR 124210)
- When port_state is less than LPFC_VPORT_READY, report
FC_PORTSTATE_BYPASSED (CR 120018)
- Added driver support for performing persistent linkdown based on
configure region 23 (CR 124534)
- Added restore state and error log when sysfs board_mode attribute
access failed (CR 124158)
- Added support for SLI4_CONFIG non-embedded COMN_GET_CNTL_ADDL_ATTR
pass-through (CR 124466)
- Rejecting un-supported multi-buffer mailbox commands (CR 124771)
- Byte swap the extended data request and response data for extended
mailbox data (CR 125081)
Signed-off-by: Alex Iannicelli <alex.iannicelli@emulex.com>
Signed-off-by: James Smart <james.smart@emulex.com>
Signed-off-by: James Bottomley <JBottomley@Parallels.com>
Diffstat (limited to 'drivers/scsi/lpfc/lpfc_attr.c')
-rw-r--r-- | drivers/scsi/lpfc/lpfc_attr.c | 413 |
1 files changed, 128 insertions, 285 deletions
diff --git a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c index d0ebaeb7ef60..7bf492e156d9 100644 --- a/drivers/scsi/lpfc/lpfc_attr.c +++ b/drivers/scsi/lpfc/lpfc_attr.c @@ -351,10 +351,23 @@ lpfc_fwrev_show(struct device *dev, struct device_attribute *attr, struct Scsi_Host *shost = class_to_shost(dev); struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; struct lpfc_hba *phba = vport->phba; + uint32_t if_type; + uint8_t sli_family; char fwrev[32]; + int len; lpfc_decode_firmware_rev(phba, fwrev, 1); - return snprintf(buf, PAGE_SIZE, "%s, sli-%d\n", fwrev, phba->sli_rev); + if_type = phba->sli4_hba.pc_sli4_params.if_type; + sli_family = phba->sli4_hba.pc_sli4_params.sli_family; + + if (phba->sli_rev < LPFC_SLI_REV4) + len = snprintf(buf, PAGE_SIZE, "%s, sli-%d\n", + fwrev, phba->sli_rev); + else + len = snprintf(buf, PAGE_SIZE, "%s, sli-%d:%d:%x\n", + fwrev, phba->sli_rev, if_type, sli_family); + + return len; } /** @@ -488,6 +501,34 @@ lpfc_link_state_show(struct device *dev, struct device_attribute *attr, } /** + * lpfc_sli4_protocol_show - Return the fip mode of the HBA + * @dev: class unused variable. + * @attr: device attribute, not used. + * @buf: on return contains the module description text. + * + * Returns: size of formatted string. + **/ +static ssize_t +lpfc_sli4_protocol_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct Scsi_Host *shost = class_to_shost(dev); + struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; + struct lpfc_hba *phba = vport->phba; + + if (phba->sli_rev < LPFC_SLI_REV4) + return snprintf(buf, PAGE_SIZE, "fc\n"); + + if (phba->sli4_hba.lnk_info.lnk_dv == LPFC_LNK_DAT_VAL) { + if (phba->sli4_hba.lnk_info.lnk_tp == LPFC_LNK_TYPE_GE) + return snprintf(buf, PAGE_SIZE, "fcoe\n"); + if (phba->sli4_hba.lnk_info.lnk_tp == LPFC_LNK_TYPE_FC) + return snprintf(buf, PAGE_SIZE, "fc\n"); + } + return snprintf(buf, PAGE_SIZE, "unknown\n"); +} + +/** * lpfc_link_state_store - Transition the link_state on an HBA port * @dev: class device that is converted into a Scsi_host. * @attr: device attribute, not used. @@ -773,7 +814,12 @@ lpfc_issue_reset(struct device *dev, struct device_attribute *attr, * the readyness after performing a firmware reset. * * Returns: - * zero for success + * zero for success, -EPERM when port does not have privilage to perform the + * reset, -EIO when port timeout from recovering from the reset. + * + * Note: + * As the caller will interpret the return code by value, be careful in making + * change or addition to return codes. **/ int lpfc_sli4_pdev_status_reg_wait(struct lpfc_hba *phba) @@ -826,9 +872,11 @@ lpfc_sli4_pdev_reg_request(struct lpfc_hba *phba, uint32_t opcode) { struct completion online_compl; struct pci_dev *pdev = phba->pcidev; + uint32_t before_fc_flag; + uint32_t sriov_nr_virtfn; uint32_t reg_val; - int status = 0; - int rc; + int status = 0, rc = 0; + int job_posted = 1, sriov_err; if (!phba->cfg_enable_hba_reset) return -EACCES; @@ -838,6 +886,10 @@ lpfc_sli4_pdev_reg_request(struct lpfc_hba *phba, uint32_t opcode) LPFC_SLI_INTF_IF_TYPE_2)) return -EPERM; + /* Keep state if we need to restore back */ + before_fc_flag = phba->pport->fc_flag; + sriov_nr_virtfn = phba->cfg_sriov_nr_virtfn; + /* Disable SR-IOV virtual functions if enabled */ if (phba->cfg_sriov_nr_virtfn) { pci_disable_sriov(pdev); @@ -869,21 +921,44 @@ lpfc_sli4_pdev_reg_request(struct lpfc_hba *phba, uint32_t opcode) /* delay driver action following IF_TYPE_2 reset */ rc = lpfc_sli4_pdev_status_reg_wait(phba); - if (rc) + if (rc == -EPERM) { + /* no privilage for reset, restore if needed */ + if (before_fc_flag & FC_OFFLINE_MODE) + goto out; + } else if (rc == -EIO) { + /* reset failed, there is nothing more we can do */ return rc; + } + + /* keep the original port state */ + if (before_fc_flag & FC_OFFLINE_MODE) + goto out; init_completion(&online_compl); - rc = lpfc_workq_post_event(phba, &status, &online_compl, - LPFC_EVT_ONLINE); - if (rc == 0) - return -ENOMEM; + job_posted = lpfc_workq_post_event(phba, &status, &online_compl, + LPFC_EVT_ONLINE); + if (!job_posted) + goto out; wait_for_completion(&online_compl); - if (status != 0) - return -EIO; +out: + /* in any case, restore the virtual functions enabled as before */ + if (sriov_nr_virtfn) { + sriov_err = + lpfc_sli_probe_sriov_nr_virtfn(phba, sriov_nr_virtfn); + if (!sriov_err) + phba->cfg_sriov_nr_virtfn = sriov_nr_virtfn; + } - return 0; + /* return proper error code */ + if (!rc) { + if (!job_posted) + rc = -ENOMEM; + else if (status) + rc = -EIO; + } + return rc; } /** @@ -955,33 +1030,38 @@ lpfc_board_mode_store(struct device *dev, struct device_attribute *attr, struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; struct lpfc_hba *phba = vport->phba; struct completion online_compl; - int status=0; + char *board_mode_str = NULL; + int status = 0; int rc; - if (!phba->cfg_enable_hba_reset) - return -EACCES; + if (!phba->cfg_enable_hba_reset) { + status = -EACCES; + goto board_mode_out; + } lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT, - "3050 lpfc_board_mode set to %s\n", buf); + "3050 lpfc_board_mode set to %s\n", buf); init_completion(&online_compl); if(strncmp(buf, "online", sizeof("online") - 1) == 0) { rc = lpfc_workq_post_event(phba, &status, &online_compl, LPFC_EVT_ONLINE); - if (rc == 0) - return -ENOMEM; + if (rc == 0) { + status = -ENOMEM; + goto board_mode_out; + } wait_for_completion(&online_compl); } else if (strncmp(buf, "offline", sizeof("offline") - 1) == 0) status = lpfc_do_offline(phba, LPFC_EVT_OFFLINE); else if (strncmp(buf, "warm", sizeof("warm") - 1) == 0) if (phba->sli_rev == LPFC_SLI_REV4) - return -EINVAL; + status = -EINVAL; else status = lpfc_do_offline(phba, LPFC_EVT_WARM_START); else if (strncmp(buf, "error", sizeof("error") - 1) == 0) if (phba->sli_rev == LPFC_SLI_REV4) - return -EINVAL; + status = -EINVAL; else status = lpfc_do_offline(phba, LPFC_EVT_KILL); else if (strncmp(buf, "dump", sizeof("dump") - 1) == 0) @@ -991,12 +1071,21 @@ lpfc_board_mode_store(struct device *dev, struct device_attribute *attr, else if (strncmp(buf, "dv_reset", sizeof("dv_reset") - 1) == 0) status = lpfc_sli4_pdev_reg_request(phba, LPFC_DV_RESET); else - return -EINVAL; + status = -EINVAL; +board_mode_out: if (!status) return strlen(buf); - else + else { + board_mode_str = strchr(buf, '\n'); + if (board_mode_str) + *board_mode_str = '\0'; + lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT, + "3097 Failed \"%s\", status(%d), " + "fc_flag(x%x)\n", + buf, status, phba->pport->fc_flag); return status; + } } /** @@ -1942,6 +2031,7 @@ static DEVICE_ATTR(lpfc_fips_rev, S_IRUGO, lpfc_fips_rev_show, NULL); static DEVICE_ATTR(lpfc_dss, S_IRUGO, lpfc_dss_show, NULL); static DEVICE_ATTR(lpfc_sriov_hw_max_virtfn, S_IRUGO, lpfc_sriov_hw_max_virtfn_show, NULL); +static DEVICE_ATTR(protocol, S_IRUGO, lpfc_sli4_protocol_show, NULL); static char *lpfc_soft_wwn_key = "C99G71SL8032A"; @@ -3830,6 +3920,7 @@ struct device_attribute *lpfc_hba_attrs[] = { &dev_attr_lpfc_fips_rev, &dev_attr_lpfc_dss, &dev_attr_lpfc_sriov_hw_max_virtfn, + &dev_attr_protocol, NULL, }; @@ -3988,23 +4079,6 @@ static struct bin_attribute sysfs_ctlreg_attr = { }; /** - * sysfs_mbox_idle - frees the sysfs mailbox - * @phba: lpfc_hba pointer - **/ -static void -sysfs_mbox_idle(struct lpfc_hba *phba) -{ - phba->sysfs_mbox.state = SMBOX_IDLE; - phba->sysfs_mbox.offset = 0; - - if (phba->sysfs_mbox.mbox) { - mempool_free(phba->sysfs_mbox.mbox, - phba->mbox_mem_pool); - phba->sysfs_mbox.mbox = NULL; - } -} - -/** * sysfs_mbox_write - Write method for writing information via mbox * @filp: open sysfs file * @kobj: kernel kobject that contains the kernel class device. @@ -4014,71 +4088,18 @@ sysfs_mbox_idle(struct lpfc_hba *phba) * @count: bytes to transfer. * * Description: - * Accessed via /sys/class/scsi_host/hostxxx/mbox. - * Uses the sysfs mbox to send buf contents to the adapter. + * Deprecated function. All mailbox access from user space is performed via the + * bsg interface. * * Returns: - * -ERANGE off and count combo out of range - * -EINVAL off, count or buff address invalid - * zero if count is zero - * -EPERM adapter is offline - * -ENOMEM failed to allocate memory for the mail box - * -EAGAIN offset, state or mbox is NULL - * count number of bytes transferred + * -EPERM operation not permitted **/ static ssize_t sysfs_mbox_write(struct file *filp, struct kobject *kobj, struct bin_attribute *bin_attr, char *buf, loff_t off, size_t count) { - struct device *dev = container_of(kobj, struct device, kobj); - struct Scsi_Host *shost = class_to_shost(dev); - struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; - struct lpfc_hba *phba = vport->phba; - struct lpfcMboxq *mbox = NULL; - - if ((count + off) > MAILBOX_CMD_SIZE) - return -ERANGE; - - if (off % 4 || count % 4 || (unsigned long)buf % 4) - return -EINVAL; - - if (count == 0) - return 0; - - if (off == 0) { - mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); - if (!mbox) - return -ENOMEM; - memset(mbox, 0, sizeof (LPFC_MBOXQ_t)); - } - - spin_lock_irq(&phba->hbalock); - - if (off == 0) { - if (phba->sysfs_mbox.mbox) - mempool_free(mbox, phba->mbox_mem_pool); - else - phba->sysfs_mbox.mbox = mbox; - phba->sysfs_mbox.state = SMBOX_WRITING; - } else { - if (phba->sysfs_mbox.state != SMBOX_WRITING || - phba->sysfs_mbox.offset != off || - phba->sysfs_mbox.mbox == NULL) { - sysfs_mbox_idle(phba); - spin_unlock_irq(&phba->hbalock); - return -EAGAIN; - } - } - - memcpy((uint8_t *) &phba->sysfs_mbox.mbox->u.mb + off, - buf, count); - - phba->sysfs_mbox.offset = off + count; - - spin_unlock_irq(&phba->hbalock); - - return count; + return -EPERM; } /** @@ -4091,201 +4112,18 @@ sysfs_mbox_write(struct file *filp, struct kobject *kobj, * @count: bytes to transfer. * * Description: - * Accessed via /sys/class/scsi_host/hostxxx/mbox. - * Uses the sysfs mbox to receive data from to the adapter. + * Deprecated function. All mailbox access from user space is performed via the + * bsg interface. * * Returns: - * -ERANGE off greater than mailbox command size - * -EINVAL off, count or buff address invalid - * zero if off and count are zero - * -EACCES adapter over temp - * -EPERM garbage can value to catch a multitude of errors - * -EAGAIN management IO not permitted, state or off error - * -ETIME mailbox timeout - * -ENODEV mailbox error - * count number of bytes transferred + * -EPERM operation not permitted **/ static ssize_t sysfs_mbox_read(struct file *filp, struct kobject *kobj, struct bin_attribute *bin_attr, char *buf, loff_t off, size_t count) { - struct device *dev = container_of(kobj, struct device, kobj); - struct Scsi_Host *shost = class_to_shost(dev); - struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; - struct lpfc_hba *phba = vport->phba; - LPFC_MBOXQ_t *mboxq; - MAILBOX_t *pmb; - uint32_t mbox_tmo; - int rc; - - if (off > MAILBOX_CMD_SIZE) - return -ERANGE; - - if ((count + off) > MAILBOX_CMD_SIZE) - count = MAILBOX_CMD_SIZE - off; - - if (off % 4 || count % 4 || (unsigned long)buf % 4) - return -EINVAL; - - if (off && count == 0) - return 0; - - spin_lock_irq(&phba->hbalock); - - if (phba->over_temp_state == HBA_OVER_TEMP) { - sysfs_mbox_idle(phba); - spin_unlock_irq(&phba->hbalock); - return -EACCES; - } - - if (off == 0 && - phba->sysfs_mbox.state == SMBOX_WRITING && - phba->sysfs_mbox.offset >= 2 * sizeof(uint32_t)) { - mboxq = (LPFC_MBOXQ_t *)&phba->sysfs_mbox.mbox; - pmb = &mboxq->u.mb; - switch (pmb->mbxCommand) { - /* Offline only */ - case MBX_INIT_LINK: - case MBX_DOWN_LINK: - case MBX_CONFIG_LINK: - case MBX_CONFIG_RING: - case MBX_RESET_RING: - case MBX_UNREG_LOGIN: - case MBX_CLEAR_LA: - case MBX_DUMP_CONTEXT: - case MBX_RUN_DIAGS: - case MBX_RESTART: - case MBX_SET_MASK: - case MBX_SET_DEBUG: - if (!(vport->fc_flag & FC_OFFLINE_MODE)) { - printk(KERN_WARNING "mbox_read:Command 0x%x " - "is illegal in on-line state\n", - pmb->mbxCommand); - sysfs_mbox_idle(phba); - spin_unlock_irq(&phba->hbalock); - return -EPERM; - } - case MBX_WRITE_NV: - case MBX_WRITE_VPARMS: - case MBX_LOAD_SM: - case MBX_READ_NV: - case MBX_READ_CONFIG: - case MBX_READ_RCONFIG: - case MBX_READ_STATUS: - case MBX_READ_XRI: - case MBX_READ_REV: - case MBX_READ_LNK_STAT: - case MBX_DUMP_MEMORY: - case MBX_DOWN_LOAD: - case MBX_UPDATE_CFG: - case MBX_KILL_BOARD: - case MBX_LOAD_AREA: - case MBX_LOAD_EXP_ROM: - case MBX_BEACON: - case MBX_DEL_LD_ENTRY: - case MBX_SET_VARIABLE: - case MBX_WRITE_WWN: - case MBX_PORT_CAPABILITIES: - case MBX_PORT_IOV_CONTROL: - break; - case MBX_SECURITY_MGMT: - case MBX_AUTH_PORT: - if (phba->pci_dev_grp == LPFC_PCI_DEV_OC) { - printk(KERN_WARNING "mbox_read:Command 0x%x " - "is not permitted\n", pmb->mbxCommand); - sysfs_mbox_idle(phba); - spin_unlock_irq(&phba->hbalock); - return -EPERM; - } - break; - case MBX_READ_SPARM64: - case MBX_READ_TOPOLOGY: - case MBX_REG_LOGIN: - case MBX_REG_LOGIN64: - case MBX_CONFIG_PORT: - case MBX_RUN_BIU_DIAG: - printk(KERN_WARNING "mbox_read: Illegal Command 0x%x\n", - pmb->mbxCommand); - sysfs_mbox_idle(phba); - spin_unlock_irq(&phba->hbalock); - return -EPERM; - default: - printk(KERN_WARNING "mbox_read: Unknown Command 0x%x\n", - pmb->mbxCommand); - sysfs_mbox_idle(phba); - spin_unlock_irq(&phba->hbalock); - return -EPERM; - } - - /* If HBA encountered an error attention, allow only DUMP - * or RESTART mailbox commands until the HBA is restarted. - */ - if (phba->pport->stopped && - pmb->mbxCommand != MBX_DUMP_MEMORY && - pmb->mbxCommand != MBX_RESTART && - pmb->mbxCommand != MBX_WRITE_VPARMS && - pmb->mbxCommand != MBX_WRITE_WWN) - lpfc_printf_log(phba, KERN_WARNING, LOG_MBOX, - "1259 mbox: Issued mailbox cmd " - "0x%x while in stopped state.\n", - pmb->mbxCommand); - - phba->sysfs_mbox.mbox->vport = vport; - - /* Don't allow mailbox commands to be sent when blocked - * or when in the middle of discovery - */ - if (phba->sli.sli_flag & LPFC_BLOCK_MGMT_IO) { - sysfs_mbox_idle(phba); - spin_unlock_irq(&phba->hbalock); - return -EAGAIN; - } - - if ((vport->fc_flag & FC_OFFLINE_MODE) || - (!(phba->sli.sli_flag & LPFC_SLI_ACTIVE))) { - - spin_unlock_irq(&phba->hbalock); - rc = lpfc_sli_issue_mbox (phba, - phba->sysfs_mbox.mbox, - MBX_POLL); - spin_lock_irq(&phba->hbalock); - - } else { - spin_unlock_irq(&phba->hbalock); - mbox_tmo = lpfc_mbox_tmo_val(phba, mboxq); - rc = lpfc_sli_issue_mbox_wait(phba, mboxq, mbox_tmo); - spin_lock_irq(&phba->hbalock); - } - - if (rc != MBX_SUCCESS) { - if (rc == MBX_TIMEOUT) { - phba->sysfs_mbox.mbox = NULL; - } - sysfs_mbox_idle(phba); - spin_unlock_irq(&phba->hbalock); - return (rc == MBX_TIMEOUT) ? -ETIME : -ENODEV; - } - phba->sysfs_mbox.state = SMBOX_READING; - } - else if (phba->sysfs_mbox.offset != off || - phba->sysfs_mbox.state != SMBOX_READING) { - printk(KERN_WARNING "mbox_read: Bad State\n"); - sysfs_mbox_idle(phba); - spin_unlock_irq(&phba->hbalock); - return -EAGAIN; - } - - memcpy(buf, (uint8_t *) &pmb + off, count); - - phba->sysfs_mbox.offset = off + count; - - if (phba->sysfs_mbox.offset == MAILBOX_CMD_SIZE) - sysfs_mbox_idle(phba); - - spin_unlock_irq(&phba->hbalock); - - return count; + return -EPERM; } static struct bin_attribute sysfs_mbox_attr = { @@ -4429,8 +4267,13 @@ lpfc_get_host_port_state(struct Scsi_Host *shost) case LPFC_LINK_UP: case LPFC_CLEAR_LA: case LPFC_HBA_READY: - /* Links up, beyond this port_type reports state */ - fc_host_port_state(shost) = FC_PORTSTATE_ONLINE; + /* Links up, reports port state accordingly */ + if (vport->port_state < LPFC_VPORT_READY) + fc_host_port_state(shost) = + FC_PORTSTATE_BYPASSED; + else + fc_host_port_state(shost) = + FC_PORTSTATE_ONLINE; break; case LPFC_HBA_ERROR: fc_host_port_state(shost) = FC_PORTSTATE_ERROR; |