diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2011-07-30 14:36:02 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2011-07-30 14:36:02 -0400 |
commit | 6c6e3b828b2a13b923b9465fc4316c5bdc92291f (patch) | |
tree | ca027f7d7645c577ed76fcc8358163eb1689d8ae /drivers/scsi/lpfc/lpfc_debugfs.c | |
parent | c11abbbaa3252875c5740a6880b9a1a6f1e2a870 (diff) | |
parent | d272281c390eb6c3f1e70ed0337c9e619d99cd9c (diff) |
Merge git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi-misc-2.6
* git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi-misc-2.6: (71 commits)
[SCSI] fcoe: cleanup cpu selection for incoming requests
[SCSI] fcoe: add fip retry to avoid missing critical keep alive
[SCSI] libfc: fix warn on in lport retry
[SCSI] libfc: Remove the reference to FCP packet from scsi_cmnd in case of error
[SCSI] libfc: cleanup sending SRR request
[SCSI] libfc: two minor changes in comments
[SCSI] libfc, fcoe: ignore rx frame with wrong xid info
[SCSI] libfc: release exchg cache
[SCSI] libfc: use FC_MAX_ERROR_CNT
[SCSI] fcoe: remove unused ptype field in fcoe_rcv_info
[SCSI] bnx2fc: Update copyright and bump version to 1.0.4
[SCSI] bnx2fc: Tx BDs cache in write tasks
[SCSI] bnx2fc: Do not arm CQ when there are no CQEs
[SCSI] bnx2fc: hold tgt lock when calling cmd_release
[SCSI] bnx2fc: Enable support for sequence level error recovery
[SCSI] bnx2fc: HSI changes for tape
[SCSI] bnx2fc: Handle REC_TOV error code from firmware
[SCSI] bnx2fc: REC/SRR link service request and response handling
[SCSI] bnx2fc: Support 'sequence cleanup' task
[SCSI] dh_rdac: Associate HBA and storage in rdac_controller to support partitions in storage
...
Diffstat (limited to 'drivers/scsi/lpfc/lpfc_debugfs.c')
-rw-r--r-- | drivers/scsi/lpfc/lpfc_debugfs.c | 1354 |
1 files changed, 1326 insertions, 28 deletions
diff --git a/drivers/scsi/lpfc/lpfc_debugfs.c b/drivers/scsi/lpfc/lpfc_debugfs.c index 30b25c5fdd7e..a0424dd90e40 100644 --- a/drivers/scsi/lpfc/lpfc_debugfs.c +++ b/drivers/scsi/lpfc/lpfc_debugfs.c | |||
@@ -48,6 +48,7 @@ | |||
48 | #include "lpfc_version.h" | 48 | #include "lpfc_version.h" |
49 | #include "lpfc_compat.h" | 49 | #include "lpfc_compat.h" |
50 | #include "lpfc_debugfs.h" | 50 | #include "lpfc_debugfs.h" |
51 | #include "lpfc_bsg.h" | ||
51 | 52 | ||
52 | #ifdef CONFIG_SCSI_LPFC_DEBUG_FS | 53 | #ifdef CONFIG_SCSI_LPFC_DEBUG_FS |
53 | /* | 54 | /* |
@@ -135,7 +136,11 @@ lpfc_debugfs_disc_trc_data(struct lpfc_vport *vport, char *buf, int size) | |||
135 | int i, index, len, enable; | 136 | int i, index, len, enable; |
136 | uint32_t ms; | 137 | uint32_t ms; |
137 | struct lpfc_debugfs_trc *dtp; | 138 | struct lpfc_debugfs_trc *dtp; |
138 | char buffer[LPFC_DEBUG_TRC_ENTRY_SIZE]; | 139 | char *buffer; |
140 | |||
141 | buffer = kmalloc(LPFC_DEBUG_TRC_ENTRY_SIZE, GFP_KERNEL); | ||
142 | if (!buffer) | ||
143 | return 0; | ||
139 | 144 | ||
140 | enable = lpfc_debugfs_enable; | 145 | enable = lpfc_debugfs_enable; |
141 | lpfc_debugfs_enable = 0; | 146 | lpfc_debugfs_enable = 0; |
@@ -167,6 +172,8 @@ lpfc_debugfs_disc_trc_data(struct lpfc_vport *vport, char *buf, int size) | |||
167 | } | 172 | } |
168 | 173 | ||
169 | lpfc_debugfs_enable = enable; | 174 | lpfc_debugfs_enable = enable; |
175 | kfree(buffer); | ||
176 | |||
170 | return len; | 177 | return len; |
171 | } | 178 | } |
172 | 179 | ||
@@ -195,8 +202,11 @@ lpfc_debugfs_slow_ring_trc_data(struct lpfc_hba *phba, char *buf, int size) | |||
195 | int i, index, len, enable; | 202 | int i, index, len, enable; |
196 | uint32_t ms; | 203 | uint32_t ms; |
197 | struct lpfc_debugfs_trc *dtp; | 204 | struct lpfc_debugfs_trc *dtp; |
198 | char buffer[LPFC_DEBUG_TRC_ENTRY_SIZE]; | 205 | char *buffer; |
199 | 206 | ||
207 | buffer = kmalloc(LPFC_DEBUG_TRC_ENTRY_SIZE, GFP_KERNEL); | ||
208 | if (!buffer) | ||
209 | return 0; | ||
200 | 210 | ||
201 | enable = lpfc_debugfs_enable; | 211 | enable = lpfc_debugfs_enable; |
202 | lpfc_debugfs_enable = 0; | 212 | lpfc_debugfs_enable = 0; |
@@ -228,6 +238,8 @@ lpfc_debugfs_slow_ring_trc_data(struct lpfc_hba *phba, char *buf, int size) | |||
228 | } | 238 | } |
229 | 239 | ||
230 | lpfc_debugfs_enable = enable; | 240 | lpfc_debugfs_enable = enable; |
241 | kfree(buffer); | ||
242 | |||
231 | return len; | 243 | return len; |
232 | } | 244 | } |
233 | 245 | ||
@@ -378,7 +390,11 @@ lpfc_debugfs_dumpHBASlim_data(struct lpfc_hba *phba, char *buf, int size) | |||
378 | int len = 0; | 390 | int len = 0; |
379 | int i, off; | 391 | int i, off; |
380 | uint32_t *ptr; | 392 | uint32_t *ptr; |
381 | char buffer[1024]; | 393 | char *buffer; |
394 | |||
395 | buffer = kmalloc(1024, GFP_KERNEL); | ||
396 | if (!buffer) | ||
397 | return 0; | ||
382 | 398 | ||
383 | off = 0; | 399 | off = 0; |
384 | spin_lock_irq(&phba->hbalock); | 400 | spin_lock_irq(&phba->hbalock); |
@@ -407,6 +423,8 @@ lpfc_debugfs_dumpHBASlim_data(struct lpfc_hba *phba, char *buf, int size) | |||
407 | } | 423 | } |
408 | 424 | ||
409 | spin_unlock_irq(&phba->hbalock); | 425 | spin_unlock_irq(&phba->hbalock); |
426 | kfree(buffer); | ||
427 | |||
410 | return len; | 428 | return len; |
411 | } | 429 | } |
412 | 430 | ||
@@ -1327,8 +1345,8 @@ lpfc_idiag_pcicfg_read(struct file *file, char __user *buf, size_t nbytes, | |||
1327 | return 0; | 1345 | return 0; |
1328 | 1346 | ||
1329 | if (idiag.cmd.opcode == LPFC_IDIAG_CMD_PCICFG_RD) { | 1347 | if (idiag.cmd.opcode == LPFC_IDIAG_CMD_PCICFG_RD) { |
1330 | where = idiag.cmd.data[0]; | 1348 | where = idiag.cmd.data[IDIAG_PCICFG_WHERE_INDX]; |
1331 | count = idiag.cmd.data[1]; | 1349 | count = idiag.cmd.data[IDIAG_PCICFG_COUNT_INDX]; |
1332 | } else | 1350 | } else |
1333 | return 0; | 1351 | return 0; |
1334 | 1352 | ||
@@ -1373,6 +1391,11 @@ pcicfg_browse: | |||
1373 | len += snprintf(pbuffer+len, LPFC_PCI_CFG_SIZE-len, | 1391 | len += snprintf(pbuffer+len, LPFC_PCI_CFG_SIZE-len, |
1374 | "%08x ", u32val); | 1392 | "%08x ", u32val); |
1375 | offset += sizeof(uint32_t); | 1393 | offset += sizeof(uint32_t); |
1394 | if (offset >= LPFC_PCI_CFG_SIZE) { | ||
1395 | len += snprintf(pbuffer+len, | ||
1396 | LPFC_PCI_CFG_SIZE-len, "\n"); | ||
1397 | break; | ||
1398 | } | ||
1376 | index -= sizeof(uint32_t); | 1399 | index -= sizeof(uint32_t); |
1377 | if (!index) | 1400 | if (!index) |
1378 | len += snprintf(pbuffer+len, LPFC_PCI_CFG_SIZE-len, | 1401 | len += snprintf(pbuffer+len, LPFC_PCI_CFG_SIZE-len, |
@@ -1385,8 +1408,11 @@ pcicfg_browse: | |||
1385 | } | 1408 | } |
1386 | 1409 | ||
1387 | /* Set up the offset for next portion of pci cfg read */ | 1410 | /* Set up the offset for next portion of pci cfg read */ |
1388 | idiag.offset.last_rd += LPFC_PCI_CFG_RD_SIZE; | 1411 | if (index == 0) { |
1389 | if (idiag.offset.last_rd >= LPFC_PCI_CFG_SIZE) | 1412 | idiag.offset.last_rd += LPFC_PCI_CFG_RD_SIZE; |
1413 | if (idiag.offset.last_rd >= LPFC_PCI_CFG_SIZE) | ||
1414 | idiag.offset.last_rd = 0; | ||
1415 | } else | ||
1390 | idiag.offset.last_rd = 0; | 1416 | idiag.offset.last_rd = 0; |
1391 | 1417 | ||
1392 | return simple_read_from_buffer(buf, nbytes, ppos, pbuffer, len); | 1418 | return simple_read_from_buffer(buf, nbytes, ppos, pbuffer, len); |
@@ -1439,8 +1465,8 @@ lpfc_idiag_pcicfg_write(struct file *file, const char __user *buf, | |||
1439 | if (rc != LPFC_PCI_CFG_RD_CMD_ARG) | 1465 | if (rc != LPFC_PCI_CFG_RD_CMD_ARG) |
1440 | goto error_out; | 1466 | goto error_out; |
1441 | /* Read command from PCI config space, set up command fields */ | 1467 | /* Read command from PCI config space, set up command fields */ |
1442 | where = idiag.cmd.data[0]; | 1468 | where = idiag.cmd.data[IDIAG_PCICFG_WHERE_INDX]; |
1443 | count = idiag.cmd.data[1]; | 1469 | count = idiag.cmd.data[IDIAG_PCICFG_COUNT_INDX]; |
1444 | if (count == LPFC_PCI_CFG_BROWSE) { | 1470 | if (count == LPFC_PCI_CFG_BROWSE) { |
1445 | if (where % sizeof(uint32_t)) | 1471 | if (where % sizeof(uint32_t)) |
1446 | goto error_out; | 1472 | goto error_out; |
@@ -1475,9 +1501,9 @@ lpfc_idiag_pcicfg_write(struct file *file, const char __user *buf, | |||
1475 | if (rc != LPFC_PCI_CFG_WR_CMD_ARG) | 1501 | if (rc != LPFC_PCI_CFG_WR_CMD_ARG) |
1476 | goto error_out; | 1502 | goto error_out; |
1477 | /* Write command to PCI config space, read-modify-write */ | 1503 | /* Write command to PCI config space, read-modify-write */ |
1478 | where = idiag.cmd.data[0]; | 1504 | where = idiag.cmd.data[IDIAG_PCICFG_WHERE_INDX]; |
1479 | count = idiag.cmd.data[1]; | 1505 | count = idiag.cmd.data[IDIAG_PCICFG_COUNT_INDX]; |
1480 | value = idiag.cmd.data[2]; | 1506 | value = idiag.cmd.data[IDIAG_PCICFG_VALUE_INDX]; |
1481 | /* Sanity checks */ | 1507 | /* Sanity checks */ |
1482 | if ((count != sizeof(uint8_t)) && | 1508 | if ((count != sizeof(uint8_t)) && |
1483 | (count != sizeof(uint16_t)) && | 1509 | (count != sizeof(uint16_t)) && |
@@ -1570,6 +1596,292 @@ error_out: | |||
1570 | } | 1596 | } |
1571 | 1597 | ||
1572 | /** | 1598 | /** |
1599 | * lpfc_idiag_baracc_read - idiag debugfs pci bar access read | ||
1600 | * @file: The file pointer to read from. | ||
1601 | * @buf: The buffer to copy the data to. | ||
1602 | * @nbytes: The number of bytes to read. | ||
1603 | * @ppos: The position in the file to start reading from. | ||
1604 | * | ||
1605 | * Description: | ||
1606 | * This routine reads data from the @phba pci bar memory mapped space | ||
1607 | * according to the idiag command, and copies to user @buf. | ||
1608 | * | ||
1609 | * Returns: | ||
1610 | * This function returns the amount of data that was read (this could be less | ||
1611 | * than @nbytes if the end of the file was reached) or a negative error value. | ||
1612 | **/ | ||
1613 | static ssize_t | ||
1614 | lpfc_idiag_baracc_read(struct file *file, char __user *buf, size_t nbytes, | ||
1615 | loff_t *ppos) | ||
1616 | { | ||
1617 | struct lpfc_debug *debug = file->private_data; | ||
1618 | struct lpfc_hba *phba = (struct lpfc_hba *)debug->i_private; | ||
1619 | int offset_label, offset, offset_run, len = 0, index; | ||
1620 | int bar_num, acc_range, bar_size; | ||
1621 | char *pbuffer; | ||
1622 | void __iomem *mem_mapped_bar; | ||
1623 | uint32_t if_type; | ||
1624 | struct pci_dev *pdev; | ||
1625 | uint32_t u32val; | ||
1626 | |||
1627 | pdev = phba->pcidev; | ||
1628 | if (!pdev) | ||
1629 | return 0; | ||
1630 | |||
1631 | /* This is a user read operation */ | ||
1632 | debug->op = LPFC_IDIAG_OP_RD; | ||
1633 | |||
1634 | if (!debug->buffer) | ||
1635 | debug->buffer = kmalloc(LPFC_PCI_BAR_RD_BUF_SIZE, GFP_KERNEL); | ||
1636 | if (!debug->buffer) | ||
1637 | return 0; | ||
1638 | pbuffer = debug->buffer; | ||
1639 | |||
1640 | if (*ppos) | ||
1641 | return 0; | ||
1642 | |||
1643 | if (idiag.cmd.opcode == LPFC_IDIAG_CMD_BARACC_RD) { | ||
1644 | bar_num = idiag.cmd.data[IDIAG_BARACC_BAR_NUM_INDX]; | ||
1645 | offset = idiag.cmd.data[IDIAG_BARACC_OFF_SET_INDX]; | ||
1646 | acc_range = idiag.cmd.data[IDIAG_BARACC_ACC_MOD_INDX]; | ||
1647 | bar_size = idiag.cmd.data[IDIAG_BARACC_BAR_SZE_INDX]; | ||
1648 | } else | ||
1649 | return 0; | ||
1650 | |||
1651 | if (acc_range == 0) | ||
1652 | return 0; | ||
1653 | |||
1654 | if_type = bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf); | ||
1655 | if (if_type == LPFC_SLI_INTF_IF_TYPE_0) { | ||
1656 | if (bar_num == IDIAG_BARACC_BAR_0) | ||
1657 | mem_mapped_bar = phba->sli4_hba.conf_regs_memmap_p; | ||
1658 | else if (bar_num == IDIAG_BARACC_BAR_1) | ||
1659 | mem_mapped_bar = phba->sli4_hba.ctrl_regs_memmap_p; | ||
1660 | else if (bar_num == IDIAG_BARACC_BAR_2) | ||
1661 | mem_mapped_bar = phba->sli4_hba.drbl_regs_memmap_p; | ||
1662 | else | ||
1663 | return 0; | ||
1664 | } else if (if_type == LPFC_SLI_INTF_IF_TYPE_2) { | ||
1665 | if (bar_num == IDIAG_BARACC_BAR_0) | ||
1666 | mem_mapped_bar = phba->sli4_hba.conf_regs_memmap_p; | ||
1667 | else | ||
1668 | return 0; | ||
1669 | } else | ||
1670 | return 0; | ||
1671 | |||
1672 | /* Read single PCI bar space register */ | ||
1673 | if (acc_range == SINGLE_WORD) { | ||
1674 | offset_run = offset; | ||
1675 | u32val = readl(mem_mapped_bar + offset_run); | ||
1676 | len += snprintf(pbuffer+len, LPFC_PCI_BAR_RD_BUF_SIZE-len, | ||
1677 | "%05x: %08x\n", offset_run, u32val); | ||
1678 | } else | ||
1679 | goto baracc_browse; | ||
1680 | |||
1681 | return simple_read_from_buffer(buf, nbytes, ppos, pbuffer, len); | ||
1682 | |||
1683 | baracc_browse: | ||
1684 | |||
1685 | /* Browse all PCI bar space registers */ | ||
1686 | offset_label = idiag.offset.last_rd; | ||
1687 | offset_run = offset_label; | ||
1688 | |||
1689 | /* Read PCI bar memory mapped space */ | ||
1690 | len += snprintf(pbuffer+len, LPFC_PCI_BAR_RD_BUF_SIZE-len, | ||
1691 | "%05x: ", offset_label); | ||
1692 | index = LPFC_PCI_BAR_RD_SIZE; | ||
1693 | while (index > 0) { | ||
1694 | u32val = readl(mem_mapped_bar + offset_run); | ||
1695 | len += snprintf(pbuffer+len, LPFC_PCI_BAR_RD_BUF_SIZE-len, | ||
1696 | "%08x ", u32val); | ||
1697 | offset_run += sizeof(uint32_t); | ||
1698 | if (acc_range == LPFC_PCI_BAR_BROWSE) { | ||
1699 | if (offset_run >= bar_size) { | ||
1700 | len += snprintf(pbuffer+len, | ||
1701 | LPFC_PCI_BAR_RD_BUF_SIZE-len, "\n"); | ||
1702 | break; | ||
1703 | } | ||
1704 | } else { | ||
1705 | if (offset_run >= offset + | ||
1706 | (acc_range * sizeof(uint32_t))) { | ||
1707 | len += snprintf(pbuffer+len, | ||
1708 | LPFC_PCI_BAR_RD_BUF_SIZE-len, "\n"); | ||
1709 | break; | ||
1710 | } | ||
1711 | } | ||
1712 | index -= sizeof(uint32_t); | ||
1713 | if (!index) | ||
1714 | len += snprintf(pbuffer+len, | ||
1715 | LPFC_PCI_BAR_RD_BUF_SIZE-len, "\n"); | ||
1716 | else if (!(index % (8 * sizeof(uint32_t)))) { | ||
1717 | offset_label += (8 * sizeof(uint32_t)); | ||
1718 | len += snprintf(pbuffer+len, | ||
1719 | LPFC_PCI_BAR_RD_BUF_SIZE-len, | ||
1720 | "\n%05x: ", offset_label); | ||
1721 | } | ||
1722 | } | ||
1723 | |||
1724 | /* Set up the offset for next portion of pci bar read */ | ||
1725 | if (index == 0) { | ||
1726 | idiag.offset.last_rd += LPFC_PCI_BAR_RD_SIZE; | ||
1727 | if (acc_range == LPFC_PCI_BAR_BROWSE) { | ||
1728 | if (idiag.offset.last_rd >= bar_size) | ||
1729 | idiag.offset.last_rd = 0; | ||
1730 | } else { | ||
1731 | if (offset_run >= offset + | ||
1732 | (acc_range * sizeof(uint32_t))) | ||
1733 | idiag.offset.last_rd = offset; | ||
1734 | } | ||
1735 | } else { | ||
1736 | if (acc_range == LPFC_PCI_BAR_BROWSE) | ||
1737 | idiag.offset.last_rd = 0; | ||
1738 | else | ||
1739 | idiag.offset.last_rd = offset; | ||
1740 | } | ||
1741 | |||
1742 | return simple_read_from_buffer(buf, nbytes, ppos, pbuffer, len); | ||
1743 | } | ||
1744 | |||
1745 | /** | ||
1746 | * lpfc_idiag_baracc_write - Syntax check and set up idiag bar access commands | ||
1747 | * @file: The file pointer to read from. | ||
1748 | * @buf: The buffer to copy the user data from. | ||
1749 | * @nbytes: The number of bytes to get. | ||
1750 | * @ppos: The position in the file to start reading from. | ||
1751 | * | ||
1752 | * This routine get the debugfs idiag command struct from user space and | ||
1753 | * then perform the syntax check for PCI bar memory mapped space read or | ||
1754 | * write command accordingly. In the case of PCI bar memory mapped space | ||
1755 | * read command, it sets up the command in the idiag command struct for | ||
1756 | * the debugfs read operation. In the case of PCI bar memorpy mapped space | ||
1757 | * write operation, it executes the write operation into the PCI bar memory | ||
1758 | * mapped space accordingly. | ||
1759 | * | ||
1760 | * It returns the @nbytges passing in from debugfs user space when successful. | ||
1761 | * In case of error conditions, it returns proper error code back to the user | ||
1762 | * space. | ||
1763 | */ | ||
1764 | static ssize_t | ||
1765 | lpfc_idiag_baracc_write(struct file *file, const char __user *buf, | ||
1766 | size_t nbytes, loff_t *ppos) | ||
1767 | { | ||
1768 | struct lpfc_debug *debug = file->private_data; | ||
1769 | struct lpfc_hba *phba = (struct lpfc_hba *)debug->i_private; | ||
1770 | uint32_t bar_num, bar_size, offset, value, acc_range; | ||
1771 | struct pci_dev *pdev; | ||
1772 | void __iomem *mem_mapped_bar; | ||
1773 | uint32_t if_type; | ||
1774 | uint32_t u32val; | ||
1775 | int rc; | ||
1776 | |||
1777 | pdev = phba->pcidev; | ||
1778 | if (!pdev) | ||
1779 | return -EFAULT; | ||
1780 | |||
1781 | /* This is a user write operation */ | ||
1782 | debug->op = LPFC_IDIAG_OP_WR; | ||
1783 | |||
1784 | rc = lpfc_idiag_cmd_get(buf, nbytes, &idiag.cmd); | ||
1785 | if (rc < 0) | ||
1786 | return rc; | ||
1787 | |||
1788 | if_type = bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf); | ||
1789 | bar_num = idiag.cmd.data[IDIAG_BARACC_BAR_NUM_INDX]; | ||
1790 | |||
1791 | if (if_type == LPFC_SLI_INTF_IF_TYPE_0) { | ||
1792 | if ((bar_num != IDIAG_BARACC_BAR_0) && | ||
1793 | (bar_num != IDIAG_BARACC_BAR_1) && | ||
1794 | (bar_num != IDIAG_BARACC_BAR_2)) | ||
1795 | goto error_out; | ||
1796 | } else if (if_type == LPFC_SLI_INTF_IF_TYPE_2) { | ||
1797 | if (bar_num != IDIAG_BARACC_BAR_0) | ||
1798 | goto error_out; | ||
1799 | } else | ||
1800 | goto error_out; | ||
1801 | |||
1802 | if (if_type == LPFC_SLI_INTF_IF_TYPE_0) { | ||
1803 | if (bar_num == IDIAG_BARACC_BAR_0) { | ||
1804 | idiag.cmd.data[IDIAG_BARACC_BAR_SZE_INDX] = | ||
1805 | LPFC_PCI_IF0_BAR0_SIZE; | ||
1806 | mem_mapped_bar = phba->sli4_hba.conf_regs_memmap_p; | ||
1807 | } else if (bar_num == IDIAG_BARACC_BAR_1) { | ||
1808 | idiag.cmd.data[IDIAG_BARACC_BAR_SZE_INDX] = | ||
1809 | LPFC_PCI_IF0_BAR1_SIZE; | ||
1810 | mem_mapped_bar = phba->sli4_hba.ctrl_regs_memmap_p; | ||
1811 | } else if (bar_num == IDIAG_BARACC_BAR_2) { | ||
1812 | idiag.cmd.data[IDIAG_BARACC_BAR_SZE_INDX] = | ||
1813 | LPFC_PCI_IF0_BAR2_SIZE; | ||
1814 | mem_mapped_bar = phba->sli4_hba.drbl_regs_memmap_p; | ||
1815 | } else | ||
1816 | goto error_out; | ||
1817 | } else if (if_type == LPFC_SLI_INTF_IF_TYPE_2) { | ||
1818 | if (bar_num == IDIAG_BARACC_BAR_0) { | ||
1819 | idiag.cmd.data[IDIAG_BARACC_BAR_SZE_INDX] = | ||
1820 | LPFC_PCI_IF2_BAR0_SIZE; | ||
1821 | mem_mapped_bar = phba->sli4_hba.conf_regs_memmap_p; | ||
1822 | } else | ||
1823 | goto error_out; | ||
1824 | } else | ||
1825 | goto error_out; | ||
1826 | |||
1827 | offset = idiag.cmd.data[IDIAG_BARACC_OFF_SET_INDX]; | ||
1828 | if (offset % sizeof(uint32_t)) | ||
1829 | goto error_out; | ||
1830 | |||
1831 | bar_size = idiag.cmd.data[IDIAG_BARACC_BAR_SZE_INDX]; | ||
1832 | if (idiag.cmd.opcode == LPFC_IDIAG_CMD_BARACC_RD) { | ||
1833 | /* Sanity check on PCI config read command line arguments */ | ||
1834 | if (rc != LPFC_PCI_BAR_RD_CMD_ARG) | ||
1835 | goto error_out; | ||
1836 | acc_range = idiag.cmd.data[IDIAG_BARACC_ACC_MOD_INDX]; | ||
1837 | if (acc_range == LPFC_PCI_BAR_BROWSE) { | ||
1838 | if (offset > bar_size - sizeof(uint32_t)) | ||
1839 | goto error_out; | ||
1840 | /* Starting offset to browse */ | ||
1841 | idiag.offset.last_rd = offset; | ||
1842 | } else if (acc_range > SINGLE_WORD) { | ||
1843 | if (offset + acc_range * sizeof(uint32_t) > bar_size) | ||
1844 | goto error_out; | ||
1845 | /* Starting offset to browse */ | ||
1846 | idiag.offset.last_rd = offset; | ||
1847 | } else if (acc_range != SINGLE_WORD) | ||
1848 | goto error_out; | ||
1849 | } else if (idiag.cmd.opcode == LPFC_IDIAG_CMD_BARACC_WR || | ||
1850 | idiag.cmd.opcode == LPFC_IDIAG_CMD_BARACC_ST || | ||
1851 | idiag.cmd.opcode == LPFC_IDIAG_CMD_BARACC_CL) { | ||
1852 | /* Sanity check on PCI bar write command line arguments */ | ||
1853 | if (rc != LPFC_PCI_BAR_WR_CMD_ARG) | ||
1854 | goto error_out; | ||
1855 | /* Write command to PCI bar space, read-modify-write */ | ||
1856 | acc_range = SINGLE_WORD; | ||
1857 | value = idiag.cmd.data[IDIAG_BARACC_REG_VAL_INDX]; | ||
1858 | if (idiag.cmd.opcode == LPFC_IDIAG_CMD_BARACC_WR) { | ||
1859 | writel(value, mem_mapped_bar + offset); | ||
1860 | readl(mem_mapped_bar + offset); | ||
1861 | } | ||
1862 | if (idiag.cmd.opcode == LPFC_IDIAG_CMD_BARACC_ST) { | ||
1863 | u32val = readl(mem_mapped_bar + offset); | ||
1864 | u32val |= value; | ||
1865 | writel(u32val, mem_mapped_bar + offset); | ||
1866 | readl(mem_mapped_bar + offset); | ||
1867 | } | ||
1868 | if (idiag.cmd.opcode == LPFC_IDIAG_CMD_BARACC_CL) { | ||
1869 | u32val = readl(mem_mapped_bar + offset); | ||
1870 | u32val &= ~value; | ||
1871 | writel(u32val, mem_mapped_bar + offset); | ||
1872 | readl(mem_mapped_bar + offset); | ||
1873 | } | ||
1874 | } else | ||
1875 | /* All other opecodes are illegal for now */ | ||
1876 | goto error_out; | ||
1877 | |||
1878 | return nbytes; | ||
1879 | error_out: | ||
1880 | memset(&idiag, 0, sizeof(idiag)); | ||
1881 | return -EINVAL; | ||
1882 | } | ||
1883 | |||
1884 | /** | ||
1573 | * lpfc_idiag_queinfo_read - idiag debugfs read queue information | 1885 | * lpfc_idiag_queinfo_read - idiag debugfs read queue information |
1574 | * @file: The file pointer to read from. | 1886 | * @file: The file pointer to read from. |
1575 | * @buf: The buffer to copy the data to. | 1887 | * @buf: The buffer to copy the data to. |
@@ -1871,8 +2183,8 @@ lpfc_idiag_queacc_read(struct file *file, char __user *buf, size_t nbytes, | |||
1871 | return 0; | 2183 | return 0; |
1872 | 2184 | ||
1873 | if (idiag.cmd.opcode == LPFC_IDIAG_CMD_QUEACC_RD) { | 2185 | if (idiag.cmd.opcode == LPFC_IDIAG_CMD_QUEACC_RD) { |
1874 | index = idiag.cmd.data[2]; | 2186 | index = idiag.cmd.data[IDIAG_QUEACC_INDEX_INDX]; |
1875 | count = idiag.cmd.data[3]; | 2187 | count = idiag.cmd.data[IDIAG_QUEACC_COUNT_INDX]; |
1876 | pque = (struct lpfc_queue *)idiag.ptr_private; | 2188 | pque = (struct lpfc_queue *)idiag.ptr_private; |
1877 | } else | 2189 | } else |
1878 | return 0; | 2190 | return 0; |
@@ -1944,12 +2256,12 @@ lpfc_idiag_queacc_write(struct file *file, const char __user *buf, | |||
1944 | return rc; | 2256 | return rc; |
1945 | 2257 | ||
1946 | /* Get and sanity check on command feilds */ | 2258 | /* Get and sanity check on command feilds */ |
1947 | quetp = idiag.cmd.data[0]; | 2259 | quetp = idiag.cmd.data[IDIAG_QUEACC_QUETP_INDX]; |
1948 | queid = idiag.cmd.data[1]; | 2260 | queid = idiag.cmd.data[IDIAG_QUEACC_QUEID_INDX]; |
1949 | index = idiag.cmd.data[2]; | 2261 | index = idiag.cmd.data[IDIAG_QUEACC_INDEX_INDX]; |
1950 | count = idiag.cmd.data[3]; | 2262 | count = idiag.cmd.data[IDIAG_QUEACC_COUNT_INDX]; |
1951 | offset = idiag.cmd.data[4]; | 2263 | offset = idiag.cmd.data[IDIAG_QUEACC_OFFST_INDX]; |
1952 | value = idiag.cmd.data[5]; | 2264 | value = idiag.cmd.data[IDIAG_QUEACC_VALUE_INDX]; |
1953 | 2265 | ||
1954 | /* Sanity check on command line arguments */ | 2266 | /* Sanity check on command line arguments */ |
1955 | if (idiag.cmd.opcode == LPFC_IDIAG_CMD_QUEACC_WR || | 2267 | if (idiag.cmd.opcode == LPFC_IDIAG_CMD_QUEACC_WR || |
@@ -2218,7 +2530,7 @@ lpfc_idiag_drbacc_read(struct file *file, char __user *buf, size_t nbytes, | |||
2218 | return 0; | 2530 | return 0; |
2219 | 2531 | ||
2220 | if (idiag.cmd.opcode == LPFC_IDIAG_CMD_DRBACC_RD) | 2532 | if (idiag.cmd.opcode == LPFC_IDIAG_CMD_DRBACC_RD) |
2221 | drb_reg_id = idiag.cmd.data[0]; | 2533 | drb_reg_id = idiag.cmd.data[IDIAG_DRBACC_REGID_INDX]; |
2222 | else | 2534 | else |
2223 | return 0; | 2535 | return 0; |
2224 | 2536 | ||
@@ -2257,7 +2569,7 @@ lpfc_idiag_drbacc_write(struct file *file, const char __user *buf, | |||
2257 | { | 2569 | { |
2258 | struct lpfc_debug *debug = file->private_data; | 2570 | struct lpfc_debug *debug = file->private_data; |
2259 | struct lpfc_hba *phba = (struct lpfc_hba *)debug->i_private; | 2571 | struct lpfc_hba *phba = (struct lpfc_hba *)debug->i_private; |
2260 | uint32_t drb_reg_id, value, reg_val; | 2572 | uint32_t drb_reg_id, value, reg_val = 0; |
2261 | void __iomem *drb_reg; | 2573 | void __iomem *drb_reg; |
2262 | int rc; | 2574 | int rc; |
2263 | 2575 | ||
@@ -2269,8 +2581,8 @@ lpfc_idiag_drbacc_write(struct file *file, const char __user *buf, | |||
2269 | return rc; | 2581 | return rc; |
2270 | 2582 | ||
2271 | /* Sanity check on command line arguments */ | 2583 | /* Sanity check on command line arguments */ |
2272 | drb_reg_id = idiag.cmd.data[0]; | 2584 | drb_reg_id = idiag.cmd.data[IDIAG_DRBACC_REGID_INDX]; |
2273 | value = idiag.cmd.data[1]; | 2585 | value = idiag.cmd.data[IDIAG_DRBACC_VALUE_INDX]; |
2274 | 2586 | ||
2275 | if (idiag.cmd.opcode == LPFC_IDIAG_CMD_DRBACC_WR || | 2587 | if (idiag.cmd.opcode == LPFC_IDIAG_CMD_DRBACC_WR || |
2276 | idiag.cmd.opcode == LPFC_IDIAG_CMD_DRBACC_ST || | 2588 | idiag.cmd.opcode == LPFC_IDIAG_CMD_DRBACC_ST || |
@@ -2330,6 +2642,679 @@ error_out: | |||
2330 | return -EINVAL; | 2642 | return -EINVAL; |
2331 | } | 2643 | } |
2332 | 2644 | ||
2645 | /** | ||
2646 | * lpfc_idiag_ctlacc_read_reg - idiag debugfs read a control registers | ||
2647 | * @phba: The pointer to hba structure. | ||
2648 | * @pbuffer: The pointer to the buffer to copy the data to. | ||
2649 | * @len: The lenght of bytes to copied. | ||
2650 | * @drbregid: The id to doorbell registers. | ||
2651 | * | ||
2652 | * Description: | ||
2653 | * This routine reads a control register and copies its content to the | ||
2654 | * user buffer pointed to by @pbuffer. | ||
2655 | * | ||
2656 | * Returns: | ||
2657 | * This function returns the amount of data that was copied into @pbuffer. | ||
2658 | **/ | ||
2659 | static int | ||
2660 | lpfc_idiag_ctlacc_read_reg(struct lpfc_hba *phba, char *pbuffer, | ||
2661 | int len, uint32_t ctlregid) | ||
2662 | { | ||
2663 | |||
2664 | if (!pbuffer) | ||
2665 | return 0; | ||
2666 | |||
2667 | switch (ctlregid) { | ||
2668 | case LPFC_CTL_PORT_SEM: | ||
2669 | len += snprintf(pbuffer+len, LPFC_CTL_ACC_BUF_SIZE-len, | ||
2670 | "Port SemReg: 0x%08x\n", | ||
2671 | readl(phba->sli4_hba.conf_regs_memmap_p + | ||
2672 | LPFC_CTL_PORT_SEM_OFFSET)); | ||
2673 | break; | ||
2674 | case LPFC_CTL_PORT_STA: | ||
2675 | len += snprintf(pbuffer+len, LPFC_CTL_ACC_BUF_SIZE-len, | ||
2676 | "Port StaReg: 0x%08x\n", | ||
2677 | readl(phba->sli4_hba.conf_regs_memmap_p + | ||
2678 | LPFC_CTL_PORT_STA_OFFSET)); | ||
2679 | break; | ||
2680 | case LPFC_CTL_PORT_CTL: | ||
2681 | len += snprintf(pbuffer+len, LPFC_CTL_ACC_BUF_SIZE-len, | ||
2682 | "Port CtlReg: 0x%08x\n", | ||
2683 | readl(phba->sli4_hba.conf_regs_memmap_p + | ||
2684 | LPFC_CTL_PORT_CTL_OFFSET)); | ||
2685 | break; | ||
2686 | case LPFC_CTL_PORT_ER1: | ||
2687 | len += snprintf(pbuffer+len, LPFC_CTL_ACC_BUF_SIZE-len, | ||
2688 | "Port Er1Reg: 0x%08x\n", | ||
2689 | readl(phba->sli4_hba.conf_regs_memmap_p + | ||
2690 | LPFC_CTL_PORT_ER1_OFFSET)); | ||
2691 | break; | ||
2692 | case LPFC_CTL_PORT_ER2: | ||
2693 | len += snprintf(pbuffer+len, LPFC_CTL_ACC_BUF_SIZE-len, | ||
2694 | "Port Er2Reg: 0x%08x\n", | ||
2695 | readl(phba->sli4_hba.conf_regs_memmap_p + | ||
2696 | LPFC_CTL_PORT_ER2_OFFSET)); | ||
2697 | break; | ||
2698 | case LPFC_CTL_PDEV_CTL: | ||
2699 | len += snprintf(pbuffer+len, LPFC_CTL_ACC_BUF_SIZE-len, | ||
2700 | "PDev CtlReg: 0x%08x\n", | ||
2701 | readl(phba->sli4_hba.conf_regs_memmap_p + | ||
2702 | LPFC_CTL_PDEV_CTL_OFFSET)); | ||
2703 | break; | ||
2704 | default: | ||
2705 | break; | ||
2706 | } | ||
2707 | return len; | ||
2708 | } | ||
2709 | |||
2710 | /** | ||
2711 | * lpfc_idiag_ctlacc_read - idiag debugfs read port and device control register | ||
2712 | * @file: The file pointer to read from. | ||
2713 | * @buf: The buffer to copy the data to. | ||
2714 | * @nbytes: The number of bytes to read. | ||
2715 | * @ppos: The position in the file to start reading from. | ||
2716 | * | ||
2717 | * Description: | ||
2718 | * This routine reads data from the @phba port and device registers according | ||
2719 | * to the idiag command, and copies to user @buf. | ||
2720 | * | ||
2721 | * Returns: | ||
2722 | * This function returns the amount of data that was read (this could be less | ||
2723 | * than @nbytes if the end of the file was reached) or a negative error value. | ||
2724 | **/ | ||
2725 | static ssize_t | ||
2726 | lpfc_idiag_ctlacc_read(struct file *file, char __user *buf, size_t nbytes, | ||
2727 | loff_t *ppos) | ||
2728 | { | ||
2729 | struct lpfc_debug *debug = file->private_data; | ||
2730 | struct lpfc_hba *phba = (struct lpfc_hba *)debug->i_private; | ||
2731 | uint32_t ctl_reg_id, i; | ||
2732 | char *pbuffer; | ||
2733 | int len = 0; | ||
2734 | |||
2735 | /* This is a user read operation */ | ||
2736 | debug->op = LPFC_IDIAG_OP_RD; | ||
2737 | |||
2738 | if (!debug->buffer) | ||
2739 | debug->buffer = kmalloc(LPFC_CTL_ACC_BUF_SIZE, GFP_KERNEL); | ||
2740 | if (!debug->buffer) | ||
2741 | return 0; | ||
2742 | pbuffer = debug->buffer; | ||
2743 | |||
2744 | if (*ppos) | ||
2745 | return 0; | ||
2746 | |||
2747 | if (idiag.cmd.opcode == LPFC_IDIAG_CMD_CTLACC_RD) | ||
2748 | ctl_reg_id = idiag.cmd.data[IDIAG_CTLACC_REGID_INDX]; | ||
2749 | else | ||
2750 | return 0; | ||
2751 | |||
2752 | if (ctl_reg_id == LPFC_CTL_ACC_ALL) | ||
2753 | for (i = 1; i <= LPFC_CTL_MAX; i++) | ||
2754 | len = lpfc_idiag_ctlacc_read_reg(phba, | ||
2755 | pbuffer, len, i); | ||
2756 | else | ||
2757 | len = lpfc_idiag_ctlacc_read_reg(phba, | ||
2758 | pbuffer, len, ctl_reg_id); | ||
2759 | |||
2760 | return simple_read_from_buffer(buf, nbytes, ppos, pbuffer, len); | ||
2761 | } | ||
2762 | |||
2763 | /** | ||
2764 | * lpfc_idiag_ctlacc_write - Syntax check and set up idiag ctlacc commands | ||
2765 | * @file: The file pointer to read from. | ||
2766 | * @buf: The buffer to copy the user data from. | ||
2767 | * @nbytes: The number of bytes to get. | ||
2768 | * @ppos: The position in the file to start reading from. | ||
2769 | * | ||
2770 | * This routine get the debugfs idiag command struct from user space and then | ||
2771 | * perform the syntax check for port and device control register read (dump) | ||
2772 | * or write (set) command accordingly. | ||
2773 | * | ||
2774 | * It returns the @nbytges passing in from debugfs user space when successful. | ||
2775 | * In case of error conditions, it returns proper error code back to the user | ||
2776 | * space. | ||
2777 | **/ | ||
2778 | static ssize_t | ||
2779 | lpfc_idiag_ctlacc_write(struct file *file, const char __user *buf, | ||
2780 | size_t nbytes, loff_t *ppos) | ||
2781 | { | ||
2782 | struct lpfc_debug *debug = file->private_data; | ||
2783 | struct lpfc_hba *phba = (struct lpfc_hba *)debug->i_private; | ||
2784 | uint32_t ctl_reg_id, value, reg_val = 0; | ||
2785 | void __iomem *ctl_reg; | ||
2786 | int rc; | ||
2787 | |||
2788 | /* This is a user write operation */ | ||
2789 | debug->op = LPFC_IDIAG_OP_WR; | ||
2790 | |||
2791 | rc = lpfc_idiag_cmd_get(buf, nbytes, &idiag.cmd); | ||
2792 | if (rc < 0) | ||
2793 | return rc; | ||
2794 | |||
2795 | /* Sanity check on command line arguments */ | ||
2796 | ctl_reg_id = idiag.cmd.data[IDIAG_CTLACC_REGID_INDX]; | ||
2797 | value = idiag.cmd.data[IDIAG_CTLACC_VALUE_INDX]; | ||
2798 | |||
2799 | if (idiag.cmd.opcode == LPFC_IDIAG_CMD_CTLACC_WR || | ||
2800 | idiag.cmd.opcode == LPFC_IDIAG_CMD_CTLACC_ST || | ||
2801 | idiag.cmd.opcode == LPFC_IDIAG_CMD_CTLACC_CL) { | ||
2802 | if (rc != LPFC_CTL_ACC_WR_CMD_ARG) | ||
2803 | goto error_out; | ||
2804 | if (ctl_reg_id > LPFC_CTL_MAX) | ||
2805 | goto error_out; | ||
2806 | } else if (idiag.cmd.opcode == LPFC_IDIAG_CMD_CTLACC_RD) { | ||
2807 | if (rc != LPFC_CTL_ACC_RD_CMD_ARG) | ||
2808 | goto error_out; | ||
2809 | if ((ctl_reg_id > LPFC_CTL_MAX) && | ||
2810 | (ctl_reg_id != LPFC_CTL_ACC_ALL)) | ||
2811 | goto error_out; | ||
2812 | } else | ||
2813 | goto error_out; | ||
2814 | |||
2815 | /* Perform the write access operation */ | ||
2816 | if (idiag.cmd.opcode == LPFC_IDIAG_CMD_CTLACC_WR || | ||
2817 | idiag.cmd.opcode == LPFC_IDIAG_CMD_CTLACC_ST || | ||
2818 | idiag.cmd.opcode == LPFC_IDIAG_CMD_CTLACC_CL) { | ||
2819 | switch (ctl_reg_id) { | ||
2820 | case LPFC_CTL_PORT_SEM: | ||
2821 | ctl_reg = phba->sli4_hba.conf_regs_memmap_p + | ||
2822 | LPFC_CTL_PORT_SEM_OFFSET; | ||
2823 | break; | ||
2824 | case LPFC_CTL_PORT_STA: | ||
2825 | ctl_reg = phba->sli4_hba.conf_regs_memmap_p + | ||
2826 | LPFC_CTL_PORT_STA_OFFSET; | ||
2827 | break; | ||
2828 | case LPFC_CTL_PORT_CTL: | ||
2829 | ctl_reg = phba->sli4_hba.conf_regs_memmap_p + | ||
2830 | LPFC_CTL_PORT_CTL_OFFSET; | ||
2831 | break; | ||
2832 | case LPFC_CTL_PORT_ER1: | ||
2833 | ctl_reg = phba->sli4_hba.conf_regs_memmap_p + | ||
2834 | LPFC_CTL_PORT_ER1_OFFSET; | ||
2835 | break; | ||
2836 | case LPFC_CTL_PORT_ER2: | ||
2837 | ctl_reg = phba->sli4_hba.conf_regs_memmap_p + | ||
2838 | LPFC_CTL_PORT_ER2_OFFSET; | ||
2839 | break; | ||
2840 | case LPFC_CTL_PDEV_CTL: | ||
2841 | ctl_reg = phba->sli4_hba.conf_regs_memmap_p + | ||
2842 | LPFC_CTL_PDEV_CTL_OFFSET; | ||
2843 | break; | ||
2844 | default: | ||
2845 | goto error_out; | ||
2846 | } | ||
2847 | |||
2848 | if (idiag.cmd.opcode == LPFC_IDIAG_CMD_CTLACC_WR) | ||
2849 | reg_val = value; | ||
2850 | if (idiag.cmd.opcode == LPFC_IDIAG_CMD_CTLACC_ST) { | ||
2851 | reg_val = readl(ctl_reg); | ||
2852 | reg_val |= value; | ||
2853 | } | ||
2854 | if (idiag.cmd.opcode == LPFC_IDIAG_CMD_CTLACC_CL) { | ||
2855 | reg_val = readl(ctl_reg); | ||
2856 | reg_val &= ~value; | ||
2857 | } | ||
2858 | writel(reg_val, ctl_reg); | ||
2859 | readl(ctl_reg); /* flush */ | ||
2860 | } | ||
2861 | return nbytes; | ||
2862 | |||
2863 | error_out: | ||
2864 | /* Clean out command structure on command error out */ | ||
2865 | memset(&idiag, 0, sizeof(idiag)); | ||
2866 | return -EINVAL; | ||
2867 | } | ||
2868 | |||
2869 | /** | ||
2870 | * lpfc_idiag_mbxacc_get_setup - idiag debugfs get mailbox access setup | ||
2871 | * @phba: Pointer to HBA context object. | ||
2872 | * @pbuffer: Pointer to data buffer. | ||
2873 | * | ||
2874 | * Description: | ||
2875 | * This routine gets the driver mailbox access debugfs setup information. | ||
2876 | * | ||
2877 | * Returns: | ||
2878 | * This function returns the amount of data that was read (this could be less | ||
2879 | * than @nbytes if the end of the file was reached) or a negative error value. | ||
2880 | **/ | ||
2881 | static int | ||
2882 | lpfc_idiag_mbxacc_get_setup(struct lpfc_hba *phba, char *pbuffer) | ||
2883 | { | ||
2884 | uint32_t mbx_dump_map, mbx_dump_cnt, mbx_word_cnt, mbx_mbox_cmd; | ||
2885 | int len = 0; | ||
2886 | |||
2887 | mbx_mbox_cmd = idiag.cmd.data[IDIAG_MBXACC_MBCMD_INDX]; | ||
2888 | mbx_dump_map = idiag.cmd.data[IDIAG_MBXACC_DPMAP_INDX]; | ||
2889 | mbx_dump_cnt = idiag.cmd.data[IDIAG_MBXACC_DPCNT_INDX]; | ||
2890 | mbx_word_cnt = idiag.cmd.data[IDIAG_MBXACC_WDCNT_INDX]; | ||
2891 | |||
2892 | len += snprintf(pbuffer+len, LPFC_MBX_ACC_BUF_SIZE-len, | ||
2893 | "mbx_dump_map: 0x%08x\n", mbx_dump_map); | ||
2894 | len += snprintf(pbuffer+len, LPFC_MBX_ACC_BUF_SIZE-len, | ||
2895 | "mbx_dump_cnt: %04d\n", mbx_dump_cnt); | ||
2896 | len += snprintf(pbuffer+len, LPFC_MBX_ACC_BUF_SIZE-len, | ||
2897 | "mbx_word_cnt: %04d\n", mbx_word_cnt); | ||
2898 | len += snprintf(pbuffer+len, LPFC_MBX_ACC_BUF_SIZE-len, | ||
2899 | "mbx_mbox_cmd: 0x%02x\n", mbx_mbox_cmd); | ||
2900 | |||
2901 | return len; | ||
2902 | } | ||
2903 | |||
2904 | /** | ||
2905 | * lpfc_idiag_mbxacc_read - idiag debugfs read on mailbox access | ||
2906 | * @file: The file pointer to read from. | ||
2907 | * @buf: The buffer to copy the data to. | ||
2908 | * @nbytes: The number of bytes to read. | ||
2909 | * @ppos: The position in the file to start reading from. | ||
2910 | * | ||
2911 | * Description: | ||
2912 | * This routine reads data from the @phba driver mailbox access debugfs setup | ||
2913 | * information. | ||
2914 | * | ||
2915 | * Returns: | ||
2916 | * This function returns the amount of data that was read (this could be less | ||
2917 | * than @nbytes if the end of the file was reached) or a negative error value. | ||
2918 | **/ | ||
2919 | static ssize_t | ||
2920 | lpfc_idiag_mbxacc_read(struct file *file, char __user *buf, size_t nbytes, | ||
2921 | loff_t *ppos) | ||
2922 | { | ||
2923 | struct lpfc_debug *debug = file->private_data; | ||
2924 | struct lpfc_hba *phba = (struct lpfc_hba *)debug->i_private; | ||
2925 | char *pbuffer; | ||
2926 | int len = 0; | ||
2927 | |||
2928 | /* This is a user read operation */ | ||
2929 | debug->op = LPFC_IDIAG_OP_RD; | ||
2930 | |||
2931 | if (!debug->buffer) | ||
2932 | debug->buffer = kmalloc(LPFC_MBX_ACC_BUF_SIZE, GFP_KERNEL); | ||
2933 | if (!debug->buffer) | ||
2934 | return 0; | ||
2935 | pbuffer = debug->buffer; | ||
2936 | |||
2937 | if (*ppos) | ||
2938 | return 0; | ||
2939 | |||
2940 | if ((idiag.cmd.opcode != LPFC_IDIAG_CMD_MBXACC_DP) && | ||
2941 | (idiag.cmd.opcode != LPFC_IDIAG_BSG_MBXACC_DP)) | ||
2942 | return 0; | ||
2943 | |||
2944 | len = lpfc_idiag_mbxacc_get_setup(phba, pbuffer); | ||
2945 | |||
2946 | return simple_read_from_buffer(buf, nbytes, ppos, pbuffer, len); | ||
2947 | } | ||
2948 | |||
2949 | /** | ||
2950 | * lpfc_idiag_mbxacc_write - Syntax check and set up idiag mbxacc commands | ||
2951 | * @file: The file pointer to read from. | ||
2952 | * @buf: The buffer to copy the user data from. | ||
2953 | * @nbytes: The number of bytes to get. | ||
2954 | * @ppos: The position in the file to start reading from. | ||
2955 | * | ||
2956 | * This routine get the debugfs idiag command struct from user space and then | ||
2957 | * perform the syntax check for driver mailbox command (dump) and sets up the | ||
2958 | * necessary states in the idiag command struct accordingly. | ||
2959 | * | ||
2960 | * It returns the @nbytges passing in from debugfs user space when successful. | ||
2961 | * In case of error conditions, it returns proper error code back to the user | ||
2962 | * space. | ||
2963 | **/ | ||
2964 | static ssize_t | ||
2965 | lpfc_idiag_mbxacc_write(struct file *file, const char __user *buf, | ||
2966 | size_t nbytes, loff_t *ppos) | ||
2967 | { | ||
2968 | struct lpfc_debug *debug = file->private_data; | ||
2969 | uint32_t mbx_dump_map, mbx_dump_cnt, mbx_word_cnt, mbx_mbox_cmd; | ||
2970 | int rc; | ||
2971 | |||
2972 | /* This is a user write operation */ | ||
2973 | debug->op = LPFC_IDIAG_OP_WR; | ||
2974 | |||
2975 | rc = lpfc_idiag_cmd_get(buf, nbytes, &idiag.cmd); | ||
2976 | if (rc < 0) | ||
2977 | return rc; | ||
2978 | |||
2979 | /* Sanity check on command line arguments */ | ||
2980 | mbx_mbox_cmd = idiag.cmd.data[IDIAG_MBXACC_MBCMD_INDX]; | ||
2981 | mbx_dump_map = idiag.cmd.data[IDIAG_MBXACC_DPMAP_INDX]; | ||
2982 | mbx_dump_cnt = idiag.cmd.data[IDIAG_MBXACC_DPCNT_INDX]; | ||
2983 | mbx_word_cnt = idiag.cmd.data[IDIAG_MBXACC_WDCNT_INDX]; | ||
2984 | |||
2985 | if (idiag.cmd.opcode == LPFC_IDIAG_CMD_MBXACC_DP) { | ||
2986 | if (!(mbx_dump_map & LPFC_MBX_DMP_MBX_ALL)) | ||
2987 | goto error_out; | ||
2988 | if ((mbx_dump_map & ~LPFC_MBX_DMP_MBX_ALL) && | ||
2989 | (mbx_dump_map != LPFC_MBX_DMP_ALL)) | ||
2990 | goto error_out; | ||
2991 | if (mbx_word_cnt > sizeof(MAILBOX_t)) | ||
2992 | goto error_out; | ||
2993 | } else if (idiag.cmd.opcode == LPFC_IDIAG_BSG_MBXACC_DP) { | ||
2994 | if (!(mbx_dump_map & LPFC_BSG_DMP_MBX_ALL)) | ||
2995 | goto error_out; | ||
2996 | if ((mbx_dump_map & ~LPFC_BSG_DMP_MBX_ALL) && | ||
2997 | (mbx_dump_map != LPFC_MBX_DMP_ALL)) | ||
2998 | goto error_out; | ||
2999 | if (mbx_word_cnt > (BSG_MBOX_SIZE)/4) | ||
3000 | goto error_out; | ||
3001 | if (mbx_mbox_cmd != 0x9b) | ||
3002 | goto error_out; | ||
3003 | } else | ||
3004 | goto error_out; | ||
3005 | |||
3006 | if (mbx_word_cnt == 0) | ||
3007 | goto error_out; | ||
3008 | if (rc != LPFC_MBX_DMP_ARG) | ||
3009 | goto error_out; | ||
3010 | if (mbx_mbox_cmd & ~0xff) | ||
3011 | goto error_out; | ||
3012 | |||
3013 | /* condition for stop mailbox dump */ | ||
3014 | if (mbx_dump_cnt == 0) | ||
3015 | goto reset_out; | ||
3016 | |||
3017 | return nbytes; | ||
3018 | |||
3019 | reset_out: | ||
3020 | /* Clean out command structure on command error out */ | ||
3021 | memset(&idiag, 0, sizeof(idiag)); | ||
3022 | return nbytes; | ||
3023 | |||
3024 | error_out: | ||
3025 | /* Clean out command structure on command error out */ | ||
3026 | memset(&idiag, 0, sizeof(idiag)); | ||
3027 | return -EINVAL; | ||
3028 | } | ||
3029 | |||
3030 | /** | ||
3031 | * lpfc_idiag_extacc_avail_get - get the available extents information | ||
3032 | * @phba: pointer to lpfc hba data structure. | ||
3033 | * @pbuffer: pointer to internal buffer. | ||
3034 | * @len: length into the internal buffer data has been copied. | ||
3035 | * | ||
3036 | * Description: | ||
3037 | * This routine is to get the available extent information. | ||
3038 | * | ||
3039 | * Returns: | ||
3040 | * overall lenth of the data read into the internal buffer. | ||
3041 | **/ | ||
3042 | static int | ||
3043 | lpfc_idiag_extacc_avail_get(struct lpfc_hba *phba, char *pbuffer, int len) | ||
3044 | { | ||
3045 | uint16_t ext_cnt, ext_size; | ||
3046 | |||
3047 | len += snprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len, | ||
3048 | "\nAvailable Extents Information:\n"); | ||
3049 | |||
3050 | len += snprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len, | ||
3051 | "\tPort Available VPI extents: "); | ||
3052 | lpfc_sli4_get_avail_extnt_rsrc(phba, LPFC_RSC_TYPE_FCOE_VPI, | ||
3053 | &ext_cnt, &ext_size); | ||
3054 | len += snprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len, | ||
3055 | "Count %3d, Size %3d\n", ext_cnt, ext_size); | ||
3056 | |||
3057 | len += snprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len, | ||
3058 | "\tPort Available VFI extents: "); | ||
3059 | lpfc_sli4_get_avail_extnt_rsrc(phba, LPFC_RSC_TYPE_FCOE_VFI, | ||
3060 | &ext_cnt, &ext_size); | ||
3061 | len += snprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len, | ||
3062 | "Count %3d, Size %3d\n", ext_cnt, ext_size); | ||
3063 | |||
3064 | len += snprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len, | ||
3065 | "\tPort Available RPI extents: "); | ||
3066 | lpfc_sli4_get_avail_extnt_rsrc(phba, LPFC_RSC_TYPE_FCOE_RPI, | ||
3067 | &ext_cnt, &ext_size); | ||
3068 | len += snprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len, | ||
3069 | "Count %3d, Size %3d\n", ext_cnt, ext_size); | ||
3070 | |||
3071 | len += snprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len, | ||
3072 | "\tPort Available XRI extents: "); | ||
3073 | lpfc_sli4_get_avail_extnt_rsrc(phba, LPFC_RSC_TYPE_FCOE_XRI, | ||
3074 | &ext_cnt, &ext_size); | ||
3075 | len += snprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len, | ||
3076 | "Count %3d, Size %3d\n", ext_cnt, ext_size); | ||
3077 | |||
3078 | return len; | ||
3079 | } | ||
3080 | |||
3081 | /** | ||
3082 | * lpfc_idiag_extacc_alloc_get - get the allocated extents information | ||
3083 | * @phba: pointer to lpfc hba data structure. | ||
3084 | * @pbuffer: pointer to internal buffer. | ||
3085 | * @len: length into the internal buffer data has been copied. | ||
3086 | * | ||
3087 | * Description: | ||
3088 | * This routine is to get the allocated extent information. | ||
3089 | * | ||
3090 | * Returns: | ||
3091 | * overall lenth of the data read into the internal buffer. | ||
3092 | **/ | ||
3093 | static int | ||
3094 | lpfc_idiag_extacc_alloc_get(struct lpfc_hba *phba, char *pbuffer, int len) | ||
3095 | { | ||
3096 | uint16_t ext_cnt, ext_size; | ||
3097 | int rc; | ||
3098 | |||
3099 | len += snprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len, | ||
3100 | "\nAllocated Extents Information:\n"); | ||
3101 | |||
3102 | len += snprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len, | ||
3103 | "\tHost Allocated VPI extents: "); | ||
3104 | rc = lpfc_sli4_get_allocated_extnts(phba, LPFC_RSC_TYPE_FCOE_VPI, | ||
3105 | &ext_cnt, &ext_size); | ||
3106 | if (!rc) | ||
3107 | len += snprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len, | ||
3108 | "Port %d Extent %3d, Size %3d\n", | ||
3109 | phba->brd_no, ext_cnt, ext_size); | ||
3110 | else | ||
3111 | len += snprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len, | ||
3112 | "N/A\n"); | ||
3113 | |||
3114 | len += snprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len, | ||
3115 | "\tHost Allocated VFI extents: "); | ||
3116 | rc = lpfc_sli4_get_allocated_extnts(phba, LPFC_RSC_TYPE_FCOE_VFI, | ||
3117 | &ext_cnt, &ext_size); | ||
3118 | if (!rc) | ||
3119 | len += snprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len, | ||
3120 | "Port %d Extent %3d, Size %3d\n", | ||
3121 | phba->brd_no, ext_cnt, ext_size); | ||
3122 | else | ||
3123 | len += snprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len, | ||
3124 | "N/A\n"); | ||
3125 | |||
3126 | len += snprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len, | ||
3127 | "\tHost Allocated RPI extents: "); | ||
3128 | rc = lpfc_sli4_get_allocated_extnts(phba, LPFC_RSC_TYPE_FCOE_RPI, | ||
3129 | &ext_cnt, &ext_size); | ||
3130 | if (!rc) | ||
3131 | len += snprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len, | ||
3132 | "Port %d Extent %3d, Size %3d\n", | ||
3133 | phba->brd_no, ext_cnt, ext_size); | ||
3134 | else | ||
3135 | len += snprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len, | ||
3136 | "N/A\n"); | ||
3137 | |||
3138 | len += snprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len, | ||
3139 | "\tHost Allocated XRI extents: "); | ||
3140 | rc = lpfc_sli4_get_allocated_extnts(phba, LPFC_RSC_TYPE_FCOE_XRI, | ||
3141 | &ext_cnt, &ext_size); | ||
3142 | if (!rc) | ||
3143 | len += snprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len, | ||
3144 | "Port %d Extent %3d, Size %3d\n", | ||
3145 | phba->brd_no, ext_cnt, ext_size); | ||
3146 | else | ||
3147 | len += snprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len, | ||
3148 | "N/A\n"); | ||
3149 | |||
3150 | return len; | ||
3151 | } | ||
3152 | |||
3153 | /** | ||
3154 | * lpfc_idiag_extacc_drivr_get - get driver extent information | ||
3155 | * @phba: pointer to lpfc hba data structure. | ||
3156 | * @pbuffer: pointer to internal buffer. | ||
3157 | * @len: length into the internal buffer data has been copied. | ||
3158 | * | ||
3159 | * Description: | ||
3160 | * This routine is to get the driver extent information. | ||
3161 | * | ||
3162 | * Returns: | ||
3163 | * overall lenth of the data read into the internal buffer. | ||
3164 | **/ | ||
3165 | static int | ||
3166 | lpfc_idiag_extacc_drivr_get(struct lpfc_hba *phba, char *pbuffer, int len) | ||
3167 | { | ||
3168 | struct lpfc_rsrc_blks *rsrc_blks; | ||
3169 | int index; | ||
3170 | |||
3171 | len += snprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len, | ||
3172 | "\nDriver Extents Information:\n"); | ||
3173 | |||
3174 | len += snprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len, | ||
3175 | "\tVPI extents:\n"); | ||
3176 | index = 0; | ||
3177 | list_for_each_entry(rsrc_blks, &phba->lpfc_vpi_blk_list, list) { | ||
3178 | len += snprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len, | ||
3179 | "\t\tBlock %3d: Start %4d, Count %4d\n", | ||
3180 | index, rsrc_blks->rsrc_start, | ||
3181 | rsrc_blks->rsrc_size); | ||
3182 | index++; | ||
3183 | } | ||
3184 | len += snprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len, | ||
3185 | "\tVFI extents:\n"); | ||
3186 | index = 0; | ||
3187 | list_for_each_entry(rsrc_blks, &phba->sli4_hba.lpfc_vfi_blk_list, | ||
3188 | list) { | ||
3189 | len += snprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len, | ||
3190 | "\t\tBlock %3d: Start %4d, Count %4d\n", | ||
3191 | index, rsrc_blks->rsrc_start, | ||
3192 | rsrc_blks->rsrc_size); | ||
3193 | index++; | ||
3194 | } | ||
3195 | |||
3196 | len += snprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len, | ||
3197 | "\tRPI extents:\n"); | ||
3198 | index = 0; | ||
3199 | list_for_each_entry(rsrc_blks, &phba->sli4_hba.lpfc_rpi_blk_list, | ||
3200 | list) { | ||
3201 | len += snprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len, | ||
3202 | "\t\tBlock %3d: Start %4d, Count %4d\n", | ||
3203 | index, rsrc_blks->rsrc_start, | ||
3204 | rsrc_blks->rsrc_size); | ||
3205 | index++; | ||
3206 | } | ||
3207 | |||
3208 | len += snprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len, | ||
3209 | "\tXRI extents:\n"); | ||
3210 | index = 0; | ||
3211 | list_for_each_entry(rsrc_blks, &phba->sli4_hba.lpfc_xri_blk_list, | ||
3212 | list) { | ||
3213 | len += snprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len, | ||
3214 | "\t\tBlock %3d: Start %4d, Count %4d\n", | ||
3215 | index, rsrc_blks->rsrc_start, | ||
3216 | rsrc_blks->rsrc_size); | ||
3217 | index++; | ||
3218 | } | ||
3219 | |||
3220 | return len; | ||
3221 | } | ||
3222 | |||
3223 | /** | ||
3224 | * lpfc_idiag_extacc_write - Syntax check and set up idiag extacc commands | ||
3225 | * @file: The file pointer to read from. | ||
3226 | * @buf: The buffer to copy the user data from. | ||
3227 | * @nbytes: The number of bytes to get. | ||
3228 | * @ppos: The position in the file to start reading from. | ||
3229 | * | ||
3230 | * This routine get the debugfs idiag command struct from user space and then | ||
3231 | * perform the syntax check for extent information access commands and sets | ||
3232 | * up the necessary states in the idiag command struct accordingly. | ||
3233 | * | ||
3234 | * It returns the @nbytges passing in from debugfs user space when successful. | ||
3235 | * In case of error conditions, it returns proper error code back to the user | ||
3236 | * space. | ||
3237 | **/ | ||
3238 | static ssize_t | ||
3239 | lpfc_idiag_extacc_write(struct file *file, const char __user *buf, | ||
3240 | size_t nbytes, loff_t *ppos) | ||
3241 | { | ||
3242 | struct lpfc_debug *debug = file->private_data; | ||
3243 | uint32_t ext_map; | ||
3244 | int rc; | ||
3245 | |||
3246 | /* This is a user write operation */ | ||
3247 | debug->op = LPFC_IDIAG_OP_WR; | ||
3248 | |||
3249 | rc = lpfc_idiag_cmd_get(buf, nbytes, &idiag.cmd); | ||
3250 | if (rc < 0) | ||
3251 | return rc; | ||
3252 | |||
3253 | ext_map = idiag.cmd.data[IDIAG_EXTACC_EXMAP_INDX]; | ||
3254 | |||
3255 | if (idiag.cmd.opcode != LPFC_IDIAG_CMD_EXTACC_RD) | ||
3256 | goto error_out; | ||
3257 | if (rc != LPFC_EXT_ACC_CMD_ARG) | ||
3258 | goto error_out; | ||
3259 | if (!(ext_map & LPFC_EXT_ACC_ALL)) | ||
3260 | goto error_out; | ||
3261 | |||
3262 | return nbytes; | ||
3263 | error_out: | ||
3264 | /* Clean out command structure on command error out */ | ||
3265 | memset(&idiag, 0, sizeof(idiag)); | ||
3266 | return -EINVAL; | ||
3267 | } | ||
3268 | |||
3269 | /** | ||
3270 | * lpfc_idiag_extacc_read - idiag debugfs read access to extent information | ||
3271 | * @file: The file pointer to read from. | ||
3272 | * @buf: The buffer to copy the data to. | ||
3273 | * @nbytes: The number of bytes to read. | ||
3274 | * @ppos: The position in the file to start reading from. | ||
3275 | * | ||
3276 | * Description: | ||
3277 | * This routine reads data from the proper extent information according to | ||
3278 | * the idiag command, and copies to user @buf. | ||
3279 | * | ||
3280 | * Returns: | ||
3281 | * This function returns the amount of data that was read (this could be less | ||
3282 | * than @nbytes if the end of the file was reached) or a negative error value. | ||
3283 | **/ | ||
3284 | static ssize_t | ||
3285 | lpfc_idiag_extacc_read(struct file *file, char __user *buf, size_t nbytes, | ||
3286 | loff_t *ppos) | ||
3287 | { | ||
3288 | struct lpfc_debug *debug = file->private_data; | ||
3289 | struct lpfc_hba *phba = (struct lpfc_hba *)debug->i_private; | ||
3290 | char *pbuffer; | ||
3291 | uint32_t ext_map; | ||
3292 | int len = 0; | ||
3293 | |||
3294 | /* This is a user read operation */ | ||
3295 | debug->op = LPFC_IDIAG_OP_RD; | ||
3296 | |||
3297 | if (!debug->buffer) | ||
3298 | debug->buffer = kmalloc(LPFC_EXT_ACC_BUF_SIZE, GFP_KERNEL); | ||
3299 | if (!debug->buffer) | ||
3300 | return 0; | ||
3301 | pbuffer = debug->buffer; | ||
3302 | if (*ppos) | ||
3303 | return 0; | ||
3304 | if (idiag.cmd.opcode != LPFC_IDIAG_CMD_EXTACC_RD) | ||
3305 | return 0; | ||
3306 | |||
3307 | ext_map = idiag.cmd.data[IDIAG_EXTACC_EXMAP_INDX]; | ||
3308 | if (ext_map & LPFC_EXT_ACC_AVAIL) | ||
3309 | len = lpfc_idiag_extacc_avail_get(phba, pbuffer, len); | ||
3310 | if (ext_map & LPFC_EXT_ACC_ALLOC) | ||
3311 | len = lpfc_idiag_extacc_alloc_get(phba, pbuffer, len); | ||
3312 | if (ext_map & LPFC_EXT_ACC_DRIVR) | ||
3313 | len = lpfc_idiag_extacc_drivr_get(phba, pbuffer, len); | ||
3314 | |||
3315 | return simple_read_from_buffer(buf, nbytes, ppos, pbuffer, len); | ||
3316 | } | ||
3317 | |||
2333 | #undef lpfc_debugfs_op_disc_trc | 3318 | #undef lpfc_debugfs_op_disc_trc |
2334 | static const struct file_operations lpfc_debugfs_op_disc_trc = { | 3319 | static const struct file_operations lpfc_debugfs_op_disc_trc = { |
2335 | .owner = THIS_MODULE, | 3320 | .owner = THIS_MODULE, |
@@ -2420,6 +3405,16 @@ static const struct file_operations lpfc_idiag_op_pciCfg = { | |||
2420 | .release = lpfc_idiag_cmd_release, | 3405 | .release = lpfc_idiag_cmd_release, |
2421 | }; | 3406 | }; |
2422 | 3407 | ||
3408 | #undef lpfc_idiag_op_barAcc | ||
3409 | static const struct file_operations lpfc_idiag_op_barAcc = { | ||
3410 | .owner = THIS_MODULE, | ||
3411 | .open = lpfc_idiag_open, | ||
3412 | .llseek = lpfc_debugfs_lseek, | ||
3413 | .read = lpfc_idiag_baracc_read, | ||
3414 | .write = lpfc_idiag_baracc_write, | ||
3415 | .release = lpfc_idiag_cmd_release, | ||
3416 | }; | ||
3417 | |||
2423 | #undef lpfc_idiag_op_queInfo | 3418 | #undef lpfc_idiag_op_queInfo |
2424 | static const struct file_operations lpfc_idiag_op_queInfo = { | 3419 | static const struct file_operations lpfc_idiag_op_queInfo = { |
2425 | .owner = THIS_MODULE, | 3420 | .owner = THIS_MODULE, |
@@ -2428,7 +3423,7 @@ static const struct file_operations lpfc_idiag_op_queInfo = { | |||
2428 | .release = lpfc_idiag_release, | 3423 | .release = lpfc_idiag_release, |
2429 | }; | 3424 | }; |
2430 | 3425 | ||
2431 | #undef lpfc_idiag_op_queacc | 3426 | #undef lpfc_idiag_op_queAcc |
2432 | static const struct file_operations lpfc_idiag_op_queAcc = { | 3427 | static const struct file_operations lpfc_idiag_op_queAcc = { |
2433 | .owner = THIS_MODULE, | 3428 | .owner = THIS_MODULE, |
2434 | .open = lpfc_idiag_open, | 3429 | .open = lpfc_idiag_open, |
@@ -2438,7 +3433,7 @@ static const struct file_operations lpfc_idiag_op_queAcc = { | |||
2438 | .release = lpfc_idiag_cmd_release, | 3433 | .release = lpfc_idiag_cmd_release, |
2439 | }; | 3434 | }; |
2440 | 3435 | ||
2441 | #undef lpfc_idiag_op_drbacc | 3436 | #undef lpfc_idiag_op_drbAcc |
2442 | static const struct file_operations lpfc_idiag_op_drbAcc = { | 3437 | static const struct file_operations lpfc_idiag_op_drbAcc = { |
2443 | .owner = THIS_MODULE, | 3438 | .owner = THIS_MODULE, |
2444 | .open = lpfc_idiag_open, | 3439 | .open = lpfc_idiag_open, |
@@ -2448,8 +3443,234 @@ static const struct file_operations lpfc_idiag_op_drbAcc = { | |||
2448 | .release = lpfc_idiag_cmd_release, | 3443 | .release = lpfc_idiag_cmd_release, |
2449 | }; | 3444 | }; |
2450 | 3445 | ||
3446 | #undef lpfc_idiag_op_ctlAcc | ||
3447 | static const struct file_operations lpfc_idiag_op_ctlAcc = { | ||
3448 | .owner = THIS_MODULE, | ||
3449 | .open = lpfc_idiag_open, | ||
3450 | .llseek = lpfc_debugfs_lseek, | ||
3451 | .read = lpfc_idiag_ctlacc_read, | ||
3452 | .write = lpfc_idiag_ctlacc_write, | ||
3453 | .release = lpfc_idiag_cmd_release, | ||
3454 | }; | ||
3455 | |||
3456 | #undef lpfc_idiag_op_mbxAcc | ||
3457 | static const struct file_operations lpfc_idiag_op_mbxAcc = { | ||
3458 | .owner = THIS_MODULE, | ||
3459 | .open = lpfc_idiag_open, | ||
3460 | .llseek = lpfc_debugfs_lseek, | ||
3461 | .read = lpfc_idiag_mbxacc_read, | ||
3462 | .write = lpfc_idiag_mbxacc_write, | ||
3463 | .release = lpfc_idiag_cmd_release, | ||
3464 | }; | ||
3465 | |||
3466 | #undef lpfc_idiag_op_extAcc | ||
3467 | static const struct file_operations lpfc_idiag_op_extAcc = { | ||
3468 | .owner = THIS_MODULE, | ||
3469 | .open = lpfc_idiag_open, | ||
3470 | .llseek = lpfc_debugfs_lseek, | ||
3471 | .read = lpfc_idiag_extacc_read, | ||
3472 | .write = lpfc_idiag_extacc_write, | ||
3473 | .release = lpfc_idiag_cmd_release, | ||
3474 | }; | ||
3475 | |||
2451 | #endif | 3476 | #endif |
2452 | 3477 | ||
3478 | /* lpfc_idiag_mbxacc_dump_bsg_mbox - idiag debugfs dump bsg mailbox command | ||
3479 | * @phba: Pointer to HBA context object. | ||
3480 | * @dmabuf: Pointer to a DMA buffer descriptor. | ||
3481 | * | ||
3482 | * Description: | ||
3483 | * This routine dump a bsg pass-through non-embedded mailbox command with | ||
3484 | * external buffer. | ||
3485 | **/ | ||
3486 | void | ||
3487 | lpfc_idiag_mbxacc_dump_bsg_mbox(struct lpfc_hba *phba, enum nemb_type nemb_tp, | ||
3488 | enum mbox_type mbox_tp, enum dma_type dma_tp, | ||
3489 | enum sta_type sta_tp, | ||
3490 | struct lpfc_dmabuf *dmabuf, uint32_t ext_buf) | ||
3491 | { | ||
3492 | #ifdef CONFIG_SCSI_LPFC_DEBUG_FS | ||
3493 | uint32_t *mbx_mbox_cmd, *mbx_dump_map, *mbx_dump_cnt, *mbx_word_cnt; | ||
3494 | char line_buf[LPFC_MBX_ACC_LBUF_SZ]; | ||
3495 | int len = 0; | ||
3496 | uint32_t do_dump = 0; | ||
3497 | uint32_t *pword; | ||
3498 | uint32_t i; | ||
3499 | |||
3500 | if (idiag.cmd.opcode != LPFC_IDIAG_BSG_MBXACC_DP) | ||
3501 | return; | ||
3502 | |||
3503 | mbx_mbox_cmd = &idiag.cmd.data[IDIAG_MBXACC_MBCMD_INDX]; | ||
3504 | mbx_dump_map = &idiag.cmd.data[IDIAG_MBXACC_DPMAP_INDX]; | ||
3505 | mbx_dump_cnt = &idiag.cmd.data[IDIAG_MBXACC_DPCNT_INDX]; | ||
3506 | mbx_word_cnt = &idiag.cmd.data[IDIAG_MBXACC_WDCNT_INDX]; | ||
3507 | |||
3508 | if (!(*mbx_dump_map & LPFC_MBX_DMP_ALL) || | ||
3509 | (*mbx_dump_cnt == 0) || | ||
3510 | (*mbx_word_cnt == 0)) | ||
3511 | return; | ||
3512 | |||
3513 | if (*mbx_mbox_cmd != 0x9B) | ||
3514 | return; | ||
3515 | |||
3516 | if ((mbox_tp == mbox_rd) && (dma_tp == dma_mbox)) { | ||
3517 | if (*mbx_dump_map & LPFC_BSG_DMP_MBX_RD_MBX) { | ||
3518 | do_dump |= LPFC_BSG_DMP_MBX_RD_MBX; | ||
3519 | printk(KERN_ERR "\nRead mbox command (x%x), " | ||
3520 | "nemb:0x%x, extbuf_cnt:%d:\n", | ||
3521 | sta_tp, nemb_tp, ext_buf); | ||
3522 | } | ||
3523 | } | ||
3524 | if ((mbox_tp == mbox_rd) && (dma_tp == dma_ebuf)) { | ||
3525 | if (*mbx_dump_map & LPFC_BSG_DMP_MBX_RD_BUF) { | ||
3526 | do_dump |= LPFC_BSG_DMP_MBX_RD_BUF; | ||
3527 | printk(KERN_ERR "\nRead mbox buffer (x%x), " | ||
3528 | "nemb:0x%x, extbuf_seq:%d:\n", | ||
3529 | sta_tp, nemb_tp, ext_buf); | ||
3530 | } | ||
3531 | } | ||
3532 | if ((mbox_tp == mbox_wr) && (dma_tp == dma_mbox)) { | ||
3533 | if (*mbx_dump_map & LPFC_BSG_DMP_MBX_WR_MBX) { | ||
3534 | do_dump |= LPFC_BSG_DMP_MBX_WR_MBX; | ||
3535 | printk(KERN_ERR "\nWrite mbox command (x%x), " | ||
3536 | "nemb:0x%x, extbuf_cnt:%d:\n", | ||
3537 | sta_tp, nemb_tp, ext_buf); | ||
3538 | } | ||
3539 | } | ||
3540 | if ((mbox_tp == mbox_wr) && (dma_tp == dma_ebuf)) { | ||
3541 | if (*mbx_dump_map & LPFC_BSG_DMP_MBX_WR_BUF) { | ||
3542 | do_dump |= LPFC_BSG_DMP_MBX_WR_BUF; | ||
3543 | printk(KERN_ERR "\nWrite mbox buffer (x%x), " | ||
3544 | "nemb:0x%x, extbuf_seq:%d:\n", | ||
3545 | sta_tp, nemb_tp, ext_buf); | ||
3546 | } | ||
3547 | } | ||
3548 | |||
3549 | /* dump buffer content */ | ||
3550 | if (do_dump) { | ||
3551 | pword = (uint32_t *)dmabuf->virt; | ||
3552 | for (i = 0; i < *mbx_word_cnt; i++) { | ||
3553 | if (!(i % 8)) { | ||
3554 | if (i != 0) | ||
3555 | printk(KERN_ERR "%s\n", line_buf); | ||
3556 | len = 0; | ||
3557 | len += snprintf(line_buf+len, | ||
3558 | LPFC_MBX_ACC_LBUF_SZ-len, | ||
3559 | "%03d: ", i); | ||
3560 | } | ||
3561 | len += snprintf(line_buf+len, LPFC_MBX_ACC_LBUF_SZ-len, | ||
3562 | "%08x ", (uint32_t)*pword); | ||
3563 | pword++; | ||
3564 | } | ||
3565 | if ((i - 1) % 8) | ||
3566 | printk(KERN_ERR "%s\n", line_buf); | ||
3567 | (*mbx_dump_cnt)--; | ||
3568 | } | ||
3569 | |||
3570 | /* Clean out command structure on reaching dump count */ | ||
3571 | if (*mbx_dump_cnt == 0) | ||
3572 | memset(&idiag, 0, sizeof(idiag)); | ||
3573 | return; | ||
3574 | #endif | ||
3575 | } | ||
3576 | |||
3577 | /* lpfc_idiag_mbxacc_dump_issue_mbox - idiag debugfs dump issue mailbox command | ||
3578 | * @phba: Pointer to HBA context object. | ||
3579 | * @dmabuf: Pointer to a DMA buffer descriptor. | ||
3580 | * | ||
3581 | * Description: | ||
3582 | * This routine dump a pass-through non-embedded mailbox command from issue | ||
3583 | * mailbox command. | ||
3584 | **/ | ||
3585 | void | ||
3586 | lpfc_idiag_mbxacc_dump_issue_mbox(struct lpfc_hba *phba, MAILBOX_t *pmbox) | ||
3587 | { | ||
3588 | #ifdef CONFIG_SCSI_LPFC_DEBUG_FS | ||
3589 | uint32_t *mbx_dump_map, *mbx_dump_cnt, *mbx_word_cnt, *mbx_mbox_cmd; | ||
3590 | char line_buf[LPFC_MBX_ACC_LBUF_SZ]; | ||
3591 | int len = 0; | ||
3592 | uint32_t *pword; | ||
3593 | uint8_t *pbyte; | ||
3594 | uint32_t i, j; | ||
3595 | |||
3596 | if (idiag.cmd.opcode != LPFC_IDIAG_CMD_MBXACC_DP) | ||
3597 | return; | ||
3598 | |||
3599 | mbx_mbox_cmd = &idiag.cmd.data[IDIAG_MBXACC_MBCMD_INDX]; | ||
3600 | mbx_dump_map = &idiag.cmd.data[IDIAG_MBXACC_DPMAP_INDX]; | ||
3601 | mbx_dump_cnt = &idiag.cmd.data[IDIAG_MBXACC_DPCNT_INDX]; | ||
3602 | mbx_word_cnt = &idiag.cmd.data[IDIAG_MBXACC_WDCNT_INDX]; | ||
3603 | |||
3604 | if (!(*mbx_dump_map & LPFC_MBX_DMP_MBX_ALL) || | ||
3605 | (*mbx_dump_cnt == 0) || | ||
3606 | (*mbx_word_cnt == 0)) | ||
3607 | return; | ||
3608 | |||
3609 | if ((*mbx_mbox_cmd != LPFC_MBX_ALL_CMD) && | ||
3610 | (*mbx_mbox_cmd != pmbox->mbxCommand)) | ||
3611 | return; | ||
3612 | |||
3613 | /* dump buffer content */ | ||
3614 | if (*mbx_dump_map & LPFC_MBX_DMP_MBX_WORD) { | ||
3615 | printk(KERN_ERR "Mailbox command:0x%x dump by word:\n", | ||
3616 | pmbox->mbxCommand); | ||
3617 | pword = (uint32_t *)pmbox; | ||
3618 | for (i = 0; i < *mbx_word_cnt; i++) { | ||
3619 | if (!(i % 8)) { | ||
3620 | if (i != 0) | ||
3621 | printk(KERN_ERR "%s\n", line_buf); | ||
3622 | len = 0; | ||
3623 | memset(line_buf, 0, LPFC_MBX_ACC_LBUF_SZ); | ||
3624 | len += snprintf(line_buf+len, | ||
3625 | LPFC_MBX_ACC_LBUF_SZ-len, | ||
3626 | "%03d: ", i); | ||
3627 | } | ||
3628 | len += snprintf(line_buf+len, LPFC_MBX_ACC_LBUF_SZ-len, | ||
3629 | "%08x ", | ||
3630 | ((uint32_t)*pword) & 0xffffffff); | ||
3631 | pword++; | ||
3632 | } | ||
3633 | if ((i - 1) % 8) | ||
3634 | printk(KERN_ERR "%s\n", line_buf); | ||
3635 | printk(KERN_ERR "\n"); | ||
3636 | } | ||
3637 | if (*mbx_dump_map & LPFC_MBX_DMP_MBX_BYTE) { | ||
3638 | printk(KERN_ERR "Mailbox command:0x%x dump by byte:\n", | ||
3639 | pmbox->mbxCommand); | ||
3640 | pbyte = (uint8_t *)pmbox; | ||
3641 | for (i = 0; i < *mbx_word_cnt; i++) { | ||
3642 | if (!(i % 8)) { | ||
3643 | if (i != 0) | ||
3644 | printk(KERN_ERR "%s\n", line_buf); | ||
3645 | len = 0; | ||
3646 | memset(line_buf, 0, LPFC_MBX_ACC_LBUF_SZ); | ||
3647 | len += snprintf(line_buf+len, | ||
3648 | LPFC_MBX_ACC_LBUF_SZ-len, | ||
3649 | "%03d: ", i); | ||
3650 | } | ||
3651 | for (j = 0; j < 4; j++) { | ||
3652 | len += snprintf(line_buf+len, | ||
3653 | LPFC_MBX_ACC_LBUF_SZ-len, | ||
3654 | "%02x", | ||
3655 | ((uint8_t)*pbyte) & 0xff); | ||
3656 | pbyte++; | ||
3657 | } | ||
3658 | len += snprintf(line_buf+len, | ||
3659 | LPFC_MBX_ACC_LBUF_SZ-len, " "); | ||
3660 | } | ||
3661 | if ((i - 1) % 8) | ||
3662 | printk(KERN_ERR "%s\n", line_buf); | ||
3663 | printk(KERN_ERR "\n"); | ||
3664 | } | ||
3665 | (*mbx_dump_cnt)--; | ||
3666 | |||
3667 | /* Clean out command structure on reaching dump count */ | ||
3668 | if (*mbx_dump_cnt == 0) | ||
3669 | memset(&idiag, 0, sizeof(idiag)); | ||
3670 | return; | ||
3671 | #endif | ||
3672 | } | ||
3673 | |||
2453 | /** | 3674 | /** |
2454 | * lpfc_debugfs_initialize - Initialize debugfs for a vport | 3675 | * lpfc_debugfs_initialize - Initialize debugfs for a vport |
2455 | * @vport: The vport pointer to initialize. | 3676 | * @vport: The vport pointer to initialize. |
@@ -2673,7 +3894,7 @@ lpfc_debugfs_initialize(struct lpfc_vport *vport) | |||
2673 | vport, &lpfc_debugfs_op_nodelist); | 3894 | vport, &lpfc_debugfs_op_nodelist); |
2674 | if (!vport->debug_nodelist) { | 3895 | if (!vport->debug_nodelist) { |
2675 | lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT, | 3896 | lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT, |
2676 | "0409 Can't create debugfs nodelist\n"); | 3897 | "2985 Can't create debugfs nodelist\n"); |
2677 | goto debug_failed; | 3898 | goto debug_failed; |
2678 | } | 3899 | } |
2679 | 3900 | ||
@@ -2710,6 +3931,20 @@ lpfc_debugfs_initialize(struct lpfc_vport *vport) | |||
2710 | idiag.offset.last_rd = 0; | 3931 | idiag.offset.last_rd = 0; |
2711 | } | 3932 | } |
2712 | 3933 | ||
3934 | /* iDiag PCI BAR access */ | ||
3935 | snprintf(name, sizeof(name), "barAcc"); | ||
3936 | if (!phba->idiag_bar_acc) { | ||
3937 | phba->idiag_bar_acc = | ||
3938 | debugfs_create_file(name, S_IFREG|S_IRUGO|S_IWUSR, | ||
3939 | phba->idiag_root, phba, &lpfc_idiag_op_barAcc); | ||
3940 | if (!phba->idiag_bar_acc) { | ||
3941 | lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT, | ||
3942 | "3056 Can't create idiag debugfs\n"); | ||
3943 | goto debug_failed; | ||
3944 | } | ||
3945 | idiag.offset.last_rd = 0; | ||
3946 | } | ||
3947 | |||
2713 | /* iDiag get PCI function queue information */ | 3948 | /* iDiag get PCI function queue information */ |
2714 | snprintf(name, sizeof(name), "queInfo"); | 3949 | snprintf(name, sizeof(name), "queInfo"); |
2715 | if (!phba->idiag_que_info) { | 3950 | if (!phba->idiag_que_info) { |
@@ -2749,6 +3984,50 @@ lpfc_debugfs_initialize(struct lpfc_vport *vport) | |||
2749 | } | 3984 | } |
2750 | } | 3985 | } |
2751 | 3986 | ||
3987 | /* iDiag access PCI function control registers */ | ||
3988 | snprintf(name, sizeof(name), "ctlAcc"); | ||
3989 | if (!phba->idiag_ctl_acc) { | ||
3990 | phba->idiag_ctl_acc = | ||
3991 | debugfs_create_file(name, S_IFREG|S_IRUGO|S_IWUSR, | ||
3992 | phba->idiag_root, phba, &lpfc_idiag_op_ctlAcc); | ||
3993 | if (!phba->idiag_ctl_acc) { | ||
3994 | lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT, | ||
3995 | "2981 Can't create idiag debugfs\n"); | ||
3996 | goto debug_failed; | ||
3997 | } | ||
3998 | } | ||
3999 | |||
4000 | /* iDiag access mbox commands */ | ||
4001 | snprintf(name, sizeof(name), "mbxAcc"); | ||
4002 | if (!phba->idiag_mbx_acc) { | ||
4003 | phba->idiag_mbx_acc = | ||
4004 | debugfs_create_file(name, S_IFREG|S_IRUGO|S_IWUSR, | ||
4005 | phba->idiag_root, phba, &lpfc_idiag_op_mbxAcc); | ||
4006 | if (!phba->idiag_mbx_acc) { | ||
4007 | lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT, | ||
4008 | "2980 Can't create idiag debugfs\n"); | ||
4009 | goto debug_failed; | ||
4010 | } | ||
4011 | } | ||
4012 | |||
4013 | /* iDiag extents access commands */ | ||
4014 | if (phba->sli4_hba.extents_in_use) { | ||
4015 | snprintf(name, sizeof(name), "extAcc"); | ||
4016 | if (!phba->idiag_ext_acc) { | ||
4017 | phba->idiag_ext_acc = | ||
4018 | debugfs_create_file(name, | ||
4019 | S_IFREG|S_IRUGO|S_IWUSR, | ||
4020 | phba->idiag_root, phba, | ||
4021 | &lpfc_idiag_op_extAcc); | ||
4022 | if (!phba->idiag_ext_acc) { | ||
4023 | lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT, | ||
4024 | "2986 Cant create " | ||
4025 | "idiag debugfs\n"); | ||
4026 | goto debug_failed; | ||
4027 | } | ||
4028 | } | ||
4029 | } | ||
4030 | |||
2752 | debug_failed: | 4031 | debug_failed: |
2753 | return; | 4032 | return; |
2754 | #endif | 4033 | #endif |
@@ -2783,7 +4062,6 @@ lpfc_debugfs_terminate(struct lpfc_vport *vport) | |||
2783 | debugfs_remove(vport->debug_nodelist); /* nodelist */ | 4062 | debugfs_remove(vport->debug_nodelist); /* nodelist */ |
2784 | vport->debug_nodelist = NULL; | 4063 | vport->debug_nodelist = NULL; |
2785 | } | 4064 | } |
2786 | |||
2787 | if (vport->vport_debugfs_root) { | 4065 | if (vport->vport_debugfs_root) { |
2788 | debugfs_remove(vport->vport_debugfs_root); /* vportX */ | 4066 | debugfs_remove(vport->vport_debugfs_root); /* vportX */ |
2789 | vport->vport_debugfs_root = NULL; | 4067 | vport->vport_debugfs_root = NULL; |
@@ -2827,6 +4105,21 @@ lpfc_debugfs_terminate(struct lpfc_vport *vport) | |||
2827 | * iDiag release | 4105 | * iDiag release |
2828 | */ | 4106 | */ |
2829 | if (phba->sli_rev == LPFC_SLI_REV4) { | 4107 | if (phba->sli_rev == LPFC_SLI_REV4) { |
4108 | if (phba->idiag_ext_acc) { | ||
4109 | /* iDiag extAcc */ | ||
4110 | debugfs_remove(phba->idiag_ext_acc); | ||
4111 | phba->idiag_ext_acc = NULL; | ||
4112 | } | ||
4113 | if (phba->idiag_mbx_acc) { | ||
4114 | /* iDiag mbxAcc */ | ||
4115 | debugfs_remove(phba->idiag_mbx_acc); | ||
4116 | phba->idiag_mbx_acc = NULL; | ||
4117 | } | ||
4118 | if (phba->idiag_ctl_acc) { | ||
4119 | /* iDiag ctlAcc */ | ||
4120 | debugfs_remove(phba->idiag_ctl_acc); | ||
4121 | phba->idiag_ctl_acc = NULL; | ||
4122 | } | ||
2830 | if (phba->idiag_drb_acc) { | 4123 | if (phba->idiag_drb_acc) { |
2831 | /* iDiag drbAcc */ | 4124 | /* iDiag drbAcc */ |
2832 | debugfs_remove(phba->idiag_drb_acc); | 4125 | debugfs_remove(phba->idiag_drb_acc); |
@@ -2842,6 +4135,11 @@ lpfc_debugfs_terminate(struct lpfc_vport *vport) | |||
2842 | debugfs_remove(phba->idiag_que_info); | 4135 | debugfs_remove(phba->idiag_que_info); |
2843 | phba->idiag_que_info = NULL; | 4136 | phba->idiag_que_info = NULL; |
2844 | } | 4137 | } |
4138 | if (phba->idiag_bar_acc) { | ||
4139 | /* iDiag barAcc */ | ||
4140 | debugfs_remove(phba->idiag_bar_acc); | ||
4141 | phba->idiag_bar_acc = NULL; | ||
4142 | } | ||
2845 | if (phba->idiag_pci_cfg) { | 4143 | if (phba->idiag_pci_cfg) { |
2846 | /* iDiag pciCfg */ | 4144 | /* iDiag pciCfg */ |
2847 | debugfs_remove(phba->idiag_pci_cfg); | 4145 | debugfs_remove(phba->idiag_pci_cfg); |