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 | |
| 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>
| -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 { |
