diff options
Diffstat (limited to 'drivers/scsi/lpfc/lpfc_debugfs.c')
-rw-r--r-- | drivers/scsi/lpfc/lpfc_debugfs.c | 931 |
1 files changed, 713 insertions, 218 deletions
diff --git a/drivers/scsi/lpfc/lpfc_debugfs.c b/drivers/scsi/lpfc/lpfc_debugfs.c index 3d967741c708..c93fca058603 100644 --- a/drivers/scsi/lpfc/lpfc_debugfs.c +++ b/drivers/scsi/lpfc/lpfc_debugfs.c | |||
@@ -1119,172 +1119,14 @@ lpfc_debugfs_dumpDataDif_release(struct inode *inode, struct file *file) | |||
1119 | } | 1119 | } |
1120 | 1120 | ||
1121 | /* | 1121 | /* |
1122 | * --------------------------------- | ||
1122 | * iDiag debugfs file access methods | 1123 | * iDiag debugfs file access methods |
1123 | */ | 1124 | * --------------------------------- |
1124 | |||
1125 | /* | ||
1126 | * iDiag PCI config space register access methods: | ||
1127 | * | ||
1128 | * The PCI config space register accessees of read, write, read-modify-write | ||
1129 | * for set bits, and read-modify-write for clear bits to SLI4 PCI functions | ||
1130 | * are provided. In the proper SLI4 PCI function's debugfs iDiag directory, | ||
1131 | * | ||
1132 | * /sys/kernel/debug/lpfc/fn<#>/iDiag | ||
1133 | * | ||
1134 | * the access is through the debugfs entry pciCfg: | ||
1135 | * | ||
1136 | * 1. For PCI config space register read access, there are two read methods: | ||
1137 | * A) read a single PCI config space register in the size of a byte | ||
1138 | * (8 bits), a word (16 bits), or a dword (32 bits); or B) browse through | ||
1139 | * the 4K extended PCI config space. | ||
1140 | * | ||
1141 | * A) Read a single PCI config space register consists of two steps: | ||
1142 | * | ||
1143 | * Step-1: Set up PCI config space register read command, the command | ||
1144 | * syntax is, | ||
1145 | * | ||
1146 | * echo 1 <where> <count> > pciCfg | ||
1147 | * | ||
1148 | * where, 1 is the iDiag command for PCI config space read, <where> is the | ||
1149 | * offset from the beginning of the device's PCI config space to read from, | ||
1150 | * and <count> is the size of PCI config space register data to read back, | ||
1151 | * it will be 1 for reading a byte (8 bits), 2 for reading a word (16 bits | ||
1152 | * or 2 bytes), or 4 for reading a dword (32 bits or 4 bytes). | ||
1153 | * | ||
1154 | * Setp-2: Perform the debugfs read operation to execute the idiag command | ||
1155 | * set up in Step-1, | ||
1156 | * | ||
1157 | * cat pciCfg | ||
1158 | * | ||
1159 | * Examples: | ||
1160 | * To read PCI device's vendor-id and device-id from PCI config space, | ||
1161 | * | ||
1162 | * echo 1 0 4 > pciCfg | ||
1163 | * cat pciCfg | ||
1164 | * | ||
1165 | * To read PCI device's currnt command from config space, | ||
1166 | * | ||
1167 | * echo 1 4 2 > pciCfg | ||
1168 | * cat pciCfg | ||
1169 | * | ||
1170 | * B) Browse through the entire 4K extended PCI config space also consists | ||
1171 | * of two steps: | ||
1172 | * | ||
1173 | * Step-1: Set up PCI config space register browsing command, the command | ||
1174 | * syntax is, | ||
1175 | * | ||
1176 | * echo 1 0 4096 > pciCfg | ||
1177 | * | ||
1178 | * where, 1 is the iDiag command for PCI config space read, 0 must be used | ||
1179 | * as the offset for PCI config space register browse, and 4096 must be | ||
1180 | * used as the count for PCI config space register browse. | ||
1181 | * | ||
1182 | * Step-2: Repeately issue the debugfs read operation to browse through | ||
1183 | * the entire PCI config space registers: | ||
1184 | * | ||
1185 | * cat pciCfg | ||
1186 | * cat pciCfg | ||
1187 | * cat pciCfg | ||
1188 | * ... | ||
1189 | * | ||
1190 | * When browsing to the end of the 4K PCI config space, the browse method | ||
1191 | * shall wrap around to start reading from beginning again, and again... | ||
1192 | * | ||
1193 | * 2. For PCI config space register write access, it supports a single PCI | ||
1194 | * config space register write in the size of a byte (8 bits), a word | ||
1195 | * (16 bits), or a dword (32 bits). The command syntax is, | ||
1196 | * | ||
1197 | * echo 2 <where> <count> <value> > pciCfg | ||
1198 | * | ||
1199 | * where, 2 is the iDiag command for PCI config space write, <where> is | ||
1200 | * the offset from the beginning of the device's PCI config space to write | ||
1201 | * into, <count> is the size of data to write into the PCI config space, | ||
1202 | * it will be 1 for writing a byte (8 bits), 2 for writing a word (16 bits | ||
1203 | * or 2 bytes), or 4 for writing a dword (32 bits or 4 bytes), and <value> | ||
1204 | * is the data to be written into the PCI config space register at the | ||
1205 | * offset. | ||
1206 | * | ||
1207 | * Examples: | ||
1208 | * To disable PCI device's interrupt assertion, | ||
1209 | * | ||
1210 | * 1) Read in device's PCI config space register command field <cmd>: | ||
1211 | * | ||
1212 | * echo 1 4 2 > pciCfg | ||
1213 | * cat pciCfg | ||
1214 | * | ||
1215 | * 2) Set bit 10 (Interrupt Disable bit) in the <cmd>: | ||
1216 | * | ||
1217 | * <cmd> = <cmd> | (1 < 10) | ||
1218 | * | ||
1219 | * 3) Write the modified command back: | ||
1220 | * | ||
1221 | * echo 2 4 2 <cmd> > pciCfg | ||
1222 | * | ||
1223 | * 3. For PCI config space register set bits access, it supports a single PCI | ||
1224 | * config space register set bits in the size of a byte (8 bits), a word | ||
1225 | * (16 bits), or a dword (32 bits). The command syntax is, | ||
1226 | * | ||
1227 | * echo 3 <where> <count> <bitmask> > pciCfg | ||
1228 | * | ||
1229 | * where, 3 is the iDiag command for PCI config space set bits, <where> is | ||
1230 | * the offset from the beginning of the device's PCI config space to set | ||
1231 | * bits into, <count> is the size of the bitmask to set into the PCI config | ||
1232 | * space, it will be 1 for setting a byte (8 bits), 2 for setting a word | ||
1233 | * (16 bits or 2 bytes), or 4 for setting a dword (32 bits or 4 bytes), and | ||
1234 | * <bitmask> is the bitmask, indicating the bits to be set into the PCI | ||
1235 | * config space register at the offset. The logic performed to the content | ||
1236 | * of the PCI config space register, regval, is, | ||
1237 | * | ||
1238 | * regval |= <bitmask> | ||
1239 | * | ||
1240 | * 4. For PCI config space register clear bits access, it supports a single | ||
1241 | * PCI config space register clear bits in the size of a byte (8 bits), | ||
1242 | * a word (16 bits), or a dword (32 bits). The command syntax is, | ||
1243 | * | ||
1244 | * echo 4 <where> <count> <bitmask> > pciCfg | ||
1245 | * | ||
1246 | * where, 4 is the iDiag command for PCI config space clear bits, <where> | ||
1247 | * is the offset from the beginning of the device's PCI config space to | ||
1248 | * clear bits from, <count> is the size of the bitmask to set into the PCI | ||
1249 | * config space, it will be 1 for setting a byte (8 bits), 2 for setting | ||
1250 | * a word(16 bits or 2 bytes), or 4 for setting a dword (32 bits or 4 | ||
1251 | * bytes), and <bitmask> is the bitmask, indicating the bits to be cleared | ||
1252 | * from the PCI config space register at the offset. the logic performed | ||
1253 | * to the content of the PCI config space register, regval, is, | ||
1254 | * | ||
1255 | * regval &= ~<bitmask> | ||
1256 | * | ||
1257 | * Note, for all single register read, write, set bits, or clear bits access, | ||
1258 | * the offset (<where>) must be aligned with the size of the data: | ||
1259 | * | ||
1260 | * For data size of byte (8 bits), the offset must be aligned to the byte | ||
1261 | * boundary; for data size of word (16 bits), the offset must be aligned | ||
1262 | * to the word boundary; while for data size of dword (32 bits), the offset | ||
1263 | * must be aligned to the dword boundary. Otherwise, the interface will | ||
1264 | * return the error: | ||
1265 | * | 1125 | * |
1266 | * "-bash: echo: write error: Invalid argument". | 1126 | * All access methods are through the proper SLI4 PCI function's debugfs |
1127 | * iDiag directory: | ||
1267 | * | 1128 | * |
1268 | * For example: | 1129 | * /sys/kernel/debug/lpfc/fn<#>/iDiag |
1269 | * | ||
1270 | * echo 1 2 4 > pciCfg | ||
1271 | * -bash: echo: write error: Invalid argument | ||
1272 | * | ||
1273 | * Note also, all of the numbers in the command fields for all read, write, | ||
1274 | * set bits, and clear bits PCI config space register command fields can be | ||
1275 | * either decimal or hex. | ||
1276 | * | ||
1277 | * For example, | ||
1278 | * echo 1 0 4096 > pciCfg | ||
1279 | * | ||
1280 | * will be the same as | ||
1281 | * echo 1 0 0x1000 > pciCfg | ||
1282 | * | ||
1283 | * And, | ||
1284 | * echo 2 155 1 10 > pciCfg | ||
1285 | * | ||
1286 | * will be | ||
1287 | * echo 2 0x9b 1 0xa > pciCfg | ||
1288 | */ | 1130 | */ |
1289 | 1131 | ||
1290 | /** | 1132 | /** |
@@ -1331,10 +1173,10 @@ static int lpfc_idiag_cmd_get(const char __user *buf, size_t nbytes, | |||
1331 | for (i = 0; i < LPFC_IDIAG_CMD_DATA_SIZE; i++) { | 1173 | for (i = 0; i < LPFC_IDIAG_CMD_DATA_SIZE; i++) { |
1332 | step_str = strsep(&pbuf, "\t "); | 1174 | step_str = strsep(&pbuf, "\t "); |
1333 | if (!step_str) | 1175 | if (!step_str) |
1334 | return 0; | 1176 | return i; |
1335 | idiag_cmd->data[i] = simple_strtol(step_str, NULL, 0); | 1177 | idiag_cmd->data[i] = simple_strtol(step_str, NULL, 0); |
1336 | } | 1178 | } |
1337 | return 0; | 1179 | return i; |
1338 | } | 1180 | } |
1339 | 1181 | ||
1340 | /** | 1182 | /** |
@@ -1403,7 +1245,7 @@ lpfc_idiag_release(struct inode *inode, struct file *file) | |||
1403 | * Description: | 1245 | * Description: |
1404 | * This routine frees the buffer that was allocated when the debugfs file | 1246 | * This routine frees the buffer that was allocated when the debugfs file |
1405 | * was opened. It also reset the fields in the idiag command struct in the | 1247 | * was opened. It also reset the fields in the idiag command struct in the |
1406 | * case the command is not continuous browsing of the data structure. | 1248 | * case of command for write operation. |
1407 | * | 1249 | * |
1408 | * Returns: | 1250 | * Returns: |
1409 | * This function returns zero. | 1251 | * This function returns zero. |
@@ -1413,18 +1255,20 @@ lpfc_idiag_cmd_release(struct inode *inode, struct file *file) | |||
1413 | { | 1255 | { |
1414 | struct lpfc_debug *debug = file->private_data; | 1256 | struct lpfc_debug *debug = file->private_data; |
1415 | 1257 | ||
1416 | /* Read PCI config register, if not read all, clear command fields */ | 1258 | if (debug->op == LPFC_IDIAG_OP_WR) { |
1417 | if ((debug->op == LPFC_IDIAG_OP_RD) && | 1259 | switch (idiag.cmd.opcode) { |
1418 | (idiag.cmd.opcode == LPFC_IDIAG_CMD_PCICFG_RD)) | 1260 | case LPFC_IDIAG_CMD_PCICFG_WR: |
1419 | if ((idiag.cmd.data[1] == sizeof(uint8_t)) || | 1261 | case LPFC_IDIAG_CMD_PCICFG_ST: |
1420 | (idiag.cmd.data[1] == sizeof(uint16_t)) || | 1262 | case LPFC_IDIAG_CMD_PCICFG_CL: |
1421 | (idiag.cmd.data[1] == sizeof(uint32_t))) | 1263 | case LPFC_IDIAG_CMD_QUEACC_WR: |
1264 | case LPFC_IDIAG_CMD_QUEACC_ST: | ||
1265 | case LPFC_IDIAG_CMD_QUEACC_CL: | ||
1422 | memset(&idiag, 0, sizeof(idiag)); | 1266 | memset(&idiag, 0, sizeof(idiag)); |
1423 | 1267 | break; | |
1424 | /* Write PCI config register, clear command fields */ | 1268 | default: |
1425 | if ((debug->op == LPFC_IDIAG_OP_WR) && | 1269 | break; |
1426 | (idiag.cmd.opcode == LPFC_IDIAG_CMD_PCICFG_WR)) | 1270 | } |
1427 | memset(&idiag, 0, sizeof(idiag)); | 1271 | } |
1428 | 1272 | ||
1429 | /* Free the buffers to the file operation */ | 1273 | /* Free the buffers to the file operation */ |
1430 | kfree(debug->buffer); | 1274 | kfree(debug->buffer); |
@@ -1504,7 +1348,7 @@ lpfc_idiag_pcicfg_read(struct file *file, char __user *buf, size_t nbytes, | |||
1504 | len += snprintf(pbuffer+len, LPFC_PCI_CFG_SIZE-len, | 1348 | len += snprintf(pbuffer+len, LPFC_PCI_CFG_SIZE-len, |
1505 | "%03x: %08x\n", where, u32val); | 1349 | "%03x: %08x\n", where, u32val); |
1506 | break; | 1350 | break; |
1507 | case LPFC_PCI_CFG_SIZE: /* browse all */ | 1351 | case LPFC_PCI_CFG_BROWSE: /* browse all */ |
1508 | goto pcicfg_browse; | 1352 | goto pcicfg_browse; |
1509 | break; | 1353 | break; |
1510 | default: | 1354 | default: |
@@ -1586,16 +1430,21 @@ lpfc_idiag_pcicfg_write(struct file *file, const char __user *buf, | |||
1586 | debug->op = LPFC_IDIAG_OP_WR; | 1430 | debug->op = LPFC_IDIAG_OP_WR; |
1587 | 1431 | ||
1588 | rc = lpfc_idiag_cmd_get(buf, nbytes, &idiag.cmd); | 1432 | rc = lpfc_idiag_cmd_get(buf, nbytes, &idiag.cmd); |
1589 | if (rc) | 1433 | if (rc < 0) |
1590 | return rc; | 1434 | return rc; |
1591 | 1435 | ||
1592 | if (idiag.cmd.opcode == LPFC_IDIAG_CMD_PCICFG_RD) { | 1436 | if (idiag.cmd.opcode == LPFC_IDIAG_CMD_PCICFG_RD) { |
1437 | /* Sanity check on PCI config read command line arguments */ | ||
1438 | if (rc != LPFC_PCI_CFG_RD_CMD_ARG) | ||
1439 | goto error_out; | ||
1593 | /* Read command from PCI config space, set up command fields */ | 1440 | /* Read command from PCI config space, set up command fields */ |
1594 | where = idiag.cmd.data[0]; | 1441 | where = idiag.cmd.data[0]; |
1595 | count = idiag.cmd.data[1]; | 1442 | count = idiag.cmd.data[1]; |
1596 | if (count == LPFC_PCI_CFG_SIZE) { | 1443 | if (count == LPFC_PCI_CFG_BROWSE) { |
1597 | if (where != 0) | 1444 | if (where % sizeof(uint32_t)) |
1598 | goto error_out; | 1445 | goto error_out; |
1446 | /* Starting offset to browse */ | ||
1447 | idiag.offset.last_rd = where; | ||
1599 | } else if ((count != sizeof(uint8_t)) && | 1448 | } else if ((count != sizeof(uint8_t)) && |
1600 | (count != sizeof(uint16_t)) && | 1449 | (count != sizeof(uint16_t)) && |
1601 | (count != sizeof(uint32_t))) | 1450 | (count != sizeof(uint32_t))) |
@@ -1621,6 +1470,9 @@ lpfc_idiag_pcicfg_write(struct file *file, const char __user *buf, | |||
1621 | } else if (idiag.cmd.opcode == LPFC_IDIAG_CMD_PCICFG_WR || | 1470 | } else if (idiag.cmd.opcode == LPFC_IDIAG_CMD_PCICFG_WR || |
1622 | idiag.cmd.opcode == LPFC_IDIAG_CMD_PCICFG_ST || | 1471 | idiag.cmd.opcode == LPFC_IDIAG_CMD_PCICFG_ST || |
1623 | idiag.cmd.opcode == LPFC_IDIAG_CMD_PCICFG_CL) { | 1472 | idiag.cmd.opcode == LPFC_IDIAG_CMD_PCICFG_CL) { |
1473 | /* Sanity check on PCI config write command line arguments */ | ||
1474 | if (rc != LPFC_PCI_CFG_WR_CMD_ARG) | ||
1475 | goto error_out; | ||
1624 | /* Write command to PCI config space, read-modify-write */ | 1476 | /* Write command to PCI config space, read-modify-write */ |
1625 | where = idiag.cmd.data[0]; | 1477 | where = idiag.cmd.data[0]; |
1626 | count = idiag.cmd.data[1]; | 1478 | count = idiag.cmd.data[1]; |
@@ -1753,10 +1605,12 @@ lpfc_idiag_queinfo_read(struct file *file, char __user *buf, size_t nbytes, | |||
1753 | len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, | 1605 | len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, |
1754 | "Slow-path EQ information:\n"); | 1606 | "Slow-path EQ information:\n"); |
1755 | len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, | 1607 | len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, |
1756 | "\tID [%02d], EQE-COUNT [%04d], " | 1608 | "\tEQID[%02d], " |
1757 | "HOST-INDEX [%04x], PORT-INDEX [%04x]\n\n", | 1609 | "QE-COUNT[%04d], QE-SIZE[%04d], " |
1610 | "HOST-INDEX[%04d], PORT-INDEX[%04d]\n\n", | ||
1758 | phba->sli4_hba.sp_eq->queue_id, | 1611 | phba->sli4_hba.sp_eq->queue_id, |
1759 | phba->sli4_hba.sp_eq->entry_count, | 1612 | phba->sli4_hba.sp_eq->entry_count, |
1613 | phba->sli4_hba.sp_eq->entry_size, | ||
1760 | phba->sli4_hba.sp_eq->host_index, | 1614 | phba->sli4_hba.sp_eq->host_index, |
1761 | phba->sli4_hba.sp_eq->hba_index); | 1615 | phba->sli4_hba.sp_eq->hba_index); |
1762 | 1616 | ||
@@ -1765,10 +1619,12 @@ lpfc_idiag_queinfo_read(struct file *file, char __user *buf, size_t nbytes, | |||
1765 | "Fast-path EQ information:\n"); | 1619 | "Fast-path EQ information:\n"); |
1766 | for (fcp_qidx = 0; fcp_qidx < phba->cfg_fcp_eq_count; fcp_qidx++) { | 1620 | for (fcp_qidx = 0; fcp_qidx < phba->cfg_fcp_eq_count; fcp_qidx++) { |
1767 | len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, | 1621 | len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, |
1768 | "\tID [%02d], EQE-COUNT [%04d], " | 1622 | "\tEQID[%02d], " |
1769 | "HOST-INDEX [%04x], PORT-INDEX [%04x]\n", | 1623 | "QE-COUNT[%04d], QE-SIZE[%04d], " |
1624 | "HOST-INDEX[%04d], PORT-INDEX[%04d]\n", | ||
1770 | phba->sli4_hba.fp_eq[fcp_qidx]->queue_id, | 1625 | phba->sli4_hba.fp_eq[fcp_qidx]->queue_id, |
1771 | phba->sli4_hba.fp_eq[fcp_qidx]->entry_count, | 1626 | phba->sli4_hba.fp_eq[fcp_qidx]->entry_count, |
1627 | phba->sli4_hba.fp_eq[fcp_qidx]->entry_size, | ||
1772 | phba->sli4_hba.fp_eq[fcp_qidx]->host_index, | 1628 | phba->sli4_hba.fp_eq[fcp_qidx]->host_index, |
1773 | phba->sli4_hba.fp_eq[fcp_qidx]->hba_index); | 1629 | phba->sli4_hba.fp_eq[fcp_qidx]->hba_index); |
1774 | } | 1630 | } |
@@ -1776,89 +1632,101 @@ lpfc_idiag_queinfo_read(struct file *file, char __user *buf, size_t nbytes, | |||
1776 | 1632 | ||
1777 | /* Get mailbox complete queue information */ | 1633 | /* Get mailbox complete queue information */ |
1778 | len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, | 1634 | len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, |
1779 | "Mailbox CQ information:\n"); | 1635 | "Slow-path MBX CQ information:\n"); |
1780 | len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, | 1636 | len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, |
1781 | "\t\tAssociated EQ-ID [%02d]:\n", | 1637 | "Associated EQID[%02d]:\n", |
1782 | phba->sli4_hba.mbx_cq->assoc_qid); | 1638 | phba->sli4_hba.mbx_cq->assoc_qid); |
1783 | len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, | 1639 | len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, |
1784 | "\tID [%02d], CQE-COUNT [%04d], " | 1640 | "\tCQID[%02d], " |
1785 | "HOST-INDEX [%04x], PORT-INDEX [%04x]\n\n", | 1641 | "QE-COUNT[%04d], QE-SIZE[%04d], " |
1642 | "HOST-INDEX[%04d], PORT-INDEX[%04d]\n\n", | ||
1786 | phba->sli4_hba.mbx_cq->queue_id, | 1643 | phba->sli4_hba.mbx_cq->queue_id, |
1787 | phba->sli4_hba.mbx_cq->entry_count, | 1644 | phba->sli4_hba.mbx_cq->entry_count, |
1645 | phba->sli4_hba.mbx_cq->entry_size, | ||
1788 | phba->sli4_hba.mbx_cq->host_index, | 1646 | phba->sli4_hba.mbx_cq->host_index, |
1789 | phba->sli4_hba.mbx_cq->hba_index); | 1647 | phba->sli4_hba.mbx_cq->hba_index); |
1790 | 1648 | ||
1791 | /* Get slow-path complete queue information */ | 1649 | /* Get slow-path complete queue information */ |
1792 | len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, | 1650 | len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, |
1793 | "Slow-path CQ information:\n"); | 1651 | "Slow-path ELS CQ information:\n"); |
1794 | len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, | 1652 | len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, |
1795 | "\t\tAssociated EQ-ID [%02d]:\n", | 1653 | "Associated EQID[%02d]:\n", |
1796 | phba->sli4_hba.els_cq->assoc_qid); | 1654 | phba->sli4_hba.els_cq->assoc_qid); |
1797 | len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, | 1655 | len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, |
1798 | "\tID [%02d], CQE-COUNT [%04d], " | 1656 | "\tCQID [%02d], " |
1799 | "HOST-INDEX [%04x], PORT-INDEX [%04x]\n\n", | 1657 | "QE-COUNT[%04d], QE-SIZE[%04d], " |
1658 | "HOST-INDEX[%04d], PORT-INDEX[%04d]\n\n", | ||
1800 | phba->sli4_hba.els_cq->queue_id, | 1659 | phba->sli4_hba.els_cq->queue_id, |
1801 | phba->sli4_hba.els_cq->entry_count, | 1660 | phba->sli4_hba.els_cq->entry_count, |
1661 | phba->sli4_hba.els_cq->entry_size, | ||
1802 | phba->sli4_hba.els_cq->host_index, | 1662 | phba->sli4_hba.els_cq->host_index, |
1803 | phba->sli4_hba.els_cq->hba_index); | 1663 | phba->sli4_hba.els_cq->hba_index); |
1804 | 1664 | ||
1805 | /* Get fast-path complete queue information */ | 1665 | /* Get fast-path complete queue information */ |
1806 | len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, | 1666 | len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, |
1807 | "Fast-path CQ information:\n"); | 1667 | "Fast-path FCP CQ information:\n"); |
1808 | for (fcp_qidx = 0; fcp_qidx < phba->cfg_fcp_eq_count; fcp_qidx++) { | 1668 | for (fcp_qidx = 0; fcp_qidx < phba->cfg_fcp_eq_count; fcp_qidx++) { |
1809 | len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, | 1669 | len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, |
1810 | "\t\tAssociated EQ-ID [%02d]:\n", | 1670 | "Associated EQID[%02d]:\n", |
1811 | phba->sli4_hba.fcp_cq[fcp_qidx]->assoc_qid); | 1671 | phba->sli4_hba.fcp_cq[fcp_qidx]->assoc_qid); |
1812 | len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, | 1672 | len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, |
1813 | "\tID [%02d], EQE-COUNT [%04d], " | 1673 | "\tCQID[%02d], " |
1814 | "HOST-INDEX [%04x], PORT-INDEX [%04x]\n", | 1674 | "QE-COUNT[%04d], QE-SIZE[%04d], " |
1815 | phba->sli4_hba.fcp_cq[fcp_qidx]->queue_id, | 1675 | "HOST-INDEX[%04d], PORT-INDEX[%04d]\n", |
1816 | phba->sli4_hba.fcp_cq[fcp_qidx]->entry_count, | 1676 | phba->sli4_hba.fcp_cq[fcp_qidx]->queue_id, |
1817 | phba->sli4_hba.fcp_cq[fcp_qidx]->host_index, | 1677 | phba->sli4_hba.fcp_cq[fcp_qidx]->entry_count, |
1818 | phba->sli4_hba.fcp_cq[fcp_qidx]->hba_index); | 1678 | phba->sli4_hba.fcp_cq[fcp_qidx]->entry_size, |
1679 | phba->sli4_hba.fcp_cq[fcp_qidx]->host_index, | ||
1680 | phba->sli4_hba.fcp_cq[fcp_qidx]->hba_index); | ||
1819 | } | 1681 | } |
1820 | len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, "\n"); | 1682 | len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, "\n"); |
1821 | 1683 | ||
1822 | /* Get mailbox queue information */ | 1684 | /* Get mailbox queue information */ |
1823 | len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, | 1685 | len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, |
1824 | "Mailbox MQ information:\n"); | 1686 | "Slow-path MBX MQ information:\n"); |
1825 | len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, | 1687 | len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, |
1826 | "\t\tAssociated CQ-ID [%02d]:\n", | 1688 | "Associated CQID[%02d]:\n", |
1827 | phba->sli4_hba.mbx_wq->assoc_qid); | 1689 | phba->sli4_hba.mbx_wq->assoc_qid); |
1828 | len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, | 1690 | len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, |
1829 | "\tID [%02d], MQE-COUNT [%04d], " | 1691 | "\tWQID[%02d], " |
1830 | "HOST-INDEX [%04x], PORT-INDEX [%04x]\n\n", | 1692 | "QE-COUNT[%04d], QE-SIZE[%04d], " |
1693 | "HOST-INDEX[%04d], PORT-INDEX[%04d]\n\n", | ||
1831 | phba->sli4_hba.mbx_wq->queue_id, | 1694 | phba->sli4_hba.mbx_wq->queue_id, |
1832 | phba->sli4_hba.mbx_wq->entry_count, | 1695 | phba->sli4_hba.mbx_wq->entry_count, |
1696 | phba->sli4_hba.mbx_wq->entry_size, | ||
1833 | phba->sli4_hba.mbx_wq->host_index, | 1697 | phba->sli4_hba.mbx_wq->host_index, |
1834 | phba->sli4_hba.mbx_wq->hba_index); | 1698 | phba->sli4_hba.mbx_wq->hba_index); |
1835 | 1699 | ||
1836 | /* Get slow-path work queue information */ | 1700 | /* Get slow-path work queue information */ |
1837 | len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, | 1701 | len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, |
1838 | "Slow-path WQ information:\n"); | 1702 | "Slow-path ELS WQ information:\n"); |
1839 | len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, | 1703 | len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, |
1840 | "\t\tAssociated CQ-ID [%02d]:\n", | 1704 | "Associated CQID[%02d]:\n", |
1841 | phba->sli4_hba.els_wq->assoc_qid); | 1705 | phba->sli4_hba.els_wq->assoc_qid); |
1842 | len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, | 1706 | len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, |
1843 | "\tID [%02d], WQE-COUNT [%04d], " | 1707 | "\tWQID[%02d], " |
1844 | "HOST-INDEX [%04x], PORT-INDEX [%04x]\n\n", | 1708 | "QE-COUNT[%04d], QE-SIZE[%04d], " |
1709 | "HOST-INDEX[%04d], PORT-INDEX[%04d]\n\n", | ||
1845 | phba->sli4_hba.els_wq->queue_id, | 1710 | phba->sli4_hba.els_wq->queue_id, |
1846 | phba->sli4_hba.els_wq->entry_count, | 1711 | phba->sli4_hba.els_wq->entry_count, |
1712 | phba->sli4_hba.els_wq->entry_size, | ||
1847 | phba->sli4_hba.els_wq->host_index, | 1713 | phba->sli4_hba.els_wq->host_index, |
1848 | phba->sli4_hba.els_wq->hba_index); | 1714 | phba->sli4_hba.els_wq->hba_index); |
1849 | 1715 | ||
1850 | /* Get fast-path work queue information */ | 1716 | /* Get fast-path work queue information */ |
1851 | len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, | 1717 | len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, |
1852 | "Fast-path WQ information:\n"); | 1718 | "Fast-path FCP WQ information:\n"); |
1853 | for (fcp_qidx = 0; fcp_qidx < phba->cfg_fcp_wq_count; fcp_qidx++) { | 1719 | for (fcp_qidx = 0; fcp_qidx < phba->cfg_fcp_wq_count; fcp_qidx++) { |
1854 | len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, | 1720 | len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, |
1855 | "\t\tAssociated CQ-ID [%02d]:\n", | 1721 | "Associated CQID[%02d]:\n", |
1856 | phba->sli4_hba.fcp_wq[fcp_qidx]->assoc_qid); | 1722 | phba->sli4_hba.fcp_wq[fcp_qidx]->assoc_qid); |
1857 | len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, | 1723 | len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, |
1858 | "\tID [%02d], WQE-COUNT [%04d], " | 1724 | "\tWQID[%02d], " |
1859 | "HOST-INDEX [%04x], PORT-INDEX [%04x]\n", | 1725 | "QE-COUNT[%04d], WQE-SIZE[%04d], " |
1726 | "HOST-INDEX[%04d], PORT-INDEX[%04d]\n", | ||
1860 | phba->sli4_hba.fcp_wq[fcp_qidx]->queue_id, | 1727 | phba->sli4_hba.fcp_wq[fcp_qidx]->queue_id, |
1861 | phba->sli4_hba.fcp_wq[fcp_qidx]->entry_count, | 1728 | phba->sli4_hba.fcp_wq[fcp_qidx]->entry_count, |
1729 | phba->sli4_hba.fcp_wq[fcp_qidx]->entry_size, | ||
1862 | phba->sli4_hba.fcp_wq[fcp_qidx]->host_index, | 1730 | phba->sli4_hba.fcp_wq[fcp_qidx]->host_index, |
1863 | phba->sli4_hba.fcp_wq[fcp_qidx]->hba_index); | 1731 | phba->sli4_hba.fcp_wq[fcp_qidx]->hba_index); |
1864 | } | 1732 | } |
@@ -1868,26 +1736,597 @@ lpfc_idiag_queinfo_read(struct file *file, char __user *buf, size_t nbytes, | |||
1868 | len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, | 1736 | len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, |
1869 | "Slow-path RQ information:\n"); | 1737 | "Slow-path RQ information:\n"); |
1870 | len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, | 1738 | len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, |
1871 | "\t\tAssociated CQ-ID [%02d]:\n", | 1739 | "Associated CQID[%02d]:\n", |
1872 | phba->sli4_hba.hdr_rq->assoc_qid); | 1740 | phba->sli4_hba.hdr_rq->assoc_qid); |
1873 | len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, | 1741 | len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, |
1874 | "\tID [%02d], RHQE-COUNT [%04d], " | 1742 | "\tHQID[%02d], " |
1875 | "HOST-INDEX [%04x], PORT-INDEX [%04x]\n", | 1743 | "QE-COUNT[%04d], QE-SIZE[%04d], " |
1744 | "HOST-INDEX[%04d], PORT-INDEX[%04d]\n", | ||
1876 | phba->sli4_hba.hdr_rq->queue_id, | 1745 | phba->sli4_hba.hdr_rq->queue_id, |
1877 | phba->sli4_hba.hdr_rq->entry_count, | 1746 | phba->sli4_hba.hdr_rq->entry_count, |
1747 | phba->sli4_hba.hdr_rq->entry_size, | ||
1878 | phba->sli4_hba.hdr_rq->host_index, | 1748 | phba->sli4_hba.hdr_rq->host_index, |
1879 | phba->sli4_hba.hdr_rq->hba_index); | 1749 | phba->sli4_hba.hdr_rq->hba_index); |
1880 | len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, | 1750 | len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, |
1881 | "\tID [%02d], RDQE-COUNT [%04d], " | 1751 | "\tDQID[%02d], " |
1882 | "HOST-INDEX [%04x], PORT-INDEX [%04x]\n", | 1752 | "QE-COUNT[%04d], QE-SIZE[%04d], " |
1753 | "HOST-INDEX[%04d], PORT-INDEX[%04d]\n", | ||
1883 | phba->sli4_hba.dat_rq->queue_id, | 1754 | phba->sli4_hba.dat_rq->queue_id, |
1884 | phba->sli4_hba.dat_rq->entry_count, | 1755 | phba->sli4_hba.dat_rq->entry_count, |
1756 | phba->sli4_hba.dat_rq->entry_size, | ||
1885 | phba->sli4_hba.dat_rq->host_index, | 1757 | phba->sli4_hba.dat_rq->host_index, |
1886 | phba->sli4_hba.dat_rq->hba_index); | 1758 | phba->sli4_hba.dat_rq->hba_index); |
1887 | 1759 | ||
1888 | return simple_read_from_buffer(buf, nbytes, ppos, pbuffer, len); | 1760 | return simple_read_from_buffer(buf, nbytes, ppos, pbuffer, len); |
1889 | } | 1761 | } |
1890 | 1762 | ||
1763 | /** | ||
1764 | * lpfc_idiag_que_param_check - queue access command parameter sanity check | ||
1765 | * @q: The pointer to queue structure. | ||
1766 | * @index: The index into a queue entry. | ||
1767 | * @count: The number of queue entries to access. | ||
1768 | * | ||
1769 | * Description: | ||
1770 | * The routine performs sanity check on device queue access method commands. | ||
1771 | * | ||
1772 | * Returns: | ||
1773 | * This function returns -EINVAL when fails the sanity check, otherwise, it | ||
1774 | * returns 0. | ||
1775 | **/ | ||
1776 | static int | ||
1777 | lpfc_idiag_que_param_check(struct lpfc_queue *q, int index, int count) | ||
1778 | { | ||
1779 | /* Only support single entry read or browsing */ | ||
1780 | if ((count != 1) && (count != LPFC_QUE_ACC_BROWSE)) | ||
1781 | return -EINVAL; | ||
1782 | if (index > q->entry_count - 1) | ||
1783 | return -EINVAL; | ||
1784 | return 0; | ||
1785 | } | ||
1786 | |||
1787 | /** | ||
1788 | * lpfc_idiag_queacc_read_qe - read a single entry from the given queue index | ||
1789 | * @pbuffer: The pointer to buffer to copy the read data into. | ||
1790 | * @pque: The pointer to the queue to be read. | ||
1791 | * @index: The index into the queue entry. | ||
1792 | * | ||
1793 | * Description: | ||
1794 | * This routine reads out a single entry from the given queue's index location | ||
1795 | * and copies it into the buffer provided. | ||
1796 | * | ||
1797 | * Returns: | ||
1798 | * This function returns 0 when it fails, otherwise, it returns the length of | ||
1799 | * the data read into the buffer provided. | ||
1800 | **/ | ||
1801 | static int | ||
1802 | lpfc_idiag_queacc_read_qe(char *pbuffer, int len, struct lpfc_queue *pque, | ||
1803 | uint32_t index) | ||
1804 | { | ||
1805 | int offset, esize; | ||
1806 | uint32_t *pentry; | ||
1807 | |||
1808 | if (!pbuffer || !pque) | ||
1809 | return 0; | ||
1810 | |||
1811 | esize = pque->entry_size; | ||
1812 | len += snprintf(pbuffer+len, LPFC_QUE_ACC_BUF_SIZE-len, | ||
1813 | "QE-INDEX[%04d]:\n", index); | ||
1814 | |||
1815 | offset = 0; | ||
1816 | pentry = pque->qe[index].address; | ||
1817 | while (esize > 0) { | ||
1818 | len += snprintf(pbuffer+len, LPFC_QUE_ACC_BUF_SIZE-len, | ||
1819 | "%08x ", *pentry); | ||
1820 | pentry++; | ||
1821 | offset += sizeof(uint32_t); | ||
1822 | esize -= sizeof(uint32_t); | ||
1823 | if (esize > 0 && !(offset % (4 * sizeof(uint32_t)))) | ||
1824 | len += snprintf(pbuffer+len, | ||
1825 | LPFC_QUE_ACC_BUF_SIZE-len, "\n"); | ||
1826 | } | ||
1827 | len += snprintf(pbuffer+len, LPFC_QUE_ACC_BUF_SIZE-len, "\n"); | ||
1828 | |||
1829 | return len; | ||
1830 | } | ||
1831 | |||
1832 | /** | ||
1833 | * lpfc_idiag_queacc_read - idiag debugfs read port queue | ||
1834 | * @file: The file pointer to read from. | ||
1835 | * @buf: The buffer to copy the data to. | ||
1836 | * @nbytes: The number of bytes to read. | ||
1837 | * @ppos: The position in the file to start reading from. | ||
1838 | * | ||
1839 | * Description: | ||
1840 | * This routine reads data from the @phba device queue memory according to the | ||
1841 | * idiag command, and copies to user @buf. Depending on the queue dump read | ||
1842 | * command setup, it does either a single queue entry read or browing through | ||
1843 | * all entries of the queue. | ||
1844 | * | ||
1845 | * Returns: | ||
1846 | * This function returns the amount of data that was read (this could be less | ||
1847 | * than @nbytes if the end of the file was reached) or a negative error value. | ||
1848 | **/ | ||
1849 | static ssize_t | ||
1850 | lpfc_idiag_queacc_read(struct file *file, char __user *buf, size_t nbytes, | ||
1851 | loff_t *ppos) | ||
1852 | { | ||
1853 | struct lpfc_debug *debug = file->private_data; | ||
1854 | uint32_t last_index, index, count; | ||
1855 | struct lpfc_queue *pque = NULL; | ||
1856 | char *pbuffer; | ||
1857 | int len = 0; | ||
1858 | |||
1859 | /* This is a user read operation */ | ||
1860 | debug->op = LPFC_IDIAG_OP_RD; | ||
1861 | |||
1862 | if (!debug->buffer) | ||
1863 | debug->buffer = kmalloc(LPFC_QUE_ACC_BUF_SIZE, GFP_KERNEL); | ||
1864 | if (!debug->buffer) | ||
1865 | return 0; | ||
1866 | pbuffer = debug->buffer; | ||
1867 | |||
1868 | if (*ppos) | ||
1869 | return 0; | ||
1870 | |||
1871 | if (idiag.cmd.opcode == LPFC_IDIAG_CMD_QUEACC_RD) { | ||
1872 | index = idiag.cmd.data[2]; | ||
1873 | count = idiag.cmd.data[3]; | ||
1874 | pque = (struct lpfc_queue *)idiag.ptr_private; | ||
1875 | } else | ||
1876 | return 0; | ||
1877 | |||
1878 | /* Browse the queue starting from index */ | ||
1879 | if (count == LPFC_QUE_ACC_BROWSE) | ||
1880 | goto que_browse; | ||
1881 | |||
1882 | /* Read a single entry from the queue */ | ||
1883 | len = lpfc_idiag_queacc_read_qe(pbuffer, len, pque, index); | ||
1884 | |||
1885 | return simple_read_from_buffer(buf, nbytes, ppos, pbuffer, len); | ||
1886 | |||
1887 | que_browse: | ||
1888 | |||
1889 | /* Browse all entries from the queue */ | ||
1890 | last_index = idiag.offset.last_rd; | ||
1891 | index = last_index; | ||
1892 | |||
1893 | while (len < LPFC_QUE_ACC_SIZE - pque->entry_size) { | ||
1894 | len = lpfc_idiag_queacc_read_qe(pbuffer, len, pque, index); | ||
1895 | index++; | ||
1896 | if (index > pque->entry_count - 1) | ||
1897 | break; | ||
1898 | } | ||
1899 | |||
1900 | /* Set up the offset for next portion of pci cfg read */ | ||
1901 | if (index > pque->entry_count - 1) | ||
1902 | index = 0; | ||
1903 | idiag.offset.last_rd = index; | ||
1904 | |||
1905 | return simple_read_from_buffer(buf, nbytes, ppos, pbuffer, len); | ||
1906 | } | ||
1907 | |||
1908 | /** | ||
1909 | * lpfc_idiag_queacc_write - Syntax check and set up idiag queacc commands | ||
1910 | * @file: The file pointer to read from. | ||
1911 | * @buf: The buffer to copy the user data from. | ||
1912 | * @nbytes: The number of bytes to get. | ||
1913 | * @ppos: The position in the file to start reading from. | ||
1914 | * | ||
1915 | * This routine get the debugfs idiag command struct from user space and then | ||
1916 | * perform the syntax check for port queue read (dump) or write (set) command | ||
1917 | * accordingly. In the case of port queue read command, it sets up the command | ||
1918 | * in the idiag command struct for the following debugfs read operation. In | ||
1919 | * the case of port queue write operation, it executes the write operation | ||
1920 | * into the port queue entry accordingly. | ||
1921 | * | ||
1922 | * It returns the @nbytges passing in from debugfs user space when successful. | ||
1923 | * In case of error conditions, it returns proper error code back to the user | ||
1924 | * space. | ||
1925 | **/ | ||
1926 | static ssize_t | ||
1927 | lpfc_idiag_queacc_write(struct file *file, const char __user *buf, | ||
1928 | size_t nbytes, loff_t *ppos) | ||
1929 | { | ||
1930 | struct lpfc_debug *debug = file->private_data; | ||
1931 | struct lpfc_hba *phba = (struct lpfc_hba *)debug->i_private; | ||
1932 | uint32_t qidx, quetp, queid, index, count, offset, value; | ||
1933 | uint32_t *pentry; | ||
1934 | struct lpfc_queue *pque; | ||
1935 | int rc; | ||
1936 | |||
1937 | /* This is a user write operation */ | ||
1938 | debug->op = LPFC_IDIAG_OP_WR; | ||
1939 | |||
1940 | rc = lpfc_idiag_cmd_get(buf, nbytes, &idiag.cmd); | ||
1941 | if (rc < 0) | ||
1942 | return rc; | ||
1943 | |||
1944 | /* Get and sanity check on command feilds */ | ||
1945 | quetp = idiag.cmd.data[0]; | ||
1946 | queid = idiag.cmd.data[1]; | ||
1947 | index = idiag.cmd.data[2]; | ||
1948 | count = idiag.cmd.data[3]; | ||
1949 | offset = idiag.cmd.data[4]; | ||
1950 | value = idiag.cmd.data[5]; | ||
1951 | |||
1952 | /* Sanity check on command line arguments */ | ||
1953 | if (idiag.cmd.opcode == LPFC_IDIAG_CMD_QUEACC_WR || | ||
1954 | idiag.cmd.opcode == LPFC_IDIAG_CMD_QUEACC_ST || | ||
1955 | idiag.cmd.opcode == LPFC_IDIAG_CMD_QUEACC_CL) { | ||
1956 | if (rc != LPFC_QUE_ACC_WR_CMD_ARG) | ||
1957 | goto error_out; | ||
1958 | if (count != 1) | ||
1959 | goto error_out; | ||
1960 | } else if (idiag.cmd.opcode == LPFC_IDIAG_CMD_QUEACC_RD) { | ||
1961 | if (rc != LPFC_QUE_ACC_RD_CMD_ARG) | ||
1962 | goto error_out; | ||
1963 | } else | ||
1964 | goto error_out; | ||
1965 | |||
1966 | switch (quetp) { | ||
1967 | case LPFC_IDIAG_EQ: | ||
1968 | /* Slow-path event queue */ | ||
1969 | if (phba->sli4_hba.sp_eq->queue_id == queid) { | ||
1970 | /* Sanity check */ | ||
1971 | rc = lpfc_idiag_que_param_check( | ||
1972 | phba->sli4_hba.sp_eq, index, count); | ||
1973 | if (rc) | ||
1974 | goto error_out; | ||
1975 | idiag.ptr_private = phba->sli4_hba.sp_eq; | ||
1976 | goto pass_check; | ||
1977 | } | ||
1978 | /* Fast-path event queue */ | ||
1979 | for (qidx = 0; qidx < phba->cfg_fcp_eq_count; qidx++) { | ||
1980 | if (phba->sli4_hba.fp_eq[qidx]->queue_id == queid) { | ||
1981 | /* Sanity check */ | ||
1982 | rc = lpfc_idiag_que_param_check( | ||
1983 | phba->sli4_hba.fp_eq[qidx], | ||
1984 | index, count); | ||
1985 | if (rc) | ||
1986 | goto error_out; | ||
1987 | idiag.ptr_private = phba->sli4_hba.fp_eq[qidx]; | ||
1988 | goto pass_check; | ||
1989 | } | ||
1990 | } | ||
1991 | goto error_out; | ||
1992 | break; | ||
1993 | case LPFC_IDIAG_CQ: | ||
1994 | /* MBX complete queue */ | ||
1995 | if (phba->sli4_hba.mbx_cq->queue_id == queid) { | ||
1996 | /* Sanity check */ | ||
1997 | rc = lpfc_idiag_que_param_check( | ||
1998 | phba->sli4_hba.mbx_cq, index, count); | ||
1999 | if (rc) | ||
2000 | goto error_out; | ||
2001 | idiag.ptr_private = phba->sli4_hba.mbx_cq; | ||
2002 | goto pass_check; | ||
2003 | } | ||
2004 | /* ELS complete queue */ | ||
2005 | if (phba->sli4_hba.els_cq->queue_id == queid) { | ||
2006 | /* Sanity check */ | ||
2007 | rc = lpfc_idiag_que_param_check( | ||
2008 | phba->sli4_hba.els_cq, index, count); | ||
2009 | if (rc) | ||
2010 | goto error_out; | ||
2011 | idiag.ptr_private = phba->sli4_hba.els_cq; | ||
2012 | goto pass_check; | ||
2013 | } | ||
2014 | /* FCP complete queue */ | ||
2015 | for (qidx = 0; qidx < phba->cfg_fcp_eq_count; qidx++) { | ||
2016 | if (phba->sli4_hba.fcp_cq[qidx]->queue_id == queid) { | ||
2017 | /* Sanity check */ | ||
2018 | rc = lpfc_idiag_que_param_check( | ||
2019 | phba->sli4_hba.fcp_cq[qidx], | ||
2020 | index, count); | ||
2021 | if (rc) | ||
2022 | goto error_out; | ||
2023 | idiag.ptr_private = | ||
2024 | phba->sli4_hba.fcp_cq[qidx]; | ||
2025 | goto pass_check; | ||
2026 | } | ||
2027 | } | ||
2028 | goto error_out; | ||
2029 | break; | ||
2030 | case LPFC_IDIAG_MQ: | ||
2031 | /* MBX work queue */ | ||
2032 | if (phba->sli4_hba.mbx_wq->queue_id == queid) { | ||
2033 | /* Sanity check */ | ||
2034 | rc = lpfc_idiag_que_param_check( | ||
2035 | phba->sli4_hba.mbx_wq, index, count); | ||
2036 | if (rc) | ||
2037 | goto error_out; | ||
2038 | idiag.ptr_private = phba->sli4_hba.mbx_wq; | ||
2039 | goto pass_check; | ||
2040 | } | ||
2041 | break; | ||
2042 | case LPFC_IDIAG_WQ: | ||
2043 | /* ELS work queue */ | ||
2044 | if (phba->sli4_hba.els_wq->queue_id == queid) { | ||
2045 | /* Sanity check */ | ||
2046 | rc = lpfc_idiag_que_param_check( | ||
2047 | phba->sli4_hba.els_wq, index, count); | ||
2048 | if (rc) | ||
2049 | goto error_out; | ||
2050 | idiag.ptr_private = phba->sli4_hba.els_wq; | ||
2051 | goto pass_check; | ||
2052 | } | ||
2053 | /* FCP work queue */ | ||
2054 | for (qidx = 0; qidx < phba->cfg_fcp_wq_count; qidx++) { | ||
2055 | if (phba->sli4_hba.fcp_wq[qidx]->queue_id == queid) { | ||
2056 | /* Sanity check */ | ||
2057 | rc = lpfc_idiag_que_param_check( | ||
2058 | phba->sli4_hba.fcp_wq[qidx], | ||
2059 | index, count); | ||
2060 | if (rc) | ||
2061 | goto error_out; | ||
2062 | idiag.ptr_private = | ||
2063 | phba->sli4_hba.fcp_wq[qidx]; | ||
2064 | goto pass_check; | ||
2065 | } | ||
2066 | } | ||
2067 | goto error_out; | ||
2068 | break; | ||
2069 | case LPFC_IDIAG_RQ: | ||
2070 | /* HDR queue */ | ||
2071 | if (phba->sli4_hba.hdr_rq->queue_id == queid) { | ||
2072 | /* Sanity check */ | ||
2073 | rc = lpfc_idiag_que_param_check( | ||
2074 | phba->sli4_hba.hdr_rq, index, count); | ||
2075 | if (rc) | ||
2076 | goto error_out; | ||
2077 | idiag.ptr_private = phba->sli4_hba.hdr_rq; | ||
2078 | goto pass_check; | ||
2079 | } | ||
2080 | /* DAT queue */ | ||
2081 | if (phba->sli4_hba.dat_rq->queue_id == queid) { | ||
2082 | /* Sanity check */ | ||
2083 | rc = lpfc_idiag_que_param_check( | ||
2084 | phba->sli4_hba.dat_rq, index, count); | ||
2085 | if (rc) | ||
2086 | goto error_out; | ||
2087 | idiag.ptr_private = phba->sli4_hba.dat_rq; | ||
2088 | goto pass_check; | ||
2089 | } | ||
2090 | goto error_out; | ||
2091 | break; | ||
2092 | default: | ||
2093 | goto error_out; | ||
2094 | break; | ||
2095 | } | ||
2096 | |||
2097 | pass_check: | ||
2098 | |||
2099 | if (idiag.cmd.opcode == LPFC_IDIAG_CMD_QUEACC_RD) { | ||
2100 | if (count == LPFC_QUE_ACC_BROWSE) | ||
2101 | idiag.offset.last_rd = index; | ||
2102 | } | ||
2103 | |||
2104 | if (idiag.cmd.opcode == LPFC_IDIAG_CMD_QUEACC_WR || | ||
2105 | idiag.cmd.opcode == LPFC_IDIAG_CMD_QUEACC_ST || | ||
2106 | idiag.cmd.opcode == LPFC_IDIAG_CMD_QUEACC_CL) { | ||
2107 | /* Additional sanity checks on write operation */ | ||
2108 | pque = (struct lpfc_queue *)idiag.ptr_private; | ||
2109 | if (offset > pque->entry_size/sizeof(uint32_t) - 1) | ||
2110 | goto error_out; | ||
2111 | pentry = pque->qe[index].address; | ||
2112 | pentry += offset; | ||
2113 | if (idiag.cmd.opcode == LPFC_IDIAG_CMD_QUEACC_WR) | ||
2114 | *pentry = value; | ||
2115 | if (idiag.cmd.opcode == LPFC_IDIAG_CMD_QUEACC_ST) | ||
2116 | *pentry |= value; | ||
2117 | if (idiag.cmd.opcode == LPFC_IDIAG_CMD_QUEACC_CL) | ||
2118 | *pentry &= ~value; | ||
2119 | } | ||
2120 | return nbytes; | ||
2121 | |||
2122 | error_out: | ||
2123 | /* Clean out command structure on command error out */ | ||
2124 | memset(&idiag, 0, sizeof(idiag)); | ||
2125 | return -EINVAL; | ||
2126 | } | ||
2127 | |||
2128 | /** | ||
2129 | * lpfc_idiag_drbacc_read_reg - idiag debugfs read a doorbell register | ||
2130 | * @phba: The pointer to hba structure. | ||
2131 | * @pbuffer: The pointer to the buffer to copy the data to. | ||
2132 | * @len: The lenght of bytes to copied. | ||
2133 | * @drbregid: The id to doorbell registers. | ||
2134 | * | ||
2135 | * Description: | ||
2136 | * This routine reads a doorbell register and copies its content to the | ||
2137 | * user buffer pointed to by @pbuffer. | ||
2138 | * | ||
2139 | * Returns: | ||
2140 | * This function returns the amount of data that was copied into @pbuffer. | ||
2141 | **/ | ||
2142 | static int | ||
2143 | lpfc_idiag_drbacc_read_reg(struct lpfc_hba *phba, char *pbuffer, | ||
2144 | int len, uint32_t drbregid) | ||
2145 | { | ||
2146 | |||
2147 | if (!pbuffer) | ||
2148 | return 0; | ||
2149 | |||
2150 | switch (drbregid) { | ||
2151 | case LPFC_DRB_EQCQ: | ||
2152 | len += snprintf(pbuffer+len, LPFC_DRB_ACC_BUF_SIZE-len, | ||
2153 | "EQCQ-DRB-REG: 0x%08x\n", | ||
2154 | readl(phba->sli4_hba.EQCQDBregaddr)); | ||
2155 | break; | ||
2156 | case LPFC_DRB_MQ: | ||
2157 | len += snprintf(pbuffer+len, LPFC_DRB_ACC_BUF_SIZE-len, | ||
2158 | "MQ-DRB-REG: 0x%08x\n", | ||
2159 | readl(phba->sli4_hba.MQDBregaddr)); | ||
2160 | break; | ||
2161 | case LPFC_DRB_WQ: | ||
2162 | len += snprintf(pbuffer+len, LPFC_DRB_ACC_BUF_SIZE-len, | ||
2163 | "WQ-DRB-REG: 0x%08x\n", | ||
2164 | readl(phba->sli4_hba.WQDBregaddr)); | ||
2165 | break; | ||
2166 | case LPFC_DRB_RQ: | ||
2167 | len += snprintf(pbuffer+len, LPFC_DRB_ACC_BUF_SIZE-len, | ||
2168 | "RQ-DRB-REG: 0x%08x\n", | ||
2169 | readl(phba->sli4_hba.RQDBregaddr)); | ||
2170 | break; | ||
2171 | default: | ||
2172 | break; | ||
2173 | } | ||
2174 | |||
2175 | return len; | ||
2176 | } | ||
2177 | |||
2178 | /** | ||
2179 | * lpfc_idiag_drbacc_read - idiag debugfs read port doorbell | ||
2180 | * @file: The file pointer to read from. | ||
2181 | * @buf: The buffer to copy the data to. | ||
2182 | * @nbytes: The number of bytes to read. | ||
2183 | * @ppos: The position in the file to start reading from. | ||
2184 | * | ||
2185 | * Description: | ||
2186 | * This routine reads data from the @phba device doorbell register according | ||
2187 | * to the idiag command, and copies to user @buf. Depending on the doorbell | ||
2188 | * register read command setup, it does either a single doorbell register | ||
2189 | * read or dump all doorbell registers. | ||
2190 | * | ||
2191 | * Returns: | ||
2192 | * This function returns the amount of data that was read (this could be less | ||
2193 | * than @nbytes if the end of the file was reached) or a negative error value. | ||
2194 | **/ | ||
2195 | static ssize_t | ||
2196 | lpfc_idiag_drbacc_read(struct file *file, char __user *buf, size_t nbytes, | ||
2197 | loff_t *ppos) | ||
2198 | { | ||
2199 | struct lpfc_debug *debug = file->private_data; | ||
2200 | struct lpfc_hba *phba = (struct lpfc_hba *)debug->i_private; | ||
2201 | uint32_t drb_reg_id, i; | ||
2202 | char *pbuffer; | ||
2203 | int len = 0; | ||
2204 | |||
2205 | /* This is a user read operation */ | ||
2206 | debug->op = LPFC_IDIAG_OP_RD; | ||
2207 | |||
2208 | if (!debug->buffer) | ||
2209 | debug->buffer = kmalloc(LPFC_DRB_ACC_BUF_SIZE, GFP_KERNEL); | ||
2210 | if (!debug->buffer) | ||
2211 | return 0; | ||
2212 | pbuffer = debug->buffer; | ||
2213 | |||
2214 | if (*ppos) | ||
2215 | return 0; | ||
2216 | |||
2217 | if (idiag.cmd.opcode == LPFC_IDIAG_CMD_DRBACC_RD) | ||
2218 | drb_reg_id = idiag.cmd.data[0]; | ||
2219 | else | ||
2220 | return 0; | ||
2221 | |||
2222 | if (drb_reg_id == LPFC_DRB_ACC_ALL) | ||
2223 | for (i = 1; i <= LPFC_DRB_MAX; i++) | ||
2224 | len = lpfc_idiag_drbacc_read_reg(phba, | ||
2225 | pbuffer, len, i); | ||
2226 | else | ||
2227 | len = lpfc_idiag_drbacc_read_reg(phba, | ||
2228 | pbuffer, len, drb_reg_id); | ||
2229 | |||
2230 | return simple_read_from_buffer(buf, nbytes, ppos, pbuffer, len); | ||
2231 | } | ||
2232 | |||
2233 | /** | ||
2234 | * lpfc_idiag_drbacc_write - Syntax check and set up idiag drbacc commands | ||
2235 | * @file: The file pointer to read from. | ||
2236 | * @buf: The buffer to copy the user data from. | ||
2237 | * @nbytes: The number of bytes to get. | ||
2238 | * @ppos: The position in the file to start reading from. | ||
2239 | * | ||
2240 | * This routine get the debugfs idiag command struct from user space and then | ||
2241 | * perform the syntax check for port doorbell register read (dump) or write | ||
2242 | * (set) command accordingly. In the case of port queue read command, it sets | ||
2243 | * up the command in the idiag command struct for the following debugfs read | ||
2244 | * operation. In the case of port doorbell register write operation, it | ||
2245 | * executes the write operation into the port doorbell register accordingly. | ||
2246 | * | ||
2247 | * It returns the @nbytges passing in from debugfs user space when successful. | ||
2248 | * In case of error conditions, it returns proper error code back to the user | ||
2249 | * space. | ||
2250 | **/ | ||
2251 | static ssize_t | ||
2252 | lpfc_idiag_drbacc_write(struct file *file, const char __user *buf, | ||
2253 | size_t nbytes, loff_t *ppos) | ||
2254 | { | ||
2255 | struct lpfc_debug *debug = file->private_data; | ||
2256 | struct lpfc_hba *phba = (struct lpfc_hba *)debug->i_private; | ||
2257 | uint32_t drb_reg_id, value, reg_val; | ||
2258 | void __iomem *drb_reg; | ||
2259 | int rc; | ||
2260 | |||
2261 | /* This is a user write operation */ | ||
2262 | debug->op = LPFC_IDIAG_OP_WR; | ||
2263 | |||
2264 | rc = lpfc_idiag_cmd_get(buf, nbytes, &idiag.cmd); | ||
2265 | if (rc < 0) | ||
2266 | return rc; | ||
2267 | |||
2268 | /* Sanity check on command line arguments */ | ||
2269 | drb_reg_id = idiag.cmd.data[0]; | ||
2270 | value = idiag.cmd.data[1]; | ||
2271 | |||
2272 | if (idiag.cmd.opcode == LPFC_IDIAG_CMD_DRBACC_WR || | ||
2273 | idiag.cmd.opcode == LPFC_IDIAG_CMD_DRBACC_ST || | ||
2274 | idiag.cmd.opcode == LPFC_IDIAG_CMD_DRBACC_CL) { | ||
2275 | if (rc != LPFC_DRB_ACC_WR_CMD_ARG) | ||
2276 | goto error_out; | ||
2277 | if (drb_reg_id > LPFC_DRB_MAX) | ||
2278 | goto error_out; | ||
2279 | } else if (idiag.cmd.opcode == LPFC_IDIAG_CMD_DRBACC_RD) { | ||
2280 | if (rc != LPFC_DRB_ACC_RD_CMD_ARG) | ||
2281 | goto error_out; | ||
2282 | if ((drb_reg_id > LPFC_DRB_MAX) && | ||
2283 | (drb_reg_id != LPFC_DRB_ACC_ALL)) | ||
2284 | goto error_out; | ||
2285 | } else | ||
2286 | goto error_out; | ||
2287 | |||
2288 | /* Perform the write access operation */ | ||
2289 | if (idiag.cmd.opcode == LPFC_IDIAG_CMD_DRBACC_WR || | ||
2290 | idiag.cmd.opcode == LPFC_IDIAG_CMD_DRBACC_ST || | ||
2291 | idiag.cmd.opcode == LPFC_IDIAG_CMD_DRBACC_CL) { | ||
2292 | switch (drb_reg_id) { | ||
2293 | case LPFC_DRB_EQCQ: | ||
2294 | drb_reg = phba->sli4_hba.EQCQDBregaddr; | ||
2295 | break; | ||
2296 | case LPFC_DRB_MQ: | ||
2297 | drb_reg = phba->sli4_hba.MQDBregaddr; | ||
2298 | break; | ||
2299 | case LPFC_DRB_WQ: | ||
2300 | drb_reg = phba->sli4_hba.WQDBregaddr; | ||
2301 | break; | ||
2302 | case LPFC_DRB_RQ: | ||
2303 | drb_reg = phba->sli4_hba.RQDBregaddr; | ||
2304 | break; | ||
2305 | default: | ||
2306 | goto error_out; | ||
2307 | } | ||
2308 | |||
2309 | if (idiag.cmd.opcode == LPFC_IDIAG_CMD_DRBACC_WR) | ||
2310 | reg_val = value; | ||
2311 | if (idiag.cmd.opcode == LPFC_IDIAG_CMD_DRBACC_ST) { | ||
2312 | reg_val = readl(drb_reg); | ||
2313 | reg_val |= value; | ||
2314 | } | ||
2315 | if (idiag.cmd.opcode == LPFC_IDIAG_CMD_DRBACC_CL) { | ||
2316 | reg_val = readl(drb_reg); | ||
2317 | reg_val &= ~value; | ||
2318 | } | ||
2319 | writel(reg_val, drb_reg); | ||
2320 | readl(drb_reg); /* flush */ | ||
2321 | } | ||
2322 | return nbytes; | ||
2323 | |||
2324 | error_out: | ||
2325 | /* Clean out command structure on command error out */ | ||
2326 | memset(&idiag, 0, sizeof(idiag)); | ||
2327 | return -EINVAL; | ||
2328 | } | ||
2329 | |||
1891 | #undef lpfc_debugfs_op_disc_trc | 2330 | #undef lpfc_debugfs_op_disc_trc |
1892 | static const struct file_operations lpfc_debugfs_op_disc_trc = { | 2331 | static const struct file_operations lpfc_debugfs_op_disc_trc = { |
1893 | .owner = THIS_MODULE, | 2332 | .owner = THIS_MODULE, |
@@ -1986,6 +2425,26 @@ static const struct file_operations lpfc_idiag_op_queInfo = { | |||
1986 | .release = lpfc_idiag_release, | 2425 | .release = lpfc_idiag_release, |
1987 | }; | 2426 | }; |
1988 | 2427 | ||
2428 | #undef lpfc_idiag_op_queacc | ||
2429 | static const struct file_operations lpfc_idiag_op_queAcc = { | ||
2430 | .owner = THIS_MODULE, | ||
2431 | .open = lpfc_idiag_open, | ||
2432 | .llseek = lpfc_debugfs_lseek, | ||
2433 | .read = lpfc_idiag_queacc_read, | ||
2434 | .write = lpfc_idiag_queacc_write, | ||
2435 | .release = lpfc_idiag_cmd_release, | ||
2436 | }; | ||
2437 | |||
2438 | #undef lpfc_idiag_op_drbacc | ||
2439 | static const struct file_operations lpfc_idiag_op_drbAcc = { | ||
2440 | .owner = THIS_MODULE, | ||
2441 | .open = lpfc_idiag_open, | ||
2442 | .llseek = lpfc_debugfs_lseek, | ||
2443 | .read = lpfc_idiag_drbacc_read, | ||
2444 | .write = lpfc_idiag_drbacc_write, | ||
2445 | .release = lpfc_idiag_cmd_release, | ||
2446 | }; | ||
2447 | |||
1989 | #endif | 2448 | #endif |
1990 | 2449 | ||
1991 | /** | 2450 | /** |
@@ -2261,6 +2720,32 @@ lpfc_debugfs_initialize(struct lpfc_vport *vport) | |||
2261 | } | 2720 | } |
2262 | } | 2721 | } |
2263 | 2722 | ||
2723 | /* iDiag access PCI function queue */ | ||
2724 | snprintf(name, sizeof(name), "queAcc"); | ||
2725 | if (!phba->idiag_que_acc) { | ||
2726 | phba->idiag_que_acc = | ||
2727 | debugfs_create_file(name, S_IFREG|S_IRUGO|S_IWUSR, | ||
2728 | phba->idiag_root, phba, &lpfc_idiag_op_queAcc); | ||
2729 | if (!phba->idiag_que_acc) { | ||
2730 | lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT, | ||
2731 | "2926 Can't create idiag debugfs\n"); | ||
2732 | goto debug_failed; | ||
2733 | } | ||
2734 | } | ||
2735 | |||
2736 | /* iDiag access PCI function doorbell registers */ | ||
2737 | snprintf(name, sizeof(name), "drbAcc"); | ||
2738 | if (!phba->idiag_drb_acc) { | ||
2739 | phba->idiag_drb_acc = | ||
2740 | debugfs_create_file(name, S_IFREG|S_IRUGO|S_IWUSR, | ||
2741 | phba->idiag_root, phba, &lpfc_idiag_op_drbAcc); | ||
2742 | if (!phba->idiag_drb_acc) { | ||
2743 | lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT, | ||
2744 | "2927 Can't create idiag debugfs\n"); | ||
2745 | goto debug_failed; | ||
2746 | } | ||
2747 | } | ||
2748 | |||
2264 | debug_failed: | 2749 | debug_failed: |
2265 | return; | 2750 | return; |
2266 | #endif | 2751 | #endif |
@@ -2339,6 +2824,16 @@ lpfc_debugfs_terminate(struct lpfc_vport *vport) | |||
2339 | * iDiag release | 2824 | * iDiag release |
2340 | */ | 2825 | */ |
2341 | if (phba->sli_rev == LPFC_SLI_REV4) { | 2826 | if (phba->sli_rev == LPFC_SLI_REV4) { |
2827 | if (phba->idiag_drb_acc) { | ||
2828 | /* iDiag drbAcc */ | ||
2829 | debugfs_remove(phba->idiag_drb_acc); | ||
2830 | phba->idiag_drb_acc = NULL; | ||
2831 | } | ||
2832 | if (phba->idiag_que_acc) { | ||
2833 | /* iDiag queAcc */ | ||
2834 | debugfs_remove(phba->idiag_que_acc); | ||
2835 | phba->idiag_que_acc = NULL; | ||
2836 | } | ||
2342 | if (phba->idiag_que_info) { | 2837 | if (phba->idiag_que_info) { |
2343 | /* iDiag queInfo */ | 2838 | /* iDiag queInfo */ |
2344 | debugfs_remove(phba->idiag_que_info); | 2839 | debugfs_remove(phba->idiag_que_info); |