[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>
This commit is contained in:
		
							parent
							
								
									4565e37063
								
							
						
					
					
						commit
						dcbad00e6b
					
				| @ -142,7 +142,9 @@ static const struct ipr_chip_cfg_t ipr_chip_cfg[] = { | ||||
| 			.ioarrin_reg = 0x00070, | ||||
| 			.sense_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) | ||||
| 	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 | ||||
|  * @ioa_cfg:			ioa config struct | ||||
| @ -2530,6 +2557,10 @@ static int ipr_get_ldump_data_section(struct ipr_ioa_cfg *ioa_cfg, | ||||
| 	volatile u32 temp_pcii_reg; | ||||
| 	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  */ | ||||
| 	writel((IPR_UPROCI_RESET_ALERT | IPR_UPROCI_IO_DEBUG_ALERT), | ||||
| 	       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) | ||||
| 	u32 num_entries, start_off, end_off; | ||||
| 	u32 bytes_to_copy, bytes_copied, rc; | ||||
| 	struct ipr_sdt *sdt; | ||||
| 	int valid = 1; | ||||
| 	int i; | ||||
| 
 | ||||
| 	ENTER; | ||||
| @ -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); | ||||
| 
 | ||||
| 	if (!ipr_sdt_is_fmt2(start_addr)) { | ||||
| 	if (!ioa_cfg->sis64 && !ipr_sdt_is_fmt2(start_addr)) { | ||||
| 		dev_err(&ioa_cfg->pdev->dev, | ||||
| 			"Invalid dump table format: %lx\n", start_addr); | ||||
| 		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) | ||||
| 
 | ||||
| 	/* IOA Dump entry */ | ||||
| 	ipr_init_dump_entry_hdr(&ioa_dump->hdr); | ||||
| 	ioa_dump->format = IPR_SDT_FMT2; | ||||
| 	ioa_dump->hdr.len = 0; | ||||
| 	ioa_dump->hdr.data_type = IPR_DUMP_DATA_TYPE_BINARY; | ||||
| 	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) | ||||
| 					sizeof(struct ipr_sdt) / sizeof(__be32)); | ||||
| 
 | ||||
| 	/* 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, | ||||
| 			"Dump of IOA failed. Dump table not valid: %d, %X.\n", | ||||
| 			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) | ||||
| 		} | ||||
| 
 | ||||
| 		if (sdt->entry[i].flags & IPR_SDT_VALID_ENTRY) { | ||||
| 			sdt_word = be32_to_cpu(sdt->entry[i].bar_str_offset); | ||||
| 			start_off = sdt_word & IPR_FMT2_MBX_ADDR_MASK; | ||||
| 			end_off = be32_to_cpu(sdt->entry[i].end_offset); | ||||
| 			sdt_word = be32_to_cpu(sdt->entry[i].start_token); | ||||
| 			if (ioa_cfg->sis64) | ||||
| 				bytes_to_copy = be32_to_cpu(sdt->entry[i].end_token); | ||||
| 			else { | ||||
| 				start_off = sdt_word & IPR_FMT2_MBX_ADDR_MASK; | ||||
| 				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; | ||||
| 				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) { | ||||
| 					sdt->entry[i].flags &= ~IPR_SDT_VALID_ENTRY; | ||||
| 					continue; | ||||
| @ -7202,7 +7241,7 @@ static void ipr_get_unit_check_buffer(struct ipr_ioa_cfg *ioa_cfg) | ||||
| 
 | ||||
| 	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); | ||||
| 		return; | ||||
| 	} | ||||
| @ -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, | ||||
| 					(sizeof(struct ipr_uc_sdt)) / sizeof(__be32)); | ||||
| 
 | ||||
| 	if (rc || (be32_to_cpu(sdt.hdr.state) != IPR_FMT2_SDT_READY_TO_USE) || | ||||
| 	    !(sdt.entry[0].flags & IPR_SDT_VALID_ENTRY)) { | ||||
| 	if (rc || !(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); | ||||
| 		return; | ||||
| 	} | ||||
| 
 | ||||
| 	/* Find length of the first sdt entry (UC buffer) */ | ||||
| 	length = (be32_to_cpu(sdt.entry[0].end_offset) - | ||||
| 		  be32_to_cpu(sdt.entry[0].bar_str_offset)) & IPR_FMT2_MBX_ADDR_MASK; | ||||
| 	if (be32_to_cpu(sdt.hdr.state) == IPR_FMT3_SDT_READY_TO_USE) | ||||
| 		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, | ||||
| 			     struct ipr_hostrcb, queue); | ||||
| @ -7227,7 +7271,7 @@ static void ipr_get_unit_check_buffer(struct ipr_ioa_cfg *ioa_cfg) | ||||
| 	memset(&hostrcb->hcam, 0, sizeof(hostrcb->hcam)); | ||||
| 
 | ||||
