qla_dbg.c 38.6 KB
Newer Older
L
Linus Torvalds 已提交
1
/*
A
Andrew Vasquez 已提交
2
 * QLogic Fibre Channel HBA Driver
3
 * Copyright (c)  2003-2008 QLogic Corporation
L
Linus Torvalds 已提交
4
 *
A
Andrew Vasquez 已提交
5
 * See LICENSE.qla2xxx for copyright and licensing details.
L
Linus Torvalds 已提交
6 7 8 9 10
 */
#include "qla_def.h"

#include <linux/delay.h>

11
static inline void
12
qla2xxx_prep_dump(struct qla_hw_data *ha, struct qla2xxx_fw_dump *fw_dump)
13 14 15 16 17 18 19 20 21 22 23 24 25
{
	fw_dump->fw_major_version = htonl(ha->fw_major_version);
	fw_dump->fw_minor_version = htonl(ha->fw_minor_version);
	fw_dump->fw_subminor_version = htonl(ha->fw_subminor_version);
	fw_dump->fw_attributes = htonl(ha->fw_attributes);

	fw_dump->vendor = htonl(ha->pdev->vendor);
	fw_dump->device = htonl(ha->pdev->device);
	fw_dump->subsystem_vendor = htonl(ha->pdev->subsystem_vendor);
	fw_dump->subsystem_device = htonl(ha->pdev->subsystem_device);
}

static inline void *
26
qla2xxx_copy_queues(scsi_qla_host_t *vha, void *ptr)
27
{
28 29 30
	struct req_que *req = vha->hw->req;
	struct rsp_que *rsp = vha->hw->rsp;

31
	/* Request queue. */
32
	memcpy(ptr, req->ring, req->length *
33 34 35
	    sizeof(request_t));

	/* Response queue. */
36 37
	ptr += req->length * sizeof(request_t);
	memcpy(ptr, rsp->ring, rsp->length  *
38 39
	    sizeof(response_t));

40
	return ptr + (rsp->length * sizeof(response_t));
41
}
L
Linus Torvalds 已提交
42

43
static int
44
qla24xx_dump_ram(struct qla_hw_data *ha, uint32_t addr, uint32_t *ram,
45
    uint32_t ram_dwords, void **nxt)
46 47
{
	int rval;
48 49
	uint32_t cnt, stat, timer, dwords, idx;
	uint16_t mb0;
50
	struct device_reg_24xx __iomem *reg = &ha->iobase->isp24;
51 52
	dma_addr_t dump_dma = ha->gid_list_dma;
	uint32_t *dump = (uint32_t *)ha->gid_list;
53 54

	rval = QLA_SUCCESS;
55
	mb0 = 0;
56

57
	WRT_REG_WORD(&reg->mailbox0, MBC_DUMP_RISC_RAM_EXTENDED);
58 59
	clear_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags);

60 61 62 63 64
	dwords = GID_LIST_SIZE / 4;
	for (cnt = 0; cnt < ram_dwords && rval == QLA_SUCCESS;
	    cnt += dwords, addr += dwords) {
		if (cnt + dwords > ram_dwords)
			dwords = ram_dwords - cnt;
65

66 67
		WRT_REG_WORD(&reg->mailbox1, LSW(addr));
		WRT_REG_WORD(&reg->mailbox8, MSW(addr));
68

69 70 71 72
		WRT_REG_WORD(&reg->mailbox2, MSW(dump_dma));
		WRT_REG_WORD(&reg->mailbox3, LSW(dump_dma));
		WRT_REG_WORD(&reg->mailbox6, MSW(MSD(dump_dma)));
		WRT_REG_WORD(&reg->mailbox7, LSW(MSD(dump_dma)));
73

74 75
		WRT_REG_WORD(&reg->mailbox4, MSW(dwords));
		WRT_REG_WORD(&reg->mailbox5, LSW(dwords));
76 77 78 79 80 81 82 83 84 85 86 87 88
		WRT_REG_DWORD(&reg->hccr, HCCRX_SET_HOST_INT);

		for (timer = 6000000; timer; timer--) {
			/* Check for pending interrupts. */
			stat = RD_REG_DWORD(&reg->host_status);
			if (stat & HSRX_RISC_INT) {
				stat &= 0xff;

				if (stat == 0x1 || stat == 0x2 ||
				    stat == 0x10 || stat == 0x11) {
					set_bit(MBX_INTERRUPT,
					    &ha->mbx_cmd_flags);

89
					mb0 = RD_REG_WORD(&reg->mailbox0);
90 91 92 93 94 95 96 97 98 99 100 101 102 103 104

					WRT_REG_DWORD(&reg->hccr,
					    HCCRX_CLR_RISC_INT);
					RD_REG_DWORD(&reg->hccr);
					break;
				}

				/* Clear this intr; it wasn't a mailbox intr */
				WRT_REG_DWORD(&reg->hccr, HCCRX_CLR_RISC_INT);
				RD_REG_DWORD(&reg->hccr);
			}
			udelay(5);
		}

		if (test_and_clear_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags)) {
105 106 107
			rval = mb0 & MBS_MASK;
			for (idx = 0; idx < dwords; idx++)
				ram[cnt + idx] = swab32(dump[idx]);
108 109 110 111 112
		} else {
			rval = QLA_FUNCTION_FAILED;
		}
	}

113
	*nxt = rval == QLA_SUCCESS ? &ram[cnt]: NULL;
114 115 116
	return rval;
}

117
static int
118
qla24xx_dump_memory(struct qla_hw_data *ha, uint32_t *code_ram,
119 120 121 122 123 124 125 126 127 128 129 130 131 132
    uint32_t cram_size, void **nxt)
{
	int rval;

	/* Code RAM. */
	rval = qla24xx_dump_ram(ha, 0x20000, code_ram, cram_size / 4, nxt);
	if (rval != QLA_SUCCESS)
		return rval;

	/* External Memory. */
	return qla24xx_dump_ram(ha, 0x100000, *nxt,
	    ha->fw_memory_size - 0x100000 + 1, nxt);
}

133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152
static uint32_t *
qla24xx_read_window(struct device_reg_24xx __iomem *reg, uint32_t iobase,
    uint32_t count, uint32_t *buf)
{
	uint32_t __iomem *dmp_reg;

	WRT_REG_DWORD(&reg->iobase_addr, iobase);
	dmp_reg = &reg->iobase_window;
	while (count--)
		*buf++ = htonl(RD_REG_DWORD(dmp_reg++));

	return buf;
}

static inline int
qla24xx_pause_risc(struct device_reg_24xx __iomem *reg)
{
	int rval = QLA_SUCCESS;
	uint32_t cnt;

153 154 155 156 157 158 159 160 161 162
	if (RD_REG_DWORD(&reg->hccr) & HCCRX_RISC_PAUSE)
		return rval;

	WRT_REG_DWORD(&reg->hccr, HCCRX_SET_RISC_PAUSE);
	for (cnt = 30000; (RD_REG_DWORD(&reg->hccr) & HCCRX_RISC_PAUSE) == 0 &&
	    rval == QLA_SUCCESS; cnt--) {
		if (cnt)
			udelay(100);
		else
			rval = QLA_FUNCTION_TIMEOUT;
163 164 165 166 167 168
	}

	return rval;
}

static int
169
qla24xx_soft_reset(struct qla_hw_data *ha)
170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219
{
	int rval = QLA_SUCCESS;
	uint32_t cnt;
	uint16_t mb0, wd;
	struct device_reg_24xx __iomem *reg = &ha->iobase->isp24;

	/* Reset RISC. */
	WRT_REG_DWORD(&reg->ctrl_status, CSRX_DMA_SHUTDOWN|MWB_4096_BYTES);
	for (cnt = 0; cnt < 30000; cnt++) {
		if ((RD_REG_DWORD(&reg->ctrl_status) & CSRX_DMA_ACTIVE) == 0)
			break;

		udelay(10);
	}

	WRT_REG_DWORD(&reg->ctrl_status,
	    CSRX_ISP_SOFT_RESET|CSRX_DMA_SHUTDOWN|MWB_4096_BYTES);
	pci_read_config_word(ha->pdev, PCI_COMMAND, &wd);

	udelay(100);
	/* Wait for firmware to complete NVRAM accesses. */
	mb0 = (uint32_t) RD_REG_WORD(&reg->mailbox0);
	for (cnt = 10000 ; cnt && mb0; cnt--) {
		udelay(5);
		mb0 = (uint32_t) RD_REG_WORD(&reg->mailbox0);
		barrier();
	}

	/* Wait for soft-reset to complete. */
	for (cnt = 0; cnt < 30000; cnt++) {
		if ((RD_REG_DWORD(&reg->ctrl_status) &
		    CSRX_ISP_SOFT_RESET) == 0)
			break;

		udelay(10);
	}
	WRT_REG_DWORD(&reg->hccr, HCCRX_CLR_RISC_RESET);
	RD_REG_DWORD(&reg->hccr);             /* PCI Posting. */

	for (cnt = 30000; RD_REG_WORD(&reg->mailbox0) != 0 &&
	    rval == QLA_SUCCESS; cnt--) {
		if (cnt)
			udelay(100);
		else
			rval = QLA_FUNCTION_TIMEOUT;
	}

	return rval;
}

