xref: /linux/drivers/scsi/qla2xxx/qla_tmpl.c (revision 4f2c0a4acffbec01079c28f839422e64ddeff004)
177adf3f0SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2f73cb695SChad Dupuis /*
3f73cb695SChad Dupuis  * QLogic Fibre Channel HBA Driver
4bd21eaf9SArmen Baloyan  * Copyright (c)  2003-2014 QLogic Corporation
5f73cb695SChad Dupuis  */
6f73cb695SChad Dupuis #include "qla_def.h"
7f73cb695SChad Dupuis #include "qla_tmpl.h"
8f73cb695SChad Dupuis 
9ce0366dfSJoe Carnuccio #define ISPREG(vha)	(&(vha)->hw->iobase->isp24)
10ce0366dfSJoe Carnuccio #define IOBAR(reg)	offsetof(typeof(*(reg)), iobase_addr)
11ce0366dfSJoe Carnuccio #define IOBASE(vha)	IOBAR(ISPREG(vha))
12c5547419SQuinn Tran #define INVALID_ENTRY ((struct qla27xx_fwdt_entry *)0xffffffffffffffffUL)
13f73cb695SChad Dupuis 
14f73cb695SChad Dupuis static inline void
qla27xx_insert16(uint16_t value,void * buf,ulong * len)15f73cb695SChad Dupuis qla27xx_insert16(uint16_t value, void *buf, ulong *len)
16f73cb695SChad Dupuis {
17f73cb695SChad Dupuis 	if (buf) {
18f73cb695SChad Dupuis 		buf += *len;
19f73cb695SChad Dupuis 		*(__le16 *)buf = cpu_to_le16(value);
20f73cb695SChad Dupuis 	}
21f73cb695SChad Dupuis 	*len += sizeof(value);
22f73cb695SChad Dupuis }
23f73cb695SChad Dupuis 
24f73cb695SChad Dupuis static inline void
qla27xx_insert32(uint32_t value,void * buf,ulong * len)25f73cb695SChad Dupuis qla27xx_insert32(uint32_t value, void *buf, ulong *len)
26f73cb695SChad Dupuis {
27f73cb695SChad Dupuis 	if (buf) {
28f73cb695SChad Dupuis 		buf += *len;
29f73cb695SChad Dupuis 		*(__le32 *)buf = cpu_to_le32(value);
30f73cb695SChad Dupuis 	}
31f73cb695SChad Dupuis 	*len += sizeof(value);
32f73cb695SChad Dupuis }
33f73cb695SChad Dupuis 
34f73cb695SChad Dupuis static inline void
qla27xx_insertbuf(void * mem,ulong size,void * buf,ulong * len)35f73cb695SChad Dupuis qla27xx_insertbuf(void *mem, ulong size, void *buf, ulong *len)
36f73cb695SChad Dupuis {
37ce9b9b08SJoe Carnuccio 	if (buf && mem && size) {
38f73cb695SChad Dupuis 		buf += *len;
39ce9b9b08SJoe Carnuccio 		memcpy(buf, mem, size);
40f73cb695SChad Dupuis 	}
41f73cb695SChad Dupuis 	*len += size;
42f73cb695SChad Dupuis }
43f73cb695SChad Dupuis 
44f73cb695SChad Dupuis static inline void
qla27xx_read8(void __iomem * window,void * buf,ulong * len)458dfa4b5aSBart Van Assche qla27xx_read8(void __iomem *window, void *buf, ulong *len)
46f73cb695SChad Dupuis {
47f73cb695SChad Dupuis 	uint8_t value = ~0;
48f73cb695SChad Dupuis 
49f73cb695SChad Dupuis 	if (buf) {
5004474d3aSBart Van Assche 		value = rd_reg_byte(window);
51f73cb695SChad Dupuis 	}
52f73cb695SChad Dupuis 	qla27xx_insert32(value, buf, len);
53f73cb695SChad Dupuis }
54f73cb695SChad Dupuis 
55f73cb695SChad Dupuis static inline void
qla27xx_read16(void __iomem * window,void * buf,ulong * len)568dfa4b5aSBart Van Assche qla27xx_read16(void __iomem *window, void *buf, ulong *len)
57f73cb695SChad Dupuis {
58f73cb695SChad Dupuis 	uint16_t value = ~0;
59f73cb695SChad Dupuis 
60f73cb695SChad Dupuis 	if (buf) {
6104474d3aSBart Van Assche 		value = rd_reg_word(window);
62f73cb695SChad Dupuis 	}
63f73cb695SChad Dupuis 	qla27xx_insert32(value, buf, len);
64f73cb695SChad Dupuis }
65f73cb695SChad Dupuis 
66f73cb695SChad Dupuis static inline void
qla27xx_read32(void __iomem * window,void * buf,ulong * len)678dfa4b5aSBart Van Assche qla27xx_read32(void __iomem *window, void *buf, ulong *len)
68f73cb695SChad Dupuis {
69f73cb695SChad Dupuis 	uint32_t value = ~0;
70f73cb695SChad Dupuis 
71f73cb695SChad Dupuis 	if (buf) {
7204474d3aSBart Van Assche 		value = rd_reg_dword(window);
73f73cb695SChad Dupuis 	}
74f73cb695SChad Dupuis 	qla27xx_insert32(value, buf, len);
75f73cb695SChad Dupuis }
76f73cb695SChad Dupuis 
qla27xx_read_vector(uint width)778dfa4b5aSBart Van Assche static inline void (*qla27xx_read_vector(uint width))(void __iomem*, void *, ulong *)
78f73cb695SChad Dupuis {
79f73cb695SChad Dupuis 	return
80f73cb695SChad Dupuis 	    (width == 1) ? qla27xx_read8 :
81f73cb695SChad Dupuis 	    (width == 2) ? qla27xx_read16 :
82f73cb695SChad Dupuis 			   qla27xx_read32;
83f73cb695SChad Dupuis }
84f73cb695SChad Dupuis 
85f73cb695SChad Dupuis static inline void
qla27xx_read_reg(__iomem struct device_reg_24xx * reg,uint offset,void * buf,ulong * len)86f73cb695SChad Dupuis qla27xx_read_reg(__iomem struct device_reg_24xx *reg,
87f73cb695SChad Dupuis 	uint offset, void *buf, ulong *len)
88f73cb695SChad Dupuis {
898dfa4b5aSBart Van Assche 	void __iomem *window = (void __iomem *)reg + offset;
90f73cb695SChad Dupuis 
91f73cb695SChad Dupuis 	qla27xx_read32(window, buf, len);
92f73cb695SChad Dupuis }
93f73cb695SChad Dupuis 
94f73cb695SChad Dupuis static inline void
qla27xx_write_reg(__iomem struct device_reg_24xx * reg,uint offset,uint32_t data,void * buf)95f73cb695SChad Dupuis qla27xx_write_reg(__iomem struct device_reg_24xx *reg,
96f73cb695SChad Dupuis 	uint offset, uint32_t data, void *buf)
97f73cb695SChad Dupuis {
98f73cb695SChad Dupuis 	if (buf) {
992ff01671SJoe Carnuccio 		void __iomem *window = (void __iomem *)reg + offset;
1002ff01671SJoe Carnuccio 
10104474d3aSBart Van Assche 		wrt_reg_dword(window, data);
102f73cb695SChad Dupuis 	}
103f73cb695SChad Dupuis }
104f73cb695SChad Dupuis 
105f73cb695SChad Dupuis static inline void
qla27xx_read_window(__iomem struct device_reg_24xx * reg,uint32_t addr,uint offset,uint count,uint width,void * buf,ulong * len)106f73cb695SChad Dupuis qla27xx_read_window(__iomem struct device_reg_24xx *reg,
107c0496401SJoe Carnuccio 	uint32_t addr, uint offset, uint count, uint width, void *buf,
108f73cb695SChad Dupuis 	ulong *len)
109f73cb695SChad Dupuis {
1108dfa4b5aSBart Van Assche 	void __iomem *window = (void __iomem *)reg + offset;
1118dfa4b5aSBart Van Assche 	void (*readn)(void __iomem*, void *, ulong *) = qla27xx_read_vector(width);
112f73cb695SChad Dupuis 
113ce0366dfSJoe Carnuccio 	qla27xx_write_reg(reg, IOBAR(reg), addr, buf);
114f73cb695SChad Dupuis 	while (count--) {
115c0496401SJoe Carnuccio 		qla27xx_insert32(addr, buf, len);
116f73cb695SChad Dupuis 		readn(window, buf, len);
117f73cb695SChad Dupuis 		window += width;
118c0496401SJoe Carnuccio 		addr++;
119f73cb695SChad Dupuis 	}
120f73cb695SChad Dupuis }
121f73cb695SChad Dupuis 
122f73cb695SChad Dupuis static inline void
qla27xx_skip_entry(struct qla27xx_fwdt_entry * ent,void * buf)123f73cb695SChad Dupuis qla27xx_skip_entry(struct qla27xx_fwdt_entry *ent, void *buf)
124f73cb695SChad Dupuis {
125f73cb695SChad Dupuis 	if (buf)
126f73cb695SChad Dupuis 		ent->hdr.driver_flags |= DRIVER_FLAG_SKIP_ENTRY;
127f73cb695SChad Dupuis }
128f73cb695SChad Dupuis 
12964f61d99SJoe Carnuccio static inline struct qla27xx_fwdt_entry *
qla27xx_next_entry(struct qla27xx_fwdt_entry * ent)13064f61d99SJoe Carnuccio qla27xx_next_entry(struct qla27xx_fwdt_entry *ent)
13164f61d99SJoe Carnuccio {
132f8f97b0cSJoe Carnuccio 	return (void *)ent + le32_to_cpu(ent->hdr.size);
13364f61d99SJoe Carnuccio }
13464f61d99SJoe Carnuccio 
13564f61d99SJoe Carnuccio static struct qla27xx_fwdt_entry *
qla27xx_fwdt_entry_t0(struct scsi_qla_host * vha,struct qla27xx_fwdt_entry * ent,void * buf,ulong * len)136f73cb695SChad Dupuis qla27xx_fwdt_entry_t0(struct scsi_qla_host *vha,
137f73cb695SChad Dupuis 	struct qla27xx_fwdt_entry *ent, void *buf, ulong *len)
138f73cb695SChad Dupuis {
139f73cb695SChad Dupuis 	ql_dbg(ql_dbg_misc, vha, 0xd100,
140f73cb695SChad Dupuis 	    "%s: nop [%lx]\n", __func__, *len);
141f73cb695SChad Dupuis 	qla27xx_skip_entry(ent, buf);
142f73cb695SChad Dupuis 
14364f61d99SJoe Carnuccio 	return qla27xx_next_entry(ent);
144f73cb695SChad Dupuis }
145f73cb695SChad Dupuis 
14664f61d99SJoe Carnuccio static struct qla27xx_fwdt_entry *
qla27xx_fwdt_entry_t255(struct scsi_qla_host * vha,struct qla27xx_fwdt_entry * ent,void * buf,ulong * len)147f73cb695SChad Dupuis qla27xx_fwdt_entry_t255(struct scsi_qla_host *vha,
148f73cb695SChad Dupuis 	struct qla27xx_fwdt_entry *ent, void *buf, ulong *len)
149f73cb695SChad Dupuis {
150f73cb695SChad Dupuis 	ql_dbg(ql_dbg_misc, vha, 0xd1ff,
151f73cb695SChad Dupuis 	    "%s: end [%lx]\n", __func__, *len);
152f73cb695SChad Dupuis 	qla27xx_skip_entry(ent, buf);
153f73cb695SChad Dupuis 
154f73cb695SChad Dupuis 	/* terminate */
15564f61d99SJoe Carnuccio 	return NULL;
156f73cb695SChad Dupuis }
157f73cb695SChad Dupuis 
15864f61d99SJoe Carnuccio static struct qla27xx_fwdt_entry *
qla27xx_fwdt_entry_t256(struct scsi_qla_host * vha,struct qla27xx_fwdt_entry * ent,void * buf,ulong * len)159f73cb695SChad Dupuis qla27xx_fwdt_entry_t256(struct scsi_qla_host *vha,
160f73cb695SChad Dupuis 	struct qla27xx_fwdt_entry *ent, void *buf, ulong *len)
161f73cb695SChad Dupuis {
162f8f97b0cSJoe Carnuccio 	ulong addr = le32_to_cpu(ent->t256.base_addr);
163f8f97b0cSJoe Carnuccio 	uint offset = ent->t256.pci_offset;
164f8f97b0cSJoe Carnuccio 	ulong count = le16_to_cpu(ent->t256.reg_count);
165f8f97b0cSJoe Carnuccio 	uint width = ent->t256.reg_width;
166f73cb695SChad Dupuis 
167f73cb695SChad Dupuis 	ql_dbg(ql_dbg_misc, vha, 0xd200,
168f73cb695SChad Dupuis 	    "%s: rdio t1 [%lx]\n", __func__, *len);
169ce0366dfSJoe Carnuccio 	qla27xx_read_window(ISPREG(vha), addr, offset, count, width, buf, len);
170f73cb695SChad Dupuis 
17164f61d99SJoe Carnuccio 	return qla27xx_next_entry(ent);
172f73cb695SChad Dupuis }
173f73cb695SChad Dupuis 
17464f61d99SJoe Carnuccio static struct qla27xx_fwdt_entry *
qla27xx_fwdt_entry_t257(struct scsi_qla_host * vha,struct qla27xx_fwdt_entry * ent,void * buf,ulong * len)175f73cb695SChad Dupuis qla27xx_fwdt_entry_t257(struct scsi_qla_host *vha,
176f73cb695SChad Dupuis 	struct qla27xx_fwdt_entry *ent, void *buf, ulong *len)
177f73cb695SChad Dupuis {
178f8f97b0cSJoe Carnuccio 	ulong addr = le32_to_cpu(ent->t257.base_addr);
179f8f97b0cSJoe Carnuccio 	uint offset = ent->t257.pci_offset;
180f8f97b0cSJoe Carnuccio 	ulong data = le32_to_cpu(ent->t257.write_data);
181f73cb695SChad Dupuis 
182f73cb695SChad Dupuis 	ql_dbg(ql_dbg_misc, vha, 0xd201,
183f73cb695SChad Dupuis 	    "%s: wrio t1 [%lx]\n", __func__, *len);
184ce0366dfSJoe Carnuccio 	qla27xx_write_reg(ISPREG(vha), IOBASE(vha), addr, buf);
185ce0366dfSJoe Carnuccio 	qla27xx_write_reg(ISPREG(vha), offset, data, buf);
186f73cb695SChad Dupuis 
18764f61d99SJoe Carnuccio 	return qla27xx_next_entry(ent);
188f73cb695SChad Dupuis }
189f73cb695SChad Dupuis 
19064f61d99SJoe Carnuccio static struct qla27xx_fwdt_entry *
qla27xx_fwdt_entry_t258(struct scsi_qla_host * vha,struct qla27xx_fwdt_entry * ent,void * buf,ulong * len)191f73cb695SChad Dupuis qla27xx_fwdt_entry_t258(struct scsi_qla_host *vha,
192f73cb695SChad Dupuis 	struct qla27xx_fwdt_entry *ent, void *buf, ulong *len)
193f73cb695SChad Dupuis {
194f8f97b0cSJoe Carnuccio 	uint banksel = ent->t258.banksel_offset;
195f8f97b0cSJoe Carnuccio 	ulong bank = le32_to_cpu(ent->t258.bank);
196f8f97b0cSJoe Carnuccio 	ulong addr = le32_to_cpu(ent->t258.base_addr);
197f8f97b0cSJoe Carnuccio 	uint offset = ent->t258.pci_offset;
198f8f97b0cSJoe Carnuccio 	uint count = le16_to_cpu(ent->t258.reg_count);
199f8f97b0cSJoe Carnuccio 	uint width = ent->t258.reg_width;
200f73cb695SChad Dupuis 
201f73cb695SChad Dupuis 	ql_dbg(ql_dbg_misc, vha, 0xd202,
202f73cb695SChad Dupuis 	    "%s: rdio t2 [%lx]\n", __func__, *len);
203ce0366dfSJoe Carnuccio 	qla27xx_write_reg(ISPREG(vha), banksel, bank, buf);
204ce0366dfSJoe Carnuccio 	qla27xx_read_window(ISPREG(vha), addr, offset, count, width, buf, len);
205f73cb695SChad Dupuis 
20664f61d99SJoe Carnuccio 	return qla27xx_next_entry(ent);
207f73cb695SChad Dupuis }
208f73cb695SChad Dupuis 
20964f61d99SJoe Carnuccio static struct qla27xx_fwdt_entry *
qla27xx_fwdt_entry_t259(struct scsi_qla_host * vha,struct qla27xx_fwdt_entry * ent,void * buf,ulong * len)210f73cb695SChad Dupuis qla27xx_fwdt_entry_t259(struct scsi_qla_host *vha,
211f73cb695SChad Dupuis 	struct qla27xx_fwdt_entry *ent, void *buf, ulong *len)
212f73cb695SChad Dupuis {
213f8f97b0cSJoe Carnuccio 	ulong addr = le32_to_cpu(ent->t259.base_addr);
214f8f97b0cSJoe Carnuccio 	uint banksel = ent->t259.banksel_offset;
215f8f97b0cSJoe Carnuccio 	ulong bank = le32_to_cpu(ent->t259.bank);
216f8f97b0cSJoe Carnuccio 	uint offset = ent->t259.pci_offset;
217f8f97b0cSJoe Carnuccio 	ulong data = le32_to_cpu(ent->t259.write_data);
218f73cb695SChad Dupuis 
219f73cb695SChad Dupuis 	ql_dbg(ql_dbg_misc, vha, 0xd203,
220f73cb695SChad Dupuis 	    "%s: wrio t2 [%lx]\n", __func__, *len);
221ce0366dfSJoe Carnuccio 	qla27xx_write_reg(ISPREG(vha), IOBASE(vha), addr, buf);
222ce0366dfSJoe Carnuccio 	qla27xx_write_reg(ISPREG(vha), banksel, bank, buf);
223ce0366dfSJoe Carnuccio 	qla27xx_write_reg(ISPREG(vha), offset, data, buf);
224f73cb695SChad Dupuis 
22564f61d99SJoe Carnuccio 	return qla27xx_next_entry(ent);
226f73cb695SChad Dupuis }
227f73cb695SChad Dupuis 
22864f61d99SJoe Carnuccio static struct qla27xx_fwdt_entry *
qla27xx_fwdt_entry_t260(struct scsi_qla_host * vha,struct qla27xx_fwdt_entry * ent,void * buf,ulong * len)229f73cb695SChad Dupuis qla27xx_fwdt_entry_t260(struct scsi_qla_host *vha,
230f73cb695SChad Dupuis 	struct qla27xx_fwdt_entry *ent, void *buf, ulong *len)
231f73cb695SChad Dupuis {
232f8f97b0cSJoe Carnuccio 	uint offset = ent->t260.pci_offset;
233f73cb695SChad Dupuis 
234f73cb695SChad Dupuis 	ql_dbg(ql_dbg_misc, vha, 0xd204,
235f73cb695SChad Dupuis 	    "%s: rdpci [%lx]\n", __func__, *len);
236f8f97b0cSJoe Carnuccio 	qla27xx_insert32(offset, buf, len);
237ce0366dfSJoe Carnuccio 	qla27xx_read_reg(ISPREG(vha), offset, buf, len);
238f73cb695SChad Dupuis 
23964f61d99SJoe Carnuccio 	return qla27xx_next_entry(ent);
240f73cb695SChad Dupuis }
241f73cb695SChad Dupuis 
24264f61d99SJoe Carnuccio static struct qla27xx_fwdt_entry *
qla27xx_fwdt_entry_t261(struct scsi_qla_host * vha,struct qla27xx_fwdt_entry * ent,void * buf,ulong * len)243f73cb695SChad Dupuis qla27xx_fwdt_entry_t261(struct scsi_qla_host *vha,
244f73cb695SChad Dupuis 	struct qla27xx_fwdt_entry *ent, void *buf, ulong *len)
245f73cb695SChad Dupuis {
246f8f97b0cSJoe Carnuccio 	uint offset = ent->t261.pci_offset;
247f8f97b0cSJoe Carnuccio 	ulong data = le32_to_cpu(ent->t261.write_data);
248f73cb695SChad Dupuis 
249f73cb695SChad Dupuis 	ql_dbg(ql_dbg_misc, vha, 0xd205,
250f73cb695SChad Dupuis 	    "%s: wrpci [%lx]\n", __func__, *len);
251ce0366dfSJoe Carnuccio 	qla27xx_write_reg(ISPREG(vha), offset, data, buf);
252f73cb695SChad Dupuis 
25364f61d99SJoe Carnuccio 	return qla27xx_next_entry(ent);
254f73cb695SChad Dupuis }
255f73cb695SChad Dupuis 
25664f61d99SJoe Carnuccio static struct qla27xx_fwdt_entry *
qla27xx_fwdt_entry_t262(struct scsi_qla_host * vha,struct qla27xx_fwdt_entry * ent,void * buf,ulong * len)257f73cb695SChad Dupuis qla27xx_fwdt_entry_t262(struct scsi_qla_host *vha,
258f73cb695SChad Dupuis 	struct qla27xx_fwdt_entry *ent, void *buf, ulong *len)
259f73cb695SChad Dupuis {
260f8f97b0cSJoe Carnuccio 	uint area = ent->t262.ram_area;
261f8f97b0cSJoe Carnuccio 	ulong start = le32_to_cpu(ent->t262.start_addr);
262f8f97b0cSJoe Carnuccio 	ulong end = le32_to_cpu(ent->t262.end_addr);
263f73cb695SChad Dupuis 	ulong dwords;
264c5547419SQuinn Tran 	int rc;
265f73cb695SChad Dupuis 
266f73cb695SChad Dupuis 	ql_dbg(ql_dbg_misc, vha, 0xd206,
267f73cb695SChad Dupuis 	    "%s: rdram(%x) [%lx]\n", __func__, ent->t262.ram_area, *len);
268f73cb695SChad Dupuis 
269f8f97b0cSJoe Carnuccio 	if (area == T262_RAM_AREA_CRITICAL_RAM) {
270f73cb695SChad Dupuis 		;
271f8f97b0cSJoe Carnuccio 	} else if (area == T262_RAM_AREA_EXTERNAL_RAM) {
272f73cb695SChad Dupuis 		end = vha->hw->fw_memory_size;
273f73cb695SChad Dupuis 		if (buf)
274f8f97b0cSJoe Carnuccio 			ent->t262.end_addr = cpu_to_le32(end);
275f8f97b0cSJoe Carnuccio 	} else if (area == T262_RAM_AREA_SHARED_RAM) {
276f73cb695SChad Dupuis 		start = vha->hw->fw_shared_ram_start;
277f73cb695SChad Dupuis 		end = vha->hw->fw_shared_ram_end;
278f73cb695SChad Dupuis 		if (buf) {
279f8f97b0cSJoe Carnuccio 			ent->t262.start_addr = cpu_to_le32(start);
280f8f97b0cSJoe Carnuccio 			ent->t262.end_addr = cpu_to_le32(end);
281f73cb695SChad Dupuis 		}
282f8f97b0cSJoe Carnuccio 	} else if (area == T262_RAM_AREA_DDR_RAM) {
283ad1ef177SJoe Carnuccio 		start = vha->hw->fw_ddr_ram_start;
284ad1ef177SJoe Carnuccio 		end = vha->hw->fw_ddr_ram_end;
285ad1ef177SJoe Carnuccio 		if (buf) {
286f8f97b0cSJoe Carnuccio 			ent->t262.start_addr = cpu_to_le32(start);
287f8f97b0cSJoe Carnuccio 			ent->t262.end_addr = cpu_to_le32(end);
288ad1ef177SJoe Carnuccio 		}
289f8f97b0cSJoe Carnuccio 	} else if (area == T262_RAM_AREA_MISC) {
29064f61d99SJoe Carnuccio 		if (buf) {
291f8f97b0cSJoe Carnuccio 			ent->t262.start_addr = cpu_to_le32(start);
292f8f97b0cSJoe Carnuccio 			ent->t262.end_addr = cpu_to_le32(end);
29364f61d99SJoe Carnuccio 		}
294f73cb695SChad Dupuis 	} else {
295f73cb695SChad Dupuis 		ql_dbg(ql_dbg_misc, vha, 0xd022,
296f8f97b0cSJoe Carnuccio 		    "%s: unknown area %x\n", __func__, area);
297f73cb695SChad Dupuis 		qla27xx_skip_entry(ent, buf);
298f73cb695SChad Dupuis 		goto done;
299f73cb695SChad Dupuis 	}
300f73cb695SChad Dupuis 
301ce6c668bSJoe Carnuccio 	if (end < start || start == 0 || end == 0) {
302f73cb695SChad Dupuis 		ql_dbg(ql_dbg_misc, vha, 0xd023,
303f8f97b0cSJoe Carnuccio 		    "%s: unusable range (start=%lx end=%lx)\n",
304f8f97b0cSJoe Carnuccio 		    __func__, start, end);
305f73cb695SChad Dupuis 		qla27xx_skip_entry(ent, buf);
306f73cb695SChad Dupuis 		goto done;
307f73cb695SChad Dupuis 	}
308f73cb695SChad Dupuis 
309f73cb695SChad Dupuis 	dwords = end - start + 1;
310f73cb695SChad Dupuis 	if (buf) {
311f73cb695SChad Dupuis 		buf += *len;
312c5547419SQuinn Tran 		rc = qla24xx_dump_ram(vha->hw, start, buf, dwords, &buf);
313c5547419SQuinn Tran 		if (rc != QLA_SUCCESS) {
314c5547419SQuinn Tran 			ql_dbg(ql_dbg_async, vha, 0xffff,
315c5547419SQuinn Tran 			    "%s: dump ram MB failed. Area %xh start %lxh end %lxh\n",
316c5547419SQuinn Tran 			    __func__, area, start, end);
317c5547419SQuinn Tran 			return INVALID_ENTRY;
318c5547419SQuinn Tran 		}
319f73cb695SChad Dupuis 	}
320f73cb695SChad Dupuis 	*len += dwords * sizeof(uint32_t);
321f73cb695SChad Dupuis done:
32264f61d99SJoe Carnuccio 	return qla27xx_next_entry(ent);
323f73cb695SChad Dupuis }
324f73cb695SChad Dupuis 
32564f61d99SJoe Carnuccio static struct qla27xx_fwdt_entry *
qla27xx_fwdt_entry_t263(struct scsi_qla_host * vha,struct qla27xx_fwdt_entry * ent,void * buf,ulong * len)326f73cb695SChad Dupuis qla27xx_fwdt_entry_t263(struct scsi_qla_host *vha,
327f73cb695SChad Dupuis 	struct qla27xx_fwdt_entry *ent, void *buf, ulong *len)
328f73cb695SChad Dupuis {
329f8f97b0cSJoe Carnuccio 	uint type = ent->t263.queue_type;
330f73cb695SChad Dupuis 	uint count = 0;
331f73cb695SChad Dupuis 	uint i;
332f73cb695SChad Dupuis 	uint length;
333f73cb695SChad Dupuis 
334f8f97b0cSJoe Carnuccio 	ql_dbg(ql_dbg_misc + ql_dbg_verbose, vha, 0xd207,
335f8f97b0cSJoe Carnuccio 	    "%s: getq(%x) [%lx]\n", __func__, type, *len);
336f8f97b0cSJoe Carnuccio 	if (type == T263_QUEUE_TYPE_REQ) {
337f73cb695SChad Dupuis 		for (i = 0; i < vha->hw->max_req_queues; i++) {
338f73cb695SChad Dupuis 			struct req_que *req = vha->hw->req_q_map[i];
339cb43285fSQuinn Tran 
340f73cb695SChad Dupuis 			if (req || !buf) {
341f73cb695SChad Dupuis 				length = req ?
342f73cb695SChad Dupuis 				    req->length : REQUEST_ENTRY_CNT_24XX;
343f73cb695SChad Dupuis 				qla27xx_insert16(i, buf, len);
344f73cb695SChad Dupuis 				qla27xx_insert16(length, buf, len);
345f73cb695SChad Dupuis 				qla27xx_insertbuf(req ? req->ring : NULL,
346f73cb695SChad Dupuis 				    length * sizeof(*req->ring), buf, len);
347f73cb695SChad Dupuis 				count++;
348f73cb695SChad Dupuis 			}
349f73cb695SChad Dupuis 		}
350f8f97b0cSJoe Carnuccio 	} else if (type == T263_QUEUE_TYPE_RSP) {
351f73cb695SChad Dupuis 		for (i = 0; i < vha->hw->max_rsp_queues; i++) {
352f73cb695SChad Dupuis 			struct rsp_que *rsp = vha->hw->rsp_q_map[i];
353cb43285fSQuinn Tran 
354f73cb695SChad Dupuis 			if (rsp || !buf) {
355f73cb695SChad Dupuis 				length = rsp ?
356f73cb695SChad Dupuis 				    rsp->length : RESPONSE_ENTRY_CNT_MQ;
357f73cb695SChad Dupuis 				qla27xx_insert16(i, buf, len);
358f73cb695SChad Dupuis 				qla27xx_insert16(length, buf, len);
359f73cb695SChad Dupuis 				qla27xx_insertbuf(rsp ? rsp->ring : NULL,
360f73cb695SChad Dupuis 				    length * sizeof(*rsp->ring), buf, len);
361f73cb695SChad Dupuis 				count++;
362f73cb695SChad Dupuis 			}
363f73cb695SChad Dupuis 		}
3641cbb9156SHimanshu Madhani 	} else if (QLA_TGT_MODE_ENABLED() &&
3651cbb9156SHimanshu Madhani 	    ent->t263.queue_type == T263_QUEUE_TYPE_ATIO) {
3661cbb9156SHimanshu Madhani 		struct qla_hw_data *ha = vha->hw;
3671cbb9156SHimanshu Madhani 		struct atio *atr = ha->tgt.atio_ring;
3681cbb9156SHimanshu Madhani 
3691cbb9156SHimanshu Madhani 		if (atr || !buf) {
3701cbb9156SHimanshu Madhani 			length = ha->tgt.atio_q_length;
3711cbb9156SHimanshu Madhani 			qla27xx_insert16(0, buf, len);
3721cbb9156SHimanshu Madhani 			qla27xx_insert16(length, buf, len);
3731cbb9156SHimanshu Madhani 			qla27xx_insertbuf(atr, length * sizeof(*atr), buf, len);
3741cbb9156SHimanshu Madhani 			count++;
3751cbb9156SHimanshu Madhani 		}
376f73cb695SChad Dupuis 	} else {
377f73cb695SChad Dupuis 		ql_dbg(ql_dbg_misc, vha, 0xd026,
378f8f97b0cSJoe Carnuccio 		    "%s: unknown queue %x\n", __func__, type);
379f73cb695SChad Dupuis 		qla27xx_skip_entry(ent, buf);
380f73cb695SChad Dupuis 	}
381f73cb695SChad Dupuis 
382998722d1SJoe Carnuccio 	if (buf) {
383998722d1SJoe Carnuccio 		if (count)
384f73cb695SChad Dupuis 			ent->t263.num_queues = count;
385998722d1SJoe Carnuccio 		else
386998722d1SJoe Carnuccio 			qla27xx_skip_entry(ent, buf);
387998722d1SJoe Carnuccio 	}
388c0496401SJoe Carnuccio 
38964f61d99SJoe Carnuccio 	return qla27xx_next_entry(ent);
390f73cb695SChad Dupuis }
391f73cb695SChad Dupuis 
39264f61d99SJoe Carnuccio static struct qla27xx_fwdt_entry *
qla27xx_fwdt_entry_t264(struct scsi_qla_host * vha,struct qla27xx_fwdt_entry * ent,void * buf,ulong * len)393f73cb695SChad Dupuis qla27xx_fwdt_entry_t264(struct scsi_qla_host *vha,
394f73cb695SChad Dupuis 	struct qla27xx_fwdt_entry *ent, void *buf, ulong *len)
395f73cb695SChad Dupuis {
396f73cb695SChad Dupuis 	ql_dbg(ql_dbg_misc, vha, 0xd208,
397f73cb695SChad Dupuis 	    "%s: getfce [%lx]\n", __func__, *len);
398f73cb695SChad Dupuis 	if (vha->hw->fce) {
399f73cb695SChad Dupuis 		if (buf) {
400f73cb695SChad Dupuis 			ent->t264.fce_trace_size = FCE_SIZE;
401f73cb695SChad Dupuis 			ent->t264.write_pointer = vha->hw->fce_wr;
402f73cb695SChad Dupuis 			ent->t264.base_pointer = vha->hw->fce_dma;
403f73cb695SChad Dupuis 			ent->t264.fce_enable_mb0 = vha->hw->fce_mb[0];
404f73cb695SChad Dupuis 			ent->t264.fce_enable_mb2 = vha->hw->fce_mb[2];
405f73cb695SChad Dupuis 			ent->t264.fce_enable_mb3 = vha->hw->fce_mb[3];
406f73cb695SChad Dupuis 			ent->t264.fce_enable_mb4 = vha->hw->fce_mb[4];
407f73cb695SChad Dupuis 			ent->t264.fce_enable_mb5 = vha->hw->fce_mb[5];
408f73cb695SChad Dupuis 			ent->t264.fce_enable_mb6 = vha->hw->fce_mb[6];
409f73cb695SChad Dupuis 		}
410f73cb695SChad Dupuis 		qla27xx_insertbuf(vha->hw->fce, FCE_SIZE, buf, len);
411f73cb695SChad Dupuis 	} else {
412f73cb695SChad Dupuis 		ql_dbg(ql_dbg_misc, vha, 0xd027,
413f73cb695SChad Dupuis 		    "%s: missing fce\n", __func__);
414f73cb695SChad Dupuis 		qla27xx_skip_entry(ent, buf);
415f73cb695SChad Dupuis 	}
416f73cb695SChad Dupuis 
41764f61d99SJoe Carnuccio 	return qla27xx_next_entry(ent);
418f73cb695SChad Dupuis }
419f73cb695SChad Dupuis 
42064f61d99SJoe Carnuccio static struct qla27xx_fwdt_entry *
qla27xx_fwdt_entry_t265(struct scsi_qla_host * vha,struct qla27xx_fwdt_entry * ent,void * buf,ulong * len)421f73cb695SChad Dupuis qla27xx_fwdt_entry_t265(struct scsi_qla_host *vha,
422f73cb695SChad Dupuis 	struct qla27xx_fwdt_entry *ent, void *buf, ulong *len)
423f73cb695SChad Dupuis {
424ce0366dfSJoe Carnuccio 	ql_dbg(ql_dbg_misc + ql_dbg_verbose, vha, 0xd209,
425f73cb695SChad Dupuis 	    "%s: pause risc [%lx]\n", __func__, *len);
426f73cb695SChad Dupuis 	if (buf)
427ce0366dfSJoe Carnuccio 		qla24xx_pause_risc(ISPREG(vha), vha->hw);
428f73cb695SChad Dupuis 
42964f61d99SJoe Carnuccio 	return qla27xx_next_entry(ent);
430f73cb695SChad Dupuis }
431f73cb695SChad Dupuis 
43264f61d99SJoe Carnuccio static struct qla27xx_fwdt_entry *
qla27xx_fwdt_entry_t266(struct scsi_qla_host * vha,struct qla27xx_fwdt_entry * ent,void * buf,ulong * len)433f73cb695SChad Dupuis qla27xx_fwdt_entry_t266(struct scsi_qla_host *vha,
434f73cb695SChad Dupuis 	struct qla27xx_fwdt_entry *ent, void *buf, ulong *len)
435f73cb695SChad Dupuis {
436f73cb695SChad Dupuis 	ql_dbg(ql_dbg_misc, vha, 0xd20a,
437f73cb695SChad Dupuis 	    "%s: reset risc [%lx]\n", __func__, *len);
438*e35920abSQuinn Tran 	if (buf) {
439*e35920abSQuinn Tran 		if (qla24xx_soft_reset(vha->hw) != QLA_SUCCESS) {
440*e35920abSQuinn Tran 			ql_dbg(ql_dbg_async, vha, 0x5001,
441*e35920abSQuinn Tran 			    "%s: unable to soft reset\n", __func__);
442*e35920abSQuinn Tran 			return INVALID_ENTRY;
443*e35920abSQuinn Tran 		}
444*e35920abSQuinn Tran 	}
445f73cb695SChad Dupuis 
44664f61d99SJoe Carnuccio 	return qla27xx_next_entry(ent);
447f73cb695SChad Dupuis }
448f73cb695SChad Dupuis 
44964f61d99SJoe Carnuccio static struct qla27xx_fwdt_entry *
qla27xx_fwdt_entry_t267(struct scsi_qla_host * vha,struct qla27xx_fwdt_entry * ent,void * buf,ulong * len)450f73cb695SChad Dupuis qla27xx_fwdt_entry_t267(struct scsi_qla_host *vha,
451f73cb695SChad Dupuis 	struct qla27xx_fwdt_entry *ent, void *buf, ulong *len)
452f73cb695SChad Dupuis {
453f8f97b0cSJoe Carnuccio 	uint offset = ent->t267.pci_offset;
454f8f97b0cSJoe Carnuccio 	ulong data = le32_to_cpu(ent->t267.data);
455f73cb695SChad Dupuis 
456f73cb695SChad Dupuis 	ql_dbg(ql_dbg_misc, vha, 0xd20b,
457f73cb695SChad Dupuis 	    "%s: dis intr [%lx]\n", __func__, *len);
458ce0366dfSJoe Carnuccio 	qla27xx_write_reg(ISPREG(vha), offset, data, buf);
459f73cb695SChad Dupuis 
46064f61d99SJoe Carnuccio 	return qla27xx_next_entry(ent);
461f73cb695SChad Dupuis }
462f73cb695SChad Dupuis 
46364f61d99SJoe Carnuccio static struct qla27xx_fwdt_entry *
qla27xx_fwdt_entry_t268(struct scsi_qla_host * vha,struct qla27xx_fwdt_entry * ent,void * buf,ulong * len)464f73cb695SChad Dupuis qla27xx_fwdt_entry_t268(struct scsi_qla_host *vha,
465f73cb695SChad Dupuis 	struct qla27xx_fwdt_entry *ent, void *buf, ulong *len)
466f73cb695SChad Dupuis {
467f73cb695SChad Dupuis 	ql_dbg(ql_dbg_misc, vha, 0xd20c,
468f73cb695SChad Dupuis 	    "%s: gethb(%x) [%lx]\n", __func__, ent->t268.buf_type, *len);
469ad0a0b01SQuinn Tran 	switch (ent->t268.buf_type) {
470ad0a0b01SQuinn Tran 	case T268_BUF_TYPE_EXTD_TRACE:
471f73cb695SChad Dupuis 		if (vha->hw->eft) {
472f73cb695SChad Dupuis 			if (buf) {
473f73cb695SChad Dupuis 				ent->t268.buf_size = EFT_SIZE;
474f73cb695SChad Dupuis 				ent->t268.start_addr = vha->hw->eft_dma;
475f73cb695SChad Dupuis 			}
476f73cb695SChad Dupuis 			qla27xx_insertbuf(vha->hw->eft, EFT_SIZE, buf, len);
477f73cb695SChad Dupuis 		} else {
478f73cb695SChad Dupuis 			ql_dbg(ql_dbg_misc, vha, 0xd028,
479f73cb695SChad Dupuis 			    "%s: missing eft\n", __func__);
480f73cb695SChad Dupuis 			qla27xx_skip_entry(ent, buf);
481f73cb695SChad Dupuis 		}
482ad0a0b01SQuinn Tran 		break;
483ad0a0b01SQuinn Tran 	case T268_BUF_TYPE_EXCH_BUFOFF:
484ad0a0b01SQuinn Tran 		if (vha->hw->exchoffld_buf) {
485ad0a0b01SQuinn Tran 			if (buf) {
486ad0a0b01SQuinn Tran 				ent->t268.buf_size = vha->hw->exchoffld_size;
487ad0a0b01SQuinn Tran 				ent->t268.start_addr =
488ad0a0b01SQuinn Tran 					vha->hw->exchoffld_buf_dma;
489ad0a0b01SQuinn Tran 			}
490ad0a0b01SQuinn Tran 			qla27xx_insertbuf(vha->hw->exchoffld_buf,
491ad0a0b01SQuinn Tran 			    vha->hw->exchoffld_size, buf, len);
492f73cb695SChad Dupuis 		} else {
493ad0a0b01SQuinn Tran 			ql_dbg(ql_dbg_misc, vha, 0xd028,
494ad0a0b01SQuinn Tran 			    "%s: missing exch offld\n", __func__);
495ad0a0b01SQuinn Tran 			qla27xx_skip_entry(ent, buf);
496ad0a0b01SQuinn Tran 		}
497ad0a0b01SQuinn Tran 		break;
498ad0a0b01SQuinn Tran 	case T268_BUF_TYPE_EXTD_LOGIN:
499ad0a0b01SQuinn Tran 		if (vha->hw->exlogin_buf) {
500ad0a0b01SQuinn Tran 			if (buf) {
501ad0a0b01SQuinn Tran 				ent->t268.buf_size = vha->hw->exlogin_size;
502ad0a0b01SQuinn Tran 				ent->t268.start_addr =
503ad0a0b01SQuinn Tran 					vha->hw->exlogin_buf_dma;
504ad0a0b01SQuinn Tran 			}
505ad0a0b01SQuinn Tran 			qla27xx_insertbuf(vha->hw->exlogin_buf,
506ad0a0b01SQuinn Tran 			    vha->hw->exlogin_size, buf, len);
507ad0a0b01SQuinn Tran 		} else {
508ad0a0b01SQuinn Tran 			ql_dbg(ql_dbg_misc, vha, 0xd028,
509ad0a0b01SQuinn Tran 			    "%s: missing ext login\n", __func__);
510ad0a0b01SQuinn Tran 			qla27xx_skip_entry(ent, buf);
511ad0a0b01SQuinn Tran 		}
512ad0a0b01SQuinn Tran 		break;
513ad0a0b01SQuinn Tran 
5143f915271SQuinn Tran 	case T268_BUF_TYPE_REQ_MIRROR:
5153f915271SQuinn Tran 	case T268_BUF_TYPE_RSP_MIRROR:
5163f915271SQuinn Tran 		/*
5173f915271SQuinn Tran 		 * Mirror pointers are not implemented in the
5183f915271SQuinn Tran 		 * driver, instead shadow pointers are used by
5193f915271SQuinn Tran 		 * the drier. Skip these entries.
5203f915271SQuinn Tran 		 */
5213f915271SQuinn Tran 		qla27xx_skip_entry(ent, buf);
5223f915271SQuinn Tran 		break;
523ad0a0b01SQuinn Tran 	default:
524ad0a0b01SQuinn Tran 		ql_dbg(ql_dbg_async, vha, 0xd02b,
525349c390fSJoe Carnuccio 		    "%s: unknown buffer %x\n", __func__, ent->t268.buf_type);
526f73cb695SChad Dupuis 		qla27xx_skip_entry(ent, buf);
527ad0a0b01SQuinn Tran 		break;
528f73cb695SChad Dupuis 	}
529f73cb695SChad Dupuis 
53064f61d99SJoe Carnuccio 	return qla27xx_next_entry(ent);
531f73cb695SChad Dupuis }
532f73cb695SChad Dupuis 
53364f61d99SJoe Carnuccio static struct qla27xx_fwdt_entry *
qla27xx_fwdt_entry_t269(struct scsi_qla_host * vha,struct qla27xx_fwdt_entry * ent,void * buf,ulong * len)534f73cb695SChad Dupuis qla27xx_fwdt_entry_t269(struct scsi_qla_host *vha,
535f73cb695SChad Dupuis 	struct qla27xx_fwdt_entry *ent, void *buf, ulong *len)
536f73cb695SChad Dupuis {
537f73cb695SChad Dupuis 	ql_dbg(ql_dbg_misc, vha, 0xd20d,
538f73cb695SChad Dupuis 	    "%s: scratch [%lx]\n", __func__, *len);
539f73cb695SChad Dupuis 	qla27xx_insert32(0xaaaaaaaa, buf, len);
540f73cb695SChad Dupuis 	qla27xx_insert32(0xbbbbbbbb, buf, len);
541f73cb695SChad Dupuis 	qla27xx_insert32(0xcccccccc, buf, len);
542f73cb695SChad Dupuis 	qla27xx_insert32(0xdddddddd, buf, len);
543f73cb695SChad Dupuis 	qla27xx_insert32(*len + sizeof(uint32_t), buf, len);
544f73cb695SChad Dupuis 	if (buf)
545f73cb695SChad Dupuis 		ent->t269.scratch_size = 5 * sizeof(uint32_t);
546f73cb695SChad Dupuis 
54764f61d99SJoe Carnuccio 	return qla27xx_next_entry(ent);
548f73cb695SChad Dupuis }
549f73cb695SChad Dupuis 
55064f61d99SJoe Carnuccio static struct qla27xx_fwdt_entry *
qla27xx_fwdt_entry_t270(struct scsi_qla_host * vha,struct qla27xx_fwdt_entry * ent,void * buf,ulong * len)551f73cb695SChad Dupuis qla27xx_fwdt_entry_t270(struct scsi_qla_host *vha,
552f73cb695SChad Dupuis 	struct qla27xx_fwdt_entry *ent, void *buf, ulong *len)
553f73cb695SChad Dupuis {
554f8f97b0cSJoe Carnuccio 	ulong addr = le32_to_cpu(ent->t270.addr);
555f8f97b0cSJoe Carnuccio 	ulong dwords = le32_to_cpu(ent->t270.count);
556f73cb695SChad Dupuis 
557f73cb695SChad Dupuis 	ql_dbg(ql_dbg_misc, vha, 0xd20e,
558f73cb695SChad Dupuis 	    "%s: rdremreg [%lx]\n", __func__, *len);
559ce0366dfSJoe Carnuccio 	qla27xx_write_reg(ISPREG(vha), IOBASE_ADDR, 0x40, buf);
560f73cb695SChad Dupuis 	while (dwords--) {
561ce0366dfSJoe Carnuccio 		qla27xx_write_reg(ISPREG(vha), 0xc0, addr|0x80000000, buf);
562f73cb695SChad Dupuis 		qla27xx_insert32(addr, buf, len);
563ce0366dfSJoe Carnuccio 		qla27xx_read_reg(ISPREG(vha), 0xc4, buf, len);
564fbce4f49SJoe Carnuccio 		addr += sizeof(uint32_t);
565f73cb695SChad Dupuis 	}
566f73cb695SChad Dupuis 
56764f61d99SJoe Carnuccio 	return qla27xx_next_entry(ent);
568f73cb695SChad Dupuis }
569f73cb695SChad Dupuis 
57064f61d99SJoe Carnuccio static struct qla27xx_fwdt_entry *
qla27xx_fwdt_entry_t271(struct scsi_qla_host * vha,struct qla27xx_fwdt_entry * ent,void * buf,ulong * len)571f73cb695SChad Dupuis qla27xx_fwdt_entry_t271(struct scsi_qla_host *vha,
572f73cb695SChad Dupuis 	struct qla27xx_fwdt_entry *ent, void *buf, ulong *len)
573f73cb695SChad Dupuis {
574f8f97b0cSJoe Carnuccio 	ulong addr = le32_to_cpu(ent->t271.addr);
575f8f97b0cSJoe Carnuccio 	ulong data = le32_to_cpu(ent->t271.data);
576f73cb695SChad Dupuis 
577f73cb695SChad Dupuis 	ql_dbg(ql_dbg_misc, vha, 0xd20f,
578f73cb695SChad Dupuis 	    "%s: wrremreg [%lx]\n", __func__, *len);
579ce0366dfSJoe Carnuccio 	qla27xx_write_reg(ISPREG(vha), IOBASE(vha), 0x40, buf);
580ce0366dfSJoe Carnuccio 	qla27xx_write_reg(ISPREG(vha), 0xc4, data, buf);
581ce0366dfSJoe Carnuccio 	qla27xx_write_reg(ISPREG(vha), 0xc0, addr, buf);
582f73cb695SChad Dupuis 
58364f61d99SJoe Carnuccio 	return qla27xx_next_entry(ent);
584f73cb695SChad Dupuis }
585f73cb695SChad Dupuis 
58664f61d99SJoe Carnuccio static struct qla27xx_fwdt_entry *
qla27xx_fwdt_entry_t272(struct scsi_qla_host * vha,struct qla27xx_fwdt_entry * ent,void * buf,ulong * len)587f73cb695SChad Dupuis qla27xx_fwdt_entry_t272(struct scsi_qla_host *vha,
588f73cb695SChad Dupuis 	struct qla27xx_fwdt_entry *ent, void *buf, ulong *len)
589f73cb695SChad Dupuis {
590f8f97b0cSJoe Carnuccio 	ulong dwords = le32_to_cpu(ent->t272.count);
591f8f97b0cSJoe Carnuccio 	ulong start = le32_to_cpu(ent->t272.addr);
592f73cb695SChad Dupuis 
593f73cb695SChad Dupuis 	ql_dbg(ql_dbg_misc, vha, 0xd210,
594f73cb695SChad Dupuis 	    "%s: rdremram [%lx]\n", __func__, *len);
595f73cb695SChad Dupuis 	if (buf) {
596f73cb695SChad Dupuis 		ql_dbg(ql_dbg_misc, vha, 0xd02c,
597f73cb695SChad Dupuis 		    "%s: @%lx -> (%lx dwords)\n", __func__, start, dwords);
598f73cb695SChad Dupuis 		buf += *len;
599f73cb695SChad Dupuis 		qla27xx_dump_mpi_ram(vha->hw, start, buf, dwords, &buf);
600f73cb695SChad Dupuis 	}
601f73cb695SChad Dupuis 	*len += dwords * sizeof(uint32_t);
602f73cb695SChad Dupuis 
60364f61d99SJoe Carnuccio 	return qla27xx_next_entry(ent);
604f73cb695SChad Dupuis }
605f73cb695SChad Dupuis 
60664f61d99SJoe Carnuccio static struct qla27xx_fwdt_entry *
qla27xx_fwdt_entry_t273(struct scsi_qla_host * vha,struct qla27xx_fwdt_entry * ent,void * buf,ulong * len)607f73cb695SChad Dupuis qla27xx_fwdt_entry_t273(struct scsi_qla_host *vha,
608f73cb695SChad Dupuis 	struct qla27xx_fwdt_entry *ent, void *buf, ulong *len)
609f73cb695SChad Dupuis {
610f8f97b0cSJoe Carnuccio 	ulong dwords = le32_to_cpu(ent->t273.count);
611f8f97b0cSJoe Carnuccio 	ulong addr = le32_to_cpu(ent->t273.addr);
612f73cb695SChad Dupuis 	uint32_t value;
613f73cb695SChad Dupuis 
614f73cb695SChad Dupuis 	ql_dbg(ql_dbg_misc, vha, 0xd211,
615f73cb695SChad Dupuis 	    "%s: pcicfg [%lx]\n", __func__, *len);
616f73cb695SChad Dupuis 	while (dwords--) {
617f73cb695SChad Dupuis 		value = ~0;
618f73cb695SChad Dupuis 		if (pci_read_config_dword(vha->hw->pdev, addr, &value))
619f73cb695SChad Dupuis 			ql_dbg(ql_dbg_misc, vha, 0xd02d,
620f73cb695SChad Dupuis 			    "%s: failed pcicfg read at %lx\n", __func__, addr);
621f73cb695SChad Dupuis 		qla27xx_insert32(addr, buf, len);
622f73cb695SChad Dupuis 		qla27xx_insert32(value, buf, len);
623c0496401SJoe Carnuccio 		addr += sizeof(uint32_t);
624f73cb695SChad Dupuis 	}
625f73cb695SChad Dupuis 
62664f61d99SJoe Carnuccio 	return qla27xx_next_entry(ent);
627f73cb695SChad Dupuis }
628f73cb695SChad Dupuis 
62964f61d99SJoe Carnuccio static struct qla27xx_fwdt_entry *
qla27xx_fwdt_entry_t274(struct scsi_qla_host * vha,struct qla27xx_fwdt_entry * ent,void * buf,ulong * len)630c0496401SJoe Carnuccio qla27xx_fwdt_entry_t274(struct scsi_qla_host *vha,
631c0496401SJoe Carnuccio 	struct qla27xx_fwdt_entry *ent, void *buf, ulong *len)
632c0496401SJoe Carnuccio {
633f8f97b0cSJoe Carnuccio 	ulong type = ent->t274.queue_type;
634c0496401SJoe Carnuccio 	uint count = 0;
635c0496401SJoe Carnuccio 	uint i;
636c0496401SJoe Carnuccio 
637f8f97b0cSJoe Carnuccio 	ql_dbg(ql_dbg_misc + ql_dbg_verbose, vha, 0xd212,
638f8f97b0cSJoe Carnuccio 	    "%s: getqsh(%lx) [%lx]\n", __func__, type, *len);
639f8f97b0cSJoe Carnuccio 	if (type == T274_QUEUE_TYPE_REQ_SHAD) {
640c0496401SJoe Carnuccio 		for (i = 0; i < vha->hw->max_req_queues; i++) {
641c0496401SJoe Carnuccio 			struct req_que *req = vha->hw->req_q_map[i];
642cb43285fSQuinn Tran 
643c0496401SJoe Carnuccio 			if (req || !buf) {
644c0496401SJoe Carnuccio 				qla27xx_insert16(i, buf, len);
645c0496401SJoe Carnuccio 				qla27xx_insert16(1, buf, len);
6467c6300e3SJoe Carnuccio 				qla27xx_insert32(req && req->out_ptr ?
6477c6300e3SJoe Carnuccio 				    *req->out_ptr : 0, buf, len);
648c0496401SJoe Carnuccio 				count++;
649c0496401SJoe Carnuccio 			}
650c0496401SJoe Carnuccio 		}
651f8f97b0cSJoe Carnuccio 	} else if (type == T274_QUEUE_TYPE_RSP_SHAD) {
652c0496401SJoe Carnuccio 		for (i = 0; i < vha->hw->max_rsp_queues; i++) {
653c0496401SJoe Carnuccio 			struct rsp_que *rsp = vha->hw->rsp_q_map[i];
654cb43285fSQuinn Tran 
655c0496401SJoe Carnuccio 			if (rsp || !buf) {
656c0496401SJoe Carnuccio 				qla27xx_insert16(i, buf, len);
657c0496401SJoe Carnuccio 				qla27xx_insert16(1, buf, len);
6587c6300e3SJoe Carnuccio 				qla27xx_insert32(rsp && rsp->in_ptr ?
6597c6300e3SJoe Carnuccio 				    *rsp->in_ptr : 0, buf, len);
660c0496401SJoe Carnuccio 				count++;
661c0496401SJoe Carnuccio 			}
662c0496401SJoe Carnuccio 		}
6631cbb9156SHimanshu Madhani 	} else if (QLA_TGT_MODE_ENABLED() &&
6641cbb9156SHimanshu Madhani 	    ent->t274.queue_type == T274_QUEUE_TYPE_ATIO_SHAD) {
6651cbb9156SHimanshu Madhani 		struct qla_hw_data *ha = vha->hw;
6661cbb9156SHimanshu Madhani 		struct atio *atr = ha->tgt.atio_ring_ptr;
6671cbb9156SHimanshu Madhani 
6681cbb9156SHimanshu Madhani 		if (atr || !buf) {
6691cbb9156SHimanshu Madhani 			qla27xx_insert16(0, buf, len);
6701cbb9156SHimanshu Madhani 			qla27xx_insert16(1, buf, len);
6711cbb9156SHimanshu Madhani 			qla27xx_insert32(ha->tgt.atio_q_in ?
6721cbb9156SHimanshu Madhani 			    readl(ha->tgt.atio_q_in) : 0, buf, len);
6731cbb9156SHimanshu Madhani 			count++;
6741cbb9156SHimanshu Madhani 		}
675c0496401SJoe Carnuccio 	} else {
676c0496401SJoe Carnuccio 		ql_dbg(ql_dbg_misc, vha, 0xd02f,
677f8f97b0cSJoe Carnuccio 		    "%s: unknown queue %lx\n", __func__, type);
678c0496401SJoe Carnuccio 		qla27xx_skip_entry(ent, buf);
679c0496401SJoe Carnuccio 	}
680c0496401SJoe Carnuccio 
681998722d1SJoe Carnuccio 	if (buf) {
682998722d1SJoe Carnuccio 		if (count)
683c0496401SJoe Carnuccio 			ent->t274.num_queues = count;
684998722d1SJoe Carnuccio 		else
685c0496401SJoe Carnuccio 			qla27xx_skip_entry(ent, buf);
686998722d1SJoe Carnuccio 	}
687c0496401SJoe Carnuccio 
68864f61d99SJoe Carnuccio 	return qla27xx_next_entry(ent);
689c0496401SJoe Carnuccio }
690c0496401SJoe Carnuccio 
69164f61d99SJoe Carnuccio static struct qla27xx_fwdt_entry *
qla27xx_fwdt_entry_t275(struct scsi_qla_host * vha,struct qla27xx_fwdt_entry * ent,void * buf,ulong * len)6922ac224bcSJoe Carnuccio qla27xx_fwdt_entry_t275(struct scsi_qla_host *vha,
6932ac224bcSJoe Carnuccio 	struct qla27xx_fwdt_entry *ent, void *buf, ulong *len)
6942ac224bcSJoe Carnuccio {
6952ac224bcSJoe Carnuccio 	ulong offset = offsetof(typeof(*ent), t275.buffer);
696f8f97b0cSJoe Carnuccio 	ulong length = le32_to_cpu(ent->t275.length);
697f8f97b0cSJoe Carnuccio 	ulong size = le32_to_cpu(ent->hdr.size);
698f8f97b0cSJoe Carnuccio 	void *buffer = ent->t275.buffer;
6992ac224bcSJoe Carnuccio 
700f8f97b0cSJoe Carnuccio 	ql_dbg(ql_dbg_misc + ql_dbg_verbose, vha, 0xd213,
701f8f97b0cSJoe Carnuccio 	    "%s: buffer(%lx) [%lx]\n", __func__, length, *len);
702f8f97b0cSJoe Carnuccio 	if (!length) {
7032ac224bcSJoe Carnuccio 		ql_dbg(ql_dbg_misc, vha, 0xd020,
7042ac224bcSJoe Carnuccio 		    "%s: buffer zero length\n", __func__);
7052ac224bcSJoe Carnuccio 		qla27xx_skip_entry(ent, buf);
7062ac224bcSJoe Carnuccio 		goto done;
7072ac224bcSJoe Carnuccio 	}
708f8f97b0cSJoe Carnuccio 	if (offset + length > size) {
7092ff01671SJoe Carnuccio 		length = size - offset;
7102ac224bcSJoe Carnuccio 		ql_dbg(ql_dbg_misc, vha, 0xd030,
7112ff01671SJoe Carnuccio 		    "%s: buffer overflow, truncate [%lx]\n", __func__, length);
7122ff01671SJoe Carnuccio 		ent->t275.length = cpu_to_le32(length);
7132ac224bcSJoe Carnuccio 	}
7142ac224bcSJoe Carnuccio 
715f8f97b0cSJoe Carnuccio 	qla27xx_insertbuf(buffer, length, buf, len);
7162ac224bcSJoe Carnuccio done:
71764f61d99SJoe Carnuccio 	return qla27xx_next_entry(ent);
7182ac224bcSJoe Carnuccio }
7192ac224bcSJoe Carnuccio 
72064f61d99SJoe Carnuccio static struct qla27xx_fwdt_entry *
qla27xx_fwdt_entry_t276(struct scsi_qla_host * vha,struct qla27xx_fwdt_entry * ent,void * buf,ulong * len)72164f61d99SJoe Carnuccio qla27xx_fwdt_entry_t276(struct scsi_qla_host *vha,
72264f61d99SJoe Carnuccio     struct qla27xx_fwdt_entry *ent, void *buf, ulong *len)
72364f61d99SJoe Carnuccio {
7242ff01671SJoe Carnuccio 	ql_dbg(ql_dbg_misc + ql_dbg_verbose, vha, 0xd214,
7252ff01671SJoe Carnuccio 	    "%s: cond [%lx]\n", __func__, *len);
7262ff01671SJoe Carnuccio 
7272ff01671SJoe Carnuccio 	if (buf) {
728f8f97b0cSJoe Carnuccio 		ulong cond1 = le32_to_cpu(ent->t276.cond1);
729f8f97b0cSJoe Carnuccio 		ulong cond2 = le32_to_cpu(ent->t276.cond2);
73064f61d99SJoe Carnuccio 		uint type = vha->hw->pdev->device >> 4 & 0xf;
73164f61d99SJoe Carnuccio 		uint func = vha->hw->port_no & 0x3;
73264f61d99SJoe Carnuccio 
733f8f97b0cSJoe Carnuccio 		if (type != cond1 || func != cond2) {
7342ff01671SJoe Carnuccio 			struct qla27xx_fwdt_template *tmp = buf;
7352ff01671SJoe Carnuccio 
7362ff01671SJoe Carnuccio 			tmp->count--;
73764f61d99SJoe Carnuccio 			ent = qla27xx_next_entry(ent);
73864f61d99SJoe Carnuccio 			qla27xx_skip_entry(ent, buf);
73964f61d99SJoe Carnuccio 		}
7402ff01671SJoe Carnuccio 	}
74164f61d99SJoe Carnuccio 
74264f61d99SJoe Carnuccio 	return qla27xx_next_entry(ent);
74364f61d99SJoe Carnuccio }
74464f61d99SJoe Carnuccio 
74564f61d99SJoe Carnuccio static struct qla27xx_fwdt_entry *
qla27xx_fwdt_entry_t277(struct scsi_qla_host * vha,struct qla27xx_fwdt_entry * ent,void * buf,ulong * len)74664f61d99SJoe Carnuccio qla27xx_fwdt_entry_t277(struct scsi_qla_host *vha,
74764f61d99SJoe Carnuccio     struct qla27xx_fwdt_entry *ent, void *buf, ulong *len)
74864f61d99SJoe Carnuccio {
749f8f97b0cSJoe Carnuccio 	ulong cmd_addr = le32_to_cpu(ent->t277.cmd_addr);
750f8f97b0cSJoe Carnuccio 	ulong wr_cmd_data = le32_to_cpu(ent->t277.wr_cmd_data);
751f8f97b0cSJoe Carnuccio 	ulong data_addr = le32_to_cpu(ent->t277.data_addr);
75264f61d99SJoe Carnuccio 
75364f61d99SJoe Carnuccio 	ql_dbg(ql_dbg_misc + ql_dbg_verbose, vha, 0xd215,
75464f61d99SJoe Carnuccio 	    "%s: rdpep [%lx]\n", __func__, *len);
755f8f97b0cSJoe Carnuccio 	qla27xx_insert32(wr_cmd_data, buf, len);
756ce0366dfSJoe Carnuccio 	qla27xx_write_reg(ISPREG(vha), cmd_addr, wr_cmd_data, buf);
757ce0366dfSJoe Carnuccio 	qla27xx_read_reg(ISPREG(vha), data_addr, buf, len);
75864f61d99SJoe Carnuccio 
75964f61d99SJoe Carnuccio 	return qla27xx_next_entry(ent);
76064f61d99SJoe Carnuccio }
76164f61d99SJoe Carnuccio 
76264f61d99SJoe Carnuccio static struct qla27xx_fwdt_entry *
qla27xx_fwdt_entry_t278(struct scsi_qla_host * vha,struct qla27xx_fwdt_entry * ent,void * buf,ulong * len)76364f61d99SJoe Carnuccio qla27xx_fwdt_entry_t278(struct scsi_qla_host *vha,
76464f61d99SJoe Carnuccio     struct qla27xx_fwdt_entry *ent, void *buf, ulong *len)
76564f61d99SJoe Carnuccio {
766f8f97b0cSJoe Carnuccio 	ulong cmd_addr = le32_to_cpu(ent->t278.cmd_addr);
767f8f97b0cSJoe Carnuccio 	ulong wr_cmd_data = le32_to_cpu(ent->t278.wr_cmd_data);
768f8f97b0cSJoe Carnuccio 	ulong data_addr = le32_to_cpu(ent->t278.data_addr);
769f8f97b0cSJoe Carnuccio 	ulong wr_data = le32_to_cpu(ent->t278.wr_data);
77064f61d99SJoe Carnuccio 
77164f61d99SJoe Carnuccio 	ql_dbg(ql_dbg_misc + ql_dbg_verbose, vha, 0xd216,
77264f61d99SJoe Carnuccio 	    "%s: wrpep [%lx]\n", __func__, *len);
773ce0366dfSJoe Carnuccio 	qla27xx_write_reg(ISPREG(vha), data_addr, wr_data, buf);
774ce0366dfSJoe Carnuccio 	qla27xx_write_reg(ISPREG(vha), cmd_addr, wr_cmd_data, buf);
77564f61d99SJoe Carnuccio 
77664f61d99SJoe Carnuccio 	return qla27xx_next_entry(ent);
77764f61d99SJoe Carnuccio }
77864f61d99SJoe Carnuccio 
77964f61d99SJoe Carnuccio static struct qla27xx_fwdt_entry *
qla27xx_fwdt_entry_other(struct scsi_qla_host * vha,struct qla27xx_fwdt_entry * ent,void * buf,ulong * len)780f73cb695SChad Dupuis qla27xx_fwdt_entry_other(struct scsi_qla_host *vha,
781f73cb695SChad Dupuis 	struct qla27xx_fwdt_entry *ent, void *buf, ulong *len)
782f73cb695SChad Dupuis {
783f8f97b0cSJoe Carnuccio 	ulong type = le32_to_cpu(ent->hdr.type);
784f8f97b0cSJoe Carnuccio 
785f73cb695SChad Dupuis 	ql_dbg(ql_dbg_misc, vha, 0xd2ff,
786f8f97b0cSJoe Carnuccio 	    "%s: other %lx [%lx]\n", __func__, type, *len);
787f73cb695SChad Dupuis 	qla27xx_skip_entry(ent, buf);
788f73cb695SChad Dupuis 
78964f61d99SJoe Carnuccio 	return qla27xx_next_entry(ent);
790f73cb695SChad Dupuis }
791f73cb695SChad Dupuis 
79264f61d99SJoe Carnuccio static struct {
793aa2dc372SJoe Carnuccio 	uint type;
79464f61d99SJoe Carnuccio 	typeof(qla27xx_fwdt_entry_other)(*call);
79564f61d99SJoe Carnuccio } qla27xx_fwdt_entry_call[] = {
796f73cb695SChad Dupuis 	{ ENTRY_TYPE_NOP,		qla27xx_fwdt_entry_t0    },
797f73cb695SChad Dupuis 	{ ENTRY_TYPE_TMP_END,		qla27xx_fwdt_entry_t255  },
798f73cb695SChad Dupuis 	{ ENTRY_TYPE_RD_IOB_T1,		qla27xx_fwdt_entry_t256  },
799f73cb695SChad Dupuis 	{ ENTRY_TYPE_WR_IOB_T1,		qla27xx_fwdt_entry_t257  },
800f73cb695SChad Dupuis 	{ ENTRY_TYPE_RD_IOB_T2,		qla27xx_fwdt_entry_t258  },
801f73cb695SChad Dupuis 	{ ENTRY_TYPE_WR_IOB_T2,		qla27xx_fwdt_entry_t259  },
802f73cb695SChad Dupuis 	{ ENTRY_TYPE_RD_PCI,		qla27xx_fwdt_entry_t260  },
803f73cb695SChad Dupuis 	{ ENTRY_TYPE_WR_PCI,		qla27xx_fwdt_entry_t261  },
804f73cb695SChad Dupuis 	{ ENTRY_TYPE_RD_RAM,		qla27xx_fwdt_entry_t262  },
805f73cb695SChad Dupuis 	{ ENTRY_TYPE_GET_QUEUE,		qla27xx_fwdt_entry_t263  },
806f73cb695SChad Dupuis 	{ ENTRY_TYPE_GET_FCE,		qla27xx_fwdt_entry_t264  },
807f73cb695SChad Dupuis 	{ ENTRY_TYPE_PSE_RISC,		qla27xx_fwdt_entry_t265  },
808f73cb695SChad Dupuis 	{ ENTRY_TYPE_RST_RISC,		qla27xx_fwdt_entry_t266  },
809f73cb695SChad Dupuis 	{ ENTRY_TYPE_DIS_INTR,		qla27xx_fwdt_entry_t267  },
810f73cb695SChad Dupuis 	{ ENTRY_TYPE_GET_HBUF,		qla27xx_fwdt_entry_t268  },
811f73cb695SChad Dupuis 	{ ENTRY_TYPE_SCRATCH,		qla27xx_fwdt_entry_t269  },
812f73cb695SChad Dupuis 	{ ENTRY_TYPE_RDREMREG,		qla27xx_fwdt_entry_t270  },
813f73cb695SChad Dupuis 	{ ENTRY_TYPE_WRREMREG,		qla27xx_fwdt_entry_t271  },
814f73cb695SChad Dupuis 	{ ENTRY_TYPE_RDREMRAM,		qla27xx_fwdt_entry_t272  },
815f73cb695SChad Dupuis 	{ ENTRY_TYPE_PCICFG,		qla27xx_fwdt_entry_t273  },
816c0496401SJoe Carnuccio 	{ ENTRY_TYPE_GET_SHADOW,	qla27xx_fwdt_entry_t274  },
8172ac224bcSJoe Carnuccio 	{ ENTRY_TYPE_WRITE_BUF,		qla27xx_fwdt_entry_t275  },
81864f61d99SJoe Carnuccio 	{ ENTRY_TYPE_CONDITIONAL,	qla27xx_fwdt_entry_t276  },
81964f61d99SJoe Carnuccio 	{ ENTRY_TYPE_RDPEPREG,		qla27xx_fwdt_entry_t277  },
82064f61d99SJoe Carnuccio 	{ ENTRY_TYPE_WRPEPREG,		qla27xx_fwdt_entry_t278  },
821f73cb695SChad Dupuis 	{ -1,				qla27xx_fwdt_entry_other }
822f73cb695SChad Dupuis };
823f73cb695SChad Dupuis 
82464f61d99SJoe Carnuccio static inline
qla27xx_find_entry(uint type)82564f61d99SJoe Carnuccio typeof(qla27xx_fwdt_entry_call->call)(qla27xx_find_entry(uint type))
826f73cb695SChad Dupuis {
82764f61d99SJoe Carnuccio 	typeof(*qla27xx_fwdt_entry_call) *list = qla27xx_fwdt_entry_call;
828f73cb695SChad Dupuis 
829aa2dc372SJoe Carnuccio 	while (list->type < type)
830f73cb695SChad Dupuis 		list++;
831f73cb695SChad Dupuis 
832aa2dc372SJoe Carnuccio 	if (list->type == type)
833f73cb695SChad Dupuis 		return list->call;
834aa2dc372SJoe Carnuccio 	return qla27xx_fwdt_entry_other;
835f73cb695SChad Dupuis }
836f73cb695SChad Dupuis 
837f73cb695SChad Dupuis static void
qla27xx_walk_template(struct scsi_qla_host * vha,struct qla27xx_fwdt_template * tmp,void * buf,ulong * len)838f73cb695SChad Dupuis qla27xx_walk_template(struct scsi_qla_host *vha,
839f73cb695SChad Dupuis 	struct qla27xx_fwdt_template *tmp, void *buf, ulong *len)
840f73cb695SChad Dupuis {
841f8f97b0cSJoe Carnuccio 	struct qla27xx_fwdt_entry *ent = (void *)tmp +
842f8f97b0cSJoe Carnuccio 	    le32_to_cpu(tmp->entry_offset);
8432ff01671SJoe Carnuccio 	ulong type;
844f73cb695SChad Dupuis 
8452ff01671SJoe Carnuccio 	tmp->count = le32_to_cpu(tmp->entry_count);
846f73cb695SChad Dupuis 	ql_dbg(ql_dbg_misc, vha, 0xd01a,
8472ff01671SJoe Carnuccio 	    "%s: entry count %u\n", __func__, tmp->count);
8482ff01671SJoe Carnuccio 	while (ent && tmp->count--) {
849f8f97b0cSJoe Carnuccio 		type = le32_to_cpu(ent->hdr.type);
850f8f97b0cSJoe Carnuccio 		ent = qla27xx_find_entry(type)(vha, ent, buf, len);
85164f61d99SJoe Carnuccio 		if (!ent)
852383a298bSJoe Carnuccio 			break;
853c5547419SQuinn Tran 
854c5547419SQuinn Tran 		if (ent == INVALID_ENTRY) {
855c5547419SQuinn Tran 			*len = 0;
856c5547419SQuinn Tran 			ql_dbg(ql_dbg_async, vha, 0xffff,
857c5547419SQuinn Tran 			    "Unable to capture FW dump");
858c5547419SQuinn Tran 			goto bailout;
859c5547419SQuinn Tran 		}
860f73cb695SChad Dupuis 	}
861299f5e27SJoe Carnuccio 
8622ff01671SJoe Carnuccio 	if (tmp->count)
863299f5e27SJoe Carnuccio 		ql_dbg(ql_dbg_misc, vha, 0xd018,
8642ff01671SJoe Carnuccio 		    "%s: entry count residual=+%u\n", __func__, tmp->count);
865299f5e27SJoe Carnuccio 
86664f61d99SJoe Carnuccio 	if (ent)
867299f5e27SJoe Carnuccio 		ql_dbg(ql_dbg_misc, vha, 0xd019,
868a28d9e4eSJoe Carnuccio 		    "%s: missing end entry\n", __func__);
869c5547419SQuinn Tran 
870c5547419SQuinn Tran bailout:
871c5547419SQuinn Tran 	cpu_to_le32s(&tmp->count);	/* endianize residual count */
872f73cb695SChad Dupuis }
873f73cb695SChad Dupuis 
874f73cb695SChad Dupuis static void
qla27xx_time_stamp(struct qla27xx_fwdt_template * tmp)875f73cb695SChad Dupuis qla27xx_time_stamp(struct qla27xx_fwdt_template *tmp)
876f73cb695SChad Dupuis {
877a31056ddSJoe Carnuccio 	tmp->capture_timestamp = cpu_to_le32(jiffies);
878f73cb695SChad Dupuis }
879f73cb695SChad Dupuis 
880f73cb695SChad Dupuis static void
qla27xx_driver_info(struct qla27xx_fwdt_template * tmp)881f73cb695SChad Dupuis qla27xx_driver_info(struct qla27xx_fwdt_template *tmp)
882f73cb695SChad Dupuis {
883f73cb695SChad Dupuis 	uint8_t v[] = { 0, 0, 0, 0, 0, 0 };
884f73cb695SChad Dupuis 
8856f153bcfSBart Van Assche 	WARN_ON_ONCE(sscanf(qla2x00_version_str,
8867dc0f671SSaurav Kashyap 			    "%hhu.%hhu.%hhu.%hhu",
8877dc0f671SSaurav Kashyap 			    v + 0, v + 1, v + 2, v + 3) != 4);
888f73cb695SChad Dupuis 
889a31056ddSJoe Carnuccio 	tmp->driver_info[0] = cpu_to_le32(
890a31056ddSJoe Carnuccio 		v[3] << 24 | v[2] << 16 | v[1] << 8 | v[0]);
891a31056ddSJoe Carnuccio 	tmp->driver_info[1] = cpu_to_le32(v[5] << 8 | v[4]);
892a31056ddSJoe Carnuccio 	tmp->driver_info[2] = __constant_cpu_to_le32(0x12345678);
893f73cb695SChad Dupuis }
894f73cb695SChad Dupuis 
895f73cb695SChad Dupuis static void
qla27xx_firmware_info(struct scsi_qla_host * vha,struct qla27xx_fwdt_template * tmp)896a28d9e4eSJoe Carnuccio qla27xx_firmware_info(struct scsi_qla_host *vha,
897a28d9e4eSJoe Carnuccio     struct qla27xx_fwdt_template *tmp)
898f73cb695SChad Dupuis {
8997ffa5b93SBart Van Assche 	tmp->firmware_version[0] = cpu_to_le32(vha->hw->fw_major_version);
9007ffa5b93SBart Van Assche 	tmp->firmware_version[1] = cpu_to_le32(vha->hw->fw_minor_version);
9017ffa5b93SBart Van Assche 	tmp->firmware_version[2] = cpu_to_le32(vha->hw->fw_subminor_version);
902a31056ddSJoe Carnuccio 	tmp->firmware_version[3] = cpu_to_le32(
903a31056ddSJoe Carnuccio 		vha->hw->fw_attributes_h << 16 | vha->hw->fw_attributes);
904a31056ddSJoe Carnuccio 	tmp->firmware_version[4] = cpu_to_le32(
905a31056ddSJoe Carnuccio 	  vha->hw->fw_attributes_ext[1] << 16 | vha->hw->fw_attributes_ext[0]);
906f73cb695SChad Dupuis }
907f73cb695SChad Dupuis 
908f73cb695SChad Dupuis static void
ql27xx_edit_template(struct scsi_qla_host * vha,struct qla27xx_fwdt_template * tmp)909f73cb695SChad Dupuis ql27xx_edit_template(struct scsi_qla_host *vha,
910f73cb695SChad Dupuis 	struct qla27xx_fwdt_template *tmp)
911f73cb695SChad Dupuis {
912f73cb695SChad Dupuis 	qla27xx_time_stamp(tmp);
913f73cb695SChad Dupuis 	qla27xx_driver_info(tmp);
914a28d9e4eSJoe Carnuccio 	qla27xx_firmware_info(vha, tmp);
915f73cb695SChad Dupuis }
916f73cb695SChad Dupuis 
917f73cb695SChad Dupuis static inline uint32_t
qla27xx_template_checksum(void * p,ulong size)918f73cb695SChad Dupuis qla27xx_template_checksum(void *p, ulong size)
919f73cb695SChad Dupuis {
920f8f97b0cSJoe Carnuccio 	__le32 *buf = p;
921f73cb695SChad Dupuis 	uint64_t sum = 0;
922f73cb695SChad Dupuis 
923f73cb695SChad Dupuis 	size /= sizeof(*buf);
924f73cb695SChad Dupuis 
925f8f97b0cSJoe Carnuccio 	for ( ; size--; buf++)
926f8f97b0cSJoe Carnuccio 		sum += le32_to_cpu(*buf);
927f73cb695SChad Dupuis 
928f73cb695SChad Dupuis 	sum = (sum & 0xffffffff) + (sum >> 32);
929f73cb695SChad Dupuis 
930f73cb695SChad Dupuis 	return ~sum;
931f73cb695SChad Dupuis }
932f73cb695SChad Dupuis 
933f73cb695SChad Dupuis static inline int
qla27xx_verify_template_checksum(struct qla27xx_fwdt_template * tmp)934f73cb695SChad Dupuis qla27xx_verify_template_checksum(struct qla27xx_fwdt_template *tmp)
935f73cb695SChad Dupuis {
9368de309e7SArun Easi 	return qla27xx_template_checksum(tmp,
9378de309e7SArun Easi 		le32_to_cpu(tmp->template_size)) == 0;
938f73cb695SChad Dupuis }
939f73cb695SChad Dupuis 
940f73cb695SChad Dupuis static inline int
qla27xx_verify_template_header(struct qla27xx_fwdt_template * tmp)941f73cb695SChad Dupuis qla27xx_verify_template_header(struct qla27xx_fwdt_template *tmp)
942f73cb695SChad Dupuis {
943f8f97b0cSJoe Carnuccio 	return le32_to_cpu(tmp->template_type) == TEMPLATE_TYPE_FWDUMP;
944f73cb695SChad Dupuis }
945f73cb695SChad Dupuis 
946a28d9e4eSJoe Carnuccio static ulong
qla27xx_execute_fwdt_template(struct scsi_qla_host * vha,struct qla27xx_fwdt_template * tmp,void * buf)947a28d9e4eSJoe Carnuccio qla27xx_execute_fwdt_template(struct scsi_qla_host *vha,
948a28d9e4eSJoe Carnuccio     struct qla27xx_fwdt_template *tmp, void *buf)
949f73cb695SChad Dupuis {
950a28d9e4eSJoe Carnuccio 	ulong len = 0;
951f73cb695SChad Dupuis 
952f73cb695SChad Dupuis 	if (qla27xx_fwdt_template_valid(tmp)) {
9538de309e7SArun Easi 		len = le32_to_cpu(tmp->template_size);
954a28d9e4eSJoe Carnuccio 		tmp = memcpy(buf, tmp, len);
955f73cb695SChad Dupuis 		ql27xx_edit_template(vha, tmp);
956a28d9e4eSJoe Carnuccio 		qla27xx_walk_template(vha, tmp, buf, &len);
957f73cb695SChad Dupuis 	}
958a28d9e4eSJoe Carnuccio 
959a28d9e4eSJoe Carnuccio 	return len;
960f73cb695SChad Dupuis }
961f73cb695SChad Dupuis 
962f73cb695SChad Dupuis ulong
qla27xx_fwdt_calculate_dump_size(struct scsi_qla_host * vha,void * p)963a28d9e4eSJoe Carnuccio qla27xx_fwdt_calculate_dump_size(struct scsi_qla_host *vha, void *p)
964f73cb695SChad Dupuis {
965a28d9e4eSJoe Carnuccio 	struct qla27xx_fwdt_template *tmp = p;
966f73cb695SChad Dupuis 	ulong len = 0;
967f73cb695SChad Dupuis 
968f73cb695SChad Dupuis 	if (qla27xx_fwdt_template_valid(tmp)) {
9698de309e7SArun Easi 		len = le32_to_cpu(tmp->template_size);
970f73cb695SChad Dupuis 		qla27xx_walk_template(vha, tmp, NULL, &len);
971f73cb695SChad Dupuis 	}
972f73cb695SChad Dupuis 
973f73cb695SChad Dupuis 	return len;
974f73cb695SChad Dupuis }
975f73cb695SChad Dupuis 
976f73cb695SChad Dupuis ulong
qla27xx_fwdt_template_size(void * p)977f73cb695SChad Dupuis qla27xx_fwdt_template_size(void *p)
978f73cb695SChad Dupuis {
979f73cb695SChad Dupuis 	struct qla27xx_fwdt_template *tmp = p;
980f73cb695SChad Dupuis 
9818de309e7SArun Easi 	return le32_to_cpu(tmp->template_size);
982f73cb695SChad Dupuis }
983f73cb695SChad Dupuis 
984f73cb695SChad Dupuis int
qla27xx_fwdt_template_valid(void * p)985f73cb695SChad Dupuis qla27xx_fwdt_template_valid(void *p)
986f73cb695SChad Dupuis {
987f73cb695SChad Dupuis 	struct qla27xx_fwdt_template *tmp = p;
988f73cb695SChad Dupuis 
989f73cb695SChad Dupuis 	if (!qla27xx_verify_template_header(tmp)) {
990f73cb695SChad Dupuis 		ql_log(ql_log_warn, NULL, 0xd01c,
991f8f97b0cSJoe Carnuccio 		    "%s: template type %x\n", __func__,
992f8f97b0cSJoe Carnuccio 		    le32_to_cpu(tmp->template_type));
993f73cb695SChad Dupuis 		return false;
994f73cb695SChad Dupuis 	}
995f73cb695SChad Dupuis 
996f73cb695SChad Dupuis 	if (!qla27xx_verify_template_checksum(tmp)) {
997f73cb695SChad Dupuis 		ql_log(ql_log_warn, NULL, 0xd01d,
998f73cb695SChad Dupuis 		    "%s: failed template checksum\n", __func__);
999f73cb695SChad Dupuis 		return false;
1000f73cb695SChad Dupuis 	}
1001f73cb695SChad Dupuis 
1002f73cb695SChad Dupuis 	return true;
1003f73cb695SChad Dupuis }
1004f73cb695SChad Dupuis 
1005f73cb695SChad Dupuis void
qla27xx_mpi_fwdump(scsi_qla_host_t * vha,int hardware_locked)1006cbb01c2fSArun Easi qla27xx_mpi_fwdump(scsi_qla_host_t *vha, int hardware_locked)
1007cbb01c2fSArun Easi {
1008cbb01c2fSArun Easi 	ulong flags = 0;
1009cbb01c2fSArun Easi 
1010cbb01c2fSArun Easi 	if (!hardware_locked)
1011cbb01c2fSArun Easi 		spin_lock_irqsave(&vha->hw->hardware_lock, flags);
1012cbb01c2fSArun Easi 	if (!vha->hw->mpi_fw_dump) {
1013cbb01c2fSArun Easi 		ql_log(ql_log_warn, vha, 0x02f3, "-> mpi_fwdump no buffer\n");
1014cbb01c2fSArun Easi 	} else {
1015cbb01c2fSArun Easi 		struct fwdt *fwdt = &vha->hw->fwdt[1];
1016cbb01c2fSArun Easi 		ulong len;
1017cbb01c2fSArun Easi 		void *buf = vha->hw->mpi_fw_dump;
10183e6efab8SArun Easi 		bool walk_template_only = false;
10193e6efab8SArun Easi 
10203e6efab8SArun Easi 		if (vha->hw->mpi_fw_dumped) {
10213e6efab8SArun Easi 			/* Use the spare area for any further dumps. */
10223e6efab8SArun Easi 			buf += fwdt->dump_size;
10233e6efab8SArun Easi 			walk_template_only = true;
10243e6efab8SArun Easi 			ql_log(ql_log_warn, vha, 0x02f4,
10253e6efab8SArun Easi 			       "-> MPI firmware already dumped -- dump saving to temporary buffer %p.\n",
10263e6efab8SArun Easi 			       buf);
10273e6efab8SArun Easi 		}
1028cbb01c2fSArun Easi 
1029cbb01c2fSArun Easi 		ql_log(ql_log_warn, vha, 0x02f5, "-> fwdt1 running...\n");
1030cbb01c2fSArun Easi 		if (!fwdt->template) {
1031cbb01c2fSArun Easi 			ql_log(ql_log_warn, vha, 0x02f6,
1032cbb01c2fSArun Easi 			       "-> fwdt1 no template\n");
1033cbb01c2fSArun Easi 			goto bailout;
1034cbb01c2fSArun Easi 		}
1035cbb01c2fSArun Easi 		len = qla27xx_execute_fwdt_template(vha, fwdt->template, buf);
1036cbb01c2fSArun Easi 		if (len == 0) {
1037cbb01c2fSArun Easi 			goto bailout;
1038cbb01c2fSArun Easi 		} else if (len != fwdt->dump_size) {
1039cbb01c2fSArun Easi 			ql_log(ql_log_warn, vha, 0x02f7,
1040cbb01c2fSArun Easi 			       "-> fwdt1 fwdump residual=%+ld\n",
1041cbb01c2fSArun Easi 			       fwdt->dump_size - len);
1042cbb01c2fSArun Easi 		}
10433e6efab8SArun Easi 		vha->hw->stat.num_mpi_reset++;
10443e6efab8SArun Easi 		if (walk_template_only)
10453e6efab8SArun Easi 			goto bailout;
1046cbb01c2fSArun Easi 
1047cbb01c2fSArun Easi 		vha->hw->mpi_fw_dump_len = len;
1048cbb01c2fSArun Easi 		vha->hw->mpi_fw_dumped = 1;
1049cbb01c2fSArun Easi 
1050cbb01c2fSArun Easi 		ql_log(ql_log_warn, vha, 0x02f8,
1051cbb01c2fSArun Easi 		       "-> MPI firmware dump saved to buffer (%lu/%p)\n",
1052cbb01c2fSArun Easi 		       vha->host_no, vha->hw->mpi_fw_dump);
1053cbb01c2fSArun Easi 		qla2x00_post_uevent_work(vha, QLA_UEVENT_CODE_FW_DUMP);
1054cbb01c2fSArun Easi 	}
1055cbb01c2fSArun Easi 
1056cbb01c2fSArun Easi bailout:
1057cbb01c2fSArun Easi 	if (!hardware_locked)
1058cbb01c2fSArun Easi 		spin_unlock_irqrestore(&vha->hw->hardware_lock, flags);
1059cbb01c2fSArun Easi }
1060cbb01c2fSArun Easi 
1061cbb01c2fSArun Easi void
qla27xx_fwdump(scsi_qla_host_t * vha)10628ae17876SBart Van Assche qla27xx_fwdump(scsi_qla_host_t *vha)
1063f73cb695SChad Dupuis {
10648ae17876SBart Van Assche 	lockdep_assert_held(&vha->hw->hardware_lock);
1065f73cb695SChad Dupuis 
1066a28d9e4eSJoe Carnuccio 	if (!vha->hw->fw_dump) {
1067a28d9e4eSJoe Carnuccio 		ql_log(ql_log_warn, vha, 0xd01e, "-> fwdump no buffer\n");
1068a28d9e4eSJoe Carnuccio 	} else if (vha->hw->fw_dumped) {
1069a28d9e4eSJoe Carnuccio 		ql_log(ql_log_warn, vha, 0xd01f,
1070a28d9e4eSJoe Carnuccio 		    "-> Firmware already dumped (%p) -- ignoring request\n",
1071a28d9e4eSJoe Carnuccio 		    vha->hw->fw_dump);
1072a28d9e4eSJoe Carnuccio 	} else {
1073a28d9e4eSJoe Carnuccio 		struct fwdt *fwdt = vha->hw->fwdt;
1074a28d9e4eSJoe Carnuccio 		ulong len;
1075a28d9e4eSJoe Carnuccio 		void *buf = vha->hw->fw_dump;
1076a28d9e4eSJoe Carnuccio 
1077cbb01c2fSArun Easi 		ql_log(ql_log_warn, vha, 0xd011, "-> fwdt0 running...\n");
1078a28d9e4eSJoe Carnuccio 		if (!fwdt->template) {
1079a28d9e4eSJoe Carnuccio 			ql_log(ql_log_warn, vha, 0xd012,
1080cbb01c2fSArun Easi 			       "-> fwdt0 no template\n");
10818ae17876SBart Van Assche 			return;
1082a28d9e4eSJoe Carnuccio 		}
1083cbb01c2fSArun Easi 		len = qla27xx_execute_fwdt_template(vha, fwdt->template, buf);
1084c5547419SQuinn Tran 		if (len == 0) {
10858ae17876SBart Van Assche 			return;
1086c5547419SQuinn Tran 		} else if (len != fwdt->dump_size) {
1087a28d9e4eSJoe Carnuccio 			ql_log(ql_log_warn, vha, 0xd013,
1088cbb01c2fSArun Easi 			       "-> fwdt0 fwdump residual=%+ld\n",
1089cbb01c2fSArun Easi 				fwdt->dump_size - len);
1090a28d9e4eSJoe Carnuccio 		}
1091cbb01c2fSArun Easi 
1092cbb01c2fSArun Easi 		vha->hw->fw_dump_len = len;
1093dbe6f492SJason Yan 		vha->hw->fw_dumped = true;
1094a28d9e4eSJoe Carnuccio 
1095a28d9e4eSJoe Carnuccio 		ql_log(ql_log_warn, vha, 0xd015,
1096a28d9e4eSJoe Carnuccio 		    "-> Firmware dump saved to buffer (%lu/%p) <%lx>\n",
1097a28d9e4eSJoe Carnuccio 		    vha->host_no, vha->hw->fw_dump, vha->hw->fw_dump_cap_flags);
1098a28d9e4eSJoe Carnuccio 		qla2x00_post_uevent_work(vha, QLA_UEVENT_CODE_FW_DUMP);
10997e84766cSQuinn Tran 	}
1100f73cb695SChad Dupuis }
1101