| 	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, | ||||
| 					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, | ||||
| 	t->sense_uproc_interrupt_reg = base + p->sense_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; | ||||
| 
 | ||||
| 	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 @@ | ||||
| #define IPR_SDT_FMT2_BAR5_SEL				0x5 | ||||
| #define IPR_SDT_FMT2_EXP_ROM_SEL			0x8 | ||||
| #define IPR_FMT2_SDT_READY_TO_USE			0xC4D4E3F2 | ||||
| #define IPR_FMT3_SDT_READY_TO_USE			0xC4D4E3F3 | ||||
| #define IPR_DOORBELL					0x82800000 | ||||
| #define IPR_RUNTIME_RESET				0x40000000 | ||||
| 
 | ||||
| @ -1093,10 +1094,9 @@ struct ipr_hostrcb { | ||||
| 
 | ||||
| /* IPR smart dump table structures */ | ||||
| struct ipr_sdt_entry { | ||||
| 	__be32 bar_str_offset; | ||||
| 	__be32 end_offset; | ||||
| 	u8 entry_byte; | ||||
| 	u8 reserved[3]; | ||||
| 	__be32 start_token; | ||||
| 	__be32 end_token; | ||||
| 	u8 reserved[4]; | ||||
| 
 | ||||
| 	u8 flags; | ||||
| #define IPR_SDT_ENDIAN		0x80 | ||||
| @ -1204,6 +1204,9 @@ struct ipr_interrupt_offsets { | ||||
| 	unsigned long sense_uproc_interrupt_reg; | ||||
| 	unsigned long set_uproc_interrupt_reg; | ||||
| 	unsigned long clr_uproc_interrupt_reg; | ||||
| 
 | ||||
| 	unsigned long dump_addr_reg; | ||||
| 	unsigned long dump_data_reg; | ||||
| }; | ||||
| 
 | ||||
| struct ipr_interrupts { | ||||
| @ -1217,6 +1220,9 @@ struct ipr_interrupts { | ||||
| 	void __iomem *sense_uproc_interrupt_reg; | ||||
| 	void __iomem *set_uproc_interrupt_reg; | ||||
| 	void __iomem *clr_uproc_interrupt_reg; | ||||
| 
 | ||||
| 	void __iomem *dump_addr_reg; | ||||
| 	void __iomem *dump_data_reg; | ||||
| }; | ||||
| 
 | ||||
| struct ipr_chip_cfg_t { | ||||
| @ -1536,8 +1542,6 @@ struct ipr_ioa_dump { | ||||
| 	u32 next_page_index; | ||||
| 	u32 page_offset; | ||||
| 	u32 format; | ||||
| #define IPR_SDT_FMT2		2 | ||||
| #define IPR_SDT_UNKNOWN		3 | ||||
| }__attribute__((packed, aligned (4))); | ||||
| 
 | ||||
| struct ipr_dump { | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user