220
static int
221 222
qla2xxx_dump_ram(struct qla_hw_data *ha, uint32_t addr, uint16_t *ram,
    uint16_t ram_words, void **nxt)
223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303
{
	int rval;
	uint32_t cnt, stat, timer, words, idx;
	uint16_t mb0;
	struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
	dma_addr_t dump_dma = ha->gid_list_dma;
	uint16_t *dump = (uint16_t *)ha->gid_list;

	rval = QLA_SUCCESS;
	mb0 = 0;

	WRT_MAILBOX_REG(ha, reg, 0, MBC_DUMP_RISC_RAM_EXTENDED);
	clear_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags);

	words = GID_LIST_SIZE / 2;
	for (cnt = 0; cnt < ram_words && rval == QLA_SUCCESS;
	    cnt += words, addr += words) {
		if (cnt + words > ram_words)
			words = ram_words - cnt;

		WRT_MAILBOX_REG(ha, reg, 1, LSW(addr));
		WRT_MAILBOX_REG(ha, reg, 8, MSW(addr));

		WRT_MAILBOX_REG(ha, reg, 2, MSW(dump_dma));
		WRT_MAILBOX_REG(ha, reg, 3, LSW(dump_dma));
		WRT_MAILBOX_REG(ha, reg, 6, MSW(MSD(dump_dma)));
		WRT_MAILBOX_REG(ha, reg, 7, LSW(MSD(dump_dma)));

		WRT_MAILBOX_REG(ha, reg, 4, words);
		WRT_REG_WORD(&reg->hccr, HCCR_SET_HOST_INT);

		for (timer = 6000000; timer; timer--) {
			/* Check for pending interrupts. */
			stat = RD_REG_DWORD(&reg->u.isp2300.host_status);
			if (stat & HSR_RISC_INT) {
				stat &= 0xff;

				if (stat == 0x1 || stat == 0x2) {
					set_bit(MBX_INTERRUPT,
					    &ha->mbx_cmd_flags);

					mb0 = RD_MAILBOX_REG(ha, reg, 0);

					/* Release mailbox registers. */
					WRT_REG_WORD(&reg->semaphore, 0);
					WRT_REG_WORD(&reg->hccr,
					    HCCR_CLR_RISC_INT);
					RD_REG_WORD(&reg->hccr);
					break;
				} else if (stat == 0x10 || stat == 0x11) {
					set_bit(MBX_INTERRUPT,
					    &ha->mbx_cmd_flags);

					mb0 = RD_MAILBOX_REG(ha, reg, 0);

					WRT_REG_WORD(&reg->hccr,
					    HCCR_CLR_RISC_INT);
					RD_REG_WORD(&reg->hccr);
					break;
				}

				/* clear this intr; it wasn't a mailbox intr */
				WRT_REG_WORD(&reg->hccr, HCCR_CLR_RISC_INT);
				RD_REG_WORD(&reg->hccr);
			}
			udelay(5);
		}

		if (test_and_clear_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags)) {
			rval = mb0 & MBS_MASK;
			for (idx = 0; idx < words; idx++)
				ram[cnt + idx] = swab16(dump[idx]);
		} else {
			rval = QLA_FUNCTION_FAILED;
		}
	}

	*nxt = rval == QLA_SUCCESS ? &ram[cnt]: NULL;
	return rval;
}

304 305 306 307 308 309 310 311 312 313
static inline void
qla2xxx_read_window(struct device_reg_2xxx __iomem *reg, uint32_t count,
    uint16_t *buf)
{
	uint16_t __iomem *dmp_reg = &reg->u.isp2300.fb_cmd;

	while (count--)
		*buf++ = htons(RD_REG_WORD(dmp_reg++));
}

L
Linus Torvalds 已提交
314 315 316 317 318 319
/**
 * qla2300_fw_dump() - Dumps binary data from the 2300 firmware.
 * @ha: HA context
 * @hardware_locked: Called with the hardware_lock
 */
void
320
qla2300_fw_dump(scsi_qla_host_t *vha, int hardware_locked)
L
Linus Torvalds 已提交
321 322
{
	int		rval;
323
	uint32_t	cnt;
324
	struct qla_hw_data *ha = vha->hw;
325
	struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
L
Linus Torvalds 已提交
326 327 328
	uint16_t __iomem *dmp_reg;
	unsigned long	flags;
	struct qla2300_fw_dump	*fw;
329
	void		*nxt;
L
Linus Torvalds 已提交
330 331 332 333 334 335

	flags = 0;

	if (!hardware_locked)
		spin_lock_irqsave(&ha->hardware_lock, flags);

336
	if (!ha->fw_dump) {
L
Linus Torvalds 已提交
337
		qla_printk(KERN_WARNING, ha,
338
		    "No buffer available for dump!!!\n");
L
Linus Torvalds 已提交
339 340 341
		goto qla2300_fw_dump_failed;
	}

342
	if (ha->fw_dumped) {
L
Linus Torvalds 已提交
343
		qla_printk(KERN_WARNING, ha,
344 345
		    "Firmware has been previously dumped (%p) -- ignoring "
		    "request...\n", ha->fw_dump);
L
Linus Torvalds 已提交
346 347
		goto qla2300_fw_dump_failed;
	}
348 349
	fw = &ha->fw_dump->isp.isp23;
	qla2xxx_prep_dump(ha, ha->fw_dump);
L
Linus Torvalds 已提交
350 351

	rval = QLA_SUCCESS;
352
	fw->hccr = htons(RD_REG_WORD(&reg->hccr));
L
Linus Torvalds 已提交
353 354

	/* Pause RISC. */
A
Andrew Vasquez 已提交
355
	WRT_REG_WORD(&reg->hccr, HCCR_PAUSE_RISC);
L
Linus Torvalds 已提交
356 357 358 359 360 361 362 363 364 365 366 367 368 369 370
	if (IS_QLA2300(ha)) {
		for (cnt = 30000;
		    (RD_REG_WORD(&reg->hccr) & HCCR_RISC_PAUSE) == 0 &&
			rval == QLA_SUCCESS; cnt--) {
			if (cnt)
				udelay(100);
			else
				rval = QLA_FUNCTION_TIMEOUT;
		}
	} else {
		RD_REG_WORD(&reg->hccr);		/* PCI Posting. */
		udelay(10);
	}

	if (rval == QLA_SUCCESS) {
371
		dmp_reg = &reg->flash_address;
A
Andrew Vasquez 已提交
372
		for (cnt = 0; cnt < sizeof(fw->pbiu_reg) / 2; cnt++)
373
			fw->pbiu_reg[cnt] = htons(RD_REG_WORD(dmp_reg++));
L
Linus Torvalds 已提交
374

375
		dmp_reg = &reg->u.isp2300.req_q_in;
A
Andrew Vasquez 已提交
376
		for (cnt = 0; cnt < sizeof(fw->risc_host_reg) / 2; cnt++)
377
			fw->risc_host_reg[cnt] = htons(RD_REG_WORD(dmp_reg++));
L
Linus Torvalds 已提交
378

379
		dmp_reg = &reg->u.isp2300.mailbox0;
A
Andrew Vasquez 已提交
380
		for (cnt = 0; cnt < sizeof(fw->mailbox_reg) / 2; cnt++)
381
			fw->mailbox_reg[cnt] = htons(RD_REG_WORD(dmp_reg++));
L
Linus Torvalds 已提交
382 383

		WRT_REG_WORD(&reg->ctrl_status, 0x40);
384
		qla2xxx_read_window(reg, 32, fw->resp_dma_reg);
L
Linus Torvalds 已提交
385 386

		WRT_REG_WORD(&reg->ctrl_status, 0x50);
387
		qla2xxx_read_window(reg, 48, fw->dma_reg);
L
Linus Torvalds 已提交
388 389

		WRT_REG_WORD(&reg->ctrl_status, 0x00);
390
		dmp_reg = &reg->risc_hw;
A
Andrew Vasquez 已提交
391
		for (cnt = 0; cnt < sizeof(fw->risc_hdw_reg) / 2; cnt++)
392
			fw->risc_hdw_reg[cnt] = htons(RD_REG_WORD(dmp_reg++));
L
Linus Torvalds 已提交
393

A
Andrew Vasquez 已提交
394
		WRT_REG_WORD(&reg->pcr, 0x2000);
395
		qla2xxx_read_window(reg, 16, fw->risc_gp0_reg);
L
Linus Torvalds 已提交
396

A
Andrew Vasquez 已提交
397
		WRT_REG_WORD(&reg->pcr, 0x2200);
398
		qla2xxx_read_window(reg, 16, fw->risc_gp1_reg);
L
Linus Torvalds 已提交
399

A
Andrew Vasquez 已提交
400
		WRT_REG_WORD(&reg->pcr, 0x2400);
401
		qla2xxx_read_window(reg, 16, fw->risc_gp2_reg);
L
Linus Torvalds 已提交
402

A
Andrew Vasquez 已提交
403
		WRT_REG_WORD(&reg->pcr, 0x2600);
404
		qla2xxx_read_window(reg, 16, fw->risc_gp3_reg);
L
Linus Torvalds 已提交
405

A
Andrew Vasquez 已提交
406
		WRT_REG_WORD(&reg->pcr, 0x2800);
407
		qla2xxx_read_window(reg, 16, fw->risc_gp4_reg);
L
Linus Torvalds 已提交
408

A
Andrew Vasquez 已提交
409
		WRT_REG_WORD(&reg->pcr, 0x2A00);
410
		qla2xxx_read_window(reg, 16, fw->risc_gp5_reg);
L
Linus Torvalds 已提交
411

A
Andrew Vasquez 已提交
412
		WRT_REG_WORD(&reg->pcr, 0x2C00);
413
		qla2xxx_read_window(reg, 16, fw->risc_gp6_reg);
L
Linus Torvalds 已提交
414

A
Andrew Vasquez 已提交
415
		WRT_REG_WORD(&reg->pcr, 0x2E00);
416
		qla2xxx_read_window(reg, 16, fw->risc_gp7_reg);
L
Linus Torvalds 已提交
417

A
Andrew Vasquez 已提交
418
		WRT_REG_WORD(&reg->ctrl_status, 0x10);
419
		qla2xxx_read_window(reg, 64, fw->frame_buf_hdw_reg);
L
Linus Torvalds 已提交
420

A
Andrew Vasquez 已提交
421
		WRT_REG_WORD(&reg->ctrl_status, 0x20);
422
		qla2xxx_read_window(reg, 64, fw->fpm_b0_reg);
L
Linus Torvalds 已提交
423

A
Andrew Vasquez 已提交
424
		WRT_REG_WORD(&reg->ctrl_status, 0x30);
425
		qla2xxx_read_window(reg, 64, fw->fpm_b1_reg);
L
Linus Torvalds 已提交
426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447

		/* Reset RISC. */
		WRT_REG_WORD(&reg->ctrl_status, CSR_ISP_SOFT_RESET);
		for (cnt = 0; cnt < 30000; cnt++) {
			if ((RD_REG_WORD(&reg->ctrl_status) &
			    CSR_ISP_SOFT_RESET) == 0)
				break;

			udelay(10);
		}
	}

	if (!IS_QLA2300(ha)) {
		for (cnt = 30000; RD_MAILBOX_REG(ha, reg, 0) != 0 &&
		    rval == QLA_SUCCESS; cnt--) {
			if (cnt)
				udelay(100);
			else
				rval = QLA_FUNCTION_TIMEOUT;
		}
	}

448 449 450 451
	/* Get RISC SRAM. */
	if (rval == QLA_SUCCESS)
		rval = qla2xxx_dump_ram(ha, 0x800, fw->risc_ram,
		    sizeof(fw->risc_ram) / 2, &nxt);
L
Linus Torvalds 已提交
452

453 454 455 456
	/* Get stack SRAM. */
	if (rval == QLA_SUCCESS)
		rval = qla2xxx_dump_ram(ha, 0x10000, fw->stack_ram,
		    sizeof(fw->stack_ram) / 2, &nxt);
L
Linus Torvalds 已提交
457

458 459 460 461
	/* Get data SRAM. */
	if (rval == QLA_SUCCESS)
		rval = qla2xxx_dump_ram(ha, 0x11000, fw->data_ram,
		    ha->fw_memory_size - 0x11000 + 1, &nxt);
L
Linus Torvalds 已提交
462

463
	if (rval == QLA_SUCCESS)
464
		qla2xxx_copy_queues(vha, nxt);
465

L
Linus Torvalds 已提交
466 467 468
	if (rval != QLA_SUCCESS) {
		qla_printk(KERN_WARNING, ha,
		    "Failed to dump firmware (%x)!!!\n", rval);
469
		ha->fw_dumped = 0;
L
Linus Torvalds 已提交
470 471 472 473

	} else {
		qla_printk(KERN_INFO, ha,
		    "Firmware dump saved to temp buffer (%ld/%p).\n",
474
		    vha->host_no, ha->fw_dump);
475
		ha->fw_dumped = 1;
L
Linus Torvalds 已提交
476 477 478 479 480 481 482 483 484 485 486 487 488
	}

qla2300_fw_dump_failed:
	if (!hardware_locked)
		spin_unlock_irqrestore(&ha->hardware_lock, flags);
}

/**
 * qla2100_fw_dump() - Dumps binary data from the 2100/2200 firmware.
 * @ha: HA context
 * @hardware_locked: Called with the hardware_lock
 */
