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