/******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * * Copyright (C) 2017-2025 Broadcom. All Rights Reserved. The term * * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. * * Copyright (C) 2004-2016 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * * www.broadcom.com * * Portions Copyright (C) 2004-2005 Christoph Hellwig * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of version 2 of the GNU General * * Public License as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful. * * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND * * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, * * FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT, ARE * * DISCLAIMED, EXCEPT TO THE EXTENT THAT SUCH DISCLAIMERS ARE HELD * * TO BE LEGALLY INVALID. See the GNU General Public License for * * more details, a copy of which can be found in the file COPYING * * included with this package. *
*******************************************************************/
#define LPFC_MAX_INFO_TMP_LEN 100 #define LPFC_INFO_MORE_STR "\nCould be more info...\n" /* * Write key size should be multiple of 4. If write key is changed * make sure that library write key is also changed.
*/ #define LPFC_REG_WRITE_KEY_SIZE 4 #define LPFC_REG_WRITE_KEY "EMLX"
constchar *const trunk_errmsg[] = { /* map errcode */ "", /* There is no such error code at index 0*/ "link negotiated speed does not match existing" " trunk - link was \"low\" speed", "link negotiated speed does not match" " existing trunk - link was \"middle\" speed", "link negotiated speed does not match existing" " trunk - link was \"high\" speed", "Attached to non-trunking port - F_Port", "Attached to non-trunking port - N_Port", "FLOGI response timeout", "non-FLOGI frame received", "Invalid FLOGI response", "Trunking initialization protocol", "Trunk peer device mismatch",
};
/** * lpfc_jedec_to_ascii - Hex to ascii convertor according to JEDEC rules * @incr: integer to convert. * @hdw: ascii string holding converted integer plus a string terminator. * * Description: * JEDEC Joint Electron Device Engineering Council. * Convert a 32 bit integer composed of 8 nibbles into an 8 byte ascii * character string. The string is then terminated with a NULL in byte 9. * Hex 0-9 becomes ascii '0' to '9'. * Hex a-f becomes ascii '=' to 'B' capital B. * * Notes: * Coded for 32 bit integers only.
**/ staticvoid
lpfc_jedec_to_ascii(int incr, char hdw[])
{ int i, j; for (i = 0; i < 8; i++) {
j = (incr & 0xf); if (j <= 9)
hdw[7 - i] = 0x30 + j; else
hdw[7 - i] = 0x61 + j - 10;
incr = (incr >> 4);
}
hdw[8] = 0; return;
}
if (!(vport->cfg_enable_fc4_type & LPFC_ENABLE_NVME)) {
len = scnprintf(buf, PAGE_SIZE, "NVME Disabled\n"); return len;
} if (phba->nvmet_support) { if (!phba->targetport) {
len = scnprintf(buf, PAGE_SIZE, "NVME Target: x%llx is not allocated\n",
wwn_to_u64(vport->fc_portname.u.wwn)); return len;
} /* Port state is only one of two values for now. */ if (phba->targetport->port_id)
statep = "REGISTERED"; else
statep = "INIT";
scnprintf(tmp, sizeof(tmp), "NVME Target Enabled State %s\n",
statep); if (strlcat(buf, tmp, PAGE_SIZE) >= PAGE_SIZE) goto buffer_done;
list_for_each_entry(ndlp, &vport->fc_nodes, nlp_listp) {
nrport = NULL;
spin_lock(&ndlp->lock);
rport = lpfc_ndlp_get_nrport(ndlp); if (rport)
nrport = rport->remoteport;
spin_unlock(&ndlp->lock); if (!nrport) continue;
/* Port state is only one of two values for now. */ switch (nrport->port_state) { case FC_OBJSTATE_ONLINE:
statep = "ONLINE"; break; case FC_OBJSTATE_UNKNOWN:
statep = "UNKNOWN "; break; default:
statep = "UNSUPPORTED"; break;
}
/* Tab in to show lport ownership. */ if (strlcat(buf, "NVME RPORT ", PAGE_SIZE) >= PAGE_SIZE) goto unlock_buf_done; if (phba->brd_no >= 10) { if (strlcat(buf, " ", PAGE_SIZE) >= PAGE_SIZE) goto unlock_buf_done;
}
/** * lpfc_info_show - Return some pci info about the host in ascii * @dev: class converted to a Scsi_host structure. * @attr: device attribute, not used. * @buf: on return contains the formatted text from lpfc_info(). * * Returns: size of formatted string.
**/ static ssize_t
lpfc_info_show(struct device *dev, struct device_attribute *attr, char *buf)
{ struct Scsi_Host *host = class_to_shost(dev);
/** * lpfc_temp_sensor_show - Return the temperature sensor level * @dev: class converted to a Scsi_host structure. * @attr: device attribute, not used. * @buf: on return contains the formatted support level. * * Description: * Returns a number indicating the temperature sensor level currently * supported, zero or one in ascii. * * Returns: size of formatted string.
**/ static ssize_t
lpfc_temp_sensor_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; return scnprintf(buf, PAGE_SIZE, "%d\n", phba->temp_sensor_support);
}
/** * lpfc_modeldesc_show - Return the model description of the hba * @dev: class converted to a Scsi_host structure. * @attr: device attribute, not used. * @buf: on return contains the scsi vpd model description. * * Returns: size of formatted string.
**/ static ssize_t
lpfc_modeldesc_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;
/** * lpfc_link_state_show - Return the link state of the port * @dev: class converted to a Scsi_host structure. * @attr: device attribute, not used. * @buf: on return contains text describing the state of the link. * * Notes: * The switch statement has no default so zero will be returned. * * Returns: size of formatted string.
**/ static ssize_t
lpfc_link_state_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; int len = 0;
switch (phba->link_state) { case LPFC_LINK_UNKNOWN: case LPFC_WARM_START: case LPFC_INIT_START: case LPFC_INIT_MBX_CMDS: case LPFC_LINK_DOWN: case LPFC_HBA_ERROR: if (test_bit(LINK_DISABLED, &phba->hba_flag))
len += scnprintf(buf + len, PAGE_SIZE-len, "Link Down - User disabled\n"); else
len += scnprintf(buf + len, PAGE_SIZE-len, "Link Down\n"); break; case LPFC_LINK_UP: case LPFC_CLEAR_LA: case LPFC_HBA_READY:
len += scnprintf(buf + len, PAGE_SIZE-len, "Link Up - ");
switch (vport->port_state) { case LPFC_LOCAL_CFG_LINK:
len += scnprintf(buf + len, PAGE_SIZE-len, "Configuring Link\n"); break; case LPFC_FDISC: case LPFC_FLOGI: case LPFC_FABRIC_CFG_LINK: case LPFC_NS_REG: case LPFC_NS_QRY: case LPFC_BUILD_DISC_LIST: case LPFC_DISC_AUTH:
len += scnprintf(buf + len, PAGE_SIZE - len, "Discovery\n"); break; case LPFC_VPORT_READY:
len += scnprintf(buf + len, PAGE_SIZE - len, "Ready\n"); break;
case LPFC_VPORT_FAILED:
len += scnprintf(buf + len, PAGE_SIZE - len, "Failed\n"); break;
case LPFC_VPORT_UNKNOWN:
len += scnprintf(buf + len, PAGE_SIZE - len, "Unknown\n"); break;
} if (phba->fc_topology == LPFC_TOPOLOGY_LOOP) { if (test_bit(FC_PUBLIC_LOOP, &vport->fc_flag))
len += scnprintf(buf + len, PAGE_SIZE-len, " Public Loop\n"); else
len += scnprintf(buf + len, PAGE_SIZE-len, " Private Loop\n");
} else { if (test_bit(FC_FABRIC, &vport->fc_flag)) { if (phba->sli_rev == LPFC_SLI_REV4 &&
vport->port_type == LPFC_PHYSICAL_PORT &&
phba->sli4_hba.fawwpn_flag &
LPFC_FAWWPN_FABRIC)
len += scnprintf(buf + len,
PAGE_SIZE - len, " Fabric FA-PWWN\n"); else
len += scnprintf(buf + len,
PAGE_SIZE - len, " Fabric\n");
} else {
len += scnprintf(buf + len, PAGE_SIZE-len, " Point-2-Point\n");
}
}
}
if ((phba->sli_rev == LPFC_SLI_REV4) &&
((bf_get(lpfc_sli_intf_if_type,
&phba->sli4_hba.sli_intf) ==
LPFC_SLI_INTF_IF_TYPE_6))) { struct lpfc_trunk_link link = phba->trunk_link;
if (bf_get(lpfc_conf_trunk_port0, &phba->sli4_hba))
len += scnprintf(buf + len, PAGE_SIZE - len, "Trunk port 0: Link %s %s\n",
(link.link0.state == LPFC_LINK_UP) ? "Up" : "Down. ",
trunk_errmsg[link.link0.fault]);
if (bf_get(lpfc_conf_trunk_port1, &phba->sli4_hba))
len += scnprintf(buf + len, PAGE_SIZE - len, "Trunk port 1: Link %s %s\n",
(link.link1.state == LPFC_LINK_UP) ? "Up" : "Down. ",
trunk_errmsg[link.link1.fault]);
if (bf_get(lpfc_conf_trunk_port2, &phba->sli4_hba))
len += scnprintf(buf + len, PAGE_SIZE - len, "Trunk port 2: Link %s %s\n",
(link.link2.state == LPFC_LINK_UP) ? "Up" : "Down. ",
trunk_errmsg[link.link2.fault]);
if (bf_get(lpfc_conf_trunk_port3, &phba->sli4_hba))
len += scnprintf(buf + len, PAGE_SIZE - len, "Trunk port 3: Link %s %s\n",
(link.link3.state == LPFC_LINK_UP) ? "Up" : "Down. ",
trunk_errmsg[link.link3.fault]);
}
return len;
}
/** * 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 scnprintf(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 scnprintf(buf, PAGE_SIZE, "fcoe\n"); if (phba->sli4_hba.lnk_info.lnk_tp == LPFC_LNK_TYPE_FC) return scnprintf(buf, PAGE_SIZE, "fc\n");
} return scnprintf(buf, PAGE_SIZE, "unknown\n");
}
/** * lpfc_oas_supported_show - Return whether or not Optimized Access Storage * (OAS) is supported. * @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_oas_supported_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;
/** * 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. * @buf: one or more lpfc_polling_flags values. * @count: not used. * * Returns: * -EINVAL if the buffer is not "up" or "down" * return from link state change function if non-zero * length of the buf on success
**/ static ssize_t
lpfc_link_state_store(struct device *dev, struct device_attribute *attr, constchar *buf, size_t count)
{ struct Scsi_Host *shost = class_to_shost(dev); struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; struct lpfc_hba *phba = vport->phba;
if (status == 0) return strlen(buf); else return status;
}
/** * lpfc_num_discovered_ports_show - Return sum of mapped and unmapped vports * @dev: class device that is converted into a Scsi_host. * @attr: device attribute, not used. * @buf: on return contains the sum of fc mapped and unmapped. * * Description: * Returns the ascii text number of the sum of the fc mapped and unmapped * vport counts. * * Returns: size of formatted string.
**/ static ssize_t
lpfc_num_discovered_ports_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;
/** * lpfc_issue_lip - Misnomer, name carried over from long ago * @shost: Scsi_Host pointer. * * Description: * Bring the link down gracefully then re-init the link. The firmware will * re-init the fiber channel interface as required. Does not issue a LIP. * * Returns: * -EPERM port offline or management commands are being blocked * -ENOMEM cannot allocate memory for the mailbox command * -EIO error sending the mailbox command * zero for success
**/ staticint
lpfc_issue_lip(struct Scsi_Host *shost)
{ struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; struct lpfc_hba *phba = vport->phba;
LPFC_MBOXQ_t *pmboxq; int mbxstatus = MBXERR_ERROR;
/* * If the link is offline, disabled or BLOCK_MGMT_IO * it doesn't make any sense to allow issue_lip
*/ if (test_bit(FC_OFFLINE_MODE, &vport->fc_flag) ||
test_bit(LINK_DISABLED, &phba->hba_flag) ||
(phba->sli.sli_flag & LPFC_BLOCK_MGMT_IO)) return -EPERM;
/** * lpfc_do_offline - Issues a mailbox command to bring the link down * @phba: lpfc_hba pointer. * @type: LPFC_EVT_OFFLINE, LPFC_EVT_WARM_START, LPFC_EVT_KILL. * * Notes: * Assumes any error from lpfc_do_offline() will be negative. * Can wait up to 5 seconds for the port ring buffers count * to reach zero, prints a warning if it is not zero and continues. * lpfc_workq_post_event() returns a non-zero return code if call fails. * * Returns: * -EIO error posting the event * zero for success
**/ staticint
lpfc_do_offline(struct lpfc_hba *phba, uint32_t type)
{ struct completion online_compl; struct lpfc_queue *qp = NULL; struct lpfc_sli_ring *pring; struct lpfc_sli *psli; int status = 0; int i; int rc;
/* * If freeing the queues have already started, don't access them. * Otherwise set FREE_WAIT to indicate that queues are being used * to hold the freeing process until we finish.
*/
spin_lock_irq(&phba->hbalock); if (!(psli->sli_flag & LPFC_QUEUE_FREE_INIT)) {
psli->sli_flag |= LPFC_QUEUE_FREE_WAIT;
} else {
spin_unlock_irq(&phba->hbalock); goto skip_wait;
}
spin_unlock_irq(&phba->hbalock);
/* Wait a little for things to settle down, but not * long enough for dev loss timeout to expire.
*/ if (phba->sli_rev != LPFC_SLI_REV4) { for (i = 0; i < psli->num_rings; i++) {
pring = &psli->sli3_ring[i]; if (!lpfc_emptyq_wait(phba, &pring->txcmplq,
&phba->hbalock)) goto out;
}
} else {
list_for_each_entry(qp, &phba->sli4_hba.lpfc_wq_list, wq_list) {
pring = qp->pring; if (!pring) continue; if (!lpfc_emptyq_wait(phba, &pring->txcmplq,
&pring->ring_lock)) goto out;
}
}
out:
spin_lock_irq(&phba->hbalock);
psli->sli_flag &= ~LPFC_QUEUE_FREE_WAIT;
spin_unlock_irq(&phba->hbalock);
/** * lpfc_reset_pci_bus - resets PCI bridge controller's secondary bus of an HBA * @phba: lpfc_hba pointer. * * Description: * Issues a PCI secondary bus reset for the phba->pcidev. * * Notes: * First walks the bus_list to ensure only PCI devices with Emulex * vendor id, device ids that support hot reset, only one occurrence * of function 0, and all ports on the bus are in offline mode to ensure the * hot reset only affects one valid HBA. * * Returns: * -ENOTSUPP, cfg_enable_hba_reset must be of value 2 * -ENODEV, NULL ptr to pcidev * -EBADSLT, detected invalid device * -EBUSY, port is not in offline state * 0, successful
*/ staticint
lpfc_reset_pci_bus(struct lpfc_hba *phba)
{ struct pci_dev *pdev = phba->pcidev; struct Scsi_Host *shost = NULL; struct lpfc_hba *phba_other = NULL; struct pci_dev *ptr = NULL; int res;
if (phba->cfg_enable_hba_reset != 2) return -ENOTSUPP;
res = lpfc_check_pci_resettable(phba); if (res) return res;
/* Walk the list of devices on the pci_dev's bus */
list_for_each_entry(ptr, &pdev->bus->devices, bus_list) { /* Check port is offline */
shost = pci_get_drvdata(ptr); if (shost) {
phba_other =
((struct lpfc_vport *)shost->hostdata)->phba; if (!test_bit(FC_OFFLINE_MODE,
&phba_other->pport->fc_flag)) {
lpfc_printf_log(phba_other, KERN_INFO, LOG_INIT, "8349 WWPN = 0x%02x%02x%02x%02x" "%02x%02x%02x%02x is not " "offline!\n",
phba_other->wwpn[0],
phba_other->wwpn[1],
phba_other->wwpn[2],
phba_other->wwpn[3],
phba_other->wwpn[4],
phba_other->wwpn[5],
phba_other->wwpn[6],
phba_other->wwpn[7]); return -EBUSY;
}
}
}
/* Issue PCI bus reset */
res = pci_reset_bus(pdev); if (res) {
lpfc_printf_log(phba, KERN_ERR, LOG_INIT, "8350 PCI reset bus failed: %d\n", res);
}
return res;
}
/** * lpfc_selective_reset - Offline then onlines the port * @phba: lpfc_hba pointer. * * Description: * If the port is configured to allow a reset then the hba is brought * offline then online. * * Notes: * Assumes any error from lpfc_do_offline() will be negative. * Do not make this function static. * * Returns: * lpfc_do_offline() return code if not zero * -EIO reset not configured or error posting the event * zero for success
**/ int
lpfc_selective_reset(struct lpfc_hba *phba)
{ struct completion online_compl; int status = 0; int rc;
if (!phba->cfg_enable_hba_reset) return -EACCES;
if (!test_bit(FC_OFFLINE_MODE, &phba->pport->fc_flag)) {
status = lpfc_do_offline(phba, LPFC_EVT_OFFLINE);
/** * lpfc_issue_reset - Selectively resets an adapter * @dev: class device that is converted into a Scsi_host. * @attr: device attribute, not used. * @buf: containing the string "selective". * @count: unused variable. * * Description: * If the buf contains the string "selective" then lpfc_selective_reset() * is called to perform the reset. * * Notes: * Assumes any error from lpfc_selective_reset() will be negative. * If lpfc_selective_reset() returns zero then the length of the buffer * is returned which indicates success * * Returns: * -EINVAL if the buffer does not contain the string "selective" * length of buf if lpfc-selective_reset() if the call succeeds * return value of lpfc_selective_reset() if the call fails
**/ static ssize_t
lpfc_issue_reset(struct device *dev, struct device_attribute *attr, constchar *buf, size_t count)
{ struct Scsi_Host *shost = class_to_shost(dev); struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; struct lpfc_hba *phba = vport->phba; int status = -EINVAL;
if (!phba->cfg_enable_hba_reset) return -EACCES;
if (strncmp(buf, "selective", sizeof("selective") - 1) == 0)
status = phba->lpfc_selective_reset(phba);
if (status == 0) return strlen(buf); else return status;
}
/** * lpfc_sli4_pdev_status_reg_wait - Wait for pdev status register for readyness * @phba: lpfc_hba pointer. * * Description: * SLI4 interface type-2 device to wait on the sliport status register for * the readyness after performing a firmware reset. * * Returns: * zero for success, -EPERM when port does not have privilege 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)
{ struct lpfc_register portstat_reg = {0}; int i;
msleep(100); if (lpfc_readl(phba->sli4_hba.u.if_type2.STATUSregaddr,
&portstat_reg.word0)) return -EIO;
/* verify if privileged for the request operation */ if (!bf_get(lpfc_sliport_status_rn, &portstat_reg) &&
!bf_get(lpfc_sliport_status_err, &portstat_reg)) return -EPERM;
/* There is no point to wait if the port is in an unrecoverable * state.
*/ if (lpfc_sli4_unrecoverable_port(&portstat_reg)) return -EIO;
/* wait for the SLI port firmware ready after firmware reset */ for (i = 0; i < LPFC_FW_RESET_MAXIMUM_WAIT_10MS_CNT; i++) {
msleep(10); if (lpfc_readl(phba->sli4_hba.u.if_type2.STATUSregaddr,
&portstat_reg.word0)) continue; if (!bf_get(lpfc_sliport_status_err, &portstat_reg)) continue; if (!bf_get(lpfc_sliport_status_rn, &portstat_reg)) continue; if (!bf_get(lpfc_sliport_status_rdy, &portstat_reg)) continue; break;
}
if (i < LPFC_FW_RESET_MAXIMUM_WAIT_10MS_CNT) return 0; else return -EIO;
}
/** * lpfc_sli4_pdev_reg_request - Request physical dev to perform a register acc * @phba: lpfc_hba pointer. * @opcode: The sli4 config command opcode. * * Description: * Request SLI4 interface type-2 device to perform a physical register set * access. * * Returns: * zero for success
**/ static ssize_t
lpfc_sli4_pdev_reg_request(struct lpfc_hba *phba, uint32_t opcode)
{ struct completion online_compl; struct pci_dev *pdev = phba->pcidev; unsignedlong before_fc_flag;
uint32_t sriov_nr_virtfn;
uint32_t reg_val; int status = 0, rc = 0; int job_posted = 1, sriov_err;
if (rc == -EPERM) { /* no privilege for reset */
lpfc_printf_log(phba, KERN_ERR, LOG_SLI, "3150 No privilege to perform the requested " "access: x%x\n", reg_val);
} elseif (rc == -EIO) { /* reset failed, there is nothing more we can do */
lpfc_printf_log(phba, KERN_ERR, LOG_SLI, "3153 Fail to perform the requested " "access: x%x\n", reg_val); if (phba->fw_dump_cmpl)
phba->fw_dump_cmpl = NULL; return rc;
}
/* keep the original port state */ if (test_bit(FC_OFFLINE_MODE, &before_fc_flag)) { if (phba->fw_dump_cmpl)
phba->fw_dump_cmpl = NULL; goto out;
}
/* Firmware dump will trigger an HA_ERATT event, and * lpfc_handle_eratt_s4 routine already handles bringing the port back * online.
*/ if (opcode == LPFC_FW_DUMP) {
wait_for_completion(phba->fw_dump_cmpl);
} else {
init_completion(&online_compl);
job_posted = lpfc_workq_post_event(phba, &status, &online_compl,
LPFC_EVT_ONLINE); if (!job_posted) goto out;
wait_for_completion(&online_compl);
}
out: /* in any case, restore the virtual functions enabled as before */ if (sriov_nr_virtfn) { /* If fw_dump was performed, first disable to clean up */ if (opcode == LPFC_FW_DUMP) {
pci_disable_sriov(pdev);
phba->cfg_sriov_nr_virtfn = 0;
}
sriov_err =
lpfc_sli_probe_sriov_nr_virtfn(phba, sriov_nr_virtfn); if (!sriov_err)
phba->cfg_sriov_nr_virtfn = sriov_nr_virtfn;
}
switch (val) { case 0:
val = 0x0; /* Disable */ break; case 2:
val = 0x1; /* Enable two port trunk */ break; case 4:
val = 0x2; /* Enable four port trunk */ break; default: return -EINVAL;
}
lpfc_printf_log(phba, KERN_ERR, LOG_MBOX, "0070 Set trunk mode with val %ld ", val);
mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); if (!mbox) return -ENOMEM;
/** * lpfc_board_mode_show - Return the state of the board * @dev: class device that is converted into a Scsi_host. * @attr: device attribute, not used. * @buf: on return contains the state of the adapter. * * Returns: size of formatted string.
**/ static ssize_t
lpfc_board_mode_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; char * state;
if (phba->link_state == LPFC_HBA_ERROR)
state = "error"; elseif (phba->link_state == LPFC_WARM_START)
state = "warm start"; elseif (phba->link_state == LPFC_INIT_START)
state = "offline"; else
state = "online";
/** * lpfc_board_mode_store - Puts the hba in online, offline, warm or error state * @dev: class device that is converted into a Scsi_host. * @attr: device attribute, not used. * @buf: containing one of the strings "online", "offline", "warm" or "error". * @count: unused variable. * * Returns: * -EACCES if enable hba reset not enabled * -EINVAL if the buffer does not contain a valid string (see above) * -EIO if lpfc_workq_post_event() or lpfc_do_offline() fails * buf length greater than zero indicates success
**/ static ssize_t
lpfc_board_mode_store(struct device *dev, struct device_attribute *attr, constchar *buf, size_t count)
{ struct Scsi_Host *shost = class_to_shost(dev); struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; struct lpfc_hba *phba = vport->phba; struct completion online_compl; char *board_mode_str = NULL; int status = 0; int rc;
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);
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) {
status = -ENOMEM; goto board_mode_out;
}
wait_for_completion(&online_compl); if (status)
status = -EIO;
} elseif (strncmp(buf, "offline", sizeof("offline") - 1) == 0)
status = lpfc_do_offline(phba, LPFC_EVT_OFFLINE); elseif (strncmp(buf, "warm", sizeof("warm") - 1) == 0) if (phba->sli_rev == LPFC_SLI_REV4)
status = -EINVAL; else
status = lpfc_do_offline(phba, LPFC_EVT_WARM_START); elseif (strncmp(buf, "error", sizeof("error") - 1) == 0) if (phba->sli_rev == LPFC_SLI_REV4)
status = -EINVAL; else
status = lpfc_do_offline(phba, LPFC_EVT_KILL); elseif (strncmp(buf, "dump", sizeof("dump") - 1) == 0)
status = lpfc_sli4_pdev_reg_request(phba, LPFC_FW_DUMP); elseif (strncmp(buf, "fw_reset", sizeof("fw_reset") - 1) == 0)
status = lpfc_sli4_pdev_reg_request(phba, LPFC_FW_RESET); elseif (strncmp(buf, "dv_reset", sizeof("dv_reset") - 1) == 0)
status = lpfc_sli4_pdev_reg_request(phba, LPFC_DV_RESET); elseif (strncmp(buf, "pci_bus_reset", sizeof("pci_bus_reset") - 1)
== 0)
status = lpfc_reset_pci_bus(phba); elseif (strncmp(buf, "heartbeat", sizeof("heartbeat") - 1) == 0)
lpfc_issue_hb_tmo(phba); elseif (strncmp(buf, "trunk", sizeof("trunk") - 1) == 0)
--> --------------------
--> maximum size reached
--> --------------------
Messung V0.5
¤ Dauer der Verarbeitung: 0.28 Sekunden
(vorverarbeitet)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.