void
489
qla2100_fw_dump(scsi_qla_host_t *vha, int hardware_locked)
L
Linus Torvalds 已提交
490 491 492 493 494
{
	int		rval;
	uint32_t	cnt, timer;
	uint16_t	risc_address;
	uint16_t	mb0, mb2;
495
	struct qla_hw_data *ha = vha->hw;
496
	struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
L
Linus Torvalds 已提交
497 498 499 500 501 502 503 504 505 506 507
	uint16_t __iomem *dmp_reg;
	unsigned long	flags;
	struct qla2100_fw_dump	*fw;

	risc_address = 0;
	mb0 = mb2 = 0;
	flags = 0;

	if (!hardware_locked)
		spin_lock_irqsave(&ha->hardware_lock, flags);

508
	if (!ha->fw_dump) {
L
Linus Torvalds 已提交
509
		qla_printk(KERN_WARNING, ha,
510
		    "No buffer available for dump!!!\n");
L
Linus Torvalds 已提交
511 512 513
		goto qla2100_fw_dump_failed;
	}

514
	if (ha->fw_dumped) {
L
Linus Torvalds 已提交
515
		qla_printk(KERN_WARNING, ha,
516 517
		    "Firmware has been previously dumped (%p) -- ignoring "
		    "request...\n", ha->fw_dump);
L
Linus Torvalds 已提交
518 519
		goto qla2100_fw_dump_failed;
	}
520 521
	fw = &ha->fw_dump->isp.isp21;
	qla2xxx_prep_dump(ha, ha->fw_dump);
L
Linus Torvalds 已提交
522 523

	rval = QLA_SUCCESS;
524
	fw->hccr = htons(RD_REG_WORD(&reg->hccr));
L
Linus Torvalds 已提交
525 526

	/* Pause RISC. */
A
Andrew Vasquez 已提交
527
	WRT_REG_WORD(&reg->hccr, HCCR_PAUSE_RISC);
L
Linus Torvalds 已提交
528 529 530 531 532 533 534 535
	for (cnt = 30000; (RD_REG_WORD(&reg->hccr) & HCCR_RISC_PAUSE) == 0 &&
	    rval == QLA_SUCCESS; cnt--) {
		if (cnt)
			udelay(100);
		else
			rval = QLA_FUNCTION_TIMEOUT;
	}
	if (rval == QLA_SUCCESS) {
536
		dmp_reg = &reg->flash_address;
A
Andrew Vasquez 已提交
537
		for (cnt = 0; cnt < sizeof(fw->pbiu_reg) / 2; cnt++)
538
			fw->pbiu_reg[cnt] = htons(RD_REG_WORD(dmp_reg++));
L
Linus Torvalds 已提交
539

540
		dmp_reg = &reg->u.isp2100.mailbox0;
L
Linus Torvalds 已提交
541
		for (cnt = 0; cnt < ha->mbx_count; cnt++) {
542 543 544
			if (cnt == 8)
				dmp_reg = &reg->u_end.isp2200.mailbox8;

545
			fw->mailbox_reg[cnt] = htons(RD_REG_WORD(dmp_reg++));
L
Linus Torvalds 已提交
546 547
		}

548
		dmp_reg = &reg->u.isp2100.unused_2[0];
A
Andrew Vasquez 已提交
549
		for (cnt = 0; cnt < sizeof(fw->dma_reg) / 2; cnt++)
550
			fw->dma_reg[cnt] = htons(RD_REG_WORD(dmp_reg++));
L
Linus Torvalds 已提交
551 552

		WRT_REG_WORD(&reg->ctrl_status, 0x00);
553
		dmp_reg = &reg->risc_hw;
A
Andrew Vasquez 已提交
554
		for (cnt = 0; cnt < sizeof(fw->risc_hdw_reg) / 2; cnt++)
555
			fw->risc_hdw_reg[cnt] = htons(RD_REG_WORD(dmp_reg++));
L
Linus Torvalds 已提交
556

A
Andrew Vasquez 已提交
557
		WRT_REG_WORD(&reg->pcr, 0x2000);
558
		qla2xxx_read_window(reg, 16, fw->risc_gp0_reg);
L
Linus Torvalds 已提交
559

A
Andrew Vasquez 已提交
560
		WRT_REG_WORD(&reg->pcr, 0x2100);
561
		qla2xxx_read_window(reg, 16, fw->risc_gp1_reg);
L
Linus Torvalds 已提交
562

A
Andrew Vasquez 已提交
563
		WRT_REG_WORD(&reg->pcr, 0x2200);
564
		qla2xxx_read_window(reg, 16, fw->risc_gp2_reg);
L
Linus Torvalds 已提交
565

A
Andrew Vasquez 已提交
566
		WRT_REG_WORD(&reg->pcr, 0x2300);
567
		qla2xxx_read_window(reg, 16, fw->risc_gp3_reg);
L
Linus Torvalds 已提交
568

A
Andrew Vasquez 已提交
569
		WRT_REG_WORD(&reg->pcr, 0x2400);
570
		qla2xxx_read_window(reg, 16, fw->risc_gp4_reg);
L
Linus Torvalds 已提交
571

A
Andrew Vasquez 已提交
572
		WRT_REG_WORD(&reg->pcr, 0x2500);
573
		qla2xxx_read_window(reg, 16, fw->risc_gp5_reg);
L
Linus Torvalds 已提交
574

A
Andrew Vasquez 已提交
575
		WRT_REG_WORD(&reg->pcr, 0x2600);
576
		qla2xxx_read_window(reg, 16, fw->risc_gp6_reg);
L
Linus Torvalds 已提交
577

A
Andrew Vasquez 已提交
578
		WRT_REG_WORD(&reg->pcr, 0x2700);
579
		qla2xxx_read_window(reg, 16, fw->risc_gp7_reg);
L
Linus Torvalds 已提交
580

A
Andrew Vasquez 已提交
581
		WRT_REG_WORD(&reg->ctrl_status, 0x10);
582
		qla2xxx_read_window(reg, 16, fw->frame_buf_hdw_reg);
L
Linus Torvalds 已提交
583

A
Andrew Vasquez 已提交
584
		WRT_REG_WORD(&reg->ctrl_status, 0x20);
585
		qla2xxx_read_window(reg, 64, fw->fpm_b0_reg);
L
Linus Torvalds 已提交
586

A
Andrew Vasquez 已提交
587
		WRT_REG_WORD(&reg->ctrl_status, 0x30);
588
		qla2xxx_read_window(reg, 64, fw->fpm_b1_reg);
L
Linus Torvalds 已提交
589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605

		/* Reset the ISP. */
		WRT_REG_WORD(&reg->ctrl_status, CSR_ISP_SOFT_RESET);
	}

	for (cnt = 30000; RD_MAILBOX_REG(ha, reg, 0) != 0 &&
	    rval == QLA_SUCCESS; cnt--) {
		if (cnt)
			udelay(100);
		else
			rval = QLA_FUNCTION_TIMEOUT;
	}

	/* Pause RISC. */
	if (rval == QLA_SUCCESS && (IS_QLA2200(ha) || (IS_QLA2100(ha) &&
	    (RD_REG_WORD(&reg->mctr) & (BIT_1 | BIT_0)) != 0))) {

A
Andrew Vasquez 已提交
606
		WRT_REG_WORD(&reg->hccr, HCCR_PAUSE_RISC);
L
Linus Torvalds 已提交
607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662
		for (cnt = 30000;
		    (RD_REG_WORD(&reg->hccr) & HCCR_RISC_PAUSE) == 0 &&
		    rval == QLA_SUCCESS; cnt--) {
			if (cnt)
				udelay(100);
			else
				rval = QLA_FUNCTION_TIMEOUT;
		}
		if (rval == QLA_SUCCESS) {
			/* Set memory configuration and timing. */
			if (IS_QLA2100(ha))
				WRT_REG_WORD(&reg->mctr, 0xf1);
			else
				WRT_REG_WORD(&reg->mctr, 0xf2);
			RD_REG_WORD(&reg->mctr);	/* PCI Posting. */

			/* Release RISC. */
			WRT_REG_WORD(&reg->hccr, HCCR_RELEASE_RISC);
		}
	}

	if (rval == QLA_SUCCESS) {
		/* Get RISC SRAM. */
		risc_address = 0x1000;
 		WRT_MAILBOX_REG(ha, reg, 0, MBC_READ_RAM_WORD);
		clear_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags);
	}
	for (cnt = 0; cnt < sizeof(fw->risc_ram) / 2 && rval == QLA_SUCCESS;
	    cnt++, risc_address++) {
 		WRT_MAILBOX_REG(ha, reg, 1, risc_address);
		WRT_REG_WORD(&reg->hccr, HCCR_SET_HOST_INT);

		for (timer = 6000000; timer != 0; timer--) {
			/* Check for pending interrupts. */
			if (RD_REG_WORD(&reg->istatus) & ISR_RISC_INT) {
				if (RD_REG_WORD(&reg->semaphore) & BIT_0) {
					set_bit(MBX_INTERRUPT,
					    &ha->mbx_cmd_flags);

					mb0 = RD_MAILBOX_REG(ha, reg, 0);
					mb2 = RD_MAILBOX_REG(ha, reg, 2);

					WRT_REG_WORD(&reg->semaphore, 0);
					WRT_REG_WORD(&reg->hccr,
					    HCCR_CLR_RISC_INT);
					RD_REG_WORD(&reg->hccr);
					break;
				}
				WRT_REG_WORD(&reg->hccr, HCCR_CLR_RISC_INT);
				RD_REG_WORD(&reg->hccr);
			}
			udelay(5);
		}

		if (test_and_clear_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags)) {
			rval = mb0 & MBS_MASK;
663
			fw->risc_ram[cnt] = htons(mb2);
L
Linus Torvalds 已提交
664 665 666 667 668
		} else {
			rval = QLA_FUNCTION_FAILED;
		}
	}

669
	if (rval == QLA_SUCCESS)
670
		qla2xxx_copy_queues(vha, &fw->risc_ram[cnt]);
671

L
Linus Torvalds 已提交
672 673 674
	if (rval != QLA_SUCCESS) {
		qla_printk(KERN_WARNING, ha,
		    "Failed to dump firmware (%x)!!!\n", rval);
675
		ha->fw_dumped = 0;
L
Linus Torvalds 已提交
676 677 678 679

	} else {
		qla_printk(KERN_INFO, ha,
		    "Firmware dump saved to temp buffer (%ld/%p).\n",
680
		    vha->host_no, ha->fw_dump);
681
		ha->fw_dumped = 1;
L
Linus Torvalds 已提交
682 683 684 685 686 687 688
	}

qla2100_fw_dump_failed:
	if (!hardware_locked)
		spin_unlock_irqrestore(&ha->hardware_lock, flags);
}

