Commit 068237c8 authored by Tej Parkash's avatar Tej Parkash Committed by James Bottomley

[SCSI] qla4xxx: Capture minidump for ISP82XX on firmware failure

Added support to capture dump (Minidump) which allows us to
catpure a snapshot of the firmware/hardware states at the time
of firmware failure
Signed-off-by: default avatarTej Parkash <tej.parkash@qlogic.com>
Signed-off-by: default avatarShyam Sundar <shyam.sundar@qlogic.com>
Signed-off-by: default avatarVikas Chaudhary <vikas.chaudhary@qlogic.com>
Signed-off-by: default avatarJames Bottomley <JBottomley@Parallels.com>
parent f7b4aa63
......@@ -9,6 +9,140 @@
#include "ql4_glbl.h"
#include "ql4_dbg.h"
static ssize_t
qla4_8xxx_sysfs_read_fw_dump(struct file *filep, struct kobject *kobj,
struct bin_attribute *ba, char *buf, loff_t off,
size_t count)
{
struct scsi_qla_host *ha = to_qla_host(dev_to_shost(container_of(kobj,
struct device, kobj)));
if (!is_qla8022(ha))
return -EINVAL;
if (!test_bit(AF_82XX_DUMP_READING, &ha->flags))
return 0;
return memory_read_from_buffer(buf, count, &off, ha->fw_dump,
ha->fw_dump_size);
}
static ssize_t
qla4_8xxx_sysfs_write_fw_dump(struct file *filep, struct kobject *kobj,
struct bin_attribute *ba, char *buf, loff_t off,
size_t count)
{
struct scsi_qla_host *ha = to_qla_host(dev_to_shost(container_of(kobj,
struct device, kobj)));
uint32_t dev_state;
long reading;
int ret = 0;
if (!is_qla8022(ha))
return -EINVAL;
if (off != 0)
return ret;
buf[1] = 0;
ret = kstrtol(buf, 10, &reading);
if (ret) {
ql4_printk(KERN_ERR, ha, "%s: Invalid input. Return err %d\n",
__func__, ret);
return ret;
}
switch (reading) {
case 0:
/* clear dump collection flags */
if (test_and_clear_bit(AF_82XX_DUMP_READING, &ha->flags)) {
clear_bit(AF_82XX_FW_DUMPED, &ha->flags);
/* Reload minidump template */
qla4xxx_alloc_fw_dump(ha);
DEBUG2(ql4_printk(KERN_INFO, ha,
"Firmware template reloaded\n"));
}
break;
case 1:
/* Set flag to read dump */
if (test_bit(AF_82XX_FW_DUMPED, &ha->flags) &&
!test_bit(AF_82XX_DUMP_READING, &ha->flags)) {
set_bit(AF_82XX_DUMP_READING, &ha->flags);
DEBUG2(ql4_printk(KERN_INFO, ha,
"Raw firmware dump ready for read on (%ld).\n",
ha->host_no));
}
break;
case 2:
/* Reset HBA */
qla4_8xxx_idc_lock(ha);
dev_state = qla4_8xxx_rd_32(ha, QLA82XX_CRB_DEV_STATE);
if (dev_state == QLA82XX_DEV_READY) {
ql4_printk(KERN_INFO, ha,
"%s: Setting Need reset, reset_owner is 0x%x.\n",
__func__, ha->func_num);
qla4_8xxx_wr_32(ha, QLA82XX_CRB_DEV_STATE,
QLA82XX_DEV_NEED_RESET);
set_bit(AF_82XX_RST_OWNER, &ha->flags);
} else
ql4_printk(KERN_INFO, ha,
"%s: Reset not performed as device state is 0x%x\n",
__func__, dev_state);
qla4_8xxx_idc_unlock(ha);
break;
default:
/* do nothing */
break;
}
return count;
}
static struct bin_attribute sysfs_fw_dump_attr = {
.attr = {
.name = "fw_dump",
.mode = S_IRUSR | S_IWUSR,
},
.size = 0,
.read = qla4_8xxx_sysfs_read_fw_dump,
.write = qla4_8xxx_sysfs_write_fw_dump,
};
static struct sysfs_entry {
char *name;
struct bin_attribute *attr;
} bin_file_entries[] = {
{ "fw_dump", &sysfs_fw_dump_attr },
{ NULL },
};
void qla4_8xxx_alloc_sysfs_attr(struct scsi_qla_host *ha)
{
struct Scsi_Host *host = ha->host;
struct sysfs_entry *iter;
int ret;
for (iter = bin_file_entries; iter->name; iter++) {
ret = sysfs_create_bin_file(&host->shost_gendev.kobj,
iter->attr);
if (ret)
ql4_printk(KERN_ERR, ha,
"Unable to create sysfs %s binary attribute (%d).\n",
iter->name, ret);
}
}
void qla4_8xxx_free_sysfs_attr(struct scsi_qla_host *ha)
{
struct Scsi_Host *host = ha->host;
struct sysfs_entry *iter;
for (iter = bin_file_entries; iter->name; iter++)
sysfs_remove_bin_file(&host->shost_gendev.kobj,
iter->attr);
}
/* Scsi_Host attributes. */
static ssize_t
qla4xxx_fw_version_show(struct device *dev,
......
......@@ -398,6 +398,16 @@ struct isp_operations {
int (*get_sys_info) (struct scsi_qla_host *);
};
struct ql4_mdump_size_table {
uint32_t size;
uint32_t size_cmask_02;
uint32_t size_cmask_04;
uint32_t size_cmask_08;
uint32_t size_cmask_10;
uint32_t size_cmask_FF;
uint32_t version;
};
/*qla4xxx ipaddress configuration details */
struct ipaddress_config {
uint16_t ipv4_options;
......@@ -485,6 +495,10 @@ struct scsi_qla_host {
#define AF_EEH_BUSY 20 /* 0x00100000 */
#define AF_PCI_CHANNEL_IO_PERM_FAILURE 21 /* 0x00200000 */
#define AF_BUILD_DDB_LIST 22 /* 0x00400000 */
#define AF_82XX_FW_DUMPED 24 /* 0x01000000 */
#define AF_82XX_RST_OWNER 25 /* 0x02000000 */
#define AF_82XX_DUMP_READING 26 /* 0x04000000 */
unsigned long dpc_flags;
#define DPC_RESET_HA 1 /* 0x00000002 */
......@@ -662,6 +676,11 @@ struct scsi_qla_host {
uint32_t nx_dev_init_timeout;
uint32_t nx_reset_timeout;
void *fw_dump;
uint32_t fw_dump_size;
uint32_t fw_dump_capture_mask;
void *fw_dump_tmplt_hdr;
uint32_t fw_dump_tmplt_size;
struct completion mbx_intr_comp;
......@@ -936,4 +955,7 @@ static inline int ql4xxx_reset_active(struct scsi_qla_host *ha)
#define PROCESS_ALL_AENS 0
#define FLUSH_DDB_CHANGED_AENS 1
/* Defines for udev events */
#define QL4_UEVENT_CODE_FW_DUMP 0
#endif /*_QLA4XXX_H */
......@@ -385,6 +385,11 @@ struct qla_flt_region {
#define MBOX_CMD_GET_IP_ADDR_STATE 0x0091
#define MBOX_CMD_SEND_IPV6_ROUTER_SOL 0x0092
#define MBOX_CMD_GET_DB_ENTRY_CURRENT_IP_ADDR 0x0093
#define MBOX_CMD_MINIDUMP 0x0129
/* Minidump subcommand */
#define MINIDUMP_GET_SIZE_SUBCOMMAND 0x00
#define MINIDUMP_GET_TMPLT_SUBCOMMAND 0x01
/* Mailbox 1 */
#define FW_STATE_READY 0x0000
......@@ -1190,4 +1195,27 @@ struct ql_iscsi_stats {
uint8_t reserved2[264]; /* 0x0308 - 0x040F */
};
#define QLA82XX_DBG_STATE_ARRAY_LEN 16
#define QLA82XX_DBG_CAP_SIZE_ARRAY_LEN 8
#define QLA82XX_DBG_RSVD_ARRAY_LEN 8
struct qla4_8xxx_minidump_template_hdr {
uint32_t entry_type;
uint32_t first_entry_offset;
uint32_t size_of_template;
uint32_t capture_debug_level;
uint32_t num_of_entries;
uint32_t version;
uint32_t driver_timestamp;
uint32_t checksum;
uint32_t driver_capture_mask;
uint32_t driver_info_word2;
uint32_t driver_info_word3;
uint32_t driver_info_word4;
uint32_t saved_state_array[QLA82XX_DBG_STATE_ARRAY_LEN];
uint32_t capture_size_array[QLA82XX_DBG_CAP_SIZE_ARRAY_LEN];
};
#endif /* _QLA4X_FW_H */
......@@ -196,10 +196,18 @@ int qla4xxx_bsg_request(struct bsg_job *bsg_job);
int qla4xxx_process_vendor_specific(struct bsg_job *bsg_job);
void qla4xxx_arm_relogin_timer(struct ddb_entry *ddb_entry);
int qla4xxx_get_minidump_template(struct scsi_qla_host *ha,
dma_addr_t phys_addr);
int qla4xxx_req_template_size(struct scsi_qla_host *ha);
void qla4_8xxx_alloc_sysfs_attr(struct scsi_qla_host *ha);
void qla4_8xxx_free_sysfs_attr(struct scsi_qla_host *ha);
void qla4xxx_alloc_fw_dump(struct scsi_qla_host *ha);
extern int ql4xextended_error_logging;
extern int ql4xdontresethba;
extern int ql4xenablemsix;
extern int ql4xmdcapmask;
extern int ql4xenablemd;
extern struct device_attribute *qla4xxx_host_attrs[];
#endif /* _QLA4x_GBL_H */
......@@ -277,6 +277,94 @@ qla4xxx_wait_for_ip_config(struct scsi_qla_host *ha)
return ipv4_wait|ipv6_wait;
}
/**
* qla4xxx_alloc_fw_dump - Allocate memory for minidump data.
* @ha: pointer to host adapter structure.
**/
void qla4xxx_alloc_fw_dump(struct scsi_qla_host *ha)
{
int status;
uint32_t capture_debug_level;
int hdr_entry_bit, k;
void *md_tmp;
dma_addr_t md_tmp_dma;
struct qla4_8xxx_minidump_template_hdr *md_hdr;
if (ha->fw_dump) {
ql4_printk(KERN_WARNING, ha,
"Firmware dump previously allocated.\n");
return;
}
status = qla4xxx_req_template_size(ha);
if (status != QLA_SUCCESS) {
ql4_printk(KERN_INFO, ha,
"scsi%ld: Failed to get template size\n",
ha->host_no);
return;
}
clear_bit(AF_82XX_FW_DUMPED, &ha->flags);
/* Allocate memory for saving the template */
md_tmp = dma_alloc_coherent(&ha->pdev->dev, ha->fw_dump_tmplt_size,
&md_tmp_dma, GFP_KERNEL);
/* Request template */
status = qla4xxx_get_minidump_template(ha, md_tmp_dma);
if (status != QLA_SUCCESS) {
ql4_printk(KERN_INFO, ha,
"scsi%ld: Failed to get minidump template\n",
ha->host_no);
goto alloc_cleanup;
}
md_hdr = (struct qla4_8xxx_minidump_template_hdr *)md_tmp;
capture_debug_level = md_hdr->capture_debug_level;
/* Get capture mask based on module loadtime setting. */
if (ql4xmdcapmask >= 0x3 && ql4xmdcapmask <= 0x7F)
ha->fw_dump_capture_mask = ql4xmdcapmask;
else
ha->fw_dump_capture_mask = capture_debug_level;
md_hdr->driver_capture_mask = ha->fw_dump_capture_mask;
DEBUG2(ql4_printk(KERN_INFO, ha, "Minimum num of entries = %d\n",
md_hdr->num_of_entries));
DEBUG2(ql4_printk(KERN_INFO, ha, "Dump template size = %d\n",
ha->fw_dump_tmplt_size));
DEBUG2(ql4_printk(KERN_INFO, ha, "Selected Capture mask =0x%x\n",
ha->fw_dump_capture_mask));
/* Calculate fw_dump_size */
for (hdr_entry_bit = 0x2, k = 1; (hdr_entry_bit & 0xFF);
hdr_entry_bit <<= 1, k++) {
if (hdr_entry_bit & ha->fw_dump_capture_mask)
ha->fw_dump_size += md_hdr->capture_size_array[k];
}
/* Total firmware dump size including command header */
ha->fw_dump_size += ha->fw_dump_tmplt_size;
ha->fw_dump = vmalloc(ha->fw_dump_size);
if (!ha->fw_dump)
goto alloc_cleanup;
DEBUG2(ql4_printk(KERN_INFO, ha,
"Minidump Tempalate Size = 0x%x KB\n",
ha->fw_dump_tmplt_size));
DEBUG2(ql4_printk(KERN_INFO, ha,
"Total Minidump size = 0x%x KB\n", ha->fw_dump_size));
memcpy(ha->fw_dump, md_tmp, ha->fw_dump_tmplt_size);
ha->fw_dump_tmplt_hdr = ha->fw_dump;
alloc_cleanup:
dma_free_coherent(&ha->pdev->dev, ha->fw_dump_tmplt_size,
md_tmp, md_tmp_dma);
}
static int qla4xxx_fw_ready(struct scsi_qla_host *ha)
{
uint32_t timeout_count;
......@@ -445,9 +533,13 @@ static int qla4xxx_init_firmware(struct scsi_qla_host *ha)
"control block\n", ha->host_no, __func__));
return status;
}
if (!qla4xxx_fw_ready(ha))
return status;
if (is_qla8022(ha) && !test_bit(AF_INIT_DONE, &ha->flags))
qla4xxx_alloc_fw_dump(ha);
return qla4xxx_get_firmware_status(ha);
}
......
......@@ -270,6 +270,79 @@ int qla4xxx_mailbox_command(struct scsi_qla_host *ha, uint8_t inCount,
return status;
}
/**
* qla4xxx_get_minidump_template - Get the firmware template
* @ha: Pointer to host adapter structure.
* @phys_addr: dma address for template
*
* Obtain the minidump template from firmware during initialization
* as it may not be available when minidump is desired.
**/
int qla4xxx_get_minidump_template(struct scsi_qla_host *ha,
dma_addr_t phys_addr)
{
uint32_t mbox_cmd[MBOX_REG_COUNT];
uint32_t mbox_sts[MBOX_REG_COUNT];
int status;
memset(&mbox_cmd, 0, sizeof(mbox_cmd));
memset(&mbox_sts, 0, sizeof(mbox_sts));
mbox_cmd[0] = MBOX_CMD_MINIDUMP;
mbox_cmd[1] = MINIDUMP_GET_TMPLT_SUBCOMMAND;
mbox_cmd[2] = LSDW(phys_addr);
mbox_cmd[3] = MSDW(phys_addr);
mbox_cmd[4] = ha->fw_dump_tmplt_size;
mbox_cmd[5] = 0;
status = qla4xxx_mailbox_command(ha, MBOX_REG_COUNT, 2, &mbox_cmd[0],
&mbox_sts[0]);
if (status != QLA_SUCCESS) {
DEBUG2(ql4_printk(KERN_INFO, ha,
"scsi%ld: %s: Cmd = %08X, mbx[0] = 0x%04x, mbx[1] = 0x%04x\n",
ha->host_no, __func__, mbox_cmd[0],
mbox_sts[0], mbox_sts[1]));
}
return status;
}
/**
* qla4xxx_req_template_size - Get minidump template size from firmware.
* @ha: Pointer to host adapter structure.
**/
int qla4xxx_req_template_size(struct scsi_qla_host *ha)
{
uint32_t mbox_cmd[MBOX_REG_COUNT];
uint32_t mbox_sts[MBOX_REG_COUNT];
int status;
memset(&mbox_cmd, 0, sizeof(mbox_cmd));
memset(&mbox_sts, 0, sizeof(mbox_sts));
mbox_cmd[0] = MBOX_CMD_MINIDUMP;
mbox_cmd[1] = MINIDUMP_GET_SIZE_SUBCOMMAND;
status = qla4xxx_mailbox_command(ha, MBOX_REG_COUNT, 8, &mbox_cmd[0],
&mbox_sts[0]);
if (status == QLA_SUCCESS) {
ha->fw_dump_tmplt_size = mbox_sts[1];
DEBUG2(ql4_printk(KERN_INFO, ha,
"%s: sts[0]=0x%04x, template size=0x%04x, size_cm_02=0x%04x, size_cm_04=0x%04x, size_cm_08=0x%04x, size_cm_10=0x%04x, size_cm_FF=0x%04x, version=0x%04x\n",
__func__, mbox_sts[0], mbox_sts[1],
mbox_sts[2], mbox_sts[3], mbox_sts[4],
mbox_sts[5], mbox_sts[6], mbox_sts[7]));
if (ha->fw_dump_tmplt_size == 0)
status = QLA_ERROR;
} else {
ql4_printk(KERN_WARNING, ha,
"%s: Error sts[0]=0x%04x, mbx[1]=0x%04x\n",
__func__, mbox_sts[0], mbox_sts[1]);
status = QLA_ERROR;
}
return status;
}
void qla4xxx_mailbox_premature_completion(struct scsi_qla_host *ha)
{
set_bit(AF_FW_RECOVERY, &ha->flags);
......
This diff is collapsed.
......@@ -792,4 +792,196 @@ struct crb_addr_pair {
#define MIU_TEST_AGT_WRDATA_UPPER_LO (0x0b0)
#define MIU_TEST_AGT_WRDATA_UPPER_HI (0x0b4)
/* Minidump related */
/* Entry Type Defines */
#define QLA82XX_RDNOP 0
#define QLA82XX_RDCRB 1
#define QLA82XX_RDMUX 2
#define QLA82XX_QUEUE 3
#define QLA82XX_BOARD 4
#define QLA82XX_RDOCM 6
#define QLA82XX_PREGS 7
#define QLA82XX_L1DTG 8
#define QLA82XX_L1ITG 9
#define QLA82XX_L1DAT 11
#define QLA82XX_L1INS 12
#define QLA82XX_L2DTG 21
#define QLA82XX_L2ITG 22
#define QLA82XX_L2DAT 23
#define QLA82XX_L2INS 24
#define QLA82XX_RDROM 71
#define QLA82XX_RDMEM 72
#define QLA82XX_CNTRL 98
#define QLA82XX_RDEND 255
/* Opcodes for Control Entries.
* These Flags are bit fields.
*/
#define QLA82XX_DBG_OPCODE_WR 0x01
#define QLA82XX_DBG_OPCODE_RW 0x02
#define QLA82XX_DBG_OPCODE_AND 0x04
#define QLA82XX_DBG_OPCODE_OR 0x08
#define QLA82XX_DBG_OPCODE_POLL 0x10
#define QLA82XX_DBG_OPCODE_RDSTATE 0x20
#define QLA82XX_DBG_OPCODE_WRSTATE 0x40
#define QLA82XX_DBG_OPCODE_MDSTATE 0x80
/* Driver Flags */
#define QLA82XX_DBG_SKIPPED_FLAG 0x80 /* driver skipped this entry */
#define QLA82XX_DBG_SIZE_ERR_FLAG 0x40 /* Entry vs Capture size
* mismatch */
/* Driver_code is for driver to write some info about the entry
* currently not used.
*/
struct qla82xx_minidump_entry_hdr {
uint32_t entry_type;
uint32_t entry_size;
uint32_t entry_capture_size;
struct {
uint8_t entry_capture_mask;
uint8_t entry_code;
uint8_t driver_code;
uint8_t driver_flags;
} d_ctrl;
};
/* Read CRB entry header */
struct qla82xx_minidump_entry_crb {
struct qla82xx_minidump_entry_hdr h;
uint32_t addr;
struct {
uint8_t addr_stride;
uint8_t state_index_a;
uint16_t poll_timeout;
} crb_strd;
uint32_t data_size;
uint32_t op_count;
struct {
uint8_t opcode;
uint8_t state_index_v;
uint8_t shl;
uint8_t shr;
} crb_ctrl;
uint32_t value_1;
uint32_t value_2;
uint32_t value_3;
};
struct qla82xx_minidump_entry_cache {
struct qla82xx_minidump_entry_hdr h;
uint32_t tag_reg_addr;
struct {
uint16_t tag_value_stride;
uint16_t init_tag_value;
} addr_ctrl;
uint32_t data_size;
uint32_t op_count;
uint32_t control_addr;
struct {
uint16_t write_value;
uint8_t poll_mask;
uint8_t poll_wait;
} cache_ctrl;
uint32_t read_addr;
struct {
uint8_t read_addr_stride;
uint8_t read_addr_cnt;
uint16_t rsvd_1;
} read_ctrl;
};
/* Read OCM */
struct qla82xx_minidump_entry_rdocm {
struct qla82xx_minidump_entry_hdr h;
uint32_t rsvd_0;
uint32_t rsvd_1;
uint32_t data_size;
uint32_t op_count;
uint32_t rsvd_2;
uint32_t rsvd_3;
uint32_t read_addr;
uint32_t read_addr_stride;
};
/* Read Memory */
struct qla82xx_minidump_entry_rdmem {
struct qla82xx_minidump_entry_hdr h;
uint32_t rsvd[6];
uint32_t read_addr;
uint32_t read_data_size;
};
/* Read ROM */
struct qla82xx_minidump_entry_rdrom {
struct qla82xx_minidump_entry_hdr h;
uint32_t rsvd[6];
uint32_t read_addr;
uint32_t read_data_size;
};
/* Mux entry */
struct qla82xx_minidump_entry_mux {
struct qla82xx_minidump_entry_hdr h;
uint32_t select_addr;
uint32_t rsvd_0;
uint32_t data_size;
uint32_t op_count;
uint32_t select_value;
uint32_t select_value_stride;
uint32_t read_addr;
uint32_t rsvd_1;
};
/* Queue entry */
struct qla82xx_minidump_entry_queue {
struct qla82xx_minidump_entry_hdr h;
uint32_t select_addr;
struct {
uint16_t queue_id_stride;
uint16_t rsvd_0;
} q_strd;
uint32_t data_size;
uint32_t op_count;
uint32_t rsvd_1;
uint32_t rsvd_2;
uint32_t read_addr;
struct {
uint8_t read_addr_stride;
uint8_t read_addr_cnt;
uint16_t rsvd_3;
} rd_strd;
};
#define QLA82XX_MINIDUMP_OCM0_SIZE (256 * 1024)
#define QLA82XX_MINIDUMP_L1C_SIZE (256 * 1024)
#define QLA82XX_MINIDUMP_L2C_SIZE 1572864
#define QLA82XX_MINIDUMP_COMMON_STR_SIZE 0
#define QLA82XX_MINIDUMP_FCOE_STR_SIZE 0
#define QLA82XX_MINIDUMP_MEM_SIZE 0
#define QLA82XX_MAX_ENTRY_HDR 4
struct qla82xx_minidump {
uint32_t md_ocm0_data[QLA82XX_MINIDUMP_OCM0_SIZE];
uint32_t md_l1c_data[QLA82XX_MINIDUMP_L1C_SIZE];
uint32_t md_l2c_data[QLA82XX_MINIDUMP_L2C_SIZE];
uint32_t md_cs_data[QLA82XX_MINIDUMP_COMMON_STR_SIZE];
uint32_t md_fcoes_data[QLA82XX_MINIDUMP_FCOE_STR_SIZE];
uint32_t md_mem_data[QLA82XX_MINIDUMP_MEM_SIZE];
};
#define MBC_DIAGNOSTIC_MINIDUMP_TEMPLATE 0x129
#define RQST_TMPLT_SIZE 0x0
#define RQST_TMPLT 0x1
#define MD_DIRECT_ROM_WINDOW 0x42110030
#define MD_DIRECT_ROM_READ_BASE 0x42150000
#define MD_MIU_TEST_AGT_CTRL 0x41000090
#define MD_MIU_TEST_AGT_ADDR_LO 0x41000094
#define MD_MIU_TEST_AGT_ADDR_HI 0x41000098
static const int MD_MIU_TEST_AGT_RDDATA[] = { 0x410000A8,
0x410000AC, 0x410000B8, 0x410000BC };
#endif
......@@ -82,6 +82,20 @@ MODULE_PARM_DESC(ql4xsess_recovery_tmo,
" Target Session Recovery Timeout.\n"
"\t\t Default: 120 sec.");
int ql4xmdcapmask = 0x1F;
module_param(ql4xmdcapmask, int, S_IRUGO);
MODULE_PARM_DESC(ql4xmdcapmask,
" Set the Minidump driver capture mask level.\n"
"\t\t Default is 0x1F.\n"
"\t\t Can be set to 0x3, 0x7, 0xF, 0x1F, 0x3F, 0x7F");
int ql4xenablemd = 1;
module_param(ql4xenablemd, int, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(ql4xenablemd,
" Set to enable minidump.\n"
"\t\t 0 - disable minidump\n"
"\t\t 1 - enable minidump (Default)");
static int qla4xxx_wait_for_hba_online(struct scsi_qla_host *ha);
/*
* SCSI host template entry points
......@@ -2265,6 +2279,9 @@ static void qla4xxx_mem_free(struct scsi_qla_host *ha)
dma_free_coherent(&ha->pdev->dev, ha->queues_len, ha->queues,
ha->queues_dma);
if (ha->fw_dump)
vfree(ha->fw_dump);
ha->queues_len = 0;
ha->queues = NULL;
ha->queues_dma = 0;
......@@ -2274,6 +2291,8 @@ static void qla4xxx_mem_free(struct scsi_qla_host *ha)
ha->response_dma = 0;
ha->shadow_regs = NULL;
ha->shadow_regs_dma = 0;
ha->fw_dump = NULL;
ha->fw_dump_size = 0;
/* Free srb pool. */
if (ha->srb_mempool)
......@@ -5068,6 +5087,8 @@ static int __devinit qla4xxx_probe_adapter(struct pci_dev *pdev,
set_bit(AF_INIT_DONE, &ha->flags);
qla4_8xxx_alloc_sysfs_attr(ha);
printk(KERN_INFO
" QLogic iSCSI HBA Driver version: %s\n"
" QLogic ISP%04x @ %s, host#=%ld, fw=%02d.%02d.%02d.%02d\n",
......@@ -5194,6 +5215,7 @@ static void __devexit qla4xxx_remove_adapter(struct pci_dev *pdev)
iscsi_boot_destroy_kset(ha->boot_kset);
qla4xxx_destroy_fw_ddb_session(ha);
qla4_8xxx_free_sysfs_attr(ha);
scsi_remove_host(ha->host);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment