From 3ce8866ceae87258cf66d1f7fd72abc918753cec Mon Sep 17 00:00:00 2001 From: Saurav Kashyap Date: Thu, 14 Jul 2011 12:00:12 -0700 Subject: [SCSI] qla2xxx: Basic infrastructure for dynamic logging. This patch adds the dynamic logging framework to the qla2xxx driver. The user will be able to change the logging levels on the fly i.e. without load/unload of the driver. This also enables logging to be enabled for a particular section of the driver such as initialization, device discovery etc. Signed-off-by: Saurav Kashyap Signed-off-by: Giridhar Malavali Signed-off-by: James Bottomley --- drivers/scsi/qla2xxx/qla_dbg.c | 278 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 278 insertions(+) (limited to 'drivers/scsi/qla2xxx/qla_dbg.c') diff --git a/drivers/scsi/qla2xxx/qla_dbg.c b/drivers/scsi/qla2xxx/qla_dbg.c index c53719a9a747..dba9eedc3ded 100644 --- a/drivers/scsi/qla2xxx/qla_dbg.c +++ b/drivers/scsi/qla2xxx/qla_dbg.c @@ -4,10 +4,36 @@ * * See LICENSE.qla2xxx for copyright and licensing details. */ + +/* + * Table for showing the current message id in use for particular level + * Change this table for addition of log/debug messages. + * ----------------------------------------------------- + * | Level | Last Value Used | + * ----------------------------------------------------- + * | Module Init and Probe | 0x0109 | + * | Mailbox commands | 0x1120 | + * | Device Discovery | 0x207d | + * | Queue Command and IO tracing | 0x304f | + * | DPC Thread | 0x401c | + * | Async Events | 0x5058 | + * | Timer Routines | 0x600d | + * | User Space Interactions | 0x70a1 | + * | Task Management | 0x8032 | + * | AER/EEH | 0x9010 | + * | Virtual Port | 0xa007 | + * | ISP82XX Specific | 0xb028 | + * | MultiQ | 0xc00b | + * | Misc | 0xd00b | + * ----------------------------------------------------- + */ + #include "qla_def.h" #include +static uint32_t ql_dbg_offset = 0x800; + static inline void qla2xxx_prep_dump(struct qla_hw_data *ha, struct qla2xxx_fw_dump *fw_dump) { @@ -1722,3 +1748,255 @@ qla2x00_dump_buffer_zipped(uint8_t *b, uint32_t size) printk(KERN_DEBUG "\n"); } } +/* + * This function is for formatting and logging debug information. + * It is to be used when vha is available. It formats the message + * and logs it to the messages file. + * parameters: + * level: The level of the debug messages to be printed. + * If ql2xextended_error_logging value is correctly set, + * this message will appear in the messages file. + * vha: Pointer to the scsi_qla_host_t. + * id: This is a unique identifier for the level. It identifies the + * part of the code from where the message originated. + * msg: The message to be displayed. + */ +void +ql_dbg(uint32_t level, scsi_qla_host_t *vha, int32_t id, char *msg, ...) { + + char pbuf[QL_DBG_BUF_LEN]; + va_list ap; + uint32_t len; + struct pci_dev *pdev = NULL; + + memset(pbuf, 0, QL_DBG_BUF_LEN); + + va_start(ap, msg); + + if ((level & ql2xextended_error_logging) == level) { + if (vha != NULL) { + pdev = vha->hw->pdev; + /* : Message */ + sprintf(pbuf, "%s [%s]-%04x:%ld: ", QL_MSGHDR, + dev_name(&(pdev->dev)), id + ql_dbg_offset, + vha->host_no); + } else + sprintf(pbuf, "%s [%s]-%04x: : ", QL_MSGHDR, + "0000:00:00.0", id + ql_dbg_offset); + + len = strlen(pbuf); + vsprintf(pbuf+len, msg, ap); + pr_warning("%s", pbuf); + } + + va_end(ap); + +} + +/* + * This function is for formatting and logging debug information. + * It is to be used when vha is not available and pci is availble, + * i.e., before host allocation. It formats the message and logs it + * to the messages file. + * parameters: + * level: The level of the debug messages to be printed. + * If ql2xextended_error_logging value is correctly set, + * this message will appear in the messages file. + * pdev: Pointer to the struct pci_dev. + * id: This is a unique id for the level. It identifies the part + * of the code from where the message originated. + * msg: The message to be displayed. + */ +void +ql_dbg_pci(uint32_t level, struct pci_dev *pdev, int32_t id, char *msg, ...) { + + char pbuf[QL_DBG_BUF_LEN]; + va_list ap; + uint32_t len; + + if (pdev == NULL) + return; + + memset(pbuf, 0, QL_DBG_BUF_LEN); + + va_start(ap, msg); + + if ((level & ql2xextended_error_logging) == level) { + /* : Message */ + sprintf(pbuf, "%s [%s]-%04x: : ", QL_MSGHDR, + dev_name(&(pdev->dev)), id + ql_dbg_offset); + + len = strlen(pbuf); + vsprintf(pbuf+len, msg, ap); + pr_warning("%s", pbuf); + } + + va_end(ap); + +} + +/* + * This function is for formatting and logging log messages. + * It is to be used when vha is available. It formats the message + * and logs it to the messages file. All the messages will be logged + * irrespective of value of ql2xextended_error_logging. + * parameters: + * level: The level of the log messages to be printed in the + * messages file. + * vha: Pointer to the scsi_qla_host_t + * id: This is a unique id for the level. It identifies the + * part of the code from where the message originated. + * msg: The message to be displayed. + */ +void +ql_log(uint32_t level, scsi_qla_host_t *vha, int32_t id, char *msg, ...) { + + char pbuf[QL_DBG_BUF_LEN]; + va_list ap; + uint32_t len; + struct pci_dev *pdev = NULL; + + memset(pbuf, 0, QL_DBG_BUF_LEN); + + va_start(ap, msg); + + if (level <= ql_errlev) { + if (vha != NULL) { + pdev = vha->hw->pdev; + /* : Message */ + sprintf(pbuf, "%s [%s]-%04x:%ld: ", QL_MSGHDR, + dev_name(&(pdev->dev)), id, vha->host_no); + } else + sprintf(pbuf, "%s [%s]-%04x: : ", QL_MSGHDR, + "0000:00:00.0", id); + + len = strlen(pbuf); + vsprintf(pbuf+len, msg, ap); + + switch (level) { + case 0: /* FATAL LOG */ + pr_crit("%s", pbuf); + break; + case 1: + pr_err("%s", pbuf); + break; + case 2: + pr_warn("%s", pbuf); + break; + default: + pr_info("%s", pbuf); + break; + } + } + + va_end(ap); +} + +/* + * This function is for formatting and logging log messages. + * It is to be used when vha is not available and pci is availble, + * i.e., before host allocation. It formats the message and logs + * it to the messages file. All the messages are logged irrespective + * of the value of ql2xextended_error_logging. + * parameters: + * level: The level of the log messages to be printed in the + * messages file. + * pdev: Pointer to the struct pci_dev. + * id: This is a unique id for the level. It identifies the + * part of the code from where the message originated. + * msg: The message to be displayed. + */ +void +ql_log_pci(uint32_t level, struct pci_dev *pdev, int32_t id, char *msg, ...) { + + char pbuf[QL_DBG_BUF_LEN]; + va_list ap; + uint32_t len; + + if (pdev == NULL) + return; + + memset(pbuf, 0, QL_DBG_BUF_LEN); + + va_start(ap, msg); + + if (level <= ql_errlev) { + /* : Message */ + sprintf(pbuf, "%s [%s]-%04x: : ", QL_MSGHDR, + dev_name(&(pdev->dev)), id); + + len = strlen(pbuf); + vsprintf(pbuf+len, msg, ap); + switch (level) { + case 0: /* FATAL LOG */ + pr_crit("%s", pbuf); + break; + case 1: + pr_err("%s", pbuf); + break; + case 2: + pr_warn("%s", pbuf); + break; + default: + pr_info("%s", pbuf); + break; + } + } + + va_end(ap); +} + +void +ql_dump_regs(uint32_t level, scsi_qla_host_t *vha, int32_t id) +{ + int i; + struct qla_hw_data *ha = vha->hw; + struct device_reg_2xxx __iomem *reg = &ha->iobase->isp; + struct device_reg_24xx __iomem *reg24 = &ha->iobase->isp24; + struct device_reg_82xx __iomem *reg82 = &ha->iobase->isp82; + uint16_t __iomem *mbx_reg; + + if ((level & ql2xextended_error_logging) == level) { + + if (IS_QLA82XX(ha)) + mbx_reg = ®82->mailbox_in[0]; + else if (IS_FWI2_CAPABLE(ha)) + mbx_reg = ®24->mailbox0; + else + mbx_reg = MAILBOX_REG(ha, reg, 0); + + ql_dbg(level, vha, id, "Mailbox registers:\n"); + for (i = 0; i < 6; i++) + ql_dbg(level, vha, id, + "mbox[%d] 0x%04x\n", i, RD_REG_WORD(mbx_reg++)); + } +} + + +void +ql_dump_buffer(uint32_t level, scsi_qla_host_t *vha, int32_t id, + uint8_t *b, uint32_t size) +{ + uint32_t cnt; + uint8_t c; + if ((level & ql2xextended_error_logging) == level) { + + ql_dbg(level, vha, id, " 0 1 2 3 4 5 6 7 8 " + "9 Ah Bh Ch Dh Eh Fh\n"); + ql_dbg(level, vha, id, "----------------------------------" + "----------------------------\n"); + + ql_dbg(level, vha, id, ""); + for (cnt = 0; cnt < size;) { + c = *b++; + printk("%02x", (uint32_t) c); + cnt++; + if (!(cnt % 16)) + printk("\n"); + else + printk(" "); + } + if (cnt % 16) + ql_dbg(level, vha, id, "\n"); + } +} -- cgit v1.2.2