689
void
690
qla24xx_fw_dump(scsi_qla_host_t *vha, int hardware_locked)
691 692
{
	int		rval;
693
	uint32_t	cnt;
694
	uint32_t	risc_address;
695
	struct qla_hw_data *ha = vha->hw;
696 697 698 699 700 701 702
	struct device_reg_24xx __iomem *reg = &ha->iobase->isp24;
	uint32_t __iomem *dmp_reg;
	uint32_t	*iter_reg;
	uint16_t __iomem *mbx_reg;
	unsigned long	flags;
	struct qla24xx_fw_dump *fw;
	uint32_t	ext_mem_cnt;
703
	void		*nxt;
704 705 706 707 708 709 710

	risc_address = ext_mem_cnt = 0;
	flags = 0;

	if (!hardware_locked)
		spin_lock_irqsave(&ha->hardware_lock, flags);

711
	if (!ha->fw_dump) {
712 713 714 715 716 717 718 719
		qla_printk(KERN_WARNING, ha,
		    "No buffer available for dump!!!\n");
		goto qla24xx_fw_dump_failed;
	}

	if (ha->fw_dumped) {
		qla_printk(KERN_WARNING, ha,
		    "Firmware has been previously dumped (%p) -- ignoring "
720
		    "request...\n", ha->fw_dump);
721 722
		goto qla24xx_fw_dump_failed;
	}
723 724
	fw = &ha->fw_dump->isp.isp24;
	qla2xxx_prep_dump(ha, ha->fw_dump);
725

726
	fw->host_status = htonl(RD_REG_DWORD(&reg->host_status));
727 728

	/* Pause RISC. */
729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908
	rval = qla24xx_pause_risc(reg);
	if (rval != QLA_SUCCESS)
		goto qla24xx_fw_dump_failed_0;

	/* Host interface registers. */
	dmp_reg = &reg->flash_addr;
	for (cnt = 0; cnt < sizeof(fw->host_reg) / 4; cnt++)
		fw->host_reg[cnt] = htonl(RD_REG_DWORD(dmp_reg++));

	/* Disable interrupts. */
	WRT_REG_DWORD(&reg->ictrl, 0);
	RD_REG_DWORD(&reg->ictrl);

	/* Shadow registers. */
	WRT_REG_DWORD(&reg->iobase_addr, 0x0F70);
	RD_REG_DWORD(&reg->iobase_addr);
	WRT_REG_DWORD(&reg->iobase_select, 0xB0000000);
	fw->shadow_reg[0] = htonl(RD_REG_DWORD(&reg->iobase_sdata));

	WRT_REG_DWORD(&reg->iobase_select, 0xB0100000);
	fw->shadow_reg[1] = htonl(RD_REG_DWORD(&reg->iobase_sdata));

	WRT_REG_DWORD(&reg->iobase_select, 0xB0200000);
	fw->shadow_reg[2] = htonl(RD_REG_DWORD(&reg->iobase_sdata));

	WRT_REG_DWORD(&reg->iobase_select, 0xB0300000);
	fw->shadow_reg[3] = htonl(RD_REG_DWORD(&reg->iobase_sdata));

	WRT_REG_DWORD(&reg->iobase_select, 0xB0400000);
	fw->shadow_reg[4] = htonl(RD_REG_DWORD(&reg->iobase_sdata));

	WRT_REG_DWORD(&reg->iobase_select, 0xB0500000);
	fw->shadow_reg[5] = htonl(RD_REG_DWORD(&reg->iobase_sdata));

	WRT_REG_DWORD(&reg->iobase_select, 0xB0600000);
	fw->shadow_reg[6] = htonl(RD_REG_DWORD(&reg->iobase_sdata));

	/* Mailbox registers. */
	mbx_reg = &reg->mailbox0;
	for (cnt = 0; cnt < sizeof(fw->mailbox_reg) / 2; cnt++)
		fw->mailbox_reg[cnt] = htons(RD_REG_WORD(mbx_reg++));

	/* Transfer sequence registers. */
	iter_reg = fw->xseq_gp_reg;
	iter_reg = qla24xx_read_window(reg, 0xBF00, 16, iter_reg);
	iter_reg = qla24xx_read_window(reg, 0xBF10, 16, iter_reg);
	iter_reg = qla24xx_read_window(reg, 0xBF20, 16, iter_reg);
	iter_reg = qla24xx_read_window(reg, 0xBF30, 16, iter_reg);
	iter_reg = qla24xx_read_window(reg, 0xBF40, 16, iter_reg);
	iter_reg = qla24xx_read_window(reg, 0xBF50, 16, iter_reg);
	iter_reg = qla24xx_read_window(reg, 0xBF60, 16, iter_reg);
	qla24xx_read_window(reg, 0xBF70, 16, iter_reg);

	qla24xx_read_window(reg, 0xBFE0, 16, fw->xseq_0_reg);
	qla24xx_read_window(reg, 0xBFF0, 16, fw->xseq_1_reg);

	/* Receive sequence registers. */
	iter_reg = fw->rseq_gp_reg;
	iter_reg = qla24xx_read_window(reg, 0xFF00, 16, iter_reg);
	iter_reg = qla24xx_read_window(reg, 0xFF10, 16, iter_reg);
	iter_reg = qla24xx_read_window(reg, 0xFF20, 16, iter_reg);
	iter_reg = qla24xx_read_window(reg, 0xFF30, 16, iter_reg);
	iter_reg = qla24xx_read_window(reg, 0xFF40, 16, iter_reg);
	iter_reg = qla24xx_read_window(reg, 0xFF50, 16, iter_reg);
	iter_reg = qla24xx_read_window(reg, 0xFF60, 16, iter_reg);
	qla24xx_read_window(reg, 0xFF70, 16, iter_reg);

	qla24xx_read_window(reg, 0xFFD0, 16, fw->rseq_0_reg);
	qla24xx_read_window(reg, 0xFFE0, 16, fw->rseq_1_reg);
	qla24xx_read_window(reg, 0xFFF0, 16, fw->rseq_2_reg);

	/* Command DMA registers. */
	qla24xx_read_window(reg, 0x7100, 16, fw->cmd_dma_reg);

	/* Queues. */
	iter_reg = fw->req0_dma_reg;
	iter_reg = qla24xx_read_window(reg, 0x7200, 8, iter_reg);
	dmp_reg = &reg->iobase_q;
	for (cnt = 0; cnt < 7; cnt++)
		*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));

	iter_reg = fw->resp0_dma_reg;
	iter_reg = qla24xx_read_window(reg, 0x7300, 8, iter_reg);
	dmp_reg = &reg->iobase_q;
	for (cnt = 0; cnt < 7; cnt++)
		*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));

	iter_reg = fw->req1_dma_reg;
	iter_reg = qla24xx_read_window(reg, 0x7400, 8, iter_reg);
	dmp_reg = &reg->iobase_q;
	for (cnt = 0; cnt < 7; cnt++)
		*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));

	/* Transmit DMA registers. */
	iter_reg = fw->xmt0_dma_reg;
	iter_reg = qla24xx_read_window(reg, 0x7600, 16, iter_reg);
	qla24xx_read_window(reg, 0x7610, 16, iter_reg);

	iter_reg = fw->xmt1_dma_reg;
	iter_reg = qla24xx_read_window(reg, 0x7620, 16, iter_reg);
	qla24xx_read_window(reg, 0x7630, 16, iter_reg);

	iter_reg = fw->xmt2_dma_reg;
	iter_reg = qla24xx_read_window(reg, 0x7640, 16, iter_reg);
	qla24xx_read_window(reg, 0x7650, 16, iter_reg);

	iter_reg = fw->xmt3_dma_reg;
	iter_reg = qla24xx_read_window(reg, 0x7660, 16, iter_reg);
	qla24xx_read_window(reg, 0x7670, 16, iter_reg);

	iter_reg = fw->xmt4_dma_reg;
	iter_reg = qla24xx_read_window(reg, 0x7680, 16, iter_reg);
	qla24xx_read_window(reg, 0x7690, 16, iter_reg);

	qla24xx_read_window(reg, 0x76A0, 16, fw->xmt_data_dma_reg);

	/* Receive DMA registers. */
	iter_reg = fw->rcvt0_data_dma_reg;
	iter_reg = qla24xx_read_window(reg, 0x7700, 16, iter_reg);
	qla24xx_read_window(reg, 0x7710, 16, iter_reg);

	iter_reg = fw->rcvt1_data_dma_reg;
	iter_reg = qla24xx_read_window(reg, 0x7720, 16, iter_reg);
	qla24xx_read_window(reg, 0x7730, 16, iter_reg);

	/* RISC registers. */
	iter_reg = fw->risc_gp_reg;
	iter_reg = qla24xx_read_window(reg, 0x0F00, 16, iter_reg);
	iter_reg = qla24xx_read_window(reg, 0x0F10, 16, iter_reg);
	iter_reg = qla24xx_read_window(reg, 0x0F20, 16, iter_reg);
	iter_reg = qla24xx_read_window(reg, 0x0F30, 16, iter_reg);
	iter_reg = qla24xx_read_window(reg, 0x0F40, 16, iter_reg);
	iter_reg = qla24xx_read_window(reg, 0x0F50, 16, iter_reg);
	iter_reg = qla24xx_read_window(reg, 0x0F60, 16, iter_reg);
	qla24xx_read_window(reg, 0x0F70, 16, iter_reg);

	/* Local memory controller registers. */
	iter_reg = fw->lmc_reg;
	iter_reg = qla24xx_read_window(reg, 0x3000, 16, iter_reg);
	iter_reg = qla24xx_read_window(reg, 0x3010, 16, iter_reg);
	iter_reg = qla24xx_read_window(reg, 0x3020, 16, iter_reg);
	iter_reg = qla24xx_read_window(reg, 0x3030, 16, iter_reg);
	iter_reg = qla24xx_read_window(reg, 0x3040, 16, iter_reg);
	iter_reg = qla24xx_read_window(reg, 0x3050, 16, iter_reg);
	qla24xx_read_window(reg, 0x3060, 16, iter_reg);

	/* Fibre Protocol Module registers. */
	iter_reg = fw->fpm_hdw_reg;
	iter_reg = qla24xx_read_window(reg, 0x4000, 16, iter_reg);
	iter_reg = qla24xx_read_window(reg, 0x4010, 16, iter_reg);
	iter_reg = qla24xx_read_window(reg, 0x4020, 16, iter_reg);
	iter_reg = qla24xx_read_window(reg, 0x4030, 16, iter_reg);
	iter_reg = qla24xx_read_window(reg, 0x4040, 16, iter_reg);
	iter_reg = qla24xx_read_window(reg, 0x4050, 16, iter_reg);
	iter_reg = qla24xx_read_window(reg, 0x4060, 16, iter_reg);
	iter_reg = qla24xx_read_window(reg, 0x4070, 16, iter_reg);
	iter_reg = qla24xx_read_window(reg, 0x4080, 16, iter_reg);
	iter_reg = qla24xx_read_window(reg, 0x4090, 16, iter_reg);
	iter_reg = qla24xx_read_window(reg, 0x40A0, 16, iter_reg);
	qla24xx_read_window(reg, 0x40B0, 16, iter_reg);

	/* Frame Buffer registers. */
	iter_reg = fw->fb_hdw_reg;
	iter_reg = qla24xx_read_window(reg, 0x6000, 16, iter_reg);
	iter_reg = qla24xx_read_window(reg, 0x6010, 16, iter_reg);
	iter_reg = qla24xx_read_window(reg, 0x6020, 16, iter_reg);
	iter_reg = qla24xx_read_window(reg, 0x6030, 16, iter_reg);
	iter_reg = qla24xx_read_window(reg, 0x6040, 16, iter_reg);
	iter_reg = qla24xx_read_window(reg, 0x6100, 16, iter_reg);
	iter_reg = qla24xx_read_window(reg, 0x6130, 16, iter_reg);
	iter_reg = qla24xx_read_window(reg, 0x6150, 16, iter_reg);
	iter_reg = qla24xx_read_window(reg, 0x6170, 16, iter_reg);
	iter_reg = qla24xx_read_window(reg, 0x6190, 16, iter_reg);
	qla24xx_read_window(reg, 0x61B0, 16, iter_reg);

	rval = qla24xx_soft_reset(ha);
	if (rval != QLA_SUCCESS)
		goto qla24xx_fw_dump_failed_0;

	rval = qla24xx_dump_memory(ha, fw->code_ram, sizeof(fw->code_ram),
909
	    &nxt);
