be37aa4b99
This patch fixes system hang/crash while firmware dump is attempted with Block MQ enabled in qla2xxx driver. Fix is to remove check in fw dump template entries for existing request and response queues so that full buffer size is calculated during template size calculation. Following stack trace is seen during firmware dump capture process [ 694.390588] qla2xxx [0000:81:00.0]-5003:11: ISP System Error - mbx1=4b1fh mbx2=10h mbx3=2ah mbx7=0h. [ 694.402336] BUG: unable to handle kernel paging request at ffffc90008c7b000 [ 694.402372] IP: memcpy_erms+0x6/0x10 [ 694.402386] PGD 105f01a067 [ 694.402386] PUD 85f89c067 [ 694.402398] PMD 10490cb067 [ 694.402409] PTE 0 [ 694.402421] [ 694.402437] Oops: 0002 [#1] PREEMPT SMP [ 694.402452] Modules linked in: netconsole configfs qla2xxx scsi_transport_fc nvme_fc nvme_fabrics bnep bluetooth rfkill xt_tcpudp unix_diag xt_multiport ip6table_filter ip6_tables iptable_filter ip_tables x_tables af_packet iscsi_ibft iscsi_boot_sysfs xfs libcrc32c ipmi_ssif sb_edac edac_core x86_pkg_temp_thermal intel_powerclamp coretemp kvm_intel kvm irqbypass igb crct10dif_pclmul crc32_pclmul ghash_clmulni_intel pcbc aesni_intel iTCO_wdt aes_x86_64 crypto_simd ptp iTCO_vendor_support glue_helper cryptd lpc_ich joydev i2c_i801 pcspkr ioatdma mei_me pps_core tpm_tis mei mfd_core acpi_power_meter tpm_tis_core ipmi_si ipmi_devintf tpm ipmi_msghandler shpchp wmi dca button acpi_pad btrfs xor uas usb_storage hid_generic usbhid raid6_pq crc32c_intel ast i2c_algo_bit drm_kms_helper syscopyarea sysfillrect [ 694.402692] sysimgblt fb_sys_fops xhci_pci ttm ehci_pci sr_mod xhci_hcd cdrom ehci_hcd drm usbcore sg [ 694.402730] CPU: 0 PID: 0 Comm: swapper/0 Not tainted 4.10.0-1-default+ #19 [ 694.402753] Hardware name: Supermicro X10DRi/X10DRi, BIOS 1.1a 10/16/2015 [ 694.402776] task: ffffffff81c0e4c0 task.stack: ffffffff81c00000 [ 694.402798] RIP: 0010:memcpy_erms+0x6/0x10 [ 694.402813] RSP: 0018:ffff88085fc03cd0 EFLAGS: 00210006 [ 694.402832] RAX: ffffc90008c7ae0c RBX: 0000000000000004 RCX: 000000000001fe0c [ 694.402856] RDX: 0000000000020000 RSI: ffff8810332c01f4 RDI: ffffc90008c7b000 [ 694.402879] RBP: ffff88085fc03d18 R08: 0000000000020000 R09: 0000000000279e0a [ 694.402903] R10: 0000000000000000 R11: f000000000000000 R12: ffff88085fc03d80 [ 694.402927] R13: ffffc90008a01000 R14: ffffc90008a056d4 R15: ffff881052ef17e0 [ 694.402951] FS: 0000000000000000(0000) GS:ffff88085fc00000(0000) knlGS:0000000000000000 [ 694.402977] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 694.403012] CR2: ffffc90008c7b000 CR3: 0000000001c09000 CR4: 00000000001406f0 [ 694.403036] Call Trace: [ 694.403047] <IRQ> [ 694.403072] ? qla27xx_fwdt_entry_t263+0x18e/0x380 [qla2xxx] [ 694.403099] qla27xx_walk_template+0x9d/0x1a0 [qla2xxx] [ 694.403124] qla27xx_fwdump+0x1f3/0x272 [qla2xxx] [ 694.403149] qla2x00_async_event+0xb08/0x1a50 [qla2xxx] [ 694.403169] ? enqueue_task_fair+0xa2/0x9d0 Signed-off-by: Mike Hernandez <michael.hernandez@cavium.com> Signed-off-by: Joe Carnuccio <joe.carnuccio@cavium.com> Signed-off-by: Himanshu Madhani <himanshu.madhani@cavium.com> Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
1000 lines
27 KiB
C
1000 lines
27 KiB
C
/*
|
|
* QLogic Fibre Channel HBA Driver
|
|
* Copyright (c) 2003-2014 QLogic Corporation
|
|
*
|
|
* See LICENSE.qla2xxx for copyright and licensing details.
|
|
*/
|
|
#include "qla_def.h"
|
|
#include "qla_tmpl.h"
|
|
|
|
/* note default template is in big endian */
|
|
static const uint32_t ql27xx_fwdt_default_template[] = {
|
|
0x63000000, 0xa4000000, 0x7c050000, 0x00000000,
|
|
0x30000000, 0x01000000, 0x00000000, 0xc0406eb4,
|
|
0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
|
0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
|
0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
|
0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
|
0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
|
0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
|
0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
|
0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
|
0x00000000, 0x04010000, 0x14000000, 0x00000000,
|
|
0x02000000, 0x44000000, 0x09010000, 0x10000000,
|
|
0x00000000, 0x02000000, 0x01010000, 0x1c000000,
|
|
0x00000000, 0x02000000, 0x00600000, 0x00000000,
|
|
0xc0000000, 0x01010000, 0x1c000000, 0x00000000,
|
|
0x02000000, 0x00600000, 0x00000000, 0xcc000000,
|
|
0x01010000, 0x1c000000, 0x00000000, 0x02000000,
|
|
0x10600000, 0x00000000, 0xd4000000, 0x01010000,
|
|
0x1c000000, 0x00000000, 0x02000000, 0x700f0000,
|
|
0x00000060, 0xf0000000, 0x00010000, 0x18000000,
|
|
0x00000000, 0x02000000, 0x00700000, 0x041000c0,
|
|
0x00010000, 0x18000000, 0x00000000, 0x02000000,
|
|
0x10700000, 0x041000c0, 0x00010000, 0x18000000,
|
|
0x00000000, 0x02000000, 0x40700000, 0x041000c0,
|
|
0x01010000, 0x1c000000, 0x00000000, 0x02000000,
|
|
0x007c0000, 0x01000000, 0xc0000000, 0x00010000,
|
|
0x18000000, 0x00000000, 0x02000000, 0x007c0000,
|
|
0x040300c4, 0x00010000, 0x18000000, 0x00000000,
|
|
0x02000000, 0x007c0000, 0x040100c0, 0x01010000,
|
|
0x1c000000, 0x00000000, 0x02000000, 0x007c0000,
|
|
0x00000000, 0xc0000000, 0x00010000, 0x18000000,
|
|
0x00000000, 0x02000000, 0x007c0000, 0x04200000,
|
|
0x0b010000, 0x18000000, 0x00000000, 0x02000000,
|
|
0x0c000000, 0x00000000, 0x02010000, 0x20000000,
|
|
0x00000000, 0x02000000, 0x700f0000, 0x040100fc,
|
|
0xf0000000, 0x000000b0, 0x02010000, 0x20000000,
|
|
0x00000000, 0x02000000, 0x700f0000, 0x040100fc,
|
|
0xf0000000, 0x000010b0, 0x02010000, 0x20000000,
|
|
0x00000000, 0x02000000, 0x700f0000, 0x040100fc,
|
|
0xf0000000, 0x000020b0, 0x02010000, 0x20000000,
|
|
0x00000000, 0x02000000, 0x700f0000, 0x040100fc,
|
|
0xf0000000, 0x000030b0, 0x02010000, 0x20000000,
|
|
0x00000000, 0x02000000, 0x700f0000, 0x040100fc,
|
|
0xf0000000, 0x000040b0, 0x02010000, 0x20000000,
|
|
0x00000000, 0x02000000, 0x700f0000, 0x040100fc,
|
|
0xf0000000, 0x000050b0, 0x02010000, 0x20000000,
|
|
0x00000000, 0x02000000, 0x700f0000, 0x040100fc,
|
|
0xf0000000, 0x000060b0, 0x02010000, 0x20000000,
|
|
0x00000000, 0x02000000, 0x700f0000, 0x040100fc,
|
|
0xf0000000, 0x000070b0, 0x02010000, 0x20000000,
|
|
0x00000000, 0x02000000, 0x700f0000, 0x040100fc,
|
|
0xf0000000, 0x000080b0, 0x02010000, 0x20000000,
|
|
0x00000000, 0x02000000, 0x700f0000, 0x040100fc,
|
|
0xf0000000, 0x000090b0, 0x02010000, 0x20000000,
|
|
0x00000000, 0x02000000, 0x700f0000, 0x040100fc,
|
|
0xf0000000, 0x0000a0b0, 0x00010000, 0x18000000,
|
|
0x00000000, 0x02000000, 0x0a000000, 0x040100c0,
|
|
0x00010000, 0x18000000, 0x00000000, 0x02000000,
|
|
0x0a000000, 0x04200080, 0x00010000, 0x18000000,
|
|
0x00000000, 0x02000000, 0x00be0000, 0x041000c0,
|
|
0x00010000, 0x18000000, 0x00000000, 0x02000000,
|
|
0x10be0000, 0x041000c0, 0x00010000, 0x18000000,
|
|
0x00000000, 0x02000000, 0x20be0000, 0x041000c0,
|
|
0x00010000, 0x18000000, 0x00000000, 0x02000000,
|
|
0x30be0000, 0x041000c0, 0x00010000, 0x18000000,
|
|
0x00000000, 0x02000000, 0x00b00000, 0x041000c0,
|
|
0x00010000, 0x18000000, 0x00000000, 0x02000000,
|
|
0x10b00000, 0x041000c0, 0x00010000, 0x18000000,
|
|
0x00000000, 0x02000000, 0x20b00000, 0x041000c0,
|
|
0x00010000, 0x18000000, 0x00000000, 0x02000000,
|
|
0x30b00000, 0x041000c0, 0x00010000, 0x18000000,
|
|
0x00000000, 0x02000000, 0x00300000, 0x041000c0,
|
|
0x00010000, 0x18000000, 0x00000000, 0x02000000,
|
|
0x10300000, 0x041000c0, 0x00010000, 0x18000000,
|
|
0x00000000, 0x02000000, 0x20300000, 0x041000c0,
|
|
0x00010000, 0x18000000, 0x00000000, 0x02000000,
|
|
0x30300000, 0x041000c0, 0x0a010000, 0x10000000,
|
|
0x00000000, 0x02000000, 0x06010000, 0x1c000000,
|
|
0x00000000, 0x02000000, 0x01000000, 0x00000200,
|
|
0xff230200, 0x06010000, 0x1c000000, 0x00000000,
|
|
0x02000000, 0x02000000, 0x00001000, 0x00000000,
|
|
0x07010000, 0x18000000, 0x00000000, 0x02000000,
|
|
0x00000000, 0x01000000, 0x07010000, 0x18000000,
|
|
0x00000000, 0x02000000, 0x00000000, 0x02000000,
|
|
0x07010000, 0x18000000, 0x00000000, 0x02000000,
|
|
0x00000000, 0x03000000, 0x0d010000, 0x14000000,
|
|
0x00000000, 0x02000000, 0x00000000, 0xff000000,
|
|
0x10000000, 0x00000000, 0x00000080,
|
|
};
|
|
|
|
static inline void __iomem *
|
|
qla27xx_isp_reg(struct scsi_qla_host *vha)
|
|
{
|
|
return &vha->hw->iobase->isp24;
|
|
}
|
|
|
|
static inline void
|
|
qla27xx_insert16(uint16_t value, void *buf, ulong *len)
|
|
{
|
|
if (buf) {
|
|
buf += *len;
|
|
*(__le16 *)buf = cpu_to_le16(value);
|
|
}
|
|
*len += sizeof(value);
|
|
}
|
|
|
|
static inline void
|
|
qla27xx_insert32(uint32_t value, void *buf, ulong *len)
|
|
{
|
|
if (buf) {
|
|
buf += *len;
|
|
*(__le32 *)buf = cpu_to_le32(value);
|
|
}
|
|
*len += sizeof(value);
|
|
}
|
|
|
|
static inline void
|
|
qla27xx_insertbuf(void *mem, ulong size, void *buf, ulong *len)
|
|
{
|
|
|
|
if (buf && mem && size) {
|
|
buf += *len;
|
|
memcpy(buf, mem, size);
|
|
}
|
|
*len += size;
|
|
}
|
|
|
|
static inline void
|
|
qla27xx_read8(void __iomem *window, void *buf, ulong *len)
|
|
{
|
|
uint8_t value = ~0;
|
|
|
|
if (buf) {
|
|
value = RD_REG_BYTE(window);
|
|
}
|
|
qla27xx_insert32(value, buf, len);
|
|
}
|
|
|
|
static inline void
|
|
qla27xx_read16(void __iomem *window, void *buf, ulong *len)
|
|
{
|
|
uint16_t value = ~0;
|
|
|
|
if (buf) {
|
|
value = RD_REG_WORD(window);
|
|
}
|
|
qla27xx_insert32(value, buf, len);
|
|
}
|
|
|
|
static inline void
|
|
qla27xx_read32(void __iomem *window, void *buf, ulong *len)
|
|
{
|
|
uint32_t value = ~0;
|
|
|
|
if (buf) {
|
|
value = RD_REG_DWORD(window);
|
|
}
|
|
qla27xx_insert32(value, buf, len);
|
|
}
|
|
|
|
static inline void (*qla27xx_read_vector(uint width))(void __iomem*, void *, ulong *)
|
|
{
|
|
return
|
|
(width == 1) ? qla27xx_read8 :
|
|
(width == 2) ? qla27xx_read16 :
|
|
qla27xx_read32;
|
|
}
|
|
|
|
static inline void
|
|
qla27xx_read_reg(__iomem struct device_reg_24xx *reg,
|
|
uint offset, void *buf, ulong *len)
|
|
{
|
|
void __iomem *window = (void __iomem *)reg + offset;
|
|
|
|
qla27xx_read32(window, buf, len);
|
|
}
|
|
|
|
static inline void
|
|
qla27xx_write_reg(__iomem struct device_reg_24xx *reg,
|
|
uint offset, uint32_t data, void *buf)
|
|
{
|
|
__iomem void *window = (void __iomem *)reg + offset;
|
|
|
|
if (buf) {
|
|
WRT_REG_DWORD(window, data);
|
|
}
|
|
}
|
|
|
|
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)
|
|
{
|
|
void __iomem *window = (void __iomem *)reg + offset;
|
|
void (*readn)(void __iomem*, void *, ulong *) = qla27xx_read_vector(width);
|
|
|
|
qla27xx_write_reg(reg, IOBASE_ADDR, addr, buf);
|
|
while (count--) {
|
|
qla27xx_insert32(addr, buf, len);
|
|
readn(window, buf, len);
|
|
window += width;
|
|
addr++;
|
|
}
|
|
}
|
|
|
|
static inline void
|
|
qla27xx_skip_entry(struct qla27xx_fwdt_entry *ent, void *buf)
|
|
{
|
|
if (buf)
|
|
ent->hdr.driver_flags |= DRIVER_FLAG_SKIP_ENTRY;
|
|
}
|
|
|
|
static int
|
|
qla27xx_fwdt_entry_t0(struct scsi_qla_host *vha,
|
|
struct qla27xx_fwdt_entry *ent, void *buf, ulong *len)
|
|
{
|
|
ql_dbg(ql_dbg_misc, vha, 0xd100,
|
|
"%s: nop [%lx]\n", __func__, *len);
|
|
qla27xx_skip_entry(ent, buf);
|
|
|
|
return false;
|
|
}
|
|
|
|
static int
|
|
qla27xx_fwdt_entry_t255(struct scsi_qla_host *vha,
|
|
struct qla27xx_fwdt_entry *ent, void *buf, ulong *len)
|
|
{
|
|
ql_dbg(ql_dbg_misc, vha, 0xd1ff,
|
|
"%s: end [%lx]\n", __func__, *len);
|
|
qla27xx_skip_entry(ent, buf);
|
|
|
|
/* terminate */
|
|
return true;
|
|
}
|
|
|
|
static int
|
|
qla27xx_fwdt_entry_t256(struct scsi_qla_host *vha,
|
|
struct qla27xx_fwdt_entry *ent, void *buf, ulong *len)
|
|
{
|
|
struct device_reg_24xx __iomem *reg = qla27xx_isp_reg(vha);
|
|
|
|
ql_dbg(ql_dbg_misc, vha, 0xd200,
|
|
"%s: rdio t1 [%lx]\n", __func__, *len);
|
|
qla27xx_read_window(reg, ent->t256.base_addr, ent->t256.pci_offset,
|
|
ent->t256.reg_count, ent->t256.reg_width, buf, len);
|
|
|
|
return false;
|
|
}
|
|
|
|
static int
|
|
qla27xx_fwdt_entry_t257(struct scsi_qla_host *vha,
|
|
struct qla27xx_fwdt_entry *ent, void *buf, ulong *len)
|
|
{
|
|
struct device_reg_24xx __iomem *reg = qla27xx_isp_reg(vha);
|
|
|
|
ql_dbg(ql_dbg_misc, vha, 0xd201,
|
|
"%s: wrio t1 [%lx]\n", __func__, *len);
|
|
qla27xx_write_reg(reg, IOBASE_ADDR, ent->t257.base_addr, buf);
|
|
qla27xx_write_reg(reg, ent->t257.pci_offset, ent->t257.write_data, buf);
|
|
|
|
return false;
|
|
}
|
|
|
|
static int
|
|
qla27xx_fwdt_entry_t258(struct scsi_qla_host *vha,
|
|
struct qla27xx_fwdt_entry *ent, void *buf, ulong *len)
|
|
{
|
|
struct device_reg_24xx __iomem *reg = qla27xx_isp_reg(vha);
|
|
|
|
ql_dbg(ql_dbg_misc, vha, 0xd202,
|
|
"%s: rdio t2 [%lx]\n", __func__, *len);
|
|
qla27xx_write_reg(reg, ent->t258.banksel_offset, ent->t258.bank, buf);
|
|
qla27xx_read_window(reg, ent->t258.base_addr, ent->t258.pci_offset,
|
|
ent->t258.reg_count, ent->t258.reg_width, buf, len);
|
|
|
|
return false;
|
|
}
|
|
|
|
static int
|
|
qla27xx_fwdt_entry_t259(struct scsi_qla_host *vha,
|
|
struct qla27xx_fwdt_entry *ent, void *buf, ulong *len)
|
|
{
|
|
struct device_reg_24xx __iomem *reg = qla27xx_isp_reg(vha);
|
|
|
|
ql_dbg(ql_dbg_misc, vha, 0xd203,
|
|
"%s: wrio t2 [%lx]\n", __func__, *len);
|
|
qla27xx_write_reg(reg, IOBASE_ADDR, ent->t259.base_addr, buf);
|
|
qla27xx_write_reg(reg, ent->t259.banksel_offset, ent->t259.bank, buf);
|
|
qla27xx_write_reg(reg, ent->t259.pci_offset, ent->t259.write_data, buf);
|
|
|
|
return false;
|
|
}
|
|
|
|
static int
|
|
qla27xx_fwdt_entry_t260(struct scsi_qla_host *vha,
|
|
struct qla27xx_fwdt_entry *ent, void *buf, ulong *len)
|
|
{
|
|
struct device_reg_24xx __iomem *reg = qla27xx_isp_reg(vha);
|
|
|
|
ql_dbg(ql_dbg_misc, vha, 0xd204,
|
|
"%s: rdpci [%lx]\n", __func__, *len);
|
|
qla27xx_insert32(ent->t260.pci_offset, buf, len);
|
|
qla27xx_read_reg(reg, ent->t260.pci_offset, buf, len);
|
|
|
|
return false;
|
|
}
|
|
|
|
static int
|
|
qla27xx_fwdt_entry_t261(struct scsi_qla_host *vha,
|
|
struct qla27xx_fwdt_entry *ent, void *buf, ulong *len)
|
|
{
|
|
struct device_reg_24xx __iomem *reg = qla27xx_isp_reg(vha);
|
|
|
|
ql_dbg(ql_dbg_misc, vha, 0xd205,
|
|
"%s: wrpci [%lx]\n", __func__, *len);
|
|
qla27xx_write_reg(reg, ent->t261.pci_offset, ent->t261.write_data, buf);
|
|
|
|
return false;
|
|
}
|
|
|
|
static int
|
|
qla27xx_fwdt_entry_t262(struct scsi_qla_host *vha,
|
|
struct qla27xx_fwdt_entry *ent, void *buf, ulong *len)
|
|
{
|
|
ulong dwords;
|
|
ulong start;
|
|
ulong end;
|
|
|
|
ql_dbg(ql_dbg_misc, vha, 0xd206,
|
|
"%s: rdram(%x) [%lx]\n", __func__, ent->t262.ram_area, *len);
|
|
start = ent->t262.start_addr;
|
|
end = ent->t262.end_addr;
|
|
|
|
if (ent->t262.ram_area == T262_RAM_AREA_CRITICAL_RAM) {
|
|
;
|
|
} else if (ent->t262.ram_area == T262_RAM_AREA_EXTERNAL_RAM) {
|
|
end = vha->hw->fw_memory_size;
|
|
if (buf)
|
|
ent->t262.end_addr = end;
|
|
} else if (ent->t262.ram_area == T262_RAM_AREA_SHARED_RAM) {
|
|
start = vha->hw->fw_shared_ram_start;
|
|
end = vha->hw->fw_shared_ram_end;
|
|
if (buf) {
|
|
ent->t262.start_addr = start;
|
|
ent->t262.end_addr = end;
|
|
}
|
|
} else if (ent->t262.ram_area == T262_RAM_AREA_DDR_RAM) {
|
|
start = vha->hw->fw_ddr_ram_start;
|
|
end = vha->hw->fw_ddr_ram_end;
|
|
if (buf) {
|
|
ent->t262.start_addr = start;
|
|
ent->t262.end_addr = end;
|
|
}
|
|
} else {
|
|
ql_dbg(ql_dbg_misc, vha, 0xd022,
|
|
"%s: unknown area %x\n", __func__, ent->t262.ram_area);
|
|
qla27xx_skip_entry(ent, buf);
|
|
goto done;
|
|
}
|
|
|
|
if (end < start || start == 0 || end == 0) {
|
|
ql_dbg(ql_dbg_misc, vha, 0xd023,
|
|
"%s: unusable range (start=%x end=%x)\n", __func__,
|
|
ent->t262.end_addr, ent->t262.start_addr);
|
|
qla27xx_skip_entry(ent, buf);
|
|
goto done;
|
|
}
|
|
|
|
dwords = end - start + 1;
|
|
if (buf) {
|
|
buf += *len;
|
|
qla24xx_dump_ram(vha->hw, start, buf, dwords, &buf);
|
|
}
|
|
*len += dwords * sizeof(uint32_t);
|
|
done:
|
|
return false;
|
|
}
|
|
|
|
static int
|
|
qla27xx_fwdt_entry_t263(struct scsi_qla_host *vha,
|
|
struct qla27xx_fwdt_entry *ent, void *buf, ulong *len)
|
|
{
|
|
uint count = 0;
|
|
uint i;
|
|
uint length;
|
|
|
|
ql_dbg(ql_dbg_misc, vha, 0xd207,
|
|
"%s: getq(%x) [%lx]\n", __func__, ent->t263.queue_type, *len);
|
|
if (ent->t263.queue_type == T263_QUEUE_TYPE_REQ) {
|
|
for (i = 0; i < vha->hw->max_req_queues; i++) {
|
|
struct req_que *req = vha->hw->req_q_map[i];
|
|
|
|
if (req || !buf) {
|
|
length = req ?
|
|
req->length : REQUEST_ENTRY_CNT_24XX;
|
|
qla27xx_insert16(i, buf, len);
|
|
qla27xx_insert16(length, buf, len);
|
|
qla27xx_insertbuf(req ? req->ring : NULL,
|
|
length * sizeof(*req->ring), buf, len);
|
|
count++;
|
|
}
|
|
}
|
|
} else if (ent->t263.queue_type == T263_QUEUE_TYPE_RSP) {
|
|
for (i = 0; i < vha->hw->max_rsp_queues; i++) {
|
|
struct rsp_que *rsp = vha->hw->rsp_q_map[i];
|
|
|
|
if (rsp || !buf) {
|
|
length = rsp ?
|
|
rsp->length : RESPONSE_ENTRY_CNT_MQ;
|
|
qla27xx_insert16(i, buf, len);
|
|
qla27xx_insert16(length, buf, len);
|
|
qla27xx_insertbuf(rsp ? rsp->ring : NULL,
|
|
length * sizeof(*rsp->ring), buf, len);
|
|
count++;
|
|
}
|
|
}
|
|
} else if (QLA_TGT_MODE_ENABLED() &&
|
|
ent->t263.queue_type == T263_QUEUE_TYPE_ATIO) {
|
|
struct qla_hw_data *ha = vha->hw;
|
|
struct atio *atr = ha->tgt.atio_ring;
|
|
|
|
if (atr || !buf) {
|
|
length = ha->tgt.atio_q_length;
|
|
qla27xx_insert16(0, buf, len);
|
|
qla27xx_insert16(length, buf, len);
|
|
qla27xx_insertbuf(atr, length * sizeof(*atr), buf, len);
|
|
count++;
|
|
}
|
|
} else {
|
|
ql_dbg(ql_dbg_misc, vha, 0xd026,
|
|
"%s: unknown queue %x\n", __func__, ent->t263.queue_type);
|
|
qla27xx_skip_entry(ent, buf);
|
|
}
|
|
|
|
if (buf)
|
|
ent->t263.num_queues = count;
|
|
|
|
return false;
|
|
}
|
|
|
|
static int
|
|
qla27xx_fwdt_entry_t264(struct scsi_qla_host *vha,
|
|
struct qla27xx_fwdt_entry *ent, void *buf, ulong *len)
|
|
{
|
|
ql_dbg(ql_dbg_misc, vha, 0xd208,
|
|
"%s: getfce [%lx]\n", __func__, *len);
|
|
if (vha->hw->fce) {
|
|
if (buf) {
|
|
ent->t264.fce_trace_size = FCE_SIZE;
|
|
ent->t264.write_pointer = vha->hw->fce_wr;
|
|
ent->t264.base_pointer = vha->hw->fce_dma;
|
|
ent->t264.fce_enable_mb0 = vha->hw->fce_mb[0];
|
|
ent->t264.fce_enable_mb2 = vha->hw->fce_mb[2];
|
|
ent->t264.fce_enable_mb3 = vha->hw->fce_mb[3];
|
|
ent->t264.fce_enable_mb4 = vha->hw->fce_mb[4];
|
|
ent->t264.fce_enable_mb5 = vha->hw->fce_mb[5];
|
|
ent->t264.fce_enable_mb6 = vha->hw->fce_mb[6];
|
|
}
|
|
qla27xx_insertbuf(vha->hw->fce, FCE_SIZE, buf, len);
|
|
} else {
|
|
ql_dbg(ql_dbg_misc, vha, 0xd027,
|
|
"%s: missing fce\n", __func__);
|
|
qla27xx_skip_entry(ent, buf);
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
static int
|
|
qla27xx_fwdt_entry_t265(struct scsi_qla_host *vha,
|
|
struct qla27xx_fwdt_entry *ent, void *buf, ulong *len)
|
|
{
|
|
struct device_reg_24xx __iomem *reg = qla27xx_isp_reg(vha);
|
|
|
|
ql_dbg(ql_dbg_misc, vha, 0xd209,
|
|
"%s: pause risc [%lx]\n", __func__, *len);
|
|
if (buf)
|
|
qla24xx_pause_risc(reg, vha->hw);
|
|
|
|
return false;
|
|
}
|
|
|
|
static int
|
|
qla27xx_fwdt_entry_t266(struct scsi_qla_host *vha,
|
|
struct qla27xx_fwdt_entry *ent, void *buf, ulong *len)
|
|
{
|
|
ql_dbg(ql_dbg_misc, vha, 0xd20a,
|
|
"%s: reset risc [%lx]\n", __func__, *len);
|
|
if (buf)
|
|
qla24xx_soft_reset(vha->hw);
|
|
|
|
return false;
|
|
}
|
|
|
|
static int
|
|
qla27xx_fwdt_entry_t267(struct scsi_qla_host *vha,
|
|
struct qla27xx_fwdt_entry *ent, void *buf, ulong *len)
|
|
{
|
|
struct device_reg_24xx __iomem *reg = qla27xx_isp_reg(vha);
|
|
|
|
ql_dbg(ql_dbg_misc, vha, 0xd20b,
|
|
"%s: dis intr [%lx]\n", __func__, *len);
|
|
qla27xx_write_reg(reg, ent->t267.pci_offset, ent->t267.data, buf);
|
|
|
|
return false;
|
|
}
|
|
|
|
static int
|
|
qla27xx_fwdt_entry_t268(struct scsi_qla_host *vha,
|
|
struct qla27xx_fwdt_entry *ent, void *buf, ulong *len)
|
|
{
|
|
ql_dbg(ql_dbg_misc, vha, 0xd20c,
|
|
"%s: gethb(%x) [%lx]\n", __func__, ent->t268.buf_type, *len);
|
|
if (ent->t268.buf_type == T268_BUF_TYPE_EXTD_TRACE) {
|
|
if (vha->hw->eft) {
|
|
if (buf) {
|
|
ent->t268.buf_size = EFT_SIZE;
|
|
ent->t268.start_addr = vha->hw->eft_dma;
|
|
}
|
|
qla27xx_insertbuf(vha->hw->eft, EFT_SIZE, buf, len);
|
|
} else {
|
|
ql_dbg(ql_dbg_misc, vha, 0xd028,
|
|
"%s: missing eft\n", __func__);
|
|
qla27xx_skip_entry(ent, buf);
|
|
}
|
|
} else {
|
|
ql_dbg(ql_dbg_misc, vha, 0xd02b,
|
|
"%s: unknown buffer %x\n", __func__, ent->t268.buf_type);
|
|
qla27xx_skip_entry(ent, buf);
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
static int
|
|
qla27xx_fwdt_entry_t269(struct scsi_qla_host *vha,
|
|
struct qla27xx_fwdt_entry *ent, void *buf, ulong *len)
|
|
{
|
|
ql_dbg(ql_dbg_misc, vha, 0xd20d,
|
|
"%s: scratch [%lx]\n", __func__, *len);
|
|
qla27xx_insert32(0xaaaaaaaa, buf, len);
|
|
qla27xx_insert32(0xbbbbbbbb, buf, len);
|
|
qla27xx_insert32(0xcccccccc, buf, len);
|
|
qla27xx_insert32(0xdddddddd, buf, len);
|
|
qla27xx_insert32(*len + sizeof(uint32_t), buf, len);
|
|
if (buf)
|
|
ent->t269.scratch_size = 5 * sizeof(uint32_t);
|
|
|
|
return false;
|
|
}
|
|
|
|
static int
|
|
qla27xx_fwdt_entry_t270(struct scsi_qla_host *vha,
|
|
struct qla27xx_fwdt_entry *ent, void *buf, ulong *len)
|
|
{
|
|
struct device_reg_24xx __iomem *reg = qla27xx_isp_reg(vha);
|
|
ulong dwords = ent->t270.count;
|
|
ulong addr = ent->t270.addr;
|
|
|
|
ql_dbg(ql_dbg_misc, vha, 0xd20e,
|
|
"%s: rdremreg [%lx]\n", __func__, *len);
|
|
qla27xx_write_reg(reg, IOBASE_ADDR, 0x40, buf);
|
|
while (dwords--) {
|
|
qla27xx_write_reg(reg, 0xc0, addr|0x80000000, buf);
|
|
qla27xx_insert32(addr, buf, len);
|
|
qla27xx_read_reg(reg, 0xc4, buf, len);
|
|
addr += sizeof(uint32_t);
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
static int
|
|
qla27xx_fwdt_entry_t271(struct scsi_qla_host *vha,
|
|
struct qla27xx_fwdt_entry *ent, void *buf, ulong *len)
|
|
{
|
|
struct device_reg_24xx __iomem *reg = qla27xx_isp_reg(vha);
|
|
ulong addr = ent->t271.addr;
|
|
ulong data = ent->t271.data;
|
|
|
|
ql_dbg(ql_dbg_misc, vha, 0xd20f,
|
|
"%s: wrremreg [%lx]\n", __func__, *len);
|
|
qla27xx_write_reg(reg, IOBASE_ADDR, 0x40, buf);
|
|
qla27xx_write_reg(reg, 0xc4, data, buf);
|
|
qla27xx_write_reg(reg, 0xc0, addr, buf);
|
|
|
|
return false;
|
|
}
|
|
|
|
static int
|
|
qla27xx_fwdt_entry_t272(struct scsi_qla_host *vha,
|
|
struct qla27xx_fwdt_entry *ent, void *buf, ulong *len)
|
|
{
|
|
ulong dwords = ent->t272.count;
|
|
ulong start = ent->t272.addr;
|
|
|
|
ql_dbg(ql_dbg_misc, vha, 0xd210,
|
|
"%s: rdremram [%lx]\n", __func__, *len);
|
|
if (buf) {
|
|
ql_dbg(ql_dbg_misc, vha, 0xd02c,
|
|
"%s: @%lx -> (%lx dwords)\n", __func__, start, dwords);
|
|
buf += *len;
|
|
qla27xx_dump_mpi_ram(vha->hw, start, buf, dwords, &buf);
|
|
}
|
|
*len += dwords * sizeof(uint32_t);
|
|
|
|
return false;
|
|
}
|
|
|
|
static int
|
|
qla27xx_fwdt_entry_t273(struct scsi_qla_host *vha,
|
|
struct qla27xx_fwdt_entry *ent, void *buf, ulong *len)
|
|
{
|
|
ulong dwords = ent->t273.count;
|
|
ulong addr = ent->t273.addr;
|
|
uint32_t value;
|
|
|
|
ql_dbg(ql_dbg_misc, vha, 0xd211,
|
|
"%s: pcicfg [%lx]\n", __func__, *len);
|
|
while (dwords--) {
|
|
value = ~0;
|
|
if (pci_read_config_dword(vha->hw->pdev, addr, &value))
|
|
ql_dbg(ql_dbg_misc, vha, 0xd02d,
|
|
"%s: failed pcicfg read at %lx\n", __func__, addr);
|
|
qla27xx_insert32(addr, buf, len);
|
|
qla27xx_insert32(value, buf, len);
|
|
addr += sizeof(uint32_t);
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
static int
|
|
qla27xx_fwdt_entry_t274(struct scsi_qla_host *vha,
|
|
struct qla27xx_fwdt_entry *ent, void *buf, ulong *len)
|
|
{
|
|
uint count = 0;
|
|
uint i;
|
|
|
|
ql_dbg(ql_dbg_misc, vha, 0xd212,
|
|
"%s: getqsh(%x) [%lx]\n", __func__, ent->t274.queue_type, *len);
|
|
if (ent->t274.queue_type == T274_QUEUE_TYPE_REQ_SHAD) {
|
|
for (i = 0; i < vha->hw->max_req_queues; i++) {
|
|
struct req_que *req = vha->hw->req_q_map[i];
|
|
|
|
if (req || !buf) {
|
|
qla27xx_insert16(i, buf, len);
|
|
qla27xx_insert16(1, buf, len);
|
|
qla27xx_insert32(req && req->out_ptr ?
|
|
*req->out_ptr : 0, buf, len);
|
|
count++;
|
|
}
|
|
}
|
|
} else if (ent->t274.queue_type == T274_QUEUE_TYPE_RSP_SHAD) {
|
|
for (i = 0; i < vha->hw->max_rsp_queues; i++) {
|
|
struct rsp_que *rsp = vha->hw->rsp_q_map[i];
|
|
|
|
if (rsp || !buf) {
|
|
qla27xx_insert16(i, buf, len);
|
|
qla27xx_insert16(1, buf, len);
|
|
qla27xx_insert32(rsp && rsp->in_ptr ?
|
|
*rsp->in_ptr : 0, buf, len);
|
|
count++;
|
|
}
|
|
}
|
|
} else if (QLA_TGT_MODE_ENABLED() &&
|
|
ent->t274.queue_type == T274_QUEUE_TYPE_ATIO_SHAD) {
|
|
struct qla_hw_data *ha = vha->hw;
|
|
struct atio *atr = ha->tgt.atio_ring_ptr;
|
|
|
|
if (atr || !buf) {
|
|
qla27xx_insert16(0, buf, len);
|
|
qla27xx_insert16(1, buf, len);
|
|
qla27xx_insert32(ha->tgt.atio_q_in ?
|
|
readl(ha->tgt.atio_q_in) : 0, buf, len);
|
|
count++;
|
|
}
|
|
} else {
|
|
ql_dbg(ql_dbg_misc, vha, 0xd02f,
|
|
"%s: unknown queue %x\n", __func__, ent->t274.queue_type);
|
|
qla27xx_skip_entry(ent, buf);
|
|
}
|
|
|
|
if (buf)
|
|
ent->t274.num_queues = count;
|
|
|
|
if (!count)
|
|
qla27xx_skip_entry(ent, buf);
|
|
|
|
return false;
|
|
}
|
|
|
|
static int
|
|
qla27xx_fwdt_entry_t275(struct scsi_qla_host *vha,
|
|
struct qla27xx_fwdt_entry *ent, void *buf, ulong *len)
|
|
{
|
|
ulong offset = offsetof(typeof(*ent), t275.buffer);
|
|
|
|
ql_dbg(ql_dbg_misc, vha, 0xd213,
|
|
"%s: buffer(%x) [%lx]\n", __func__, ent->t275.length, *len);
|
|
if (!ent->t275.length) {
|
|
ql_dbg(ql_dbg_misc, vha, 0xd020,
|
|
"%s: buffer zero length\n", __func__);
|
|
qla27xx_skip_entry(ent, buf);
|
|
goto done;
|
|
}
|
|
if (offset + ent->t275.length > ent->hdr.entry_size) {
|
|
ql_dbg(ql_dbg_misc, vha, 0xd030,
|
|
"%s: buffer overflow\n", __func__);
|
|
qla27xx_skip_entry(ent, buf);
|
|
goto done;
|
|
}
|
|
|
|
qla27xx_insertbuf(ent->t275.buffer, ent->t275.length, buf, len);
|
|
done:
|
|
return false;
|
|
}
|
|
|
|
static int
|
|
qla27xx_fwdt_entry_other(struct scsi_qla_host *vha,
|
|
struct qla27xx_fwdt_entry *ent, void *buf, ulong *len)
|
|
{
|
|
ql_dbg(ql_dbg_misc, vha, 0xd2ff,
|
|
"%s: type %x [%lx]\n", __func__, ent->hdr.entry_type, *len);
|
|
qla27xx_skip_entry(ent, buf);
|
|
|
|
return false;
|
|
}
|
|
|
|
struct qla27xx_fwdt_entry_call {
|
|
uint type;
|
|
int (*call)(
|
|
struct scsi_qla_host *,
|
|
struct qla27xx_fwdt_entry *,
|
|
void *,
|
|
ulong *);
|
|
};
|
|
|
|
static struct qla27xx_fwdt_entry_call ql27xx_fwdt_entry_call_list[] = {
|
|
{ ENTRY_TYPE_NOP , qla27xx_fwdt_entry_t0 } ,
|
|
{ ENTRY_TYPE_TMP_END , qla27xx_fwdt_entry_t255 } ,
|
|
{ ENTRY_TYPE_RD_IOB_T1 , qla27xx_fwdt_entry_t256 } ,
|
|
{ ENTRY_TYPE_WR_IOB_T1 , qla27xx_fwdt_entry_t257 } ,
|
|
{ ENTRY_TYPE_RD_IOB_T2 , qla27xx_fwdt_entry_t258 } ,
|
|
{ ENTRY_TYPE_WR_IOB_T2 , qla27xx_fwdt_entry_t259 } ,
|
|
{ ENTRY_TYPE_RD_PCI , qla27xx_fwdt_entry_t260 } ,
|
|
{ ENTRY_TYPE_WR_PCI , qla27xx_fwdt_entry_t261 } ,
|
|
{ ENTRY_TYPE_RD_RAM , qla27xx_fwdt_entry_t262 } ,
|
|
{ ENTRY_TYPE_GET_QUEUE , qla27xx_fwdt_entry_t263 } ,
|
|
{ ENTRY_TYPE_GET_FCE , qla27xx_fwdt_entry_t264 } ,
|
|
{ ENTRY_TYPE_PSE_RISC , qla27xx_fwdt_entry_t265 } ,
|
|
{ ENTRY_TYPE_RST_RISC , qla27xx_fwdt_entry_t266 } ,
|
|
{ ENTRY_TYPE_DIS_INTR , qla27xx_fwdt_entry_t267 } ,
|
|
{ ENTRY_TYPE_GET_HBUF , qla27xx_fwdt_entry_t268 } ,
|
|
{ ENTRY_TYPE_SCRATCH , qla27xx_fwdt_entry_t269 } ,
|
|
{ ENTRY_TYPE_RDREMREG , qla27xx_fwdt_entry_t270 } ,
|
|
{ ENTRY_TYPE_WRREMREG , qla27xx_fwdt_entry_t271 } ,
|
|
{ ENTRY_TYPE_RDREMRAM , qla27xx_fwdt_entry_t272 } ,
|
|
{ ENTRY_TYPE_PCICFG , qla27xx_fwdt_entry_t273 } ,
|
|
{ ENTRY_TYPE_GET_SHADOW , qla27xx_fwdt_entry_t274 } ,
|
|
{ ENTRY_TYPE_WRITE_BUF , qla27xx_fwdt_entry_t275 } ,
|
|
{ -1 , qla27xx_fwdt_entry_other }
|
|
};
|
|
|
|
static inline int (*qla27xx_find_entry(uint type))
|
|
(struct scsi_qla_host *, struct qla27xx_fwdt_entry *, void *, ulong *)
|
|
{
|
|
struct qla27xx_fwdt_entry_call *list = ql27xx_fwdt_entry_call_list;
|
|
|
|
while (list->type < type)
|
|
list++;
|
|
|
|
if (list->type == type)
|
|
return list->call;
|
|
return qla27xx_fwdt_entry_other;
|
|
}
|
|
|
|
static inline void *
|
|
qla27xx_next_entry(void *p)
|
|
{
|
|
struct qla27xx_fwdt_entry *ent = p;
|
|
|
|
return p + ent->hdr.entry_size;
|
|
}
|
|
|
|
static void
|
|
qla27xx_walk_template(struct scsi_qla_host *vha,
|
|
struct qla27xx_fwdt_template *tmp, void *buf, ulong *len)
|
|
{
|
|
struct qla27xx_fwdt_entry *ent = (void *)tmp + tmp->entry_offset;
|
|
ulong count = tmp->entry_count;
|
|
|
|
ql_dbg(ql_dbg_misc, vha, 0xd01a,
|
|
"%s: entry count %lx\n", __func__, count);
|
|
while (count--) {
|
|
if (buf && *len >= vha->hw->fw_dump_len)
|
|
break;
|
|
if (qla27xx_find_entry(ent->hdr.entry_type)(vha, ent, buf, len))
|
|
break;
|
|
ent = qla27xx_next_entry(ent);
|
|
}
|
|
|
|
if (count)
|
|
ql_dbg(ql_dbg_misc, vha, 0xd018,
|
|
"%s: entry residual count (%lx)\n", __func__, count);
|
|
|
|
if (ent->hdr.entry_type != ENTRY_TYPE_TMP_END)
|
|
ql_dbg(ql_dbg_misc, vha, 0xd019,
|
|
"%s: missing end entry (%lx)\n", __func__, count);
|
|
|
|
if (buf && *len != vha->hw->fw_dump_len)
|
|
ql_dbg(ql_dbg_misc, vha, 0xd01b,
|
|
"%s: length=%#lx residual=%+ld\n",
|
|
__func__, *len, vha->hw->fw_dump_len - *len);
|
|
|
|
if (buf) {
|
|
ql_log(ql_log_warn, vha, 0xd015,
|
|
"Firmware dump saved to temp buffer (%lu/%p)\n",
|
|
vha->host_no, vha->hw->fw_dump);
|
|
qla2x00_post_uevent_work(vha, QLA_UEVENT_CODE_FW_DUMP);
|
|
}
|
|
}
|
|
|
|
static void
|
|
qla27xx_time_stamp(struct qla27xx_fwdt_template *tmp)
|
|
{
|
|
tmp->capture_timestamp = jiffies;
|
|
}
|
|
|
|
static void
|
|
qla27xx_driver_info(struct qla27xx_fwdt_template *tmp)
|
|
{
|
|
uint8_t v[] = { 0, 0, 0, 0, 0, 0 };
|
|
|
|
sscanf(qla2x00_version_str, "%hhu.%hhu.%hhu.%hhu.%hhu.%hhu",
|
|
v+0, v+1, v+2, v+3, v+4, v+5);
|
|
|
|
tmp->driver_info[0] = v[3] << 24 | v[2] << 16 | v[1] << 8 | v[0];
|
|
tmp->driver_info[1] = v[5] << 8 | v[4];
|
|
tmp->driver_info[2] = 0x12345678;
|
|
}
|
|
|
|
static void
|
|
qla27xx_firmware_info(struct qla27xx_fwdt_template *tmp,
|
|
struct scsi_qla_host *vha)
|
|
{
|
|
tmp->firmware_version[0] = vha->hw->fw_major_version;
|
|
tmp->firmware_version[1] = vha->hw->fw_minor_version;
|
|
tmp->firmware_version[2] = vha->hw->fw_subminor_version;
|
|
tmp->firmware_version[3] =
|
|
vha->hw->fw_attributes_h << 16 | vha->hw->fw_attributes;
|
|
tmp->firmware_version[4] =
|
|
vha->hw->fw_attributes_ext[1] << 16 | vha->hw->fw_attributes_ext[0];
|
|
}
|
|
|
|
static void
|
|
ql27xx_edit_template(struct scsi_qla_host *vha,
|
|
struct qla27xx_fwdt_template *tmp)
|
|
{
|
|
qla27xx_time_stamp(tmp);
|
|
qla27xx_driver_info(tmp);
|
|
qla27xx_firmware_info(tmp, vha);
|
|
}
|
|
|
|
static inline uint32_t
|
|
qla27xx_template_checksum(void *p, ulong size)
|
|
{
|
|
uint32_t *buf = p;
|
|
uint64_t sum = 0;
|
|
|
|
size /= sizeof(*buf);
|
|
|
|
while (size--)
|
|
sum += *buf++;
|
|
|
|
sum = (sum & 0xffffffff) + (sum >> 32);
|
|
|
|
return ~sum;
|
|
}
|
|
|
|
static inline int
|
|
qla27xx_verify_template_checksum(struct qla27xx_fwdt_template *tmp)
|
|
{
|
|
return qla27xx_template_checksum(tmp, tmp->template_size) == 0;
|
|
}
|
|
|
|
static inline int
|
|
qla27xx_verify_template_header(struct qla27xx_fwdt_template *tmp)
|
|
{
|
|
return tmp->template_type == TEMPLATE_TYPE_FWDUMP;
|
|
}
|
|
|
|
static void
|
|
qla27xx_execute_fwdt_template(struct scsi_qla_host *vha)
|
|
{
|
|
struct qla27xx_fwdt_template *tmp = vha->hw->fw_dump_template;
|
|
ulong len;
|
|
|
|
if (qla27xx_fwdt_template_valid(tmp)) {
|
|
len = tmp->template_size;
|
|
tmp = memcpy(vha->hw->fw_dump, tmp, len);
|
|
ql27xx_edit_template(vha, tmp);
|
|
qla27xx_walk_template(vha, tmp, tmp, &len);
|
|
vha->hw->fw_dump_len = len;
|
|
vha->hw->fw_dumped = 1;
|
|
}
|
|
}
|
|
|
|
ulong
|
|
qla27xx_fwdt_calculate_dump_size(struct scsi_qla_host *vha)
|
|
{
|
|
struct qla27xx_fwdt_template *tmp = vha->hw->fw_dump_template;
|
|
ulong len = 0;
|
|
|
|
if (qla27xx_fwdt_template_valid(tmp)) {
|
|
len = tmp->template_size;
|
|
qla27xx_walk_template(vha, tmp, NULL, &len);
|
|
}
|
|
|
|
return len;
|
|
}
|
|
|
|
ulong
|
|
qla27xx_fwdt_template_size(void *p)
|
|
{
|
|
struct qla27xx_fwdt_template *tmp = p;
|
|
|
|
return tmp->template_size;
|
|
}
|
|
|
|
ulong
|
|
qla27xx_fwdt_template_default_size(void)
|
|
{
|
|
return sizeof(ql27xx_fwdt_default_template);
|
|
}
|
|
|
|
const void *
|
|
qla27xx_fwdt_template_default(void)
|
|
{
|
|
return ql27xx_fwdt_default_template;
|
|
}
|
|
|
|
int
|
|
qla27xx_fwdt_template_valid(void *p)
|
|
{
|
|
struct qla27xx_fwdt_template *tmp = p;
|
|
|
|
if (!qla27xx_verify_template_header(tmp)) {
|
|
ql_log(ql_log_warn, NULL, 0xd01c,
|
|
"%s: template type %x\n", __func__, tmp->template_type);
|
|
return false;
|
|
}
|
|
|
|
if (!qla27xx_verify_template_checksum(tmp)) {
|
|
ql_log(ql_log_warn, NULL, 0xd01d,
|
|
"%s: failed template checksum\n", __func__);
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
void
|
|
qla27xx_fwdump(scsi_qla_host_t *vha, int hardware_locked)
|
|
{
|
|
ulong flags = 0;
|
|
|
|
#ifndef __CHECKER__
|
|
if (!hardware_locked)
|
|
spin_lock_irqsave(&vha->hw->hardware_lock, flags);
|
|
#endif
|
|
|
|
if (!vha->hw->fw_dump)
|
|
ql_log(ql_log_warn, vha, 0xd01e, "fwdump buffer missing.\n");
|
|
else if (!vha->hw->fw_dump_template)
|
|
ql_log(ql_log_warn, vha, 0xd01f, "fwdump template missing.\n");
|
|
else if (vha->hw->fw_dumped)
|
|
ql_log(ql_log_warn, vha, 0xd300,
|
|
"Firmware has been previously dumped (%p),"
|
|
" -- ignoring request\n", vha->hw->fw_dump);
|
|
else
|
|
qla27xx_execute_fwdt_template(vha);
|
|
|
|
#ifndef __CHECKER__
|
|
if (!hardware_locked)
|
|
spin_unlock_irqrestore(&vha->hw->hardware_lock, flags);
|
|
#endif
|
|
}
|