Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 08de2844 authored by Giridhar Malavali's avatar Giridhar Malavali Committed by James Bottomley
Browse files

[SCSI] qla2xxx: Add support for ISP82xx to capture dump (minidump) on failure.



Minidump allows us to catpure a snapshot of the firmware/hardware states at the
time of failure for further analysis.

[jejb: added missing #include <linux/vmalloc.h>
Reported-by: Stephen Rothwell <sfr@canb.auug.org.au> ]
Signed-off-by: default avatarGiridhar Malavali <giridhar.malavali@qlogic.com>
Signed-off-by: default avatarChad Dupuis <chad.dupuis@qlogic.com>
Signed-off-by: default avatarJames Bottomley <JBottomley@Parallels.com>
parent 86a9668a
Loading
Loading
Loading
Loading
+42 −8
Original line number Diff line number Diff line
@@ -23,10 +23,22 @@ qla2x00_sysfs_read_fw_dump(struct file *filp, struct kobject *kobj,
	struct scsi_qla_host *vha = shost_priv(dev_to_shost(container_of(kobj,
	    struct device, kobj)));
	struct qla_hw_data *ha = vha->hw;
	int rval = 0;

	if (ha->fw_dump_reading == 0)
		return 0;

	if (IS_QLA82XX(ha)) {
		if (off < ha->md_template_size) {
			rval = memory_read_from_buffer(buf, count,
			    &off, ha->md_tmplt_hdr, ha->md_template_size);
			return rval;
		}
		off -= ha->md_template_size;
		rval = memory_read_from_buffer(buf, count,
		    &off, ha->md_dump, ha->md_dump_size);
		return rval;
	} else
		return memory_read_from_buffer(buf, count, &off, ha->fw_dump,
					ha->fw_dump_len);
}
@@ -41,12 +53,6 @@ qla2x00_sysfs_write_fw_dump(struct file *filp, struct kobject *kobj,
	struct qla_hw_data *ha = vha->hw;
	int reading;

	if (IS_QLA82XX(ha)) {
		ql_dbg(ql_dbg_user, vha, 0x705b,
		    "Firmware dump not supported for ISP82xx\n");
		return count;
	}

	if (off != 0)
		return (0);

@@ -59,6 +65,10 @@ qla2x00_sysfs_write_fw_dump(struct file *filp, struct kobject *kobj,
		ql_log(ql_log_info, vha, 0x705d,
		    "Firmware dump cleared on (%ld).\n", vha->host_no);

		if (IS_QLA82XX(vha->hw)) {
			qla82xx_md_free(vha);
			qla82xx_md_prep(vha);
		}
		ha->fw_dump_reading = 0;
		ha->fw_dumped = 0;
		break;
@@ -75,8 +85,27 @@ qla2x00_sysfs_write_fw_dump(struct file *filp, struct kobject *kobj,
		qla2x00_alloc_fw_dump(vha);
		break;
	case 3:
		if (IS_QLA82XX(ha)) {
			qla82xx_idc_lock(ha);
			qla82xx_set_reset_owner(vha);
			qla82xx_idc_unlock(ha);
		} else
			qla2x00_system_error(vha);
		break;
	case 4:
		if (IS_QLA82XX(ha)) {
			if (ha->md_tmplt_hdr)
				ql_dbg(ql_dbg_user, vha, 0x705b,
				    "MiniDump supported with this firmware.\n");
			else
				ql_dbg(ql_dbg_user, vha, 0x709d,
				    "MiniDump not supported with this firmware.\n");
		}
		break;
	case 5:
		if (IS_QLA82XX(ha))
			set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
		break;
	}
	return (count);
}
@@ -546,6 +575,11 @@ qla2x00_sysfs_write_reset(struct file *filp, struct kobject *kobj,

		scsi_block_requests(vha->host);
		set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
		if (IS_QLA82XX(ha)) {
			qla82xx_idc_lock(ha);
			qla82xx_set_reset_owner(vha);
			qla82xx_idc_unlock(ha);
		}
		qla2xxx_wake_dpc(vha);
		qla2x00_wait_for_chip_reset(vha);
		scsi_unblock_requests(vha->host);
+1 −1
Original line number Diff line number Diff line
@@ -403,7 +403,7 @@ qla25xx_copy_mq(struct qla_hw_data *ha, void *ptr, uint32_t **last_chain)
	return ptr + sizeof(struct qla2xxx_mq_chain);
}

static void
void
qla2xxx_dump_post_process(scsi_qla_host_t *vha, int rval)
{
	struct qla_hw_data *ha = vha->hw;
+8 −1
Original line number Diff line number Diff line
@@ -2438,7 +2438,8 @@ struct qla_hw_data {
		uint32_t	quiesce_owner:1;
		uint32_t	thermal_supported:1;
		uint32_t	isp82xx_reset_hdlr_active:1;
		/* 26 bits */
		uint32_t	isp82xx_reset_owner:1;
		/* 28 bits */
	} flags;

	/* This spinlock is used to protect "io transactions", you must
@@ -2822,6 +2823,12 @@ struct qla_hw_data {

	uint8_t fw_type;
	__le32 file_prd_off;	/* File firmware product offset */

	uint32_t	md_template_size;
	void		*md_tmplt_hdr;
	dma_addr_t      md_tmplt_hdr_dma;
	void            *md_dump;
	uint32_t	md_dump_size;
};

/*
+14 −0
Original line number Diff line number Diff line
@@ -104,6 +104,8 @@ extern int ql2xenablehba_err_chk;
extern int ql2xtargetreset;
extern int ql2xdontresethba;
extern unsigned int ql2xmaxlun;
extern int ql2xmdcapmask;
extern int ql2xmdenable;

extern int qla2x00_loop_reset(scsi_qla_host_t *);
extern void qla2x00_abort_all_cmds(scsi_qla_host_t *, int);
@@ -442,6 +444,7 @@ extern void qla2x00_dump_buffer_zipped(uint8_t *, uint32_t);
extern void ql_dump_regs(uint32_t, scsi_qla_host_t *, int32_t);
extern void ql_dump_buffer(uint32_t, scsi_qla_host_t *, int32_t,
	uint8_t *, uint32_t);
extern void qla2xxx_dump_post_process(scsi_qla_host_t *, int);

/*
 * Global Function Prototypes in qla_gs.c source file.
@@ -570,6 +573,7 @@ extern int qla82xx_mbx_intr_disable(scsi_qla_host_t *);
extern void qla82xx_start_iocbs(srb_t *);
extern int qla82xx_fcoe_ctx_reset(scsi_qla_host_t *);
extern void qla82xx_chip_reset_cleanup(scsi_qla_host_t *);
extern char *qdev_state(uint32_t);

/* BSG related functions */
extern int qla24xx_bsg_request(struct fc_bsg_job *);
@@ -579,4 +583,14 @@ extern int qla2x00_issue_iocb_timeout(scsi_qla_host_t *, void *,
	dma_addr_t, size_t, uint32_t);
extern int qla2x00_get_idma_speed(scsi_qla_host_t *, uint16_t,
	uint16_t *, uint16_t *);

/* Minidump related functions */
extern int qla82xx_md_get_template_size(scsi_qla_host_t *);
extern int qla82xx_md_get_template(scsi_qla_host_t *);
extern int qla82xx_md_alloc(scsi_qla_host_t *);
extern void qla82xx_md_free(scsi_qla_host_t *);
extern int qla82xx_md_collect(scsi_qla_host_t *);
extern void qla82xx_md_prep(scsi_qla_host_t *);
extern void qla82xx_set_reset_owner(scsi_qla_host_t *);

#endif /* _QLA_GBL_H */
+4 −6
Original line number Diff line number Diff line
@@ -1503,11 +1503,9 @@ qla2x00_setup_chip(scsi_qla_host_t *vha)
				    &ha->fw_xcb_count, NULL, NULL,
				    &ha->max_npiv_vports, NULL);

				if (!fw_major_version && ql2xallocfwdump) {
					if (!IS_QLA82XX(ha))
				if (!fw_major_version && ql2xallocfwdump)
					qla2x00_alloc_fw_dump(vha);
			}
			}
		} else {
			ql_log(ql_log_fatal, vha, 0x00cd,
			    "ISP Firmware failed checksum.\n");
@@ -1924,7 +1922,7 @@ qla2x00_fw_ready(scsi_qla_host_t *vha)
					rval = qla84xx_init_chip(vha);
					if (rval != QLA_SUCCESS) {
						ql_log(ql_log_warn,
						    vha, 0x8043,
						    vha, 0x8026,
						    "Init chip failed.\n");
						break;
					}
@@ -1933,7 +1931,7 @@ qla2x00_fw_ready(scsi_qla_host_t *vha)
					cs84xx_time = jiffies - cs84xx_time;
					wtime += cs84xx_time;
					mtime += cs84xx_time;
					ql_dbg(ql_dbg_taskm, vha, 0x8042,
					ql_dbg(ql_dbg_taskm, vha, 0x8025,
					    "Increasing wait time by %ld. "
					    "New time %ld.\n", cs84xx_time,
					    wtime);
Loading