910 911 912
	if (rval != QLA_SUCCESS)
		goto qla24xx_fw_dump_failed_0;

913
	nxt = qla2xxx_copy_queues(vha, nxt);
914 915 916 917
	if (ha->eft)
		memcpy(nxt, ha->eft, ntohl(ha->fw_dump->eft_size));

qla24xx_fw_dump_failed_0:
918 919 920 921
	if (rval != QLA_SUCCESS) {
		qla_printk(KERN_WARNING, ha,
		    "Failed to dump firmware (%x)!!!\n", rval);
		ha->fw_dumped = 0;
922

923 924 925
	} else {
		qla_printk(KERN_INFO, ha,
		    "Firmware dump saved to temp buffer (%ld/%p).\n",
926
		    vha->host_no, ha->fw_dump);
927 928
		ha->fw_dumped = 1;
	}
929

930 931 932 933
qla24xx_fw_dump_failed:
	if (!hardware_locked)
		spin_unlock_irqrestore(&ha->hardware_lock, flags);
}
934

935
void
936
qla25xx_fw_dump(scsi_qla_host_t *vha, int hardware_locked)
937 938 939 940
{
	int		rval;
	uint32_t	cnt;
	uint32_t	risc_address;
941
	struct qla_hw_data *ha = vha->hw;
942 943 944 945 946 947 948 949
	struct device_reg_24xx __iomem *reg = &ha->iobase->isp24;
	uint32_t __iomem *dmp_reg;
	uint32_t	*iter_reg;
	uint16_t __iomem *mbx_reg;
	unsigned long	flags;
	struct qla25xx_fw_dump *fw;
	uint32_t	ext_mem_cnt;
	void		*nxt;
950
	struct qla2xxx_fce_chain *fcec;
951

952 953
	risc_address = ext_mem_cnt = 0;
	flags = 0;
954

955 956
	if (!hardware_locked)
		spin_lock_irqsave(&ha->hardware_lock, flags);
957

958 959 960 961 962
	if (!ha->fw_dump) {
		qla_printk(KERN_WARNING, ha,
		    "No buffer available for dump!!!\n");
		goto qla25xx_fw_dump_failed;
	}
963

964 965 966 967 968 969 970 971
	if (ha->fw_dumped) {
		qla_printk(KERN_WARNING, ha,
		    "Firmware has been previously dumped (%p) -- ignoring "
		    "request...\n", ha->fw_dump);
		goto qla25xx_fw_dump_failed;
	}
	fw = &ha->fw_dump->isp.isp25;
	qla2xxx_prep_dump(ha, ha->fw_dump);
972
	ha->fw_dump->version = __constant_htonl(2);
973

974
	fw->host_status = htonl(RD_REG_DWORD(&reg->host_status));
975

976
	/* Pause RISC. */
977 978 979 980
	rval = qla24xx_pause_risc(reg);
	if (rval != QLA_SUCCESS)
		goto qla25xx_fw_dump_failed_0;

981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997
	/* Host/Risc registers. */
	iter_reg = fw->host_risc_reg;
	iter_reg = qla24xx_read_window(reg, 0x7000, 16, iter_reg);
	qla24xx_read_window(reg, 0x7010, 16, iter_reg);

	/* PCIe registers. */
	WRT_REG_DWORD(&reg->iobase_addr, 0x7C00);
	RD_REG_DWORD(&reg->iobase_addr);
	WRT_REG_DWORD(&reg->iobase_window, 0x01);
	dmp_reg = &reg->iobase_c4;
	fw->pcie_regs[0] = htonl(RD_REG_DWORD(dmp_reg++));
	fw->pcie_regs[1] = htonl(RD_REG_DWORD(dmp_reg++));
	fw->pcie_regs[2] = htonl(RD_REG_DWORD(dmp_reg));
	fw->pcie_regs[3] = htonl(RD_REG_DWORD(&reg->iobase_window));
	WRT_REG_DWORD(&reg->iobase_window, 0x00);
	RD_REG_DWORD(&reg->iobase_window);

998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216
	/* Host interface registers. */
	dmp_reg = &reg->flash_addr;
	for (cnt = 0; cnt < sizeof(fw->host_reg) / 4; cnt++)
		fw->host_reg[cnt] = htonl(RD_REG_DWORD(dmp_reg++));

	/* Disable interrupts. */
	WRT_REG_DWORD(&reg->ictrl, 0);
	RD_REG_DWORD(&reg->ictrl);

	/* Shadow registers. */
	WRT_REG_DWORD(&reg->iobase_addr, 0x0F70);
	RD_REG_DWORD(&reg->iobase_addr);
	WRT_REG_DWORD(&reg->iobase_select, 0xB0000000);
	fw->shadow_reg[0] = htonl(RD_REG_DWORD(&reg->iobase_sdata));

	WRT_REG_DWORD(&reg->iobase_select, 0xB0100000);
	fw->shadow_reg[1] = htonl(RD_REG_DWORD(&reg->iobase_sdata));

	WRT_REG_DWORD(&reg->iobase_select, 0xB0200000);
	fw->shadow_reg[2] = htonl(RD_REG_DWORD(&reg->iobase_sdata));

	WRT_REG_DWORD(&reg->iobase_select, 0xB0300000);
	fw->shadow_reg[3] = htonl(RD_REG_DWORD(&reg->iobase_sdata));

	WRT_REG_DWORD(&reg->iobase_select, 0xB0400000);
	fw->shadow_reg[4] = htonl(RD_REG_DWORD(&reg->iobase_sdata));

	WRT_REG_DWORD(&reg->iobase_select, 0xB0500000);
	fw->shadow_reg[5] = htonl(RD_REG_DWORD(&reg->iobase_sdata));

	WRT_REG_DWORD(&reg->iobase_select, 0xB0600000);
	fw->shadow_reg[6] = htonl(RD_REG_DWORD(&reg->iobase_sdata));

	WRT_REG_DWORD(&reg->iobase_select, 0xB0700000);
	fw->shadow_reg[7] = htonl(RD_REG_DWORD(&reg->iobase_sdata));

	WRT_REG_DWORD(&reg->iobase_select, 0xB0800000);
	fw->shadow_reg[8] = htonl(RD_REG_DWORD(&reg->iobase_sdata));

	WRT_REG_DWORD(&reg->iobase_select, 0xB0900000);
	fw->shadow_reg[9] = htonl(RD_REG_DWORD(&reg->iobase_sdata));

	WRT_REG_DWORD(&reg->iobase_select, 0xB0A00000);
	fw->shadow_reg[10] = htonl(RD_REG_DWORD(&reg->iobase_sdata));

	/* RISC I/O register. */
	WRT_REG_DWORD(&reg->iobase_addr, 0x0010);
	fw->risc_io_reg = htonl(RD_REG_DWORD(&reg->iobase_window));

	/* Mailbox registers. */
	mbx_reg = &reg->mailbox0;
	for (cnt = 0; cnt < sizeof(fw->mailbox_reg) / 2; cnt++)
		fw->mailbox_reg[cnt] = htons(RD_REG_WORD(mbx_reg++));

	/* Transfer sequence registers. */
	iter_reg = fw->xseq_gp_reg;
	iter_reg = qla24xx_read_window(reg, 0xBF00, 16, iter_reg);
	iter_reg = qla24xx_read_window(reg, 0xBF10, 16, iter_reg);
	iter_reg = qla24xx_read_window(reg, 0xBF20, 16, iter_reg);
	iter_reg = qla24xx_read_window(reg, 0xBF30, 16, iter_reg);
	iter_reg = qla24xx_read_window(reg, 0xBF40, 16, iter_reg);
	iter_reg = qla24xx_read_window(reg, 0xBF50, 16, iter_reg);
	iter_reg = qla24xx_read_window(reg, 0xBF60, 16, iter_reg);
	qla24xx_read_window(reg, 0xBF70, 16, iter_reg);

	iter_reg = fw->xseq_0_reg;
	iter_reg = qla24xx_read_window(reg, 0xBFC0, 16, iter_reg);
	iter_reg = qla24xx_read_window(reg, 0xBFD0, 16, iter_reg);
	qla24xx_read_window(reg, 0xBFE0, 16, iter_reg);

	qla24xx_read_window(reg, 0xBFF0, 16, fw->xseq_1_reg);

	/* Receive sequence registers. */
	iter_reg = fw->rseq_gp_reg;
	iter_reg = qla24xx_read_window(reg, 0xFF00, 16, iter_reg);
	iter_reg = qla24xx_read_window(reg, 0xFF10, 16, iter_reg);
	iter_reg = qla24xx_read_window(reg, 0xFF20, 16, iter_reg);
	iter_reg = qla24xx_read_window(reg, 0xFF30, 16, iter_reg);
	iter_reg = qla24xx_read_window(reg, 0xFF40, 16, iter_reg);
	iter_reg = qla24xx_read_window(reg, 0xFF50, 16, iter_reg);
	iter_reg = qla24xx_read_window(reg, 0xFF60, 16, iter_reg);
	qla24xx_read_window(reg, 0xFF70, 16, iter_reg);

	iter_reg = fw->rseq_0_reg;
	iter_reg = qla24xx_read_window(reg, 0xFFC0, 16, iter_reg);
	qla24xx_read_window(reg, 0xFFD0, 16, iter_reg);

	qla24xx_read_window(reg, 0xFFE0, 16, fw->rseq_1_reg);
	qla24xx_read_window(reg, 0xFFF0, 16, fw->rseq_2_reg);

	/* Auxiliary sequence registers. */
	iter_reg = fw->aseq_gp_reg;
	iter_reg = qla24xx_read_window(reg, 0xB000, 16, iter_reg);
	iter_reg = qla24xx_read_window(reg, 0xB010, 16, iter_reg);
	iter_reg = qla24xx_read_window(reg, 0xB020, 16, iter_reg);
	iter_reg = qla24xx_read_window(reg, 0xB030, 16, iter_reg);
	iter_reg = qla24xx_read_window(reg, 0xB040, 16, iter_reg);
	iter_reg = qla24xx_read_window(reg, 0xB050, 16, iter_reg);
	iter_reg = qla24xx_read_window(reg, 0xB060, 16, iter_reg);
	qla24xx_read_window(reg, 0xB070, 16, iter_reg);

	iter_reg = fw->aseq_0_reg;
	iter_reg = qla24xx_read_window(reg, 0xB0C0, 16, iter_reg);
	qla24xx_read_window(reg, 0xB0D0, 16, iter_reg);

	qla24xx_read_window(reg, 0xB0E0, 16, fw->aseq_1_reg);
	qla24xx_read_window(reg, 0xB0F0, 16, fw->aseq_2_reg);

	/* Command DMA registers. */
	qla24xx_read_window(reg, 0x7100, 16, fw->cmd_dma_reg);

	/* Queues. */
	iter_reg = fw->req0_dma_reg;
	iter_reg = qla24xx_read_window(reg, 0x7200, 8, iter_reg);
	dmp_reg = &reg->iobase_q;
	for (cnt = 0; cnt < 7; cnt++)
		*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));

	iter_reg = fw->resp0_dma_reg;
	iter_reg = qla24xx_read_window(reg, 0x7300, 8, iter_reg);
	dmp_reg = &reg->iobase_q;
	for (cnt = 0; cnt < 7; cnt++)
		*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));

	iter_reg = fw->req1_dma_reg;
	iter_reg = qla24xx_read_window(reg, 0x7400, 8, iter_reg);
	dmp_reg = &reg->iobase_q;
	for (cnt = 0; cnt < 7; cnt++)
		*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));

	/* Transmit DMA registers. */
	iter_reg = fw->xmt0_dma_reg;
	iter_reg = qla24xx_read_window(reg, 0x7600, 16, iter_reg);
	qla24xx_read_window(reg, 0x7610, 16, iter_reg);

	iter_reg = fw->xmt1_dma_reg;
	iter_reg = qla24xx_read_window(reg, 0x7620, 16, iter_reg);
	qla24xx_read_window(reg, 0x7630, 16, iter_reg);

	iter_reg = fw->xmt2_dma_reg;
	iter_reg = qla24xx_read_window(reg, 0x7640, 16, iter_reg);
	qla24xx_read_window(reg, 0x7650, 16, iter_reg);

	iter_reg = fw->xmt3_dma_reg;
	iter_reg = qla24xx_read_window(reg, 0x7660, 16, iter_reg);
	qla24xx_read_window(reg, 0x7670, 16, iter_reg);

	iter_reg = fw->xmt4_dma_reg;
	iter_reg = qla24xx_read_window(reg, 0x7680, 16, iter_reg);
	qla24xx_read_window(reg, 0x7690, 16, iter_reg);

	qla24xx_read_window(reg, 0x76A0, 16, fw->xmt_data_dma_reg);

	/* Receive DMA registers. */
	iter_reg = fw->rcvt0_data_dma_reg;
	iter_reg = qla24xx_read_window(reg, 0x7700, 16, iter_reg);
	qla24xx_read_window(reg, 0x7710, 16, iter_reg);

	iter_reg = fw->rcvt1_data_dma_reg;
	iter_reg = qla24xx_read_window(reg, 0x7720, 16, iter_reg);
	qla24xx_read_window(reg, 0x7730, 16, iter_reg);

	/* RISC registers. */
	iter_reg = fw->risc_gp_reg;
	iter_reg = qla24xx_read_window(reg, 0x0F00, 16, iter_reg);
	iter_reg = qla24xx_read_window(reg, 0x0F10, 16, iter_reg);
	iter_reg = qla24xx_read_window(reg, 0x0F20, 16, iter_reg);
	iter_reg = qla24xx_read_window(reg, 0x0F30, 16, iter_reg);
	iter_reg = qla24xx_read_window(reg, 0x0F40, 16, iter_reg);
	iter_reg = qla24xx_read_window(reg, 0x0F50, 16, iter_reg);
	iter_reg = qla24xx_read_window(reg, 0x0F60, 16, iter_reg);
	qla24xx_read_window(reg, 0x0F70, 16, iter_reg);

	/* Local memory controller registers. */
	iter_reg = fw->lmc_reg;
	iter_reg = qla24xx_read_window(reg, 0x3000, 16, iter_reg);
	iter_reg = qla24xx_read_window(reg, 0x3010, 16, iter_reg);
	iter_reg = qla24xx_read_window(reg, 0x3020, 16, iter_reg);
	iter_reg = qla24xx_read_window(reg, 0x3030, 16, iter_reg);
	iter_reg = qla24xx_read_window(reg, 0x3040, 16, iter_reg);
	iter_reg = qla24xx_read_window(reg, 0x3050, 16, iter_reg);
	iter_reg = qla24xx_read_window(reg, 0x3060, 16, iter_reg);
	qla24xx_read_window(reg, 0x3070, 16, iter_reg);

	/* Fibre Protocol Module registers. */
	iter_reg = fw->fpm_hdw_reg;
	iter_reg = qla24xx_read_window(reg, 0x4000, 16, iter_reg);
	iter_reg = qla24xx_read_window(reg, 0x4010, 16, iter_reg);
	iter_reg = qla24xx_read_window(reg, 0x4020, 16, iter_reg);
	iter_reg = qla24xx_read_window(reg, 0x4030, 16, iter_reg);
	iter_reg = qla24xx_read_window(reg, 0x4040, 16, iter_reg);
	iter_reg = qla24xx_read_window(reg, 0x4050, 16, iter_reg);
	iter_reg = qla24xx_read_window(reg, 0x4060, 16, iter_reg);
	iter_reg = qla24xx_read_window(reg, 0x4070, 16, iter_reg);
	iter_reg = qla24xx_read_window(reg, 0x4080, 16, iter_reg);
	iter_reg = qla24xx_read_window(reg, 0x4090, 16, iter_reg);
	iter_reg = qla24xx_read_window(reg, 0x40A0, 16, iter_reg);
	qla24xx_read_window(reg, 0x40B0, 16, iter_reg);

	/* Frame Buffer registers. */
	iter_reg = fw->fb_hdw_reg;
	iter_reg = qla24xx_read_window(reg, 0x6000, 16, iter_reg);
	iter_reg = qla24xx_read_window(reg, 0x6010, 16, iter_reg);
	iter_reg = qla24xx_read_window(reg, 0x6020, 16, iter_reg);
	iter_reg = qla24xx_read_window(reg, 0x6030, 16, iter_reg);
	iter_reg = qla24xx_read_window(reg, 0x6040, 16, iter_reg);
	iter_reg = qla24xx_read_window(reg, 0x6100, 16, iter_reg);
	iter_reg = qla24xx_read_window(reg, 0x6130, 16, iter_reg);
	iter_reg = qla24xx_read_window(reg, 0x6150, 16, iter_reg);
	iter_reg = qla24xx_read_window(reg, 0x6170, 16, iter_reg);
	iter_reg = qla24xx_read_window(reg, 0x6190, 16, iter_reg);
	iter_reg = qla24xx_read_window(reg, 0x61B0, 16, iter_reg);
	qla24xx_read_window(reg, 0x6F00, 16, iter_reg);

	rval = qla24xx_soft_reset(ha);
	if (rval != QLA_SUCCESS)
		goto qla25xx_fw_dump_failed_0;

	rval = qla24xx_dump_memory(ha, fw->code_ram, sizeof(fw->code_ram),
1217
	    &nxt);
