Commit dcbad00e authored by Wayne Boyer's avatar Wayne Boyer Committed by James Bottomley

[SCSI] ipr: add hardware assisted smart dump functionality

This patch adds the hardware assisted smart dump functionality for the next
generation IOA PCI interface chip.
Signea-off-by: default avatarWayne Boyer <wayneb@linux.vnet.ibm.com>
Signed-off-by: default avatarJames Bottomley <James.Bottomley@suse.de>
parent 4565e370
...@@ -142,7 +142,9 @@ static const struct ipr_chip_cfg_t ipr_chip_cfg[] = { ...@@ -142,7 +142,9 @@ static const struct ipr_chip_cfg_t ipr_chip_cfg[] = {
.ioarrin_reg = 0x00070, .ioarrin_reg = 0x00070,
.sense_uproc_interrupt_reg = 0x00020, .sense_uproc_interrupt_reg = 0x00020,
.set_uproc_interrupt_reg = 0x00020, .set_uproc_interrupt_reg = 0x00020,
.clr_uproc_interrupt_reg = 0x00028 .clr_uproc_interrupt_reg = 0x00028,
.dump_addr_reg = 0x00064,
.dump_data_reg = 0x00068
} }
}, },
}; };
...@@ -2513,6 +2515,31 @@ static int ipr_wait_iodbg_ack(struct ipr_ioa_cfg *ioa_cfg, int max_delay) ...@@ -2513,6 +2515,31 @@ static int ipr_wait_iodbg_ack(struct ipr_ioa_cfg *ioa_cfg, int max_delay)
return -EIO; return -EIO;
} }
/**
* ipr_get_sis64_dump_data_section - Dump IOA memory
* @ioa_cfg: ioa config struct
* @start_addr: adapter address to dump
* @dest: destination kernel buffer
* @length_in_words: length to dump in 4 byte words
*
* Return value:
* 0 on success
**/
static int ipr_get_sis64_dump_data_section(struct ipr_ioa_cfg *ioa_cfg,
u32 start_addr,
__be32 *dest, u32 length_in_words)
{
int i;
for (i = 0; i < length_in_words; i++) {
writel(start_addr+(i*4), ioa_cfg->regs.dump_addr_reg);
*dest = cpu_to_be32(readl(ioa_cfg->regs.dump_data_reg));
dest++;
}
return 0;
}
/** /**
* ipr_get_ldump_data_section - Dump IOA memory * ipr_get_ldump_data_section - Dump IOA memory
* @ioa_cfg: ioa config struct * @ioa_cfg: ioa config struct
...@@ -2530,6 +2557,10 @@ static int ipr_get_ldump_data_section(struct ipr_ioa_cfg *ioa_cfg, ...@@ -2530,6 +2557,10 @@ static int ipr_get_ldump_data_section(struct ipr_ioa_cfg *ioa_cfg,
volatile u32 temp_pcii_reg; volatile u32 temp_pcii_reg;
int i, delay = 0; int i, delay = 0;
if (ioa_cfg->sis64)
return ipr_get_sis64_dump_data_section(ioa_cfg, start_addr,
dest, length_in_words);
/* Write IOA interrupt reg starting LDUMP state */ /* Write IOA interrupt reg starting LDUMP state */
writel((IPR_UPROCI_RESET_ALERT | IPR_UPROCI_IO_DEBUG_ALERT), writel((IPR_UPROCI_RESET_ALERT | IPR_UPROCI_IO_DEBUG_ALERT),
ioa_cfg->regs.set_uproc_interrupt_reg); ioa_cfg->regs.set_uproc_interrupt_reg);
...@@ -2787,6 +2818,7 @@ static void ipr_get_ioa_dump(struct ipr_ioa_cfg *ioa_cfg, struct ipr_dump *dump) ...@@ -2787,6 +2818,7 @@ static void ipr_get_ioa_dump(struct ipr_ioa_cfg *ioa_cfg, struct ipr_dump *dump)
u32 num_entries, start_off, end_off; u32 num_entries, start_off, end_off;
u32 bytes_to_copy, bytes_copied, rc; u32 bytes_to_copy, bytes_copied, rc;
struct ipr_sdt *sdt; struct ipr_sdt *sdt;
int valid = 1;
int i; int i;
ENTER; ENTER;
...@@ -2800,7 +2832,7 @@ static void ipr_get_ioa_dump(struct ipr_ioa_cfg *ioa_cfg, struct ipr_dump *dump) ...@@ -2800,7 +2832,7 @@ static void ipr_get_ioa_dump(struct ipr_ioa_cfg *ioa_cfg, struct ipr_dump *dump)
start_addr = readl(ioa_cfg->ioa_mailbox); start_addr = readl(ioa_cfg->ioa_mailbox);
if (!ipr_sdt_is_fmt2(start_addr)) { if (!ioa_cfg->sis64 && !ipr_sdt_is_fmt2(start_addr)) {
dev_err(&ioa_cfg->pdev->dev, dev_err(&ioa_cfg->pdev->dev,
"Invalid dump table format: %lx\n", start_addr); "Invalid dump table format: %lx\n", start_addr);
spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
...@@ -2829,7 +2861,6 @@ static void ipr_get_ioa_dump(struct ipr_ioa_cfg *ioa_cfg, struct ipr_dump *dump) ...@@ -2829,7 +2861,6 @@ static void ipr_get_ioa_dump(struct ipr_ioa_cfg *ioa_cfg, struct ipr_dump *dump)
/* IOA Dump entry */ /* IOA Dump entry */
ipr_init_dump_entry_hdr(&ioa_dump->hdr); ipr_init_dump_entry_hdr(&ioa_dump->hdr);
ioa_dump->format = IPR_SDT_FMT2;
ioa_dump->hdr.len = 0; ioa_dump->hdr.len = 0;
ioa_dump->hdr.data_type = IPR_DUMP_DATA_TYPE_BINARY; ioa_dump->hdr.data_type = IPR_DUMP_DATA_TYPE_BINARY;
ioa_dump->hdr.id = IPR_DUMP_IOA_DUMP_ID; ioa_dump->hdr.id = IPR_DUMP_IOA_DUMP_ID;
...@@ -2844,7 +2875,8 @@ static void ipr_get_ioa_dump(struct ipr_ioa_cfg *ioa_cfg, struct ipr_dump *dump) ...@@ -2844,7 +2875,8 @@ static void ipr_get_ioa_dump(struct ipr_ioa_cfg *ioa_cfg, struct ipr_dump *dump)
sizeof(struct ipr_sdt) / sizeof(__be32)); sizeof(struct ipr_sdt) / sizeof(__be32));
/* Smart Dump table is ready to use and the first entry is valid */ /* Smart Dump table is ready to use and the first entry is valid */
if (rc || (be32_to_cpu(sdt->hdr.state) != IPR_FMT2_SDT_READY_TO_USE)) { if (rc || ((be32_to_cpu(sdt->hdr.state) != IPR_FMT3_SDT_READY_TO_USE) &&
(be32_to_cpu(sdt->hdr.state) != IPR_FMT2_SDT_READY_TO_USE))) {
dev_err(&ioa_cfg->pdev->dev, dev_err(&ioa_cfg->pdev->dev,
"Dump of IOA failed. Dump table not valid: %d, %X.\n", "Dump of IOA failed. Dump table not valid: %d, %X.\n",
rc, be32_to_cpu(sdt->hdr.state)); rc, be32_to_cpu(sdt->hdr.state));
...@@ -2868,12 +2900,19 @@ static void ipr_get_ioa_dump(struct ipr_ioa_cfg *ioa_cfg, struct ipr_dump *dump) ...@@ -2868,12 +2900,19 @@ static void ipr_get_ioa_dump(struct ipr_ioa_cfg *ioa_cfg, struct ipr_dump *dump)
} }
if (sdt->entry[i].flags & IPR_SDT_VALID_ENTRY) { if (sdt->entry[i].flags & IPR_SDT_VALID_ENTRY) {
sdt_word = be32_to_cpu(sdt->entry[i].bar_str_offset); sdt_word = be32_to_cpu(sdt->entry[i].start_token);
start_off = sdt_word & IPR_FMT2_MBX_ADDR_MASK; if (ioa_cfg->sis64)
end_off = be32_to_cpu(sdt->entry[i].end_offset); bytes_to_copy = be32_to_cpu(sdt->entry[i].end_token);
else {
if (ipr_sdt_is_fmt2(sdt_word) && sdt_word) { start_off = sdt_word & IPR_FMT2_MBX_ADDR_MASK;
bytes_to_copy = end_off - start_off; end_off = be32_to_cpu(sdt->entry[i].end_token);
if (ipr_sdt_is_fmt2(sdt_word) && sdt_word)
bytes_to_copy = end_off - start_off;
else
valid = 0;
}
if (valid) {
if (bytes_to_copy > IPR_MAX_IOA_DUMP_SIZE) { if (bytes_to_copy > IPR_MAX_IOA_DUMP_SIZE) {
sdt->entry[i].flags &= ~IPR_SDT_VALID_ENTRY; sdt->entry[i].flags &= ~IPR_SDT_VALID_ENTRY;
continue; continue;
...@@ -7202,7 +7241,7 @@ static void ipr_get_unit_check_buffer(struct ipr_ioa_cfg *ioa_cfg) ...@@ -7202,7 +7241,7 @@ static void ipr_get_unit_check_buffer(struct ipr_ioa_cfg *ioa_cfg)
mailbox = readl(ioa_cfg->ioa_mailbox); mailbox = readl(ioa_cfg->ioa_mailbox);
if (!ipr_sdt_is_fmt2(mailbox)) { if (!ioa_cfg->sis64 && !ipr_sdt_is_fmt2(mailbox)) {
ipr_unit_check_no_data(ioa_cfg); ipr_unit_check_no_data(ioa_cfg);
return; return;
} }
...@@ -7211,15 +7250,20 @@ static void ipr_get_unit_check_buffer(struct ipr_ioa_cfg *ioa_cfg) ...@@ -7211,15 +7250,20 @@ static void ipr_get_unit_check_buffer(struct ipr_ioa_cfg *ioa_cfg)
rc = ipr_get_ldump_data_section(ioa_cfg, mailbox, (__be32 *) &sdt, rc = ipr_get_ldump_data_section(ioa_cfg, mailbox, (__be32 *) &sdt,
(sizeof(struct ipr_uc_sdt)) / sizeof(__be32)); (sizeof(struct ipr_uc_sdt)) / sizeof(__be32));
if (rc || (be32_to_cpu(sdt.hdr.state) != IPR_FMT2_SDT_READY_TO_USE) || if (rc || !(sdt.entry[0].flags & IPR_SDT_VALID_ENTRY) ||
!(sdt.entry[0].flags & IPR_SDT_VALID_ENTRY)) { ((be32_to_cpu(sdt.hdr.state) != IPR_FMT3_SDT_READY_TO_USE) &&
(be32_to_cpu(sdt.hdr.state) != IPR_FMT2_SDT_READY_TO_USE))) {
ipr_unit_check_no_data(ioa_cfg); ipr_unit_check_no_data(ioa_cfg);
return; return;
} }
/* Find length of the first sdt entry (UC buffer) */ /* Find length of the first sdt entry (UC buffer) */
length = (be32_to_cpu(sdt.entry[0].end_offset) - if (be32_to_cpu(sdt.hdr.state) == IPR_FMT3_SDT_READY_TO_USE)
be32_to_cpu(sdt.entry[0].bar_str_offset)) & IPR_FMT2_MBX_ADDR_MASK; length = be32_to_cpu(sdt.entry[0].end_token);
else
length = (be32_to_cpu(sdt.entry[0].end_token) -
be32_to_cpu(sdt.entry[0].start_token)) &
IPR_FMT2_MBX_ADDR_MASK;
hostrcb = list_entry(ioa_cfg->hostrcb_free_q.next, hostrcb = list_entry(ioa_cfg->hostrcb_free_q.next,
struct ipr_hostrcb, queue); struct ipr_hostrcb, queue);
...@@ -7227,7 +7271,7 @@ static void ipr_get_unit_check_buffer(struct ipr_ioa_cfg *ioa_cfg) ...@@ -7227,7 +7271,7 @@ static void ipr_get_unit_check_buffer(struct ipr_ioa_cfg *ioa_cfg)
memset(&hostrcb->hcam, 0, sizeof(hostrcb->hcam)); memset(&hostrcb->hcam, 0, sizeof(hostrcb->hcam));
rc = ipr_get_ldump_data_section(ioa_cfg, rc = ipr_get_ldump_data_section(ioa_cfg,
be32_to_cpu(sdt.entry[0].bar_str_offset), be32_to_cpu(sdt.entry[0].start_token),
(__be32 *)&hostrcb->hcam, (__be32 *)&hostrcb->hcam,
min(length, (int)sizeof(hostrcb->hcam)) / sizeof(__be32)); min(length, (int)sizeof(hostrcb->hcam)) / sizeof(__be32));
...@@ -8202,6 +8246,11 @@ static void __devinit ipr_init_ioa_cfg(struct ipr_ioa_cfg *ioa_cfg, ...@@ -8202,6 +8246,11 @@ static void __devinit ipr_init_ioa_cfg(struct ipr_ioa_cfg *ioa_cfg,
t->sense_uproc_interrupt_reg = base + p->sense_uproc_interrupt_reg; t->sense_uproc_interrupt_reg = base + p->sense_uproc_interrupt_reg;
t->set_uproc_interrupt_reg = base + p->set_uproc_interrupt_reg; t->set_uproc_interrupt_reg = base + p->set_uproc_interrupt_reg;
t->clr_uproc_interrupt_reg = base + p->clr_uproc_interrupt_reg; t->clr_uproc_interrupt_reg = base + p->clr_uproc_interrupt_reg;
if (ioa_cfg->sis64) {
t->dump_addr_reg = base + p->dump_addr_reg;
t->dump_data_reg = base + p->dump_data_reg;
}
} }
/** /**
......
...@@ -228,6 +228,7 @@ ...@@ -228,6 +228,7 @@
#define IPR_SDT_FMT2_BAR5_SEL 0x5 #define IPR_SDT_FMT2_BAR5_SEL 0x5
#define IPR_SDT_FMT2_EXP_ROM_SEL 0x8 #define IPR_SDT_FMT2_EXP_ROM_SEL 0x8
#define IPR_FMT2_SDT_READY_TO_USE 0xC4D4E3F2 #define IPR_FMT2_SDT_READY_TO_USE 0xC4D4E3F2
#define IPR_FMT3_SDT_READY_TO_USE 0xC4D4E3F3
#define IPR_DOORBELL 0x82800000 #define IPR_DOORBELL 0x82800000
#define IPR_RUNTIME_RESET 0x40000000 #define IPR_RUNTIME_RESET 0x40000000
...@@ -1093,10 +1094,9 @@ struct ipr_hostrcb { ...@@ -1093,10 +1094,9 @@ struct ipr_hostrcb {
/* IPR smart dump table structures */ /* IPR smart dump table structures */
struct ipr_sdt_entry { struct ipr_sdt_entry {
__be32 bar_str_offset; __be32 start_token;
__be32 end_offset; __be32 end_token;
u8 entry_byte; u8 reserved[4];
u8 reserved[3];
u8 flags; u8 flags;
#define IPR_SDT_ENDIAN 0x80 #define IPR_SDT_ENDIAN 0x80
...@@ -1204,6 +1204,9 @@ struct ipr_interrupt_offsets { ...@@ -1204,6 +1204,9 @@ struct ipr_interrupt_offsets {
unsigned long sense_uproc_interrupt_reg; unsigned long sense_uproc_interrupt_reg;
unsigned long set_uproc_interrupt_reg; unsigned long set_uproc_interrupt_reg;
unsigned long clr_uproc_interrupt_reg; unsigned long clr_uproc_interrupt_reg;
unsigned long dump_addr_reg;
unsigned long dump_data_reg;
}; };
struct ipr_interrupts { struct ipr_interrupts {
...@@ -1217,6 +1220,9 @@ struct ipr_interrupts { ...@@ -1217,6 +1220,9 @@ struct ipr_interrupts {
void __iomem *sense_uproc_interrupt_reg; void __iomem *sense_uproc_interrupt_reg;
void __iomem *set_uproc_interrupt_reg; void __iomem *set_uproc_interrupt_reg;
void __iomem *clr_uproc_interrupt_reg; void __iomem *clr_uproc_interrupt_reg;
void __iomem *dump_addr_reg;
void __iomem *dump_data_reg;
}; };
struct ipr_chip_cfg_t { struct ipr_chip_cfg_t {
...@@ -1536,8 +1542,6 @@ struct ipr_ioa_dump { ...@@ -1536,8 +1542,6 @@ struct ipr_ioa_dump {
u32 next_page_index; u32 next_page_index;
u32 page_offset; u32 page_offset;
u32 format; u32 format;
#define IPR_SDT_FMT2 2
#define IPR_SDT_UNKNOWN 3
}__attribute__((packed, aligned (4))); }__attribute__((packed, aligned (4)));
struct ipr_dump { struct ipr_dump {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment