xref: /openbmc/linux/drivers/scsi/qla2xxx/qla_tmpl.c (revision b34e08d5)
1 /*
2  * QLogic Fibre Channel HBA Driver
3  * Copyright (c)  2003-2013 QLogic Corporation
4  *
5  * See LICENSE.qla2xxx for copyright and licensing details.
6  */
7 #include "qla_def.h"
8 #include "qla_tmpl.h"
9 
10 /* note default template is in big endian */
11 static const uint32_t ql27xx_fwdt_default_template[] = {
12 	0x63000000, 0xa4000000, 0x7c050000, 0x00000000,
13 	0x30000000, 0x01000000, 0x00000000, 0xc0406eb4,
14 	0x00000000, 0x00000000, 0x00000000, 0x00000000,
15 	0x00000000, 0x00000000, 0x00000000, 0x00000000,
16 	0x00000000, 0x00000000, 0x00000000, 0x00000000,
17 	0x00000000, 0x00000000, 0x00000000, 0x00000000,
18 	0x00000000, 0x00000000, 0x00000000, 0x00000000,
19 	0x00000000, 0x00000000, 0x00000000, 0x00000000,
20 	0x00000000, 0x00000000, 0x00000000, 0x00000000,
21 	0x00000000, 0x00000000, 0x00000000, 0x00000000,
22 	0x00000000, 0x04010000, 0x14000000, 0x00000000,
23 	0x02000000, 0x44000000, 0x09010000, 0x10000000,
24 	0x00000000, 0x02000000, 0x01010000, 0x1c000000,
25 	0x00000000, 0x02000000, 0x00600000, 0x00000000,
26 	0xc0000000, 0x01010000, 0x1c000000, 0x00000000,
27 	0x02000000, 0x00600000, 0x00000000, 0xcc000000,
28 	0x01010000, 0x1c000000, 0x00000000, 0x02000000,
29 	0x10600000, 0x00000000, 0xd4000000, 0x01010000,
30 	0x1c000000, 0x00000000, 0x02000000, 0x700f0000,
31 	0x00000060, 0xf0000000, 0x00010000, 0x18000000,
32 	0x00000000, 0x02000000, 0x00700000, 0x041000c0,
33 	0x00010000, 0x18000000, 0x00000000, 0x02000000,
34 	0x10700000, 0x041000c0, 0x00010000, 0x18000000,
35 	0x00000000, 0x02000000, 0x40700000, 0x041000c0,
36 	0x01010000, 0x1c000000, 0x00000000, 0x02000000,
37 	0x007c0000, 0x01000000, 0xc0000000, 0x00010000,
38 	0x18000000, 0x00000000, 0x02000000, 0x007c0000,
39 	0x040300c4, 0x00010000, 0x18000000, 0x00000000,
40 	0x02000000, 0x007c0000, 0x040100c0, 0x01010000,
41 	0x1c000000, 0x00000000, 0x02000000, 0x007c0000,
42 	0x00000000, 0xc0000000, 0x00010000, 0x18000000,
43 	0x00000000, 0x02000000, 0x007c0000, 0x04200000,
44 	0x0b010000, 0x18000000, 0x00000000, 0x02000000,
45 	0x0c000000, 0x00000000, 0x02010000, 0x20000000,
46 	0x00000000, 0x02000000, 0x700f0000, 0x040100fc,
47 	0xf0000000, 0x000000b0, 0x02010000, 0x20000000,
48 	0x00000000, 0x02000000, 0x700f0000, 0x040100fc,
49 	0xf0000000, 0x000010b0, 0x02010000, 0x20000000,
50 	0x00000000, 0x02000000, 0x700f0000, 0x040100fc,
51 	0xf0000000, 0x000020b0, 0x02010000, 0x20000000,
52 	0x00000000, 0x02000000, 0x700f0000, 0x040100fc,
53 	0xf0000000, 0x000030b0, 0x02010000, 0x20000000,
54 	0x00000000, 0x02000000, 0x700f0000, 0x040100fc,
55 	0xf0000000, 0x000040b0, 0x02010000, 0x20000000,
56 	0x00000000, 0x02000000, 0x700f0000, 0x040100fc,
57 	0xf0000000, 0x000050b0, 0x02010000, 0x20000000,
58 	0x00000000, 0x02000000, 0x700f0000, 0x040100fc,
59 	0xf0000000, 0x000060b0, 0x02010000, 0x20000000,
60 	0x00000000, 0x02000000, 0x700f0000, 0x040100fc,
61 	0xf0000000, 0x000070b0, 0x02010000, 0x20000000,
62 	0x00000000, 0x02000000, 0x700f0000, 0x040100fc,
63 	0xf0000000, 0x000080b0, 0x02010000, 0x20000000,
64 	0x00000000, 0x02000000, 0x700f0000, 0x040100fc,
65 	0xf0000000, 0x000090b0, 0x02010000, 0x20000000,
66 	0x00000000, 0x02000000, 0x700f0000, 0x040100fc,
67 	0xf0000000, 0x0000a0b0, 0x00010000, 0x18000000,
68 	0x00000000, 0x02000000, 0x0a000000, 0x040100c0,
69 	0x00010000, 0x18000000, 0x00000000, 0x02000000,
70 	0x0a000000, 0x04200080, 0x00010000, 0x18000000,
71 	0x00000000, 0x02000000, 0x00be0000, 0x041000c0,
72 	0x00010000, 0x18000000, 0x00000000, 0x02000000,
73 	0x10be0000, 0x041000c0, 0x00010000, 0x18000000,
74 	0x00000000, 0x02000000, 0x20be0000, 0x041000c0,
75 	0x00010000, 0x18000000, 0x00000000, 0x02000000,
76 	0x30be0000, 0x041000c0, 0x00010000, 0x18000000,
77 	0x00000000, 0x02000000, 0x00b00000, 0x041000c0,
78 	0x00010000, 0x18000000, 0x00000000, 0x02000000,
79 	0x10b00000, 0x041000c0, 0x00010000, 0x18000000,
80 	0x00000000, 0x02000000, 0x20b00000, 0x041000c0,
81 	0x00010000, 0x18000000, 0x00000000, 0x02000000,
82 	0x30b00000, 0x041000c0, 0x00010000, 0x18000000,
83 	0x00000000, 0x02000000, 0x00300000, 0x041000c0,
84 	0x00010000, 0x18000000, 0x00000000, 0x02000000,
85 	0x10300000, 0x041000c0, 0x00010000, 0x18000000,
86 	0x00000000, 0x02000000, 0x20300000, 0x041000c0,
87 	0x00010000, 0x18000000, 0x00000000, 0x02000000,
88 	0x30300000, 0x041000c0, 0x0a010000, 0x10000000,
89 	0x00000000, 0x02000000, 0x06010000, 0x1c000000,
90 	0x00000000, 0x02000000, 0x01000000, 0x00000200,
91 	0xff230200, 0x06010000, 0x1c000000, 0x00000000,
92 	0x02000000, 0x02000000, 0x00001000, 0x00000000,
93 	0x07010000, 0x18000000, 0x00000000, 0x02000000,
94 	0x00000000, 0x01000000, 0x07010000, 0x18000000,
95 	0x00000000, 0x02000000, 0x00000000, 0x02000000,
96 	0x07010000, 0x18000000, 0x00000000, 0x02000000,
97 	0x00000000, 0x03000000, 0x0d010000, 0x14000000,
98 	0x00000000, 0x02000000, 0x00000000, 0xff000000,
99 	0x10000000, 0x00000000, 0x00000080,
100 };
101 
102 static inline void __iomem *
103 qla27xx_isp_reg(struct scsi_qla_host *vha)
104 {
105 	return &vha->hw->iobase->isp24;
106 }
107 
108 static inline void
109 qla27xx_insert16(uint16_t value, void *buf, ulong *len)
110 {
111 	if (buf) {
112 		buf += *len;
113 		*(__le16 *)buf = cpu_to_le16(value);
114 	}
115 	*len += sizeof(value);
116 }
117 
118 static inline void
119 qla27xx_insert32(uint32_t value, void *buf, ulong *len)
120 {
121 	if (buf) {
122 		buf += *len;
123 		*(__le32 *)buf = cpu_to_le32(value);
124 	}
125 	*len += sizeof(value);
126 }
127 
128 static inline void
129 qla27xx_insertbuf(void *mem, ulong size, void *buf, ulong *len)
130 {
131 	ulong cnt = size;
132 
133 	if (buf && mem) {
134 		buf += *len;
135 		while (cnt >= sizeof(uint32_t)) {
136 			*(__le32 *)buf = cpu_to_le32p(mem);
137 			buf += sizeof(uint32_t);
138 			mem += sizeof(uint32_t);
139 			cnt -= sizeof(uint32_t);
140 		}
141 		if (cnt)
142 			memcpy(buf, mem, cnt);
143 	}
144 	*len += size;
145 }
146 
147 static inline void
148 qla27xx_read8(void *window, void *buf, ulong *len)
149 {
150 	uint8_t value = ~0;
151 
152 	if (buf) {
153 		value = RD_REG_BYTE((__iomem void *)window);
154 		ql_dbg(ql_dbg_misc, NULL, 0xd011,
155 		    "%s: -> %x\n", __func__, value);
156 	}
157 	qla27xx_insert32(value, buf, len);
158 }
159 
160 static inline void
161 qla27xx_read16(void *window, void *buf, ulong *len)
162 {
163 	uint16_t value = ~0;
164 
165 	if (buf) {
166 		value = RD_REG_WORD((__iomem void *)window);
167 		ql_dbg(ql_dbg_misc, NULL, 0xd012,
168 		    "%s: -> %x\n", __func__, value);
169 	}
170 	qla27xx_insert32(value, buf, len);
171 }
172 
173 static inline void
174 qla27xx_read32(void *window, void *buf, ulong *len)
175 {
176 	uint32_t value = ~0;
177 
178 	if (buf) {
179 		value = RD_REG_DWORD((__iomem void *)window);
180 		ql_dbg(ql_dbg_misc, NULL, 0xd013,
181 		    "%s: -> %x\n", __func__, value);
182 	}
183 	qla27xx_insert32(value, buf, len);
184 }
185 
186 static inline void (*qla27xx_read_vector(uint width))(void *, void *, ulong *)
187 {
188 	return
189 	    (width == 1) ? qla27xx_read8 :
190 	    (width == 2) ? qla27xx_read16 :
191 			   qla27xx_read32;
192 }
193 
194 static inline void
195 qla27xx_read_reg(__iomem struct device_reg_24xx *reg,
196 	uint offset, void *buf, ulong *len)
197 {
198 	void *window = (void *)reg + offset;
199 
200 	if (buf) {
201 		ql_dbg(ql_dbg_misc, NULL, 0xd014,
202 		    "%s: @%x\n", __func__, offset);
203 	}
204 	qla27xx_insert32(offset, buf, len);
205 	qla27xx_read32(window, buf, len);
206 }
207 
208 static inline void
209 qla27xx_write_reg(__iomem struct device_reg_24xx *reg,
210 	uint offset, uint32_t data, void *buf)
211 {
212 	__iomem void *window = reg + offset;
213 
214 	if (buf) {
215 		ql_dbg(ql_dbg_misc, NULL, 0xd015,
216 		    "%s: @%x <- %x\n", __func__, offset, data);
217 		WRT_REG_DWORD(window, data);
218 	}
219 }
220 
221 static inline void
222 qla27xx_read_window(__iomem struct device_reg_24xx *reg,
223 	uint32_t base, uint offset, uint count, uint width, void *buf,
224 	ulong *len)
225 {
226 	void *window = (void *)reg + offset;
227 	void (*readn)(void *, void *, ulong *) = qla27xx_read_vector(width);
228 
229 	if (buf) {
230 		ql_dbg(ql_dbg_misc, NULL, 0xd016,
231 		    "%s: base=%x offset=%x count=%x width=%x\n",
232 		    __func__, base, offset, count, width);
233 	}
234 	qla27xx_write_reg(reg, IOBASE_ADDR, base, buf);
235 	while (count--) {
236 		qla27xx_insert32(base, buf, len);
237 		readn(window, buf, len);
238 		window += width;
239 		base += width;
240 	}
241 }
242 
243 static inline void
244 qla27xx_skip_entry(struct qla27xx_fwdt_entry *ent, void *buf)
245 {
246 	if (buf)
247 		ent->hdr.driver_flags |= DRIVER_FLAG_SKIP_ENTRY;
248 }
249 
250 static int
251 qla27xx_fwdt_entry_t0(struct scsi_qla_host *vha,
252 	struct qla27xx_fwdt_entry *ent, void *buf, ulong *len)
253 {
254 	ql_dbg(ql_dbg_misc, vha, 0xd100,
255 	    "%s: nop [%lx]\n", __func__, *len);
256 	qla27xx_skip_entry(ent, buf);
257 
258 	return false;
259 }
260 
261 static int
262 qla27xx_fwdt_entry_t255(struct scsi_qla_host *vha,
263 	struct qla27xx_fwdt_entry *ent, void *buf, ulong *len)
264 {
265 	ql_dbg(ql_dbg_misc, vha, 0xd1ff,
266 	    "%s: end [%lx]\n", __func__, *len);
267 	qla27xx_skip_entry(ent, buf);
268 
269 	/* terminate */
270 	return true;
271 }
272 
273 static int
274 qla27xx_fwdt_entry_t256(struct scsi_qla_host *vha,
275 	struct qla27xx_fwdt_entry *ent, void *buf, ulong *len)
276 {
277 	struct device_reg_24xx __iomem *reg = qla27xx_isp_reg(vha);
278 
279 	ql_dbg(ql_dbg_misc, vha, 0xd200,
280 	    "%s: rdio t1 [%lx]\n", __func__, *len);
281 	qla27xx_read_window(reg, ent->t256.base_addr, ent->t256.pci_offset,
282 	    ent->t256.reg_count, ent->t256.reg_width, buf, len);
283 
284 	return false;
285 }
286 
287 static int
288 qla27xx_fwdt_entry_t257(struct scsi_qla_host *vha,
289 	struct qla27xx_fwdt_entry *ent, void *buf, ulong *len)
290 {
291 	struct device_reg_24xx __iomem *reg = qla27xx_isp_reg(vha);
292 
293 	ql_dbg(ql_dbg_misc, vha, 0xd201,
294 	    "%s: wrio t1 [%lx]\n", __func__, *len);
295 	qla27xx_write_reg(reg, IOBASE_ADDR, ent->t257.base_addr, buf);
296 	qla27xx_write_reg(reg, ent->t257.pci_offset, ent->t257.write_data, buf);
297 
298 	return false;
299 }
300 
301 static int
302 qla27xx_fwdt_entry_t258(struct scsi_qla_host *vha,
303 	struct qla27xx_fwdt_entry *ent, void *buf, ulong *len)
304 {
305 	struct device_reg_24xx __iomem *reg = qla27xx_isp_reg(vha);
306 
307 	ql_dbg(ql_dbg_misc, vha, 0xd202,
308 	    "%s: rdio t2 [%lx]\n", __func__, *len);
309 	qla27xx_write_reg(reg, ent->t258.banksel_offset, ent->t258.bank, buf);
310 	qla27xx_read_window(reg, ent->t258.base_addr, ent->t258.pci_offset,
311 	    ent->t258.reg_count, ent->t258.reg_width, buf, len);
312 
313 	return false;
314 }
315 
316 static int
317 qla27xx_fwdt_entry_t259(struct scsi_qla_host *vha,
318 	struct qla27xx_fwdt_entry *ent, void *buf, ulong *len)
319 {
320 	struct device_reg_24xx __iomem *reg = qla27xx_isp_reg(vha);
321 
322 	ql_dbg(ql_dbg_misc, vha, 0xd203,
323 	    "%s: wrio t2 [%lx]\n", __func__, *len);
324 	qla27xx_write_reg(reg, IOBASE_ADDR, ent->t259.base_addr, buf);
325 	qla27xx_write_reg(reg, ent->t259.banksel_offset, ent->t259.bank, buf);
326 	qla27xx_write_reg(reg, ent->t259.pci_offset, ent->t259.write_data, buf);
327 
328 	return false;
329 }
330 
331 static int
332 qla27xx_fwdt_entry_t260(struct scsi_qla_host *vha,
333 	struct qla27xx_fwdt_entry *ent, void *buf, ulong *len)
334 {
335 	struct device_reg_24xx __iomem *reg = qla27xx_isp_reg(vha);
336 
337 	ql_dbg(ql_dbg_misc, vha, 0xd204,
338 	    "%s: rdpci [%lx]\n", __func__, *len);
339 	qla27xx_read_reg(reg, ent->t260.pci_addr, buf, len);
340 
341 	return false;
342 }
343 
344 static int
345 qla27xx_fwdt_entry_t261(struct scsi_qla_host *vha,
346 	struct qla27xx_fwdt_entry *ent, void *buf, ulong *len)
347 {
348 	struct device_reg_24xx __iomem *reg = qla27xx_isp_reg(vha);
349 
350 	ql_dbg(ql_dbg_misc, vha, 0xd205,
351 	    "%s: wrpci [%lx]\n", __func__, *len);
352 	qla27xx_write_reg(reg, ent->t261.pci_addr, ent->t261.write_data, buf);
353 
354 	return false;
355 }
356 
357 static int
358 qla27xx_fwdt_entry_t262(struct scsi_qla_host *vha,
359 	struct qla27xx_fwdt_entry *ent, void *buf, ulong *len)
360 {
361 	ulong dwords;
362 	ulong start;
363 	ulong end;
364 
365 	ql_dbg(ql_dbg_misc, vha, 0xd206,
366 	    "%s: rdram(%x) [%lx]\n", __func__, ent->t262.ram_area, *len);
367 	start = ent->t262.start_addr;
368 	end = ent->t262.end_addr;
369 
370 	if (ent->t262.ram_area == T262_RAM_AREA_CRITICAL_RAM) {
371 		;
372 	} else if (ent->t262.ram_area == T262_RAM_AREA_EXTERNAL_RAM) {
373 		end = vha->hw->fw_memory_size;
374 		if (buf)
375 			ent->t262.end_addr = end;
376 	} else if (ent->t262.ram_area == T262_RAM_AREA_SHARED_RAM) {
377 		start = vha->hw->fw_shared_ram_start;
378 		end = vha->hw->fw_shared_ram_end;
379 		if (buf) {
380 			ent->t262.start_addr = start;
381 			ent->t262.end_addr = end;
382 		}
383 	} else if (ent->t262.ram_area == T262_RAM_AREA_DDR_RAM) {
384 		ql_dbg(ql_dbg_misc, vha, 0xd021,
385 		    "%s: unsupported ddr ram\n", __func__);
386 		qla27xx_skip_entry(ent, buf);
387 		goto done;
388 	} else {
389 		ql_dbg(ql_dbg_misc, vha, 0xd022,
390 		    "%s: unknown area %u\n", __func__, ent->t262.ram_area);
391 		qla27xx_skip_entry(ent, buf);
392 		goto done;
393 	}
394 
395 	if (end < start) {
396 		ql_dbg(ql_dbg_misc, vha, 0xd023,
397 		    "%s: bad range (start=%x end=%x)\n", __func__,
398 		    ent->t262.end_addr, ent->t262.start_addr);
399 		qla27xx_skip_entry(ent, buf);
400 		goto done;
401 	}
402 
403 	dwords = end - start + 1;
404 	if (buf) {
405 		ql_dbg(ql_dbg_misc, vha, 0xd024,
406 		    "%s: @%lx -> (%lx dwords)\n", __func__, start, dwords);
407 		buf += *len;
408 		qla24xx_dump_ram(vha->hw, start, buf, dwords, &buf);
409 	}
410 	*len += dwords * sizeof(uint32_t);
411 done:
412 	return false;
413 }
414 
415 static int
416 qla27xx_fwdt_entry_t263(struct scsi_qla_host *vha,
417 	struct qla27xx_fwdt_entry *ent, void *buf, ulong *len)
418 {
419 	uint count = 0;
420 	uint i;
421 	uint length;
422 
423 	ql_dbg(ql_dbg_misc, vha, 0xd207,
424 	    "%s: getq(%x) [%lx]\n", __func__, ent->t263.queue_type, *len);
425 	if (ent->t263.queue_type == T263_QUEUE_TYPE_REQ) {
426 		for (i = 0; i < vha->hw->max_req_queues; i++) {
427 			struct req_que *req = vha->hw->req_q_map[i];
428 			if (req || !buf) {
429 				length = req ?
430 				    req->length : REQUEST_ENTRY_CNT_24XX;
431 				qla27xx_insert16(i, buf, len);
432 				qla27xx_insert16(length, buf, len);
433 				qla27xx_insertbuf(req ? req->ring : NULL,
434 				    length * sizeof(*req->ring), buf, len);
435 				count++;
436 			}
437 		}
438 	} else if (ent->t263.queue_type == T263_QUEUE_TYPE_RSP) {
439 		for (i = 0; i < vha->hw->max_rsp_queues; i++) {
440 			struct rsp_que *rsp = vha->hw->rsp_q_map[i];
441 			if (rsp || !buf) {
442 				length = rsp ?
443 				    rsp->length : RESPONSE_ENTRY_CNT_MQ;
444 				qla27xx_insert16(i, buf, len);
445 				qla27xx_insert16(length, buf, len);
446 				qla27xx_insertbuf(rsp ? rsp->ring : NULL,
447 				    length * sizeof(*rsp->ring), buf, len);
448 				count++;
449 			}
450 		}
451 	} else if (ent->t263.queue_type == T263_QUEUE_TYPE_ATIO) {
452 		ql_dbg(ql_dbg_misc, vha, 0xd025,
453 		    "%s: unsupported atio queue\n", __func__);
454 		qla27xx_skip_entry(ent, buf);
455 		goto done;
456 	} else {
457 		ql_dbg(ql_dbg_misc, vha, 0xd026,
458 		    "%s: unknown queue %u\n", __func__, ent->t263.queue_type);
459 		qla27xx_skip_entry(ent, buf);
460 		goto done;
461 	}
462 
463 	if (buf)
464 		ent->t263.num_queues = count;
465 done:
466 	return false;
467 }
468 
469 static int
470 qla27xx_fwdt_entry_t264(struct scsi_qla_host *vha,
471 	struct qla27xx_fwdt_entry *ent, void *buf, ulong *len)
472 {
473 	ql_dbg(ql_dbg_misc, vha, 0xd208,
474 	    "%s: getfce [%lx]\n", __func__, *len);
475 	if (vha->hw->fce) {
476 		if (buf) {
477 			ent->t264.fce_trace_size = FCE_SIZE;
478 			ent->t264.write_pointer = vha->hw->fce_wr;
479 			ent->t264.base_pointer = vha->hw->fce_dma;
480 			ent->t264.fce_enable_mb0 = vha->hw->fce_mb[0];
481 			ent->t264.fce_enable_mb2 = vha->hw->fce_mb[2];
482 			ent->t264.fce_enable_mb3 = vha->hw->fce_mb[3];
483 			ent->t264.fce_enable_mb4 = vha->hw->fce_mb[4];
484 			ent->t264.fce_enable_mb5 = vha->hw->fce_mb[5];
485 			ent->t264.fce_enable_mb6 = vha->hw->fce_mb[6];
486 		}
487 		qla27xx_insertbuf(vha->hw->fce, FCE_SIZE, buf, len);
488 	} else {
489 		ql_dbg(ql_dbg_misc, vha, 0xd027,
490 		    "%s: missing fce\n", __func__);
491 		qla27xx_skip_entry(ent, buf);
492 	}
493 
494 	return false;
495 }
496 
497 static int
498 qla27xx_fwdt_entry_t265(struct scsi_qla_host *vha,
499 	struct qla27xx_fwdt_entry *ent, void *buf, ulong *len)
500 {
501 	struct device_reg_24xx __iomem *reg = qla27xx_isp_reg(vha);
502 
503 	ql_dbg(ql_dbg_misc, vha, 0xd209,
504 	    "%s: pause risc [%lx]\n", __func__, *len);
505 	if (buf)
506 		qla24xx_pause_risc(reg);
507 
508 	return false;
509 }
510 
511 static int
512 qla27xx_fwdt_entry_t266(struct scsi_qla_host *vha,
513 	struct qla27xx_fwdt_entry *ent, void *buf, ulong *len)
514 {
515 	ql_dbg(ql_dbg_misc, vha, 0xd20a,
516 	    "%s: reset risc [%lx]\n", __func__, *len);
517 	if (buf)
518 		qla24xx_soft_reset(vha->hw);
519 
520 	return false;
521 }
522 
523 static int
524 qla27xx_fwdt_entry_t267(struct scsi_qla_host *vha,
525 	struct qla27xx_fwdt_entry *ent, void *buf, ulong *len)
526 {
527 	struct device_reg_24xx __iomem *reg = qla27xx_isp_reg(vha);
528 
529 	ql_dbg(ql_dbg_misc, vha, 0xd20b,
530 	    "%s: dis intr [%lx]\n", __func__, *len);
531 	qla27xx_write_reg(reg, ent->t267.pci_offset, ent->t267.data, buf);
532 
533 	return false;
534 }
535 
536 static int
537 qla27xx_fwdt_entry_t268(struct scsi_qla_host *vha,
538 	struct qla27xx_fwdt_entry *ent, void *buf, ulong *len)
539 {
540 	ql_dbg(ql_dbg_misc, vha, 0xd20c,
541 	    "%s: gethb(%x) [%lx]\n", __func__, ent->t268.buf_type, *len);
542 	if (ent->t268.buf_type == T268_BUF_TYPE_EXTD_TRACE) {
543 		if (vha->hw->eft) {
544 			if (buf) {
545 				ent->t268.buf_size = EFT_SIZE;
546 				ent->t268.start_addr = vha->hw->eft_dma;
547 			}
548 			qla27xx_insertbuf(vha->hw->eft, EFT_SIZE, buf, len);
549 		} else {
550 			ql_dbg(ql_dbg_misc, vha, 0xd028,
551 			    "%s: missing eft\n", __func__);
552 			qla27xx_skip_entry(ent, buf);
553 		}
554 	} else if (ent->t268.buf_type == T268_BUF_TYPE_EXCH_BUFOFF) {
555 		ql_dbg(ql_dbg_misc, vha, 0xd029,
556 		    "%s: unsupported exchange offload buffer\n", __func__);
557 		qla27xx_skip_entry(ent, buf);
558 	} else if (ent->t268.buf_type == T268_BUF_TYPE_EXTD_LOGIN) {
559 		ql_dbg(ql_dbg_misc, vha, 0xd02a,
560 		    "%s: unsupported extended login buffer\n", __func__);
561 		qla27xx_skip_entry(ent, buf);
562 	} else {
563 		ql_dbg(ql_dbg_misc, vha, 0xd02b,
564 		    "%s: unknown buf %x\n", __func__, ent->t268.buf_type);
565 		qla27xx_skip_entry(ent, buf);
566 	}
567 
568 	return false;
569 }
570 
571 static int
572 qla27xx_fwdt_entry_t269(struct scsi_qla_host *vha,
573 	struct qla27xx_fwdt_entry *ent, void *buf, ulong *len)
574 {
575 	ql_dbg(ql_dbg_misc, vha, 0xd20d,
576 	    "%s: scratch [%lx]\n", __func__, *len);
577 	qla27xx_insert32(0xaaaaaaaa, buf, len);
578 	qla27xx_insert32(0xbbbbbbbb, buf, len);
579 	qla27xx_insert32(0xcccccccc, buf, len);
580 	qla27xx_insert32(0xdddddddd, buf, len);
581 	qla27xx_insert32(*len + sizeof(uint32_t), buf, len);
582 	if (buf)
583 		ent->t269.scratch_size = 5 * sizeof(uint32_t);
584 
585 	return false;
586 }
587 
588 static int
589 qla27xx_fwdt_entry_t270(struct scsi_qla_host *vha,
590 	struct qla27xx_fwdt_entry *ent, void *buf, ulong *len)
591 {
592 	struct device_reg_24xx __iomem *reg = qla27xx_isp_reg(vha);
593 	void *window = (void *)reg + 0xc4;
594 	ulong dwords = ent->t270.count;
595 	ulong addr = ent->t270.addr;
596 
597 	ql_dbg(ql_dbg_misc, vha, 0xd20e,
598 	    "%s: rdremreg [%lx]\n", __func__, *len);
599 	qla27xx_write_reg(reg, IOBASE_ADDR, 0x40, buf);
600 	while (dwords--) {
601 		qla27xx_write_reg(reg, 0xc0, addr|0x80000000, buf);
602 		qla27xx_read_reg(reg, 0xc4, buf, len);
603 		qla27xx_insert32(addr, buf, len);
604 		qla27xx_read32(window, buf, len);
605 		addr++;
606 	}
607 
608 	return false;
609 }
610 
611 static int
612 qla27xx_fwdt_entry_t271(struct scsi_qla_host *vha,
613 	struct qla27xx_fwdt_entry *ent, void *buf, ulong *len)
614 {
615 	struct device_reg_24xx __iomem *reg = qla27xx_isp_reg(vha);
616 	ulong addr = ent->t271.addr;
617 
618 	ql_dbg(ql_dbg_misc, vha, 0xd20f,
619 	    "%s: wrremreg [%lx]\n", __func__, *len);
620 	qla27xx_write_reg(reg, IOBASE_ADDR, 0x40, buf);
621 	qla27xx_read_reg(reg, 0xc4, buf, len);
622 	qla27xx_insert32(addr, buf, len);
623 	qla27xx_write_reg(reg, 0xc0, addr, buf);
624 
625 	return false;
626 }
627 
628 static int
629 qla27xx_fwdt_entry_t272(struct scsi_qla_host *vha,
630 	struct qla27xx_fwdt_entry *ent, void *buf, ulong *len)
631 {
632 	ulong dwords = ent->t272.count;
633 	ulong start = ent->t272.addr;
634 
635 	ql_dbg(ql_dbg_misc, vha, 0xd210,
636 	    "%s: rdremram [%lx]\n", __func__, *len);
637 	if (buf) {
638 		ql_dbg(ql_dbg_misc, vha, 0xd02c,
639 		    "%s: @%lx -> (%lx dwords)\n", __func__, start, dwords);
640 		buf += *len;
641 		qla27xx_dump_mpi_ram(vha->hw, start, buf, dwords, &buf);
642 	}
643 	*len += dwords * sizeof(uint32_t);
644 
645 	return false;
646 }
647 
648 static int
649 qla27xx_fwdt_entry_t273(struct scsi_qla_host *vha,
650 	struct qla27xx_fwdt_entry *ent, void *buf, ulong *len)
651 {
652 	ulong dwords = ent->t273.count;
653 	ulong addr = ent->t273.addr;
654 	uint32_t value;
655 
656 	ql_dbg(ql_dbg_misc, vha, 0xd211,
657 	    "%s: pcicfg [%lx]\n", __func__, *len);
658 	while (dwords--) {
659 		value = ~0;
660 		if (pci_read_config_dword(vha->hw->pdev, addr, &value))
661 			ql_dbg(ql_dbg_misc, vha, 0xd02d,
662 			    "%s: failed pcicfg read at %lx\n", __func__, addr);
663 		qla27xx_insert32(addr, buf, len);
664 		qla27xx_insert32(value, buf, len);
665 		addr += 4;
666 	}
667 
668 	return false;
669 }
670 
671 static int
672 qla27xx_fwdt_entry_other(struct scsi_qla_host *vha,
673 	struct qla27xx_fwdt_entry *ent, void *buf, ulong *len)
674 {
675 	ql_dbg(ql_dbg_misc, vha, 0xd2ff,
676 	    "%s: type %x [%lx]\n", __func__, ent->hdr.entry_type, *len);
677 	qla27xx_skip_entry(ent, buf);
678 
679 	return false;
680 }
681 
682 struct qla27xx_fwdt_entry_call {
683 	int type;
684 	int (*call)(
685 	    struct scsi_qla_host *,
686 	    struct qla27xx_fwdt_entry *,
687 	    void *,
688 	    ulong *);
689 };
690 
691 static struct qla27xx_fwdt_entry_call ql27xx_fwdt_entry_call_list[] = {
692 	{ ENTRY_TYPE_NOP		, qla27xx_fwdt_entry_t0    } ,
693 	{ ENTRY_TYPE_TMP_END		, qla27xx_fwdt_entry_t255  } ,
694 	{ ENTRY_TYPE_RD_IOB_T1		, qla27xx_fwdt_entry_t256  } ,
695 	{ ENTRY_TYPE_WR_IOB_T1		, qla27xx_fwdt_entry_t257  } ,
696 	{ ENTRY_TYPE_RD_IOB_T2		, qla27xx_fwdt_entry_t258  } ,
697 	{ ENTRY_TYPE_WR_IOB_T2		, qla27xx_fwdt_entry_t259  } ,
698 	{ ENTRY_TYPE_RD_PCI		, qla27xx_fwdt_entry_t260  } ,
699 	{ ENTRY_TYPE_WR_PCI		, qla27xx_fwdt_entry_t261  } ,
700 	{ ENTRY_TYPE_RD_RAM		, qla27xx_fwdt_entry_t262  } ,
701 	{ ENTRY_TYPE_GET_QUEUE		, qla27xx_fwdt_entry_t263  } ,
702 	{ ENTRY_TYPE_GET_FCE		, qla27xx_fwdt_entry_t264  } ,
703 	{ ENTRY_TYPE_PSE_RISC		, qla27xx_fwdt_entry_t265  } ,
704 	{ ENTRY_TYPE_RST_RISC		, qla27xx_fwdt_entry_t266  } ,
705 	{ ENTRY_TYPE_DIS_INTR		, qla27xx_fwdt_entry_t267  } ,
706 	{ ENTRY_TYPE_GET_HBUF		, qla27xx_fwdt_entry_t268  } ,
707 	{ ENTRY_TYPE_SCRATCH		, qla27xx_fwdt_entry_t269  } ,
708 	{ ENTRY_TYPE_RDREMREG		, qla27xx_fwdt_entry_t270  } ,
709 	{ ENTRY_TYPE_WRREMREG		, qla27xx_fwdt_entry_t271  } ,
710 	{ ENTRY_TYPE_RDREMRAM		, qla27xx_fwdt_entry_t272  } ,
711 	{ ENTRY_TYPE_PCICFG		, qla27xx_fwdt_entry_t273  } ,
712 	{ -1				, qla27xx_fwdt_entry_other }
713 };
714 
715 static inline int (*qla27xx_find_entry(int type))
716 	(struct scsi_qla_host *, struct qla27xx_fwdt_entry *, void *, ulong *)
717 {
718 	struct qla27xx_fwdt_entry_call *list = ql27xx_fwdt_entry_call_list;
719 
720 	while (list->type != -1 && list->type != type)
721 		list++;
722 
723 	return list->call;
724 }
725 
726 static inline void *
727 qla27xx_next_entry(void *p)
728 {
729 	struct qla27xx_fwdt_entry *ent = p;
730 
731 	return p + ent->hdr.entry_size;
732 }
733 
734 static void
735 qla27xx_walk_template(struct scsi_qla_host *vha,
736 	struct qla27xx_fwdt_template *tmp, void *buf, ulong *len)
737 {
738 	struct qla27xx_fwdt_entry *ent = (void *)tmp + tmp->entry_offset;
739 	ulong count = tmp->entry_count;
740 
741 	ql_dbg(ql_dbg_misc, vha, 0xd01a,
742 	    "%s: entry count %lx\n", __func__, count);
743 	while (count--) {
744 		if (qla27xx_find_entry(ent->hdr.entry_type)(vha, ent, buf, len))
745 			break;
746 		ent = qla27xx_next_entry(ent);
747 	}
748 	ql_dbg(ql_dbg_misc, vha, 0xd01b,
749 	    "%s: len=%lx\n", __func__, *len);
750 }
751 
752 static void
753 qla27xx_time_stamp(struct qla27xx_fwdt_template *tmp)
754 {
755 	tmp->capture_timestamp = jiffies;
756 }
757 
758 static void
759 qla27xx_driver_info(struct qla27xx_fwdt_template *tmp)
760 {
761 	uint8_t v[] = { 0, 0, 0, 0, 0, 0 };
762 	int rval = 0;
763 
764 	rval = sscanf(qla2x00_version_str, "%hhu.%hhu.%hhu.%hhu.%hhu.%hhu",
765 	    v+0, v+1, v+2, v+3, v+4, v+5);
766 
767 	tmp->driver_info[0] = v[3] << 24 | v[2] << 16 | v[1] << 8 | v[0];
768 	tmp->driver_info[1] = v[5] << 8 | v[4];
769 	tmp->driver_info[2] = 0x12345678;
770 }
771 
772 static void
773 qla27xx_firmware_info(struct qla27xx_fwdt_template *tmp,
774 	struct scsi_qla_host *vha)
775 {
776 	tmp->firmware_version[0] = vha->hw->fw_major_version;
777 	tmp->firmware_version[1] = vha->hw->fw_minor_version;
778 	tmp->firmware_version[2] = vha->hw->fw_subminor_version;
779 	tmp->firmware_version[3] =
780 	    vha->hw->fw_attributes_h << 16 | vha->hw->fw_attributes;
781 	tmp->firmware_version[4] =
782 	    vha->hw->fw_attributes_ext[1] << 16 | vha->hw->fw_attributes_ext[0];
783 }
784 
785 static void
786 ql27xx_edit_template(struct scsi_qla_host *vha,
787 	struct qla27xx_fwdt_template *tmp)
788 {
789 	qla27xx_time_stamp(tmp);
790 	qla27xx_driver_info(tmp);
791 	qla27xx_firmware_info(tmp, vha);
792 }
793 
794 static inline uint32_t
795 qla27xx_template_checksum(void *p, ulong size)
796 {
797 	uint32_t *buf = p;
798 	uint64_t sum = 0;
799 
800 	size /= sizeof(*buf);
801 
802 	while (size--)
803 		sum += *buf++;
804 
805 	sum = (sum & 0xffffffff) + (sum >> 32);
806 
807 	return ~sum;
808 }
809 
810 static inline int
811 qla27xx_verify_template_checksum(struct qla27xx_fwdt_template *tmp)
812 {
813 	return qla27xx_template_checksum(tmp, tmp->template_size) == 0;
814 }
815 
816 static inline int
817 qla27xx_verify_template_header(struct qla27xx_fwdt_template *tmp)
818 {
819 	return tmp->template_type == TEMPLATE_TYPE_FWDUMP;
820 }
821 
822 static void
823 qla27xx_execute_fwdt_template(struct scsi_qla_host *vha)
824 {
825 	struct qla27xx_fwdt_template *tmp = vha->hw->fw_dump_template;
826 	ulong len;
827 
828 	if (qla27xx_fwdt_template_valid(tmp)) {
829 		len = tmp->template_size;
830 		tmp = memcpy(vha->hw->fw_dump, tmp, len);
831 		ql27xx_edit_template(vha, tmp);
832 		qla27xx_walk_template(vha, tmp, tmp, &len);
833 		vha->hw->fw_dump_len = len;
834 		vha->hw->fw_dumped = 1;
835 	}
836 }
837 
838 ulong
839 qla27xx_fwdt_calculate_dump_size(struct scsi_qla_host *vha)
840 {
841 	struct qla27xx_fwdt_template *tmp = vha->hw->fw_dump_template;
842 	ulong len = 0;
843 
844 	if (qla27xx_fwdt_template_valid(tmp)) {
845 		len = tmp->template_size;
846 		qla27xx_walk_template(vha, tmp, NULL, &len);
847 	}
848 
849 	return len;
850 }
851 
852 ulong
853 qla27xx_fwdt_template_size(void *p)
854 {
855 	struct qla27xx_fwdt_template *tmp = p;
856 
857 	return tmp->template_size;
858 }
859 
860 ulong
861 qla27xx_fwdt_template_default_size(void)
862 {
863 	return sizeof(ql27xx_fwdt_default_template);
864 }
865 
866 const void *
867 qla27xx_fwdt_template_default(void)
868 {
869 	return ql27xx_fwdt_default_template;
870 }
871 
872 int
873 qla27xx_fwdt_template_valid(void *p)
874 {
875 	struct qla27xx_fwdt_template *tmp = p;
876 
877 	if (!qla27xx_verify_template_header(tmp)) {
878 		ql_log(ql_log_warn, NULL, 0xd01c,
879 		    "%s: template type %x\n", __func__, tmp->template_type);
880 		return false;
881 	}
882 
883 	if (!qla27xx_verify_template_checksum(tmp)) {
884 		ql_log(ql_log_warn, NULL, 0xd01d,
885 		    "%s: failed template checksum\n", __func__);
886 		return false;
887 	}
888 
889 	return true;
890 }
891 
892 void
893 qla27xx_fwdump(scsi_qla_host_t *vha, int hardware_locked)
894 {
895 	ulong flags = 0;
896 
897 	if (!hardware_locked)
898 		spin_lock_irqsave(&vha->hw->hardware_lock, flags);
899 
900 	if (!vha->hw->fw_dump)
901 		ql_log(ql_log_warn, vha, 0xd01e, "fwdump buffer missing.\n");
902 	else if (!vha->hw->fw_dump_template)
903 		ql_log(ql_log_warn, vha, 0xd01f, "fwdump template missing.\n");
904 	else
905 		qla27xx_execute_fwdt_template(vha);
906 
907 	if (!hardware_locked)
908 		spin_unlock_irqrestore(&vha->hw->hardware_lock, flags);
909 }
910