1218 1219 1220
	if (rval != QLA_SUCCESS)
		goto qla25xx_fw_dump_failed_0;

1221
	/* Fibre Channel Trace Buffer. */
1222
	nxt = qla2xxx_copy_queues(vha, nxt);
1223 1224 1225
	if (ha->eft)
		memcpy(nxt, ha->eft, ntohl(ha->fw_dump->eft_size));

1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245
	/* Fibre Channel Event Buffer. */
	if (!ha->fce)
		goto qla25xx_fw_dump_failed_0;

	ha->fw_dump->version |= __constant_htonl(DUMP_CHAIN_VARIANT);

	fcec = nxt + ntohl(ha->fw_dump->eft_size);
	fcec->type = __constant_htonl(DUMP_CHAIN_FCE | DUMP_CHAIN_LAST);
	fcec->chain_size = htonl(sizeof(struct qla2xxx_fce_chain) +
	    fce_calc_size(ha->fce_bufs));
	fcec->size = htonl(fce_calc_size(ha->fce_bufs));
	fcec->addr_l = htonl(LSD(ha->fce_dma));
	fcec->addr_h = htonl(MSD(ha->fce_dma));

	iter_reg = fcec->eregs;
	for (cnt = 0; cnt < 8; cnt++)
		*iter_reg++ = htonl(ha->fce_mb[cnt]);

	memcpy(iter_reg, ha->fce, ntohl(fcec->size));

