diff options
author | Wayne Boyer <wayneb@linux.vnet.ibm.com> | 2010-02-19 16:24:14 -0500 |
---|---|---|
committer | James Bottomley <James.Bottomley@suse.de> | 2010-03-03 05:35:00 -0500 |
commit | dcbad00e6b403089b1846e788bc1a0c67b2bfd2d (patch) | |
tree | 75b7d0408cd07eb3d4c863ade52dfda1510f9e8a /drivers/scsi | |
parent | 4565e3706329f65b5e64328b5369c53b6ab2715c (diff) |
[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: Wayne Boyer <wayneb@linux.vnet.ibm.com>
Signed-off-by: James Bottomley <James.Bottomley@suse.de>
Diffstat (limited to 'drivers/scsi')
-rw-r--r-- | drivers/scsi/ipr.c | 81 | ||||
-rw-r--r-- | drivers/scsi/ipr.h | 16 |
2 files changed, 75 insertions, 22 deletions
diff --git a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c index b2e60bd4a0c6..dd12486ba520 100644 --- a/drivers/scsi/ipr.c +++ b/drivers/scsi/ipr.c | |||
@@ -142,7 +142,9 @@ static const struct ipr_chip_cfg_t ipr_chip_cfg[] = { | |||
142 | .ioarrin_reg = 0x00070, | 142 | .ioarrin_reg = 0x00070, |
143 | .sense_uproc_interrupt_reg = 0x00020, | 143 | .sense_uproc_interrupt_reg = 0x00020, |
144 | .set_uproc_interrupt_reg = 0x00020, | 144 | .set_uproc_interrupt_reg = 0x00020, |
145 | .clr_uproc_interrupt_reg = 0x00028 | 145 | .clr_uproc_interrupt_reg = 0x00028, |
146 | .dump_addr_reg = 0x00064, | ||
147 | .dump_data_reg = 0x00068 | ||
146 | } | 148 | } |
147 | }, | 149 | }, |
148 | }; | 150 | }; |
@@ -2514,6 +2516,31 @@ static int ipr_wait_iodbg_ack(struct ipr_ioa_cfg *ioa_cfg, int max_delay) | |||
2514 | } | 2516 | } |
2515 | 2517 | ||
2516 | /** | 2518 | /** |
2519 | * ipr_get_sis64_dump_data_section - Dump IOA memory | ||
2520 | * @ioa_cfg: ioa config struct | ||
2521 | * @start_addr: adapter address to dump | ||
2522 | * @dest: destination kernel buffer | ||
2523 | * @length_in_words: length to dump in 4 byte words | ||
2524 | * | ||
2525 | * Return value: | ||
2526 | * 0 on success | ||
2527 | **/ | ||
2528 | static int ipr_get_sis64_dump_data_section(struct ipr_ioa_cfg *ioa_cfg, | ||
2529 | u32 start_addr, | ||
2530 | __be32 *dest, u32 length_in_words) | ||
2531 | { | ||
2532 | int i; | ||
2533 | |||
2534 | for (i = 0; i < length_in_words; i++) { | ||
2535 | writel(start_addr+(i*4), ioa_cfg->regs.dump_addr_reg); | ||
2536 | *dest = cpu_to_be32(readl(ioa_cfg->regs.dump_data_reg)); | ||
2537 | dest++; | ||
2538 | } | ||
2539 | |||
2540 | return 0; | ||
2541 | } | ||
2542 | |||
2543 | /** | ||
2517 | * ipr_get_ldump_data_section - Dump IOA memory | 2544 | * ipr_get_ldump_data_section - Dump IOA memory |
2518 | * @ioa_cfg: ioa config struct | 2545 | * @ioa_cfg: ioa config struct |
2519 | * @start_addr: adapter address to dump | 2546 | * @start_addr: adapter address to dump |
@@ -2530,6 +2557,10 @@ static int ipr_get_ldump_data_section(struct ipr_ioa_cfg *ioa_cfg, | |||
2530 | volatile u32 temp_pcii_reg; | 2557 | volatile u32 temp_pcii_reg; |
2531 | int i, delay = 0; | 2558 | int i, delay = 0; |
2532 | 2559 | ||
2560 | if (ioa_cfg->sis64) | ||
2561 | return ipr_get_sis64_dump_data_section(ioa_cfg, start_addr, | ||
2562 | dest, length_in_words); | ||
2563 | |||
2533 | /* Write IOA interrupt reg starting LDUMP state */ | 2564 | /* Write IOA interrupt reg starting LDUMP state */ |
2534 | writel((IPR_UPROCI_RESET_ALERT | IPR_UPROCI_IO_DEBUG_ALERT), | 2565 | writel((IPR_UPROCI_RESET_ALERT | IPR_UPROCI_IO_DEBUG_ALERT), |
2535 | ioa_cfg->regs.set_uproc_interrupt_reg); | 2566 | 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 | u32 num_entries, start_off, end_off; | 2818 | u32 num_entries, start_off, end_off; |
2788 | u32 bytes_to_copy, bytes_copied, rc; | 2819 | u32 bytes_to_copy, bytes_copied, rc; |
2789 | struct ipr_sdt *sdt; | 2820 | struct ipr_sdt *sdt; |
2821 | int valid = 1; | ||
2790 | int i; | 2822 | int i; |
2791 | 2823 | ||
2792 | ENTER; | 2824 | ENTER; |
@@ -2800,7 +2832,7 @@ static void ipr_get_ioa_dump(struct ipr_ioa_cfg *ioa_cfg, struct ipr_dump *dump) | |||
2800 | 2832 | ||
2801 | start_addr = readl(ioa_cfg->ioa_mailbox); | 2833 | start_addr = readl(ioa_cfg->ioa_mailbox); |
2802 | 2834 | ||
2803 | if (!ipr_sdt_is_fmt2(start_addr)) { | 2835 | if (!ioa_cfg->sis64 && !ipr_sdt_is_fmt2(start_addr)) { |
2804 | dev_err(&ioa_cfg->pdev->dev, | 2836 | dev_err(&ioa_cfg->pdev->dev, |
2805 | "Invalid dump table format: %lx\n", start_addr); | 2837 | "Invalid dump table format: %lx\n", start_addr); |
2806 | spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); | 2838 | 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 | 2861 | ||
2830 | /* IOA Dump entry */ | 2862 | /* IOA Dump entry */ |
2831 | ipr_init_dump_entry_hdr(&ioa_dump->hdr); | 2863 | ipr_init_dump_entry_hdr(&ioa_dump->hdr); |
2832 | ioa_dump->format = IPR_SDT_FMT2; | ||
2833 | ioa_dump->hdr.len = 0; | 2864 | ioa_dump->hdr.len = 0; |
2834 | ioa_dump->hdr.data_type = IPR_DUMP_DATA_TYPE_BINARY; | 2865 | ioa_dump->hdr.data_type = IPR_DUMP_DATA_TYPE_BINARY; |
2835 | ioa_dump->hdr.id = IPR_DUMP_IOA_DUMP_ID; | 2866 | 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 | sizeof(struct ipr_sdt) / sizeof(__be32)); | 2875 | sizeof(struct ipr_sdt) / sizeof(__be32)); |
2845 | 2876 | ||
2846 | /* Smart Dump table is ready to use and the first entry is valid */ | 2877 | /* Smart Dump table is ready to use and the first entry is valid */ |
2847 | if (rc || (be32_to_cpu(sdt->hdr.state) != IPR_FMT2_SDT_READY_TO_USE)) { | 2878 | if (rc || ((be32_to_cpu(sdt->hdr.state) != IPR_FMT3_SDT_READY_TO_USE) && |
2879 | (be32_to_cpu(sdt->hdr.state) != IPR_FMT2_SDT_READY_TO_USE))) { | ||
2848 | dev_err(&ioa_cfg->pdev->dev, | 2880 | dev_err(&ioa_cfg->pdev->dev, |
2849 | "Dump of IOA failed. Dump table not valid: %d, %X.\n", | 2881 | "Dump of IOA failed. Dump table not valid: %d, %X.\n", |
2850 | rc, be32_to_cpu(sdt->hdr.state)); | 2882 | 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 | } | 2900 | } |
2869 | 2901 | ||
2870 | if (sdt->entry[i].flags & IPR_SDT_VALID_ENTRY) { | 2902 | if (sdt->entry[i].flags & IPR_SDT_VALID_ENTRY) { |
2871 | sdt_word = be32_to_cpu(sdt->entry[i].bar_str_offset); | 2903 | sdt_word = be32_to_cpu(sdt->entry[i].start_token); |
2872 | start_off = sdt_word & IPR_FMT2_MBX_ADDR_MASK; | 2904 | if (ioa_cfg->sis64) |
2873 | end_off = be32_to_cpu(sdt->entry[i].end_offset); | 2905 | bytes_to_copy = be32_to_cpu(sdt->entry[i].end_token); |
2874 | 2906 | else { | |
2875 | if (ipr_sdt_is_fmt2(sdt_word) && sdt_word) { | 2907 | start_off = sdt_word & IPR_FMT2_MBX_ADDR_MASK; |
2876 | bytes_to_copy = end_off - start_off; | 2908 | end_off = be32_to_cpu(sdt->entry[i].end_token); |
2909 | |||
2910 | if (ipr_sdt_is_fmt2(sdt_word) && sdt_word) | ||
2911 | bytes_to_copy = end_off - start_off; | ||
2912 | else | ||
2913 | valid = 0; | ||
2914 | } | ||
2915 | if (valid) { | ||
2877 | if (bytes_to_copy > IPR_MAX_IOA_DUMP_SIZE) { | 2916 | if (bytes_to_copy > IPR_MAX_IOA_DUMP_SIZE) { |
2878 | sdt->entry[i].flags &= ~IPR_SDT_VALID_ENTRY; | 2917 | sdt->entry[i].flags &= ~IPR_SDT_VALID_ENTRY; |
2879 | continue; | 2918 | continue; |
@@ -7202,7 +7241,7 @@ static void ipr_get_unit_check_buffer(struct ipr_ioa_cfg *ioa_cfg) | |||
7202 | 7241 | ||
7203 | mailbox = readl(ioa_cfg->ioa_mailbox); | 7242 | mailbox = readl(ioa_cfg->ioa_mailbox); |
7204 | 7243 | ||
7205 | if (!ipr_sdt_is_fmt2(mailbox)) { | 7244 | if (!ioa_cfg->sis64 && !ipr_sdt_is_fmt2(mailbox)) { |
7206 | ipr_unit_check_no_data(ioa_cfg); | 7245 | ipr_unit_check_no_data(ioa_cfg); |
7207 | return; | 7246 | return; |
7208 | } | 7247 | } |
@@ -7211,15 +7250,20 @@ static void ipr_get_unit_check_buffer(struct ipr_ioa_cfg *ioa_cfg) | |||
7211 | rc = ipr_get_ldump_data_section(ioa_cfg, mailbox, (__be32 *) &sdt, | 7250 | rc = ipr_get_ldump_data_section(ioa_cfg, mailbox, (__be32 *) &sdt, |
7212 | (sizeof(struct ipr_uc_sdt)) / sizeof(__be32)); | 7251 | (sizeof(struct ipr_uc_sdt)) / sizeof(__be32)); |
7213 | 7252 | ||
7214 | if (rc || (be32_to_cpu(sdt.hdr.state) != IPR_FMT2_SDT_READY_TO_USE) || | 7253 | if (rc || !(sdt.entry[0].flags & IPR_SDT_VALID_ENTRY) || |
7215 | !(sdt.entry[0].flags & IPR_SDT_VALID_ENTRY)) { | 7254 | ((be32_to_cpu(sdt.hdr.state) != IPR_FMT3_SDT_READY_TO_USE) && |
7255 | (be32_to_cpu(sdt.hdr.state) != IPR_FMT2_SDT_READY_TO_USE))) { | ||
7216 | ipr_unit_check_no_data(ioa_cfg); | 7256 | ipr_unit_check_no_data(ioa_cfg); |
7217 | return; | 7257 | return; |
7218 | } | 7258 | } |
7219 | 7259 | ||
7220 | /* Find length of the first sdt entry (UC buffer) */ | 7260 | /* Find length of the first sdt entry (UC buffer) */ |
7221 | length = (be32_to_cpu(sdt.entry[0].end_offset) - | 7261 | if (be32_to_cpu(sdt.hdr.state) == IPR_FMT3_SDT_READY_TO_USE) |
7222 | be32_to_cpu(sdt.entry[0].bar_str_offset)) & IPR_FMT2_MBX_ADDR_MASK; | 7262 | length = be32_to_cpu(sdt.entry[0].end_token); |
7263 | else | ||
7264 | length = (be32_to_cpu(sdt.entry[0].end_token) - | ||
7265 | be32_to_cpu(sdt.entry[0].start_token)) & | ||
7266 | IPR_FMT2_MBX_ADDR_MASK; | ||
7223 | 7267 | ||
7224 | hostrcb = list_entry(ioa_cfg->hostrcb_free_q.next, | 7268 | hostrcb = list_entry(ioa_cfg->hostrcb_free_q.next, |
7225 | struct ipr_hostrcb, queue); | 7269 | struct ipr_hostrcb, queue); |
@@ -7227,7 +7271,7 @@ static void ipr_get_unit_check_buffer(struct ipr_ioa_cfg *ioa_cfg) | |||
7227 | memset(&hostrcb->hcam, 0, sizeof(hostrcb->hcam)); | 7271 | memset(&hostrcb->hcam, 0, sizeof(hostrcb->hcam)); |
7228 | 7272 | ||
7229 | rc = ipr_get_ldump_data_section(ioa_cfg, | 7273 | rc = ipr_get_ldump_data_section(ioa_cfg, |
7230 | be32_to_cpu(sdt.entry[0].bar_str_offset), | 7274 | be32_to_cpu(sdt.entry[0].start_token), |
7231 | (__be32 *)&hostrcb->hcam, | 7275 | (__be32 *)&hostrcb->hcam, |
7232 | min(length, (int)sizeof(hostrcb->hcam)) / sizeof(__be32)); | 7276 | min(length, (int)sizeof(hostrcb->hcam)) / sizeof(__be32)); |
7233 | 7277 | ||
@@ -8202,6 +8246,11 @@ static void __devinit ipr_init_ioa_cfg(struct ipr_ioa_cfg *ioa_cfg, | |||
8202 | t->sense_uproc_interrupt_reg = base + p->sense_uproc_interrupt_reg; | 8246 | t->sense_uproc_interrupt_reg = base + p->sense_uproc_interrupt_reg; |
8203 | t->set_uproc_interrupt_reg = base + p->set_uproc_interrupt_reg; | 8247 | t->set_uproc_interrupt_reg = base + p->set_uproc_interrupt_reg; |
8204 | t->clr_uproc_interrupt_reg = base + p->clr_uproc_interrupt_reg; | 8248 | t->clr_uproc_interrupt_reg = base + p->clr_uproc_interrupt_reg; |
8249 | |||
8250 | if (ioa_cfg->sis64) { | ||
8251 | t->dump_addr_reg = base + p->dump_addr_reg; | ||
8252 | t->dump_data_reg = base + p->dump_data_reg; | ||
8253 | } | ||
8205 | } | 8254 | } |
8206 | 8255 | ||
8207 | /** | 8256 | /** |
diff --git a/drivers/scsi/ipr.h b/drivers/scsi/ipr.h index e6e90179e45e..4f2f1d2e9875 100644 --- a/drivers/scsi/ipr.h +++ b/drivers/scsi/ipr.h | |||
@@ -228,6 +228,7 @@ | |||
228 | #define IPR_SDT_FMT2_BAR5_SEL 0x5 | 228 | #define IPR_SDT_FMT2_BAR5_SEL 0x5 |
229 | #define IPR_SDT_FMT2_EXP_ROM_SEL 0x8 | 229 | #define IPR_SDT_FMT2_EXP_ROM_SEL 0x8 |
230 | #define IPR_FMT2_SDT_READY_TO_USE 0xC4D4E3F2 | 230 | #define IPR_FMT2_SDT_READY_TO_USE 0xC4D4E3F2 |
231 | #define IPR_FMT3_SDT_READY_TO_USE 0xC4D4E3F3 | ||
231 | #define IPR_DOORBELL 0x82800000 | 232 | #define IPR_DOORBELL 0x82800000 |
232 | #define IPR_RUNTIME_RESET 0x40000000 | 233 | #define IPR_RUNTIME_RESET 0x40000000 |
233 | 234 | ||
@@ -1093,10 +1094,9 @@ struct ipr_hostrcb { | |||
1093 | 1094 | ||
1094 | /* IPR smart dump table structures */ | 1095 | /* IPR smart dump table structures */ |
1095 | struct ipr_sdt_entry { | 1096 | struct ipr_sdt_entry { |
1096 | __be32 bar_str_offset; | 1097 | __be32 start_token; |
1097 | __be32 end_offset; | 1098 | __be32 end_token; |
1098 | u8 entry_byte; | 1099 | u8 reserved[4]; |
1099 | u8 reserved[3]; | ||
1100 | 1100 | ||
1101 | u8 flags; | 1101 | u8 flags; |
1102 | #define IPR_SDT_ENDIAN 0x80 | 1102 | #define IPR_SDT_ENDIAN 0x80 |
@@ -1204,6 +1204,9 @@ struct ipr_interrupt_offsets { | |||
1204 | unsigned long sense_uproc_interrupt_reg; | 1204 | unsigned long sense_uproc_interrupt_reg; |
1205 | unsigned long set_uproc_interrupt_reg; | 1205 | unsigned long set_uproc_interrupt_reg; |
1206 | unsigned long clr_uproc_interrupt_reg; | 1206 | unsigned long clr_uproc_interrupt_reg; |
1207 | |||
1208 | unsigned long dump_addr_reg; | ||
1209 | unsigned long dump_data_reg; | ||
1207 | }; | 1210 | }; |
1208 | 1211 | ||
1209 | struct ipr_interrupts { | 1212 | struct ipr_interrupts { |
@@ -1217,6 +1220,9 @@ struct ipr_interrupts { | |||
1217 | void __iomem *sense_uproc_interrupt_reg; | 1220 | void __iomem *sense_uproc_interrupt_reg; |
1218 | void __iomem *set_uproc_interrupt_reg; | 1221 | void __iomem *set_uproc_interrupt_reg; |
1219 | void __iomem *clr_uproc_interrupt_reg; | 1222 | void __iomem *clr_uproc_interrupt_reg; |
1223 | |||
1224 | void __iomem *dump_addr_reg; | ||
1225 | void __iomem *dump_data_reg; | ||
1220 | }; | 1226 | }; |
1221 | 1227 | ||
1222 | struct ipr_chip_cfg_t { | 1228 | struct ipr_chip_cfg_t { |
@@ -1536,8 +1542,6 @@ struct ipr_ioa_dump { | |||
1536 | u32 next_page_index; | 1542 | u32 next_page_index; |
1537 | u32 page_offset; | 1543 | u32 page_offset; |
1538 | u32 format; | 1544 | u32 format; |
1539 | #define IPR_SDT_FMT2 2 | ||
1540 | #define IPR_SDT_UNKNOWN 3 | ||
1541 | }__attribute__((packed, aligned (4))); | 1545 | }__attribute__((packed, aligned (4))); |
1542 | 1546 | ||
1543 | struct ipr_dump { | 1547 | struct ipr_dump { |