1246
qla25xx_fw_dump_failed_0:
1247 1248 1249 1250
	if (rval != QLA_SUCCESS) {
		qla_printk(KERN_WARNING, ha,
		    "Failed to dump firmware (%x)!!!\n", rval);
		ha->fw_dumped = 0;
1251 1252 1253 1254

	} else {
		qla_printk(KERN_INFO, ha,
		    "Firmware dump saved to temp buffer (%ld/%p).\n",
1255
		    vha->host_no, ha->fw_dump);
1256 1257 1258
		ha->fw_dumped = 1;
	}

1259
qla25xx_fw_dump_failed:
1260 1261 1262 1263
	if (!hardware_locked)
		spin_unlock_irqrestore(&ha->hardware_lock, flags);
}

L
Linus Torvalds 已提交
1264 1265 1266 1267
/****************************************************************************/
/*                         Driver Debug Functions.                          */
/****************************************************************************/

A
Andrew Vasquez 已提交
1268
void
1269
qla2x00_dump_regs(scsi_qla_host_t *vha)
L
Linus Torvalds 已提交
1270
{
1271
	int i;
1272
	struct qla_hw_data *ha = vha->hw;
1273
	struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
1274 1275 1276 1277 1278
	struct device_reg_24xx __iomem *reg24 = &ha->iobase->isp24;
	uint16_t __iomem *mbx_reg;

	mbx_reg = IS_FWI2_CAPABLE(ha) ? &reg24->mailbox0:
	    MAILBOX_REG(ha, reg, 0);
L
Linus Torvalds 已提交
1279 1280

	printk("Mailbox registers:\n");
1281
	for (i = 0; i < 6; i++)
1282
		printk("scsi(%ld): mbox %d 0x%04x \n", vha->host_no, i,
1283
		    RD_REG_WORD(mbx_reg++));
L
Linus Torvalds 已提交
1284 1285 1286 1287
}


void
A
Andrew Vasquez 已提交
1288
qla2x00_dump_buffer(uint8_t * b, uint32_t size)
L
Linus Torvalds 已提交
1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309
{
	uint32_t cnt;
	uint8_t c;

	printk(" 0   1   2   3   4   5   6   7   8   9  "
	    "Ah  Bh  Ch  Dh  Eh  Fh\n");
	printk("----------------------------------------"
	    "----------------------\n");

	for (cnt = 0; cnt < size;) {
		c = *b++;
		printk("%02x",(uint32_t) c);
		cnt++;
		if (!(cnt % 16))
			printk("\n");
		else
			printk("  ");
	}
	if (cnt % 16)
		printk("\n");
}