diff options
author | Giridhar Malavali <giridhar.malavali@qlogic.com> | 2011-08-16 14:31:44 -0400 |
---|---|---|
committer | James Bottomley <JBottomley@Parallels.com> | 2011-08-29 03:12:26 -0400 |
commit | 08de2844c626511cfd1db9c36e5e7d126707f780 (patch) | |
tree | 0acfe3150cc5d0eb28c4c242c040c45cec5758af /drivers/scsi | |
parent | 86a9668a8d29ea711613e1cb37efa68e7c4db564 (diff) |
[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: Giridhar Malavali <giridhar.malavali@qlogic.com>
Signed-off-by: Chad Dupuis <chad.dupuis@qlogic.com>
Signed-off-by: James Bottomley <JBottomley@Parallels.com>
Diffstat (limited to 'drivers/scsi')
-rw-r--r-- | drivers/scsi/qla2xxx/qla_attr.c | 50 | ||||
-rw-r--r-- | drivers/scsi/qla2xxx/qla_dbg.c | 2 | ||||
-rw-r--r-- | drivers/scsi/qla2xxx/qla_def.h | 9 | ||||
-rw-r--r-- | drivers/scsi/qla2xxx/qla_gbl.h | 14 | ||||
-rw-r--r-- | drivers/scsi/qla2xxx/qla_init.c | 10 | ||||
-rw-r--r-- | drivers/scsi/qla2xxx/qla_mbx.c | 89 | ||||
-rw-r--r-- | drivers/scsi/qla2xxx/qla_nx.c | 910 | ||||
-rw-r--r-- | drivers/scsi/qla2xxx/qla_nx.h | 254 | ||||
-rw-r--r-- | drivers/scsi/qla2xxx/qla_os.c | 27 |
9 files changed, 1315 insertions, 50 deletions
diff --git a/drivers/scsi/qla2xxx/qla_attr.c b/drivers/scsi/qla2xxx/qla_attr.c index a31e05f3bfd4..df0002f78805 100644 --- a/drivers/scsi/qla2xxx/qla_attr.c +++ b/drivers/scsi/qla2xxx/qla_attr.c | |||
@@ -23,11 +23,23 @@ qla2x00_sysfs_read_fw_dump(struct file *filp, struct kobject *kobj, | |||
23 | struct scsi_qla_host *vha = shost_priv(dev_to_shost(container_of(kobj, | 23 | struct scsi_qla_host *vha = shost_priv(dev_to_shost(container_of(kobj, |
24 | struct device, kobj))); | 24 | struct device, kobj))); |
25 | struct qla_hw_data *ha = vha->hw; | 25 | struct qla_hw_data *ha = vha->hw; |
26 | int rval = 0; | ||
26 | 27 | ||
27 | if (ha->fw_dump_reading == 0) | 28 | if (ha->fw_dump_reading == 0) |
28 | return 0; | 29 | return 0; |
29 | 30 | ||
30 | return memory_read_from_buffer(buf, count, &off, ha->fw_dump, | 31 | if (IS_QLA82XX(ha)) { |
32 | if (off < ha->md_template_size) { | ||
33 | rval = memory_read_from_buffer(buf, count, | ||
34 | &off, ha->md_tmplt_hdr, ha->md_template_size); | ||
35 | return rval; | ||
36 | } | ||
37 | off -= ha->md_template_size; | ||
38 | rval = memory_read_from_buffer(buf, count, | ||
39 | &off, ha->md_dump, ha->md_dump_size); | ||
40 | return rval; | ||
41 | } else | ||
42 | return memory_read_from_buffer(buf, count, &off, ha->fw_dump, | ||
31 | ha->fw_dump_len); | 43 | ha->fw_dump_len); |
32 | } | 44 | } |
33 | 45 | ||
@@ -41,12 +53,6 @@ qla2x00_sysfs_write_fw_dump(struct file *filp, struct kobject *kobj, | |||
41 | struct qla_hw_data *ha = vha->hw; | 53 | struct qla_hw_data *ha = vha->hw; |
42 | int reading; | 54 | int reading; |
43 | 55 | ||
44 | if (IS_QLA82XX(ha)) { | ||
45 | ql_dbg(ql_dbg_user, vha, 0x705b, | ||
46 | "Firmware dump not supported for ISP82xx\n"); | ||
47 | return count; | ||
48 | } | ||
49 | |||
50 | if (off != 0) | 56 | if (off != 0) |
51 | return (0); | 57 | return (0); |
52 | 58 | ||
@@ -59,6 +65,10 @@ qla2x00_sysfs_write_fw_dump(struct file *filp, struct kobject *kobj, | |||
59 | ql_log(ql_log_info, vha, 0x705d, | 65 | ql_log(ql_log_info, vha, 0x705d, |
60 | "Firmware dump cleared on (%ld).\n", vha->host_no); | 66 | "Firmware dump cleared on (%ld).\n", vha->host_no); |
61 | 67 | ||
68 | if (IS_QLA82XX(vha->hw)) { | ||
69 | qla82xx_md_free(vha); | ||
70 | qla82xx_md_prep(vha); | ||
71 | } | ||
62 | ha->fw_dump_reading = 0; | 72 | ha->fw_dump_reading = 0; |
63 | ha->fw_dumped = 0; | 73 | ha->fw_dumped = 0; |
64 | break; | 74 | break; |
@@ -75,7 +85,26 @@ qla2x00_sysfs_write_fw_dump(struct file *filp, struct kobject *kobj, | |||
75 | qla2x00_alloc_fw_dump(vha); | 85 | qla2x00_alloc_fw_dump(vha); |
76 | break; | 86 | break; |
77 | case 3: | 87 | case 3: |
78 | qla2x00_system_error(vha); | 88 | if (IS_QLA82XX(ha)) { |
89 | qla82xx_idc_lock(ha); | ||
90 | qla82xx_set_reset_owner(vha); | ||
91 | qla82xx_idc_unlock(ha); | ||
92 | } else | ||
93 | qla2x00_system_error(vha); | ||
94 | break; | ||
95 | case 4: | ||
96 | if (IS_QLA82XX(ha)) { | ||
97 | if (ha->md_tmplt_hdr) | ||
98 | ql_dbg(ql_dbg_user, vha, 0x705b, | ||
99 | "MiniDump supported with this firmware.\n"); | ||
100 | else | ||
101 | ql_dbg(ql_dbg_user, vha, 0x709d, | ||
102 | "MiniDump not supported with this firmware.\n"); | ||
103 | } | ||
104 | break; | ||
105 | case 5: | ||
106 | if (IS_QLA82XX(ha)) | ||
107 | set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags); | ||
79 | break; | 108 | break; |
80 | } | 109 | } |
81 | return (count); | 110 | return (count); |
@@ -546,6 +575,11 @@ qla2x00_sysfs_write_reset(struct file *filp, struct kobject *kobj, | |||
546 | 575 | ||
547 | scsi_block_requests(vha->host); | 576 | scsi_block_requests(vha->host); |
548 | set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags); | 577 | set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags); |
578 | if (IS_QLA82XX(ha)) { | ||
579 | qla82xx_idc_lock(ha); | ||
580 | qla82xx_set_reset_owner(vha); | ||
581 | qla82xx_idc_unlock(ha); | ||
582 | } | ||
549 | qla2xxx_wake_dpc(vha); | 583 | qla2xxx_wake_dpc(vha); |
550 | qla2x00_wait_for_chip_reset(vha); | 584 | qla2x00_wait_for_chip_reset(vha); |
551 | scsi_unblock_requests(vha->host); | 585 | scsi_unblock_requests(vha->host); |
diff --git a/drivers/scsi/qla2xxx/qla_dbg.c b/drivers/scsi/qla2xxx/qla_dbg.c index d79cd8a5f831..238bc9178219 100644 --- a/drivers/scsi/qla2xxx/qla_dbg.c +++ b/drivers/scsi/qla2xxx/qla_dbg.c | |||
@@ -403,7 +403,7 @@ qla25xx_copy_mq(struct qla_hw_data *ha, void *ptr, uint32_t **last_chain) | |||
403 | return ptr + sizeof(struct qla2xxx_mq_chain); | 403 | return ptr + sizeof(struct qla2xxx_mq_chain); |
404 | } | 404 | } |
405 | 405 | ||
406 | static void | 406 | void |
407 | qla2xxx_dump_post_process(scsi_qla_host_t *vha, int rval) | 407 | qla2xxx_dump_post_process(scsi_qla_host_t *vha, int rval) |
408 | { | 408 | { |
409 | struct qla_hw_data *ha = vha->hw; | 409 | struct qla_hw_data *ha = vha->hw; |
diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h index a03eaf40f377..fcf052c50bf5 100644 --- a/drivers/scsi/qla2xxx/qla_def.h +++ b/drivers/scsi/qla2xxx/qla_def.h | |||
@@ -2438,7 +2438,8 @@ struct qla_hw_data { | |||
2438 | uint32_t quiesce_owner:1; | 2438 | uint32_t quiesce_owner:1; |
2439 | uint32_t thermal_supported:1; | 2439 | uint32_t thermal_supported:1; |
2440 | uint32_t isp82xx_reset_hdlr_active:1; | 2440 | uint32_t isp82xx_reset_hdlr_active:1; |
2441 | /* 26 bits */ | 2441 | uint32_t isp82xx_reset_owner:1; |
2442 | /* 28 bits */ | ||
2442 | } flags; | 2443 | } flags; |
2443 | 2444 | ||
2444 | /* This spinlock is used to protect "io transactions", you must | 2445 | /* This spinlock is used to protect "io transactions", you must |
@@ -2822,6 +2823,12 @@ struct qla_hw_data { | |||
2822 | 2823 | ||
2823 | uint8_t fw_type; | 2824 | uint8_t fw_type; |
2824 | __le32 file_prd_off; /* File firmware product offset */ | 2825 | __le32 file_prd_off; /* File firmware product offset */ |
2826 | |||
2827 | uint32_t md_template_size; | ||
2828 | void *md_tmplt_hdr; | ||
2829 | dma_addr_t md_tmplt_hdr_dma; | ||
2830 | void *md_dump; | ||
2831 | uint32_t md_dump_size; | ||
2825 | }; | 2832 | }; |
2826 | 2833 | ||
2827 | /* | 2834 | /* |
diff --git a/drivers/scsi/qla2xxx/qla_gbl.h b/drivers/scsi/qla2xxx/qla_gbl.h index 29b1a3e28231..df58e2451781 100644 --- a/drivers/scsi/qla2xxx/qla_gbl.h +++ b/drivers/scsi/qla2xxx/qla_gbl.h | |||
@@ -104,6 +104,8 @@ extern int ql2xenablehba_err_chk; | |||
104 | extern int ql2xtargetreset; | 104 | extern int ql2xtargetreset; |
105 | extern int ql2xdontresethba; | 105 | extern int ql2xdontresethba; |
106 | extern unsigned int ql2xmaxlun; | 106 | extern unsigned int ql2xmaxlun; |
107 | extern int ql2xmdcapmask; | ||
108 | extern int ql2xmdenable; | ||
107 | 109 | ||
108 | extern int qla2x00_loop_reset(scsi_qla_host_t *); | 110 | extern int qla2x00_loop_reset(scsi_qla_host_t *); |
109 | extern void qla2x00_abort_all_cmds(scsi_qla_host_t *, int); | 111 | 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); | |||
442 | extern void ql_dump_regs(uint32_t, scsi_qla_host_t *, int32_t); | 444 | extern void ql_dump_regs(uint32_t, scsi_qla_host_t *, int32_t); |
443 | extern void ql_dump_buffer(uint32_t, scsi_qla_host_t *, int32_t, | 445 | extern void ql_dump_buffer(uint32_t, scsi_qla_host_t *, int32_t, |
444 | uint8_t *, uint32_t); | 446 | uint8_t *, uint32_t); |
447 | extern void qla2xxx_dump_post_process(scsi_qla_host_t *, int); | ||
445 | 448 | ||
446 | /* | 449 | /* |
447 | * Global Function Prototypes in qla_gs.c source file. | 450 | * Global Function Prototypes in qla_gs.c source file. |
@@ -570,6 +573,7 @@ extern int qla82xx_mbx_intr_disable(scsi_qla_host_t *); | |||
570 | extern void qla82xx_start_iocbs(srb_t *); | 573 | extern void qla82xx_start_iocbs(srb_t *); |
571 | extern int qla82xx_fcoe_ctx_reset(scsi_qla_host_t *); | 574 | extern int qla82xx_fcoe_ctx_reset(scsi_qla_host_t *); |
572 | extern void qla82xx_chip_reset_cleanup(scsi_qla_host_t *); | 575 | extern void qla82xx_chip_reset_cleanup(scsi_qla_host_t *); |
576 | extern char *qdev_state(uint32_t); | ||
573 | 577 | ||
574 | /* BSG related functions */ | 578 | /* BSG related functions */ |
575 | extern int qla24xx_bsg_request(struct fc_bsg_job *); | 579 | extern int qla24xx_bsg_request(struct fc_bsg_job *); |
@@ -579,4 +583,14 @@ extern int qla2x00_issue_iocb_timeout(scsi_qla_host_t *, void *, | |||
579 | dma_addr_t, size_t, uint32_t); | 583 | dma_addr_t, size_t, uint32_t); |
580 | extern int qla2x00_get_idma_speed(scsi_qla_host_t *, uint16_t, | 584 | extern int qla2x00_get_idma_speed(scsi_qla_host_t *, uint16_t, |
581 | uint16_t *, uint16_t *); | 585 | uint16_t *, uint16_t *); |
586 | |||
587 | /* Minidump related functions */ | ||
588 | extern int qla82xx_md_get_template_size(scsi_qla_host_t *); | ||
589 | extern int qla82xx_md_get_template(scsi_qla_host_t *); | ||
590 | extern int qla82xx_md_alloc(scsi_qla_host_t *); | ||
591 | extern void qla82xx_md_free(scsi_qla_host_t *); | ||
592 | extern int qla82xx_md_collect(scsi_qla_host_t *); | ||
593 | extern void qla82xx_md_prep(scsi_qla_host_t *); | ||
594 | extern void qla82xx_set_reset_owner(scsi_qla_host_t *); | ||
595 | |||
582 | #endif /* _QLA_GBL_H */ | 596 | #endif /* _QLA_GBL_H */ |
diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c index 37da04d3db26..2375e38964e9 100644 --- a/drivers/scsi/qla2xxx/qla_init.c +++ b/drivers/scsi/qla2xxx/qla_init.c | |||
@@ -1503,10 +1503,8 @@ enable_82xx_npiv: | |||
1503 | &ha->fw_xcb_count, NULL, NULL, | 1503 | &ha->fw_xcb_count, NULL, NULL, |
1504 | &ha->max_npiv_vports, NULL); | 1504 | &ha->max_npiv_vports, NULL); |
1505 | 1505 | ||
1506 | if (!fw_major_version && ql2xallocfwdump) { | 1506 | if (!fw_major_version && ql2xallocfwdump) |
1507 | if (!IS_QLA82XX(ha)) | 1507 | qla2x00_alloc_fw_dump(vha); |
1508 | qla2x00_alloc_fw_dump(vha); | ||
1509 | } | ||
1510 | } | 1508 | } |
1511 | } else { | 1509 | } else { |
1512 | ql_log(ql_log_fatal, vha, 0x00cd, | 1510 | ql_log(ql_log_fatal, vha, 0x00cd, |
@@ -1924,7 +1922,7 @@ qla2x00_fw_ready(scsi_qla_host_t *vha) | |||
1924 | rval = qla84xx_init_chip(vha); | 1922 | rval = qla84xx_init_chip(vha); |
1925 | if (rval != QLA_SUCCESS) { | 1923 | if (rval != QLA_SUCCESS) { |
1926 | ql_log(ql_log_warn, | 1924 | ql_log(ql_log_warn, |
1927 | vha, 0x8043, | 1925 | vha, 0x8026, |
1928 | "Init chip failed.\n"); | 1926 | "Init chip failed.\n"); |
1929 | break; | 1927 | break; |
1930 | } | 1928 | } |
@@ -1933,7 +1931,7 @@ qla2x00_fw_ready(scsi_qla_host_t *vha) | |||
1933 | cs84xx_time = jiffies - cs84xx_time; | 1931 | cs84xx_time = jiffies - cs84xx_time; |
1934 | wtime += cs84xx_time; | 1932 | wtime += cs84xx_time; |
1935 | mtime += cs84xx_time; | 1933 | mtime += cs84xx_time; |
1936 | ql_dbg(ql_dbg_taskm, vha, 0x8042, | 1934 | ql_dbg(ql_dbg_taskm, vha, 0x8025, |
1937 | "Increasing wait time by %ld. " | 1935 | "Increasing wait time by %ld. " |
1938 | "New time %ld.\n", cs84xx_time, | 1936 | "New time %ld.\n", cs84xx_time, |
1939 | wtime); | 1937 | wtime); |
diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c index f7604ea1af83..a41137452c41 100644 --- a/drivers/scsi/qla2xxx/qla_mbx.c +++ b/drivers/scsi/qla2xxx/qla_mbx.c | |||
@@ -4186,3 +4186,92 @@ qla82xx_mbx_intr_disable(scsi_qla_host_t *vha) | |||
4186 | 4186 | ||
4187 | return rval; | 4187 | return rval; |
4188 | } | 4188 | } |
4189 | |||
4190 | int | ||
4191 | qla82xx_md_get_template_size(scsi_qla_host_t *vha) | ||
4192 | { | ||
4193 | struct qla_hw_data *ha = vha->hw; | ||
4194 | mbx_cmd_t mc; | ||
4195 | mbx_cmd_t *mcp = &mc; | ||
4196 | int rval = QLA_FUNCTION_FAILED; | ||
4197 | |||
4198 | ql_dbg(ql_dbg_mbx, vha, 0x111f, "Entered %s.\n", __func__); | ||
4199 | |||
4200 | memset(mcp->mb, 0 , sizeof(mcp->mb)); | ||
4201 | mcp->mb[0] = LSW(MBC_DIAGNOSTIC_MINIDUMP_TEMPLATE); | ||
4202 | mcp->mb[1] = MSW(MBC_DIAGNOSTIC_MINIDUMP_TEMPLATE); | ||
4203 | mcp->mb[2] = LSW(RQST_TMPLT_SIZE); | ||
4204 | mcp->mb[3] = MSW(RQST_TMPLT_SIZE); | ||
4205 | |||
4206 | mcp->out_mb = MBX_3|MBX_2|MBX_1|MBX_0; | ||
4207 | mcp->in_mb = MBX_14|MBX_13|MBX_12|MBX_11|MBX_10|MBX_9|MBX_8| | ||
4208 | MBX_7|MBX_6|MBX_5|MBX_4|MBX_3|MBX_2|MBX_1|MBX_0; | ||
4209 | |||
4210 | mcp->flags = MBX_DMA_OUT|MBX_DMA_IN|IOCTL_CMD; | ||
4211 | mcp->tov = MBX_TOV_SECONDS; | ||
4212 | rval = qla2x00_mailbox_command(vha, mcp); | ||
4213 | |||
4214 | /* Always copy back return mailbox values. */ | ||
4215 | if (rval != QLA_SUCCESS) { | ||
4216 | ql_dbg(ql_dbg_mbx, vha, 0x1120, | ||
4217 | "mailbox command FAILED=0x%x, subcode=%x.\n", | ||
4218 | (mcp->mb[1] << 16) | mcp->mb[0], | ||
4219 | (mcp->mb[3] << 16) | mcp->mb[2]); | ||
4220 | } else { | ||
4221 | ql_dbg(ql_dbg_mbx, vha, 0x1121, "Done %s.\n", __func__); | ||
4222 | ha->md_template_size = ((mcp->mb[3] << 16) | mcp->mb[2]); | ||
4223 | if (!ha->md_template_size) { | ||
4224 | ql_dbg(ql_dbg_mbx, vha, 0x1122, | ||
4225 | "Null template size obtained.\n"); | ||
4226 | rval = QLA_FUNCTION_FAILED; | ||
4227 | } | ||
4228 | } | ||
4229 | return rval; | ||
4230 | } | ||
4231 | |||
4232 | int | ||
4233 | qla82xx_md_get_template(scsi_qla_host_t *vha) | ||
4234 | { | ||
4235 | struct qla_hw_data *ha = vha->hw; | ||
4236 | mbx_cmd_t mc; | ||
4237 | mbx_cmd_t *mcp = &mc; | ||
4238 | int rval = QLA_FUNCTION_FAILED; | ||
4239 | |||
4240 | ql_dbg(ql_dbg_mbx, vha, 0x1123, "Entered %s.\n", __func__); | ||
4241 | |||
4242 | ha->md_tmplt_hdr = dma_alloc_coherent(&ha->pdev->dev, | ||
4243 | ha->md_template_size, &ha->md_tmplt_hdr_dma, GFP_KERNEL); | ||
4244 | if (!ha->md_tmplt_hdr) { | ||
4245 | ql_log(ql_log_warn, vha, 0x1124, | ||
4246 | "Unable to allocate memory for Minidump template.\n"); | ||
4247 | return rval; | ||
4248 | } | ||
4249 | |||
4250 | memset(mcp->mb, 0 , sizeof(mcp->mb)); | ||
4251 | mcp->mb[0] = LSW(MBC_DIAGNOSTIC_MINIDUMP_TEMPLATE); | ||
4252 | mcp->mb[1] = MSW(MBC_DIAGNOSTIC_MINIDUMP_TEMPLATE); | ||
4253 | mcp->mb[2] = LSW(RQST_TMPLT); | ||
4254 | mcp->mb[3] = MSW(RQST_TMPLT); | ||
4255 | mcp->mb[4] = LSW(LSD(ha->md_tmplt_hdr_dma)); | ||
4256 | mcp->mb[5] = MSW(LSD(ha->md_tmplt_hdr_dma)); | ||
4257 | mcp->mb[6] = LSW(MSD(ha->md_tmplt_hdr_dma)); | ||
4258 | mcp->mb[7] = MSW(MSD(ha->md_tmplt_hdr_dma)); | ||
4259 | mcp->mb[8] = LSW(ha->md_template_size); | ||
4260 | mcp->mb[9] = MSW(ha->md_template_size); | ||
4261 | |||
4262 | mcp->flags = MBX_DMA_OUT|MBX_DMA_IN|IOCTL_CMD; | ||
4263 | mcp->tov = MBX_TOV_SECONDS; | ||
4264 | mcp->out_mb = MBX_11|MBX_10|MBX_9|MBX_8| | ||
4265 | MBX_7|MBX_6|MBX_5|MBX_4|MBX_3|MBX_2|MBX_1|MBX_0; | ||
4266 | mcp->in_mb = MBX_3|MBX_2|MBX_1|MBX_0; | ||
4267 | rval = qla2x00_mailbox_command(vha, mcp); | ||
4268 | |||
4269 | if (rval != QLA_SUCCESS) { | ||
4270 | ql_dbg(ql_dbg_mbx, vha, 0x1125, | ||
4271 | "mailbox command FAILED=0x%x, subcode=%x.\n", | ||
4272 | ((mcp->mb[1] << 16) | mcp->mb[0]), | ||
4273 | ((mcp->mb[3] << 16) | mcp->mb[2])); | ||
4274 | } else | ||
4275 | ql_dbg(ql_dbg_mbx, vha, 0x1126, "Done %s.\n", __func__); | ||
4276 | return rval; | ||
4277 | } | ||
diff --git a/drivers/scsi/qla2xxx/qla_nx.c b/drivers/scsi/qla2xxx/qla_nx.c index 049807cda419..43a0a9a4556f 100644 --- a/drivers/scsi/qla2xxx/qla_nx.c +++ b/drivers/scsi/qla2xxx/qla_nx.c | |||
@@ -7,6 +7,8 @@ | |||
7 | #include "qla_def.h" | 7 | #include "qla_def.h" |
8 | #include <linux/delay.h> | 8 | #include <linux/delay.h> |
9 | #include <linux/pci.h> | 9 | #include <linux/pci.h> |
10 | #include <linux/ratelimit.h> | ||
11 | #include <linux/vmalloc.h> | ||
10 | #include <scsi/scsi_tcq.h> | 12 | #include <scsi/scsi_tcq.h> |
11 | 13 | ||
12 | #define MASK(n) ((1ULL<<(n))-1) | 14 | #define MASK(n) ((1ULL<<(n))-1) |
@@ -328,7 +330,7 @@ unsigned qla82xx_crb_hub_agt[64] = { | |||
328 | }; | 330 | }; |
329 | 331 | ||
330 | /* Device states */ | 332 | /* Device states */ |
331 | char *qdev_state[] = { | 333 | char *q_dev_state[] = { |
332 | "Unknown", | 334 | "Unknown", |
333 | "Cold", | 335 | "Cold", |
334 | "Initializing", | 336 | "Initializing", |
@@ -339,6 +341,11 @@ char *qdev_state[] = { | |||
339 | "Quiescent", | 341 | "Quiescent", |
340 | }; | 342 | }; |
341 | 343 | ||
344 | char *qdev_state(uint32_t dev_state) | ||
345 | { | ||
346 | return q_dev_state[dev_state]; | ||
347 | } | ||
348 | |||
342 | /* | 349 | /* |
343 | * In: 'off' is offset from CRB space in 128M pci map | 350 | * In: 'off' is offset from CRB space in 128M pci map |
344 | * Out: 'off' is 2M pci map addr | 351 | * Out: 'off' is 2M pci map addr |
@@ -2355,9 +2362,13 @@ qla82xx_need_reset(struct qla_hw_data *ha) | |||
2355 | uint32_t drv_state; | 2362 | uint32_t drv_state; |
2356 | int rval; | 2363 | int rval; |
2357 | 2364 | ||
2358 | drv_state = qla82xx_rd_32(ha, QLA82XX_CRB_DRV_STATE); | 2365 | if (ha->flags.isp82xx_reset_owner) |
2359 | rval = drv_state & (QLA82XX_DRVST_RST_RDY << (ha->portnum * 4)); | 2366 | return 1; |
2360 | return rval; | 2367 | else { |
2368 | drv_state = qla82xx_rd_32(ha, QLA82XX_CRB_DRV_STATE); | ||
2369 | rval = drv_state & (QLA82XX_DRVST_RST_RDY << (ha->portnum * 4)); | ||
2370 | return rval; | ||
2371 | } | ||
2361 | } | 2372 | } |
2362 | 2373 | ||
2363 | static inline void | 2374 | static inline void |
@@ -2374,8 +2385,8 @@ qla82xx_set_rst_ready(struct qla_hw_data *ha) | |||
2374 | drv_state = qla82xx_rd_32(ha, QLA82XX_CRB_DRV_STATE); | 2385 | drv_state = qla82xx_rd_32(ha, QLA82XX_CRB_DRV_STATE); |
2375 | } | 2386 | } |
2376 | drv_state |= (QLA82XX_DRVST_RST_RDY << (ha->portnum * 4)); | 2387 | drv_state |= (QLA82XX_DRVST_RST_RDY << (ha->portnum * 4)); |
2377 | ql_log(ql_log_info, vha, 0x00bb, | 2388 | ql_dbg(ql_dbg_init, vha, 0x00bb, |
2378 | "drv_state = 0x%x.\n", drv_state); | 2389 | "drv_state = 0x%08x.\n", drv_state); |
2379 | qla82xx_wr_32(ha, QLA82XX_CRB_DRV_STATE, drv_state); | 2390 | qla82xx_wr_32(ha, QLA82XX_CRB_DRV_STATE, drv_state); |
2380 | } | 2391 | } |
2381 | 2392 | ||
@@ -3528,7 +3539,7 @@ qla82xx_dev_failed_handler(scsi_qla_host_t *vha) | |||
3528 | static void | 3539 | static void |
3529 | qla82xx_need_reset_handler(scsi_qla_host_t *vha) | 3540 | qla82xx_need_reset_handler(scsi_qla_host_t *vha) |
3530 | { | 3541 | { |
3531 | uint32_t dev_state, drv_state, drv_active; | 3542 | uint32_t dev_state, drv_state, drv_active, active_mask; |
3532 | unsigned long reset_timeout; | 3543 | unsigned long reset_timeout; |
3533 | struct qla_hw_data *ha = vha->hw; | 3544 | struct qla_hw_data *ha = vha->hw; |
3534 | struct req_que *req = ha->req_q_map[0]; | 3545 | struct req_que *req = ha->req_q_map[0]; |
@@ -3541,15 +3552,32 @@ qla82xx_need_reset_handler(scsi_qla_host_t *vha) | |||
3541 | qla82xx_idc_lock(ha); | 3552 | qla82xx_idc_lock(ha); |
3542 | } | 3553 | } |
3543 | 3554 | ||
3544 | qla82xx_set_rst_ready(ha); | 3555 | drv_active = qla82xx_rd_32(ha, QLA82XX_CRB_DRV_ACTIVE); |
3556 | if (!ha->flags.isp82xx_reset_owner) { | ||
3557 | ql_dbg(ql_dbg_p3p, vha, 0xb028, | ||
3558 | "reset_acknowledged by 0x%x\n", ha->portnum); | ||
3559 | qla82xx_set_rst_ready(ha); | ||
3560 | } else { | ||
3561 | active_mask = ~(QLA82XX_DRV_ACTIVE << (ha->portnum * 4)); | ||
3562 | drv_active &= active_mask; | ||
3563 | ql_dbg(ql_dbg_p3p, vha, 0xb029, | ||
3564 | "active_mask: 0x%08x\n", active_mask); | ||
3565 | } | ||
3545 | 3566 | ||
3546 | /* wait for 10 seconds for reset ack from all functions */ | 3567 | /* wait for 10 seconds for reset ack from all functions */ |
3547 | reset_timeout = jiffies + (ha->nx_reset_timeout * HZ); | 3568 | reset_timeout = jiffies + (ha->nx_reset_timeout * HZ); |
3548 | 3569 | ||
3549 | drv_state = qla82xx_rd_32(ha, QLA82XX_CRB_DRV_STATE); | 3570 | drv_state = qla82xx_rd_32(ha, QLA82XX_CRB_DRV_STATE); |
3550 | drv_active = qla82xx_rd_32(ha, QLA82XX_CRB_DRV_ACTIVE); | 3571 | drv_active = qla82xx_rd_32(ha, QLA82XX_CRB_DRV_ACTIVE); |
3572 | dev_state = qla82xx_rd_32(ha, QLA82XX_CRB_DEV_STATE); | ||
3551 | 3573 | ||
3552 | while (drv_state != drv_active) { | 3574 | ql_dbg(ql_dbg_p3p, vha, 0xb02a, |
3575 | "drv_state: 0x%08x, drv_active: 0x%08x, " | ||
3576 | "dev_state: 0x%08x, active_mask: 0x%08x\n", | ||
3577 | drv_state, drv_active, dev_state, active_mask); | ||
3578 | |||
3579 | while (drv_state != drv_active && | ||
3580 | dev_state != QLA82XX_DEV_INITIALIZING) { | ||
3553 | if (time_after_eq(jiffies, reset_timeout)) { | 3581 | if (time_after_eq(jiffies, reset_timeout)) { |
3554 | ql_log(ql_log_warn, vha, 0x00b5, | 3582 | ql_log(ql_log_warn, vha, 0x00b5, |
3555 | "Reset timeout.\n"); | 3583 | "Reset timeout.\n"); |
@@ -3560,22 +3588,78 @@ qla82xx_need_reset_handler(scsi_qla_host_t *vha) | |||
3560 | qla82xx_idc_lock(ha); | 3588 | qla82xx_idc_lock(ha); |
3561 | drv_state = qla82xx_rd_32(ha, QLA82XX_CRB_DRV_STATE); | 3589 | drv_state = qla82xx_rd_32(ha, QLA82XX_CRB_DRV_STATE); |
3562 | drv_active = qla82xx_rd_32(ha, QLA82XX_CRB_DRV_ACTIVE); | 3590 | drv_active = qla82xx_rd_32(ha, QLA82XX_CRB_DRV_ACTIVE); |
3591 | if (ha->flags.isp82xx_reset_owner) | ||
3592 | drv_active &= active_mask; | ||
3593 | dev_state = qla82xx_rd_32(ha, QLA82XX_CRB_DEV_STATE); | ||
3563 | } | 3594 | } |
3564 | 3595 | ||
3565 | dev_state = qla82xx_rd_32(ha, QLA82XX_CRB_DEV_STATE); | 3596 | ql_dbg(ql_dbg_p3p, vha, 0xb02b, |
3597 | "drv_state: 0x%08x, drv_active: 0x%08x, " | ||
3598 | "dev_state: 0x%08x, active_mask: 0x%08x\n", | ||
3599 | drv_state, drv_active, dev_state, active_mask); | ||
3600 | |||
3566 | ql_log(ql_log_info, vha, 0x00b6, | 3601 | ql_log(ql_log_info, vha, 0x00b6, |
3567 | "Device state is 0x%x = %s.\n", | 3602 | "Device state is 0x%x = %s.\n", |
3568 | dev_state, | 3603 | dev_state, |
3569 | dev_state < MAX_STATES ? qdev_state[dev_state] : "Unknown"); | 3604 | dev_state < MAX_STATES ? qdev_state(dev_state) : "Unknown"); |
3570 | 3605 | ||
3571 | /* Force to DEV_COLD unless someone else is starting a reset */ | 3606 | /* Force to DEV_COLD unless someone else is starting a reset */ |
3572 | if (dev_state != QLA82XX_DEV_INITIALIZING) { | 3607 | if (dev_state != QLA82XX_DEV_INITIALIZING && |
3608 | dev_state != QLA82XX_DEV_COLD) { | ||
3573 | ql_log(ql_log_info, vha, 0x00b7, | 3609 | ql_log(ql_log_info, vha, 0x00b7, |
3574 | "HW State: COLD/RE-INIT.\n"); | 3610 | "HW State: COLD/RE-INIT.\n"); |
3575 | qla82xx_wr_32(ha, QLA82XX_CRB_DEV_STATE, QLA82XX_DEV_COLD); | 3611 | qla82xx_wr_32(ha, QLA82XX_CRB_DEV_STATE, QLA82XX_DEV_COLD); |
3612 | if (ql2xmdenable) { | ||
3613 | if (qla82xx_md_collect(vha)) | ||
3614 | ql_log(ql_log_warn, vha, 0xb02c, | ||
3615 | "Not able to collect minidump.\n"); | ||
3616 | } else | ||
3617 | ql_log(ql_log_warn, vha, 0xb04f, | ||
3618 | "Minidump disabled.\n"); | ||
3576 | } | 3619 | } |
3577 | } | 3620 | } |
3578 | 3621 | ||
3622 | static void | ||
3623 | qla82xx_check_md_needed(scsi_qla_host_t *vha) | ||
3624 | { | ||
3625 | struct qla_hw_data *ha = vha->hw; | ||
3626 | uint16_t fw_major_version, fw_minor_version, fw_subminor_version; | ||
3627 | uint16_t fw_attributes; | ||
3628 | uint32_t fw_memory_size, mpi_capabilities; | ||
3629 | uint8_t mpi_version[3], phy_version[3]; | ||
3630 | |||
3631 | if (!ha->fw_dumped) { | ||
3632 | qla2x00_get_fw_version(vha, | ||
3633 | &fw_major_version, | ||
3634 | &fw_minor_version, | ||
3635 | &fw_subminor_version, | ||
3636 | &fw_attributes, &fw_memory_size, | ||
3637 | mpi_version, &mpi_capabilities, | ||
3638 | phy_version); | ||
3639 | |||
3640 | if (fw_major_version != ha->fw_major_version || | ||
3641 | fw_minor_version != ha->fw_minor_version || | ||
3642 | fw_subminor_version != ha->fw_subminor_version) { | ||
3643 | ql_log(ql_log_info, vha, 0xb02d, | ||
3644 | "Firmware version differs " | ||
3645 | "Previous version: %d:%d:%d - " | ||
3646 | "New version: %d:%d:%d\n", | ||
3647 | ha->fw_major_version, | ||
3648 | ha->fw_minor_version, ha->fw_subminor_version, | ||
3649 | fw_major_version, fw_minor_version, | ||
3650 | fw_subminor_version); | ||
3651 | /* Release MiniDump resources */ | ||
3652 | qla82xx_md_free(vha); | ||
3653 | /* ALlocate MiniDump resources */ | ||
3654 | qla82xx_md_prep(vha); | ||
3655 | } | ||
3656 | } else | ||
3657 | ql_log(ql_log_info, vha, 0xb02e, | ||
3658 | "Firmware dump available to retrieve\n", | ||
3659 | vha->host_no); | ||
3660 | } | ||
3661 | |||
3662 | |||
3579 | int | 3663 | int |
3580 | qla82xx_check_fw_alive(scsi_qla_host_t *vha) | 3664 | qla82xx_check_fw_alive(scsi_qla_host_t *vha) |
3581 | { | 3665 | { |
@@ -3637,7 +3721,7 @@ qla82xx_device_state_handler(scsi_qla_host_t *vha) | |||
3637 | ql_log(ql_log_info, vha, 0x009b, | 3721 | ql_log(ql_log_info, vha, 0x009b, |
3638 | "Device state is 0x%x = %s.\n", | 3722 | "Device state is 0x%x = %s.\n", |
3639 | dev_state, | 3723 | dev_state, |
3640 | dev_state < MAX_STATES ? qdev_state[dev_state] : "Unknown"); | 3724 | dev_state < MAX_STATES ? qdev_state(dev_state) : "Unknown"); |
3641 | 3725 | ||
3642 | /* wait for 30 seconds for device to go ready */ | 3726 | /* wait for 30 seconds for device to go ready */ |
3643 | dev_init_timeout = jiffies + (ha->nx_dev_init_timeout * HZ); | 3727 | dev_init_timeout = jiffies + (ha->nx_dev_init_timeout * HZ); |
@@ -3659,16 +3743,18 @@ qla82xx_device_state_handler(scsi_qla_host_t *vha) | |||
3659 | ql_log(ql_log_info, vha, 0x009d, | 3743 | ql_log(ql_log_info, vha, 0x009d, |
3660 | "Device state is 0x%x = %s.\n", | 3744 | "Device state is 0x%x = %s.\n", |
3661 | dev_state, | 3745 | dev_state, |
3662 | dev_state < MAX_STATES ? qdev_state[dev_state] : | 3746 | dev_state < MAX_STATES ? qdev_state(dev_state) : |
3663 | "Unknown"); | 3747 | "Unknown"); |
3664 | } | 3748 | } |
3665 | 3749 | ||
3666 | switch (dev_state) { | 3750 | switch (dev_state) { |
3667 | case QLA82XX_DEV_READY: | 3751 | case QLA82XX_DEV_READY: |
3752 | qla82xx_check_md_needed(vha); | ||
3753 | ha->flags.isp82xx_reset_owner = 0; | ||
3668 | goto exit; | 3754 | goto exit; |
3669 | case QLA82XX_DEV_COLD: | 3755 | case QLA82XX_DEV_COLD: |
3670 | rval = qla82xx_device_bootstrap(vha); | 3756 | rval = qla82xx_device_bootstrap(vha); |
3671 | goto exit; | 3757 | break; |
3672 | case QLA82XX_DEV_INITIALIZING: | 3758 | case QLA82XX_DEV_INITIALIZING: |
3673 | qla82xx_idc_unlock(ha); | 3759 | qla82xx_idc_unlock(ha); |
3674 | msleep(1000); | 3760 | msleep(1000); |
@@ -3791,6 +3877,28 @@ int qla82xx_load_risc(scsi_qla_host_t *vha, uint32_t *srisc_addr) | |||
3791 | return rval; | 3877 | return rval; |
3792 | } | 3878 | } |
3793 | 3879 | ||
3880 | void | ||
3881 | qla82xx_set_reset_owner(scsi_qla_host_t *vha) | ||
3882 | { | ||
3883 | struct qla_hw_data *ha = vha->hw; | ||
3884 | uint32_t dev_state; | ||
3885 | |||
3886 | dev_state = qla82xx_rd_32(ha, QLA82XX_CRB_DEV_STATE); | ||
3887 | if (dev_state == QLA82XX_DEV_READY) { | ||
3888 | ql_log(ql_log_info, vha, 0xb02f, | ||
3889 | "HW State: NEED RESET\n"); | ||
3890 | qla82xx_wr_32(ha, QLA82XX_CRB_DEV_STATE, | ||
3891 | QLA82XX_DEV_NEED_RESET); | ||
3892 | ha->flags.isp82xx_reset_owner = 1; | ||
3893 | ql_dbg(ql_dbg_p3p, vha, 0xb030, | ||
3894 | "reset_owner is 0x%x\n", ha->portnum); | ||
3895 | } else | ||
3896 | ql_log(ql_log_info, vha, 0xb031, | ||
3897 | "Device state is 0x%x = %s.\n", | ||
3898 | dev_state, | ||
3899 | dev_state < MAX_STATES ? qdev_state(dev_state) : "Unknown"); | ||
3900 | } | ||
3901 | |||
3794 | /* | 3902 | /* |
3795 | * qla82xx_abort_isp | 3903 | * qla82xx_abort_isp |
3796 | * Resets ISP and aborts all outstanding commands. | 3904 | * Resets ISP and aborts all outstanding commands. |
@@ -3806,7 +3914,6 @@ qla82xx_abort_isp(scsi_qla_host_t *vha) | |||
3806 | { | 3914 | { |
3807 | int rval; | 3915 | int rval; |
3808 | struct qla_hw_data *ha = vha->hw; | 3916 | struct qla_hw_data *ha = vha->hw; |
3809 | uint32_t dev_state; | ||
3810 | 3917 | ||
3811 | if (vha->device_flags & DFLG_DEV_FAILED) { | 3918 | if (vha->device_flags & DFLG_DEV_FAILED) { |
3812 | ql_log(ql_log_warn, vha, 0x8024, | 3919 | ql_log(ql_log_warn, vha, 0x8024, |
@@ -3816,16 +3923,7 @@ qla82xx_abort_isp(scsi_qla_host_t *vha) | |||
3816 | ha->flags.isp82xx_reset_hdlr_active = 1; | 3923 | ha->flags.isp82xx_reset_hdlr_active = 1; |
3817 | 3924 | ||
3818 | qla82xx_idc_lock(ha); | 3925 | qla82xx_idc_lock(ha); |
3819 | dev_state = qla82xx_rd_32(ha, QLA82XX_CRB_DEV_STATE); | 3926 | qla82xx_set_reset_owner(vha); |
3820 | if (dev_state == QLA82XX_DEV_READY) { | ||
3821 | ql_log(ql_log_info, vha, 0x8025, | ||
3822 | "HW State: NEED RESET.\n"); | ||
3823 | qla82xx_wr_32(ha, QLA82XX_CRB_DEV_STATE, | ||
3824 | QLA82XX_DEV_NEED_RESET); | ||
3825 | } else | ||
3826 | ql_log(ql_log_info, vha, 0x8026, | ||
3827 | "Hw State: %s.\n", dev_state < MAX_STATES ? | ||
3828 | qdev_state[dev_state] : "Unknown"); | ||
3829 | qla82xx_idc_unlock(ha); | 3927 | qla82xx_idc_unlock(ha); |
3830 | 3928 | ||
3831 | rval = qla82xx_device_state_handler(vha); | 3929 | rval = qla82xx_device_state_handler(vha); |
@@ -4016,3 +4114,763 @@ qla82xx_chip_reset_cleanup(scsi_qla_host_t *vha) | |||
4016 | } | 4114 | } |
4017 | } | 4115 | } |
4018 | } | 4116 | } |
4117 | |||
4118 | /* Minidump related functions */ | ||
4119 | int | ||
4120 | qla82xx_md_rw_32(struct qla_hw_data *ha, uint32_t off, u32 data, uint8_t flag) | ||
4121 | { | ||
4122 | uint32_t off_value, rval = 0; | ||
4123 | |||
4124 | WRT_REG_DWORD((void *)(CRB_WINDOW_2M + ha->nx_pcibase), | ||
4125 | (off & 0xFFFF0000)); | ||
4126 | |||
4127 | /* Read back value to make sure write has gone through */ | ||
4128 | RD_REG_DWORD((void *)(CRB_WINDOW_2M + ha->nx_pcibase)); | ||
4129 | off_value = (off & 0x0000FFFF); | ||
4130 | |||
4131 | if (flag) | ||
4132 | WRT_REG_DWORD((void *) | ||
4133 | (off_value + CRB_INDIRECT_2M + ha->nx_pcibase), | ||
4134 | data); | ||
4135 | else | ||
4136 | rval = RD_REG_DWORD((void *) | ||
4137 | (off_value + CRB_INDIRECT_2M + ha->nx_pcibase)); | ||
4138 | |||
4139 | return rval; | ||
4140 | } | ||
4141 | |||
4142 | static int | ||
4143 | qla82xx_minidump_process_control(scsi_qla_host_t *vha, | ||
4144 | qla82xx_md_entry_hdr_t *entry_hdr, uint32_t **d_ptr) | ||
4145 | { | ||
4146 | struct qla_hw_data *ha = vha->hw; | ||
4147 | struct qla82xx_md_entry_crb *crb_entry; | ||
4148 | uint32_t read_value, opcode, poll_time; | ||
4149 | uint32_t addr, index, crb_addr; | ||
4150 | unsigned long wtime; | ||
4151 | struct qla82xx_md_template_hdr *tmplt_hdr; | ||
4152 | uint32_t rval = QLA_SUCCESS; | ||
4153 | int i; | ||
4154 | |||
4155 | tmplt_hdr = (struct qla82xx_md_template_hdr *)ha->md_tmplt_hdr; | ||
4156 | crb_entry = (struct qla82xx_md_entry_crb *)entry_hdr; | ||
4157 | crb_addr = crb_entry->addr; | ||
4158 | |||
4159 | for (i = 0; i < crb_entry->op_count; i++) { | ||
4160 | opcode = crb_entry->crb_ctrl.opcode; | ||
4161 | if (opcode & QLA82XX_DBG_OPCODE_WR) { | ||
4162 | qla82xx_md_rw_32(ha, crb_addr, | ||
4163 | crb_entry->value_1, 1); | ||
4164 | opcode &= ~QLA82XX_DBG_OPCODE_WR; | ||
4165 | } | ||
4166 | |||
4167 | if (opcode & QLA82XX_DBG_OPCODE_RW) { | ||
4168 | read_value = qla82xx_md_rw_32(ha, crb_addr, 0, 0); | ||
4169 | qla82xx_md_rw_32(ha, crb_addr, read_value, 1); | ||
4170 | opcode &= ~QLA82XX_DBG_OPCODE_RW; | ||
4171 | } | ||
4172 | |||
4173 | if (opcode & QLA82XX_DBG_OPCODE_AND) { | ||
4174 | read_value = qla82xx_md_rw_32(ha, crb_addr, 0, 0); | ||
4175 | read_value &= crb_entry->value_2; | ||
4176 | opcode &= ~QLA82XX_DBG_OPCODE_AND; | ||
4177 | if (opcode & QLA82XX_DBG_OPCODE_OR) { | ||
4178 | read_value |= crb_entry->value_3; | ||
4179 | opcode &= ~QLA82XX_DBG_OPCODE_OR; | ||
4180 | } | ||
4181 | qla82xx_md_rw_32(ha, crb_addr, read_value, 1); | ||
4182 | } | ||
4183 | |||
4184 | if (opcode & QLA82XX_DBG_OPCODE_OR) { | ||
4185 | read_value = qla82xx_md_rw_32(ha, crb_addr, 0, 0); | ||
4186 | read_value |= crb_entry->value_3; | ||
4187 | qla82xx_md_rw_32(ha, crb_addr, read_value, 1); | ||
4188 | opcode &= ~QLA82XX_DBG_OPCODE_OR; | ||
4189 | } | ||
4190 | |||
4191 | if (opcode & QLA82XX_DBG_OPCODE_POLL) { | ||
4192 | poll_time = crb_entry->crb_strd.poll_timeout; | ||
4193 | wtime = jiffies + poll_time; | ||
4194 | read_value = qla82xx_md_rw_32(ha, crb_addr, 0, 0); | ||
4195 | |||
4196 | do { | ||
4197 | if ((read_value & crb_entry->value_2) | ||
4198 | == crb_entry->value_1) | ||
4199 | break; | ||
4200 | else if (time_after_eq(jiffies, wtime)) { | ||
4201 | /* capturing dump failed */ | ||
4202 | rval = QLA_FUNCTION_FAILED; | ||
4203 | break; | ||
4204 | } else | ||
4205 | read_value = qla82xx_md_rw_32(ha, | ||
4206 | crb_addr, 0, 0); | ||
4207 | } while (1); | ||
4208 | opcode &= ~QLA82XX_DBG_OPCODE_POLL; | ||
4209 | } | ||
4210 | |||
4211 | if (opcode & QLA82XX_DBG_OPCODE_RDSTATE) { | ||
4212 | if (crb_entry->crb_strd.state_index_a) { | ||
4213 | index = crb_entry->crb_strd.state_index_a; | ||
4214 | addr = tmplt_hdr->saved_state_array[index]; | ||
4215 | } else | ||
4216 | addr = crb_addr; | ||
4217 | |||
4218 | read_value = qla82xx_md_rw_32(ha, addr, 0, 0); | ||
4219 | index = crb_entry->crb_ctrl.state_index_v; | ||
4220 | tmplt_hdr->saved_state_array[index] = read_value; | ||
4221 | opcode &= ~QLA82XX_DBG_OPCODE_RDSTATE; | ||
4222 | } | ||
4223 | |||
4224 | if (opcode & QLA82XX_DBG_OPCODE_WRSTATE) { | ||
4225 | if (crb_entry->crb_strd.state_index_a) { | ||
4226 | index = crb_entry->crb_strd.state_index_a; | ||
4227 | addr = tmplt_hdr->saved_state_array[index]; | ||
4228 | } else | ||
4229 | addr = crb_addr; | ||
4230 | |||
4231 | if (crb_entry->crb_ctrl.state_index_v) { | ||
4232 | index = crb_entry->crb_ctrl.state_index_v; | ||
4233 | read_value = | ||
4234 | tmplt_hdr->saved_state_array[index]; | ||
4235 | } else | ||
4236 | read_value = crb_entry->value_1; | ||
4237 | |||
4238 | qla82xx_md_rw_32(ha, addr, read_value, 1); | ||
4239 | opcode &= ~QLA82XX_DBG_OPCODE_WRSTATE; | ||
4240 | } | ||
4241 | |||
4242 | if (opcode & QLA82XX_DBG_OPCODE_MDSTATE) { | ||
4243 | index = crb_entry->crb_ctrl.state_index_v; | ||
4244 | read_value = tmplt_hdr->saved_state_array[index]; | ||
4245 | read_value <<= crb_entry->crb_ctrl.shl; | ||
4246 | read_value >>= crb_entry->crb_ctrl.shr; | ||
4247 | if (crb_entry->value_2) | ||
4248 | read_value &= crb_entry->value_2; | ||
4249 | read_value |= crb_entry->value_3; | ||
4250 | read_value += crb_entry->value_1; | ||
4251 | tmplt_hdr->saved_state_array[index] = read_value; | ||
4252 | opcode &= ~QLA82XX_DBG_OPCODE_MDSTATE; | ||
4253 | } | ||
4254 | crb_addr += crb_entry->crb_strd.addr_stride; | ||
4255 | } | ||
4256 | return rval; | ||
4257 | } | ||
4258 | |||
4259 | static void | ||
4260 | qla82xx_minidump_process_rdocm(scsi_qla_host_t *vha, | ||
4261 | qla82xx_md_entry_hdr_t *entry_hdr, uint32_t **d_ptr) | ||
4262 | { | ||
4263 | struct qla_hw_data *ha = vha->hw; | ||
4264 | uint32_t r_addr, r_stride, loop_cnt, i, r_value; | ||
4265 | struct qla82xx_md_entry_rdocm *ocm_hdr; | ||
4266 | uint32_t *data_ptr = *d_ptr; | ||
4267 | |||
4268 | ocm_hdr = (struct qla82xx_md_entry_rdocm *)entry_hdr; | ||
4269 | r_addr = ocm_hdr->read_addr; | ||
4270 | r_stride = ocm_hdr->read_addr_stride; | ||
4271 | loop_cnt = ocm_hdr->op_count; | ||
4272 | |||
4273 | for (i = 0; i < loop_cnt; i++) { | ||
4274 | r_value = RD_REG_DWORD((void *)(r_addr + ha->nx_pcibase)); | ||
4275 | *data_ptr++ = cpu_to_le32(r_value); | ||
4276 | r_addr += r_stride; | ||
4277 | } | ||
4278 | *d_ptr = data_ptr; | ||
4279 | } | ||
4280 | |||
4281 | static void | ||
4282 | qla82xx_minidump_process_rdmux(scsi_qla_host_t *vha, | ||
4283 | qla82xx_md_entry_hdr_t *entry_hdr, uint32_t **d_ptr) | ||
4284 | { | ||
4285 | struct qla_hw_data *ha = vha->hw; | ||
4286 | uint32_t r_addr, s_stride, s_addr, s_value, loop_cnt, i, r_value; | ||
4287 | struct qla82xx_md_entry_mux *mux_hdr; | ||
4288 | uint32_t *data_ptr = *d_ptr; | ||
4289 | |||
4290 | mux_hdr = (struct qla82xx_md_entry_mux *)entry_hdr; | ||
4291 | r_addr = mux_hdr->read_addr; | ||
4292 | s_addr = mux_hdr->select_addr; | ||
4293 | s_stride = mux_hdr->select_value_stride; | ||
4294 | s_value = mux_hdr->select_value; | ||
4295 | loop_cnt = mux_hdr->op_count; | ||
4296 | |||
4297 | for (i = 0; i < loop_cnt; i++) { | ||
4298 | qla82xx_md_rw_32(ha, s_addr, s_value, 1); | ||
4299 | r_value = qla82xx_md_rw_32(ha, r_addr, 0, 0); | ||
4300 | *data_ptr++ = cpu_to_le32(s_value); | ||
4301 | *data_ptr++ = cpu_to_le32(r_value); | ||
4302 | s_value += s_stride; | ||
4303 | } | ||
4304 | *d_ptr = data_ptr; | ||
4305 | } | ||
4306 | |||
4307 | static void | ||
4308 | qla82xx_minidump_process_rdcrb(scsi_qla_host_t *vha, | ||
4309 | qla82xx_md_entry_hdr_t *entry_hdr, uint32_t **d_ptr) | ||
4310 | { | ||
4311 | struct qla_hw_data *ha = vha->hw; | ||
4312 | uint32_t r_addr, r_stride, loop_cnt, i, r_value; | ||
4313 | struct qla82xx_md_entry_crb *crb_hdr; | ||
4314 | uint32_t *data_ptr = *d_ptr; | ||
4315 | |||
4316 | crb_hdr = (struct qla82xx_md_entry_crb *)entry_hdr; | ||
4317 | r_addr = crb_hdr->addr; | ||
4318 | r_stride = crb_hdr->crb_strd.addr_stride; | ||
4319 | loop_cnt = crb_hdr->op_count; | ||
4320 | |||
4321 | for (i = 0; i < loop_cnt; i++) { | ||
4322 | r_value = qla82xx_md_rw_32(ha, r_addr, 0, 0); | ||
4323 | *data_ptr++ = cpu_to_le32(r_addr); | ||
4324 | *data_ptr++ = cpu_to_le32(r_value); | ||
4325 | r_addr += r_stride; | ||
4326 | } | ||
4327 | *d_ptr = data_ptr; | ||
4328 | } | ||
4329 | |||
4330 | static int | ||
4331 | qla82xx_minidump_process_l2tag(scsi_qla_host_t *vha, | ||
4332 | qla82xx_md_entry_hdr_t *entry_hdr, uint32_t **d_ptr) | ||
4333 | { | ||
4334 | struct qla_hw_data *ha = vha->hw; | ||
4335 | uint32_t addr, r_addr, c_addr, t_r_addr; | ||
4336 | uint32_t i, k, loop_count, t_value, r_cnt, r_value; | ||
4337 | unsigned long p_wait, w_time, p_mask; | ||
4338 | uint32_t c_value_w, c_value_r; | ||
4339 | struct qla82xx_md_entry_cache *cache_hdr; | ||
4340 | int rval = QLA_FUNCTION_FAILED; | ||
4341 | uint32_t *data_ptr = *d_ptr; | ||
4342 | |||
4343 | cache_hdr = (struct qla82xx_md_entry_cache *)entry_hdr; | ||
4344 | loop_count = cache_hdr->op_count; | ||
4345 | r_addr = cache_hdr->read_addr; | ||
4346 | c_addr = cache_hdr->control_addr; | ||
4347 | c_value_w = cache_hdr->cache_ctrl.write_value; | ||
4348 | |||
4349 | t_r_addr = cache_hdr->tag_reg_addr; | ||
4350 | t_value = cache_hdr->addr_ctrl.init_tag_value; | ||
4351 | r_cnt = cache_hdr->read_ctrl.read_addr_cnt; | ||
4352 | p_wait = cache_hdr->cache_ctrl.poll_wait; | ||
4353 | p_mask = cache_hdr->cache_ctrl.poll_mask; | ||
4354 | |||
4355 | for (i = 0; i < loop_count; i++) { | ||
4356 | qla82xx_md_rw_32(ha, t_r_addr, t_value, 1); | ||
4357 | if (c_value_w) | ||
4358 | qla82xx_md_rw_32(ha, c_addr, c_value_w, 1); | ||
4359 | |||
4360 | if (p_mask) { | ||
4361 | w_time = jiffies + p_wait; | ||
4362 | do { | ||
4363 | c_value_r = qla82xx_md_rw_32(ha, c_addr, 0, 0); | ||
4364 | if ((c_value_r & p_mask) == 0) | ||
4365 | break; | ||
4366 | else if (time_after_eq(jiffies, w_time)) { | ||
4367 | /* capturing dump failed */ | ||
4368 | ql_dbg(ql_dbg_p3p, vha, 0xb032, | ||
4369 | "c_value_r: 0x%x, poll_mask: 0x%lx, " | ||
4370 | "w_time: 0x%lx\n", | ||
4371 | c_value_r, p_mask, w_time); | ||
4372 | return rval; | ||
4373 | } | ||
4374 | } while (1); | ||
4375 | } | ||
4376 | |||
4377 | addr = r_addr; | ||
4378 | for (k = 0; k < r_cnt; k++) { | ||
4379 | r_value = qla82xx_md_rw_32(ha, addr, 0, 0); | ||
4380 | *data_ptr++ = cpu_to_le32(r_value); | ||
4381 | addr += cache_hdr->read_ctrl.read_addr_stride; | ||
4382 | } | ||
4383 | t_value += cache_hdr->addr_ctrl.tag_value_stride; | ||
4384 | } | ||
4385 | *d_ptr = data_ptr; | ||
4386 | return QLA_SUCCESS; | ||
4387 | } | ||
4388 | |||
4389 | static void | ||
4390 | qla82xx_minidump_process_l1cache(scsi_qla_host_t *vha, | ||
4391 | qla82xx_md_entry_hdr_t *entry_hdr, uint32_t **d_ptr) | ||
4392 | { | ||
4393 | struct qla_hw_data *ha = vha->hw; | ||
4394 | uint32_t addr, r_addr, c_addr, t_r_addr; | ||
4395 | uint32_t i, k, loop_count, t_value, r_cnt, r_value; | ||
4396 | uint32_t c_value_w; | ||
4397 | struct qla82xx_md_entry_cache *cache_hdr; | ||
4398 | uint32_t *data_ptr = *d_ptr; | ||
4399 | |||
4400 | cache_hdr = (struct qla82xx_md_entry_cache *)entry_hdr; | ||
4401 | loop_count = cache_hdr->op_count; | ||
4402 | r_addr = cache_hdr->read_addr; | ||
4403 | c_addr = cache_hdr->control_addr; | ||
4404 | c_value_w = cache_hdr->cache_ctrl.write_value; | ||
4405 | |||
4406 | t_r_addr = cache_hdr->tag_reg_addr; | ||
4407 | t_value = cache_hdr->addr_ctrl.init_tag_value; | ||
4408 | r_cnt = cache_hdr->read_ctrl.read_addr_cnt; | ||
4409 | |||
4410 | for (i = 0; i < loop_count; i++) { | ||
4411 | qla82xx_md_rw_32(ha, t_r_addr, t_value, 1); | ||
4412 | qla82xx_md_rw_32(ha, c_addr, c_value_w, 1); | ||
4413 | addr = r_addr; | ||
4414 | for (k = 0; k < r_cnt; k++) { | ||
4415 | r_value = qla82xx_md_rw_32(ha, addr, 0, 0); | ||
4416 | *data_ptr++ = cpu_to_le32(r_value); | ||
4417 | addr += cache_hdr->read_ctrl.read_addr_stride; | ||
4418 | } | ||
4419 | t_value += cache_hdr->addr_ctrl.tag_value_stride; | ||
4420 | } | ||
4421 | *d_ptr = data_ptr; | ||
4422 | } | ||
4423 | |||
4424 | static void | ||
4425 | qla82xx_minidump_process_queue(scsi_qla_host_t *vha, | ||
4426 | qla82xx_md_entry_hdr_t *entry_hdr, uint32_t **d_ptr) | ||
4427 | { | ||
4428 | struct qla_hw_data *ha = vha->hw; | ||
4429 | uint32_t s_addr, r_addr; | ||
4430 | uint32_t r_stride, r_value, r_cnt, qid = 0; | ||
4431 | uint32_t i, k, loop_cnt; | ||
4432 | struct qla82xx_md_entry_queue *q_hdr; | ||
4433 | uint32_t *data_ptr = *d_ptr; | ||
4434 | |||
4435 | q_hdr = (struct qla82xx_md_entry_queue *)entry_hdr; | ||
4436 | s_addr = q_hdr->select_addr; | ||
4437 | r_cnt = q_hdr->rd_strd.read_addr_cnt; | ||
4438 | r_stride = q_hdr->rd_strd.read_addr_stride; | ||
4439 | loop_cnt = q_hdr->op_count; | ||
4440 | |||
4441 | for (i = 0; i < loop_cnt; i++) { | ||
4442 | qla82xx_md_rw_32(ha, s_addr, qid, 1); | ||
4443 | r_addr = q_hdr->read_addr; | ||
4444 | for (k = 0; k < r_cnt; k++) { | ||
4445 | r_value = qla82xx_md_rw_32(ha, r_addr, 0, 0); | ||
4446 | *data_ptr++ = cpu_to_le32(r_value); | ||
4447 | r_addr += r_stride; | ||
4448 | } | ||
4449 | qid += q_hdr->q_strd.queue_id_stride; | ||
4450 | } | ||
4451 | *d_ptr = data_ptr; | ||
4452 | } | ||
4453 | |||
4454 | static void | ||
4455 | qla82xx_minidump_process_rdrom(scsi_qla_host_t *vha, | ||
4456 | qla82xx_md_entry_hdr_t *entry_hdr, uint32_t **d_ptr) | ||
4457 | { | ||
4458 | struct qla_hw_data *ha = vha->hw; | ||
4459 | uint32_t r_addr, r_value; | ||
4460 | uint32_t i, loop_cnt; | ||
4461 | struct qla82xx_md_entry_rdrom *rom_hdr; | ||
4462 | uint32_t *data_ptr = *d_ptr; | ||
4463 | |||
4464 | rom_hdr = (struct qla82xx_md_entry_rdrom *)entry_hdr; | ||
4465 | r_addr = rom_hdr->read_addr; | ||
4466 | loop_cnt = rom_hdr->read_data_size/sizeof(uint32_t); | ||
4467 | |||
4468 | for (i = 0; i < loop_cnt; i++) { | ||
4469 | qla82xx_md_rw_32(ha, MD_DIRECT_ROM_WINDOW, | ||
4470 | (r_addr & 0xFFFF0000), 1); | ||
4471 | r_value = qla82xx_md_rw_32(ha, | ||
4472 | MD_DIRECT_ROM_READ_BASE + | ||
4473 | (r_addr & 0x0000FFFF), 0, 0); | ||
4474 | *data_ptr++ = cpu_to_le32(r_value); | ||
4475 | r_addr += sizeof(uint32_t); | ||
4476 | } | ||
4477 | *d_ptr = data_ptr; | ||
4478 | } | ||
4479 | |||
4480 | static int | ||
4481 | qla82xx_minidump_process_rdmem(scsi_qla_host_t *vha, | ||
4482 | qla82xx_md_entry_hdr_t *entry_hdr, uint32_t **d_ptr) | ||
4483 | { | ||
4484 | struct qla_hw_data *ha = vha->hw; | ||
4485 | uint32_t r_addr, r_value, r_data; | ||
4486 | uint32_t i, j, loop_cnt; | ||
4487 | struct qla82xx_md_entry_rdmem *m_hdr; | ||
4488 | unsigned long flags; | ||
4489 | int rval = QLA_FUNCTION_FAILED; | ||
4490 | uint32_t *data_ptr = *d_ptr; | ||
4491 | |||
4492 | m_hdr = (struct qla82xx_md_entry_rdmem *)entry_hdr; | ||
4493 | r_addr = m_hdr->read_addr; | ||
4494 | loop_cnt = m_hdr->read_data_size/16; | ||
4495 | |||
4496 | if (r_addr & 0xf) { | ||
4497 | ql_log(ql_log_warn, vha, 0xb033, | ||
4498 | "Read addr 0x%x not 16 bytes alligned\n", r_addr); | ||
4499 | return rval; | ||
4500 | } | ||
4501 | |||
4502 | if (m_hdr->read_data_size % 16) { | ||
4503 | ql_log(ql_log_warn, vha, 0xb034, | ||
4504 | "Read data[0x%x] not multiple of 16 bytes\n", | ||
4505 | m_hdr->read_data_size); | ||
4506 | return rval; | ||
4507 | } | ||
4508 | |||
4509 | ql_dbg(ql_dbg_p3p, vha, 0xb035, | ||
4510 | "[%s]: rdmem_addr: 0x%x, read_data_size: 0x%x, loop_cnt: 0x%x\n", | ||
4511 | __func__, r_addr, m_hdr->read_data_size, loop_cnt); | ||
4512 | |||
4513 | write_lock_irqsave(&ha->hw_lock, flags); | ||
4514 | for (i = 0; i < loop_cnt; i++) { | ||
4515 | qla82xx_md_rw_32(ha, MD_MIU_TEST_AGT_ADDR_LO, r_addr, 1); | ||
4516 | r_value = 0; | ||
4517 | qla82xx_md_rw_32(ha, MD_MIU_TEST_AGT_ADDR_HI, r_value, 1); | ||
4518 | r_value = MIU_TA_CTL_ENABLE; | ||
4519 | qla82xx_md_rw_32(ha, MD_MIU_TEST_AGT_CTRL, r_value, 1); | ||
4520 | r_value = MIU_TA_CTL_START | MIU_TA_CTL_ENABLE; | ||
4521 | qla82xx_md_rw_32(ha, MD_MIU_TEST_AGT_CTRL, r_value, 1); | ||
4522 | |||
4523 | for (j = 0; j < MAX_CTL_CHECK; j++) { | ||
4524 | r_value = qla82xx_md_rw_32(ha, | ||
4525 | MD_MIU_TEST_AGT_CTRL, 0, 0); | ||
4526 | if ((r_value & MIU_TA_CTL_BUSY) == 0) | ||
4527 | break; | ||
4528 | } | ||
4529 | |||
4530 | if (j >= MAX_CTL_CHECK) { | ||
4531 | printk_ratelimited(KERN_ERR | ||
4532 | "failed to read through agent\n"); | ||
4533 | write_unlock_irqrestore(&ha->hw_lock, flags); | ||
4534 | return rval; | ||
4535 | } | ||
4536 | |||
4537 | for (j = 0; j < 4; j++) { | ||
4538 | r_data = qla82xx_md_rw_32(ha, | ||
4539 | MD_MIU_TEST_AGT_RDDATA[j], 0, 0); | ||
4540 | *data_ptr++ = cpu_to_le32(r_data); | ||
4541 | } | ||
4542 | r_addr += 16; | ||
4543 | } | ||
4544 | write_unlock_irqrestore(&ha->hw_lock, flags); | ||
4545 | *d_ptr = data_ptr; | ||
4546 | return QLA_SUCCESS; | ||
4547 | } | ||
4548 | |||
4549 | static int | ||
4550 | qla82xx_validate_template_chksum(scsi_qla_host_t *vha) | ||
4551 | { | ||
4552 | struct qla_hw_data *ha = vha->hw; | ||
4553 | uint64_t chksum = 0; | ||
4554 | uint32_t *d_ptr = (uint32_t *)ha->md_tmplt_hdr; | ||
4555 | int count = ha->md_template_size/sizeof(uint32_t); | ||
4556 | |||
4557 | while (count-- > 0) | ||
4558 | chksum += *d_ptr++; | ||
4559 | while (chksum >> 32) | ||
4560 | chksum = (chksum & 0xFFFFFFFF) + (chksum >> 32); | ||
4561 | return ~chksum; | ||
4562 | } | ||
4563 | |||
4564 | static void | ||
4565 | qla82xx_mark_entry_skipped(scsi_qla_host_t *vha, | ||
4566 | qla82xx_md_entry_hdr_t *entry_hdr, int index) | ||
4567 | { | ||
4568 | entry_hdr->d_ctrl.driver_flags |= QLA82XX_DBG_SKIPPED_FLAG; | ||
4569 | ql_dbg(ql_dbg_p3p, vha, 0xb036, | ||
4570 | "Skipping entry[%d]: " | ||
4571 | "ETYPE[0x%x]-ELEVEL[0x%x]\n", | ||
4572 | index, entry_hdr->entry_type, | ||
4573 | entry_hdr->d_ctrl.entry_capture_mask); | ||
4574 | } | ||
4575 | |||
4576 | int | ||
4577 | qla82xx_md_collect(scsi_qla_host_t *vha) | ||
4578 | { | ||
4579 | struct qla_hw_data *ha = vha->hw; | ||
4580 | int no_entry_hdr = 0; | ||
4581 | qla82xx_md_entry_hdr_t *entry_hdr; | ||
4582 | struct qla82xx_md_template_hdr *tmplt_hdr; | ||
4583 | uint32_t *data_ptr; | ||
4584 | uint32_t total_data_size = 0, f_capture_mask, data_collected = 0; | ||
4585 | int i = 0, rval = QLA_FUNCTION_FAILED; | ||
4586 | |||
4587 | tmplt_hdr = (struct qla82xx_md_template_hdr *)ha->md_tmplt_hdr; | ||
4588 | data_ptr = (uint32_t *)ha->md_dump; | ||
4589 | |||
4590 | if (ha->fw_dumped) { | ||
4591 | ql_log(ql_log_info, vha, 0xb037, | ||
4592 | "Firmware dump available to retrive\n"); | ||
4593 | goto md_failed; | ||
4594 | } | ||
4595 | |||
4596 | ha->fw_dumped = 0; | ||
4597 | |||
4598 | if (!ha->md_tmplt_hdr || !ha->md_dump) { | ||
4599 | ql_log(ql_log_warn, vha, 0xb038, | ||
4600 | "Memory not allocated for minidump capture\n"); | ||
4601 | goto md_failed; | ||
4602 | } | ||
4603 | |||
4604 | if (qla82xx_validate_template_chksum(vha)) { | ||
4605 | ql_log(ql_log_info, vha, 0xb039, | ||
4606 | "Template checksum validation error\n"); | ||
4607 | goto md_failed; | ||
4608 | } | ||
4609 | |||
4610 | no_entry_hdr = tmplt_hdr->num_of_entries; | ||
4611 | ql_dbg(ql_dbg_p3p, vha, 0xb03a, | ||
4612 | "No of entry headers in Template: 0x%x\n", no_entry_hdr); | ||
4613 | |||
4614 | ql_dbg(ql_dbg_p3p, vha, 0xb03b, | ||
4615 | "Capture Mask obtained: 0x%x\n", tmplt_hdr->capture_debug_level); | ||
4616 | |||
4617 | f_capture_mask = tmplt_hdr->capture_debug_level & 0xFF; | ||
4618 | |||
4619 | /* Validate whether required debug level is set */ | ||
4620 | if ((f_capture_mask & 0x3) != 0x3) { | ||
4621 | ql_log(ql_log_warn, vha, 0xb03c, | ||
4622 | "Minimum required capture mask[0x%x] level not set\n", | ||
4623 | f_capture_mask); | ||
4624 | goto md_failed; | ||
4625 | } | ||
4626 | tmplt_hdr->driver_capture_mask = ql2xmdcapmask; | ||
4627 | |||
4628 | tmplt_hdr->driver_info[0] = vha->host_no; | ||
4629 | tmplt_hdr->driver_info[1] = (QLA_DRIVER_MAJOR_VER << 24) | | ||
4630 | (QLA_DRIVER_MINOR_VER << 16) | (QLA_DRIVER_PATCH_VER << 8) | | ||
4631 | QLA_DRIVER_BETA_VER; | ||
4632 | |||
4633 | total_data_size = ha->md_dump_size; | ||
4634 | |||
4635 | ql_dbg(ql_log_info, vha, 0xb03d, | ||
4636 | "Total minidump data_size 0x%x to be captured\n", total_data_size); | ||
4637 | |||
4638 | /* Check whether template obtained is valid */ | ||
4639 | if (tmplt_hdr->entry_type != QLA82XX_TLHDR) { | ||
4640 | ql_log(ql_log_warn, vha, 0xb04e, | ||
4641 | "Bad template header entry type: 0x%x obtained\n", | ||
4642 | tmplt_hdr->entry_type); | ||
4643 | goto md_failed; | ||
4644 | } | ||
4645 | |||
4646 | entry_hdr = (qla82xx_md_entry_hdr_t *) \ | ||
4647 | (((uint8_t *)ha->md_tmplt_hdr) + tmplt_hdr->first_entry_offset); | ||
4648 | |||
4649 | /* Walk through the entry headers */ | ||
4650 | for (i = 0; i < no_entry_hdr; i++) { | ||
4651 | |||
4652 | if (data_collected > total_data_size) { | ||
4653 | ql_log(ql_log_warn, vha, 0xb03e, | ||
4654 | "More MiniDump data collected: [0x%x]\n", | ||
4655 | data_collected); | ||
4656 | goto md_failed; | ||
4657 | } | ||
4658 | |||
4659 | if (!(entry_hdr->d_ctrl.entry_capture_mask & | ||
4660 | ql2xmdcapmask)) { | ||
4661 | entry_hdr->d_ctrl.driver_flags |= | ||
4662 | QLA82XX_DBG_SKIPPED_FLAG; | ||
4663 | ql_dbg(ql_dbg_p3p, vha, 0xb03f, | ||
4664 | "Skipping entry[%d]: " | ||
4665 | "ETYPE[0x%x]-ELEVEL[0x%x]\n", | ||
4666 | i, entry_hdr->entry_type, | ||
4667 | entry_hdr->d_ctrl.entry_capture_mask); | ||
4668 | goto skip_nxt_entry; | ||
4669 | } | ||
4670 | |||
4671 | ql_dbg(ql_dbg_p3p, vha, 0xb040, | ||
4672 | "[%s]: data ptr[%d]: %p, entry_hdr: %p\n" | ||
4673 | "entry_type: 0x%x, captrue_mask: 0x%x\n", | ||
4674 | __func__, i, data_ptr, entry_hdr, | ||
4675 | entry_hdr->entry_type, | ||
4676 | entry_hdr->d_ctrl.entry_capture_mask); | ||
4677 | |||
4678 | ql_dbg(ql_dbg_p3p, vha, 0xb041, | ||
4679 | "Data collected: [0x%x], Dump size left:[0x%x]\n", | ||
4680 | data_collected, (ha->md_dump_size - data_collected)); | ||
4681 | |||
4682 | /* Decode the entry type and take | ||
4683 | * required action to capture debug data */ | ||
4684 | switch (entry_hdr->entry_type) { | ||
4685 | case QLA82XX_RDEND: | ||
4686 | qla82xx_mark_entry_skipped(vha, entry_hdr, i); | ||
4687 | break; | ||
4688 | case QLA82XX_CNTRL: | ||
4689 | rval = qla82xx_minidump_process_control(vha, | ||
4690 | entry_hdr, &data_ptr); | ||
4691 | if (rval != QLA_SUCCESS) { | ||
4692 | qla82xx_mark_entry_skipped(vha, entry_hdr, i); | ||
4693 | goto md_failed; | ||
4694 | } | ||
4695 | break; | ||
4696 | case QLA82XX_RDCRB: | ||
4697 | qla82xx_minidump_process_rdcrb(vha, | ||
4698 | entry_hdr, &data_ptr); | ||
4699 | break; | ||
4700 | case QLA82XX_RDMEM: | ||
4701 | rval = qla82xx_minidump_process_rdmem(vha, | ||
4702 | entry_hdr, &data_ptr); | ||
4703 | if (rval != QLA_SUCCESS) { | ||
4704 | qla82xx_mark_entry_skipped(vha, entry_hdr, i); | ||
4705 | goto md_failed; | ||
4706 | } | ||
4707 | break; | ||
4708 | case QLA82XX_BOARD: | ||
4709 | case QLA82XX_RDROM: | ||
4710 | qla82xx_minidump_process_rdrom(vha, | ||
4711 | entry_hdr, &data_ptr); | ||
4712 | break; | ||
4713 | case QLA82XX_L2DTG: | ||
4714 | case QLA82XX_L2ITG: | ||
4715 | case QLA82XX_L2DAT: | ||
4716 | case QLA82XX_L2INS: | ||
4717 | rval = qla82xx_minidump_process_l2tag(vha, | ||
4718 | entry_hdr, &data_ptr); | ||
4719 | if (rval != QLA_SUCCESS) { | ||
4720 | qla82xx_mark_entry_skipped(vha, entry_hdr, i); | ||
4721 | goto md_failed; | ||
4722 | } | ||
4723 | break; | ||
4724 | case QLA82XX_L1DAT: | ||
4725 | case QLA82XX_L1INS: | ||
4726 | qla82xx_minidump_process_l1cache(vha, | ||
4727 | entry_hdr, &data_ptr); | ||
4728 | break; | ||
4729 | case QLA82XX_RDOCM: | ||
4730 | qla82xx_minidump_process_rdocm(vha, | ||
4731 | entry_hdr, &data_ptr); | ||
4732 | break; | ||
4733 | case QLA82XX_RDMUX: | ||
4734 | qla82xx_minidump_process_rdmux(vha, | ||
4735 | entry_hdr, &data_ptr); | ||
4736 | break; | ||
4737 | case QLA82XX_QUEUE: | ||
4738 | qla82xx_minidump_process_queue(vha, | ||
4739 | entry_hdr, &data_ptr); | ||
4740 | break; | ||
4741 | case QLA82XX_RDNOP: | ||
4742 | default: | ||
4743 | qla82xx_mark_entry_skipped(vha, entry_hdr, i); | ||
4744 | break; | ||
4745 | } | ||
4746 | |||
4747 | ql_dbg(ql_dbg_p3p, vha, 0xb042, | ||
4748 | "[%s]: data ptr[%d]: %p\n", __func__, i, data_ptr); | ||
4749 | |||
4750 | data_collected = (uint8_t *)data_ptr - | ||
4751 | (uint8_t *)ha->md_dump; | ||
4752 | skip_nxt_entry: | ||
4753 | entry_hdr = (qla82xx_md_entry_hdr_t *) \ | ||
4754 | (((uint8_t *)entry_hdr) + entry_hdr->entry_size); | ||
4755 | } | ||
4756 | |||
4757 | if (data_collected != total_data_size) { | ||
4758 | ql_dbg(ql_log_warn, vha, 0xb043, | ||
4759 | "MiniDump data mismatch: Data collected: [0x%x]," | ||
4760 | "total_data_size:[0x%x]\n", | ||
4761 | data_collected, total_data_size); | ||
4762 | goto md_failed; | ||
4763 | } | ||
4764 | |||
4765 | ql_log(ql_log_info, vha, 0xb044, | ||
4766 | "Firmware dump saved to temp buffer (%ld/%p %ld/%p).\n", | ||
4767 | vha->host_no, ha->md_tmplt_hdr, vha->host_no, ha->md_dump); | ||
4768 | ha->fw_dumped = 1; | ||
4769 | qla2x00_post_uevent_work(vha, QLA_UEVENT_CODE_FW_DUMP); | ||
4770 | |||
4771 | md_failed: | ||
4772 | return rval; | ||
4773 | } | ||
4774 | |||
4775 | int | ||
4776 | qla82xx_md_alloc(scsi_qla_host_t *vha) | ||
4777 | { | ||
4778 | struct qla_hw_data *ha = vha->hw; | ||
4779 | int i, k; | ||
4780 | struct qla82xx_md_template_hdr *tmplt_hdr; | ||
4781 | |||
4782 | tmplt_hdr = (struct qla82xx_md_template_hdr *)ha->md_tmplt_hdr; | ||
4783 | |||
4784 | if (ql2xmdcapmask < 0x3 || ql2xmdcapmask > 0x7F) { | ||
4785 | ql2xmdcapmask = tmplt_hdr->capture_debug_level & 0xFF; | ||
4786 | ql_log(ql_log_info, vha, 0xb045, | ||
4787 | "Forcing driver capture mask to firmware default capture mask: 0x%x.\n", | ||
4788 | ql2xmdcapmask); | ||
4789 | } | ||
4790 | |||
4791 | for (i = 0x2, k = 1; (i & QLA82XX_DEFAULT_CAP_MASK); i <<= 1, k++) { | ||
4792 | if (i & ql2xmdcapmask) | ||
4793 | ha->md_dump_size += tmplt_hdr->capture_size_array[k]; | ||
4794 | } | ||
4795 | |||
4796 | if (ha->md_dump) { | ||
4797 | ql_log(ql_log_warn, vha, 0xb046, | ||
4798 | "Firmware dump previously allocated.\n"); | ||
4799 | return 1; | ||
4800 | } | ||
4801 | |||
4802 | ha->md_dump = vmalloc(ha->md_dump_size); | ||
4803 | if (ha->md_dump == NULL) { | ||
4804 | ql_log(ql_log_warn, vha, 0xb047, | ||
4805 | "Unable to allocate memory for Minidump size " | ||
4806 | "(0x%x).\n", ha->md_dump_size); | ||
4807 | return 1; | ||
4808 | } | ||
4809 | return 0; | ||
4810 | } | ||
4811 | |||
4812 | void | ||
4813 | qla82xx_md_free(scsi_qla_host_t *vha) | ||
4814 | { | ||
4815 | struct qla_hw_data *ha = vha->hw; | ||
4816 | |||
4817 | /* Release the template header allocated */ | ||
4818 | if (ha->md_tmplt_hdr) { | ||
4819 | ql_log(ql_log_info, vha, 0xb048, | ||
4820 | "Free MiniDump template: %p, size (%d KB)\n", | ||
4821 | ha->md_tmplt_hdr, ha->md_template_size / 1024); | ||
4822 | dma_free_coherent(&ha->pdev->dev, ha->md_template_size, | ||
4823 | ha->md_tmplt_hdr, ha->md_tmplt_hdr_dma); | ||
4824 | ha->md_tmplt_hdr = 0; | ||
4825 | } | ||
4826 | |||
4827 | /* Release the template data buffer allocated */ | ||
4828 | if (ha->md_dump) { | ||
4829 | ql_log(ql_log_info, vha, 0xb049, | ||
4830 | "Free MiniDump memory: %p, size (%d KB)\n", | ||
4831 | ha->md_dump, ha->md_dump_size / 1024); | ||
4832 | vfree(ha->md_dump); | ||
4833 | ha->md_dump_size = 0; | ||
4834 | ha->md_dump = 0; | ||
4835 | } | ||
4836 | } | ||
4837 | |||
4838 | void | ||
4839 | qla82xx_md_prep(scsi_qla_host_t *vha) | ||
4840 | { | ||
4841 | struct qla_hw_data *ha = vha->hw; | ||
4842 | int rval; | ||
4843 | |||
4844 | /* Get Minidump template size */ | ||
4845 | rval = qla82xx_md_get_template_size(vha); | ||
4846 | if (rval == QLA_SUCCESS) { | ||
4847 | ql_log(ql_log_info, vha, 0xb04a, | ||
4848 | "MiniDump Template size obtained (%d KB)\n", | ||
4849 | ha->md_template_size / 1024); | ||
4850 | |||
4851 | /* Get Minidump template */ | ||
4852 | rval = qla82xx_md_get_template(vha); | ||
4853 | if (rval == QLA_SUCCESS) { | ||
4854 | ql_dbg(ql_dbg_p3p, vha, 0xb04b, | ||
4855 | "MiniDump Template obtained\n"); | ||
4856 | |||
4857 | /* Allocate memory for minidump */ | ||
4858 | rval = qla82xx_md_alloc(vha); | ||
4859 | if (rval == QLA_SUCCESS) | ||
4860 | ql_log(ql_log_info, vha, 0xb04c, | ||
4861 | "MiniDump memory allocated (%d KB)\n", | ||
4862 | ha->md_dump_size / 1024); | ||
4863 | else { | ||
4864 | ql_log(ql_log_info, vha, 0xb04d, | ||
4865 | "Free MiniDump template: %p, size: (%d KB)\n", | ||
4866 | ha->md_tmplt_hdr, | ||
4867 | ha->md_template_size / 1024); | ||
4868 | dma_free_coherent(&ha->pdev->dev, | ||
4869 | ha->md_template_size, | ||
4870 | ha->md_tmplt_hdr, ha->md_tmplt_hdr_dma); | ||
4871 | ha->md_tmplt_hdr = 0; | ||
4872 | } | ||
4873 | |||
4874 | } | ||
4875 | } | ||
4876 | } | ||
diff --git a/drivers/scsi/qla2xxx/qla_nx.h b/drivers/scsi/qla2xxx/qla_nx.h index 8a21832c6693..97ee250b63bb 100644 --- a/drivers/scsi/qla2xxx/qla_nx.h +++ b/drivers/scsi/qla2xxx/qla_nx.h | |||
@@ -484,8 +484,6 @@ | |||
484 | #define QLA82XX_ADDR_OCM1 (0x0000000200400000ULL) | 484 | #define QLA82XX_ADDR_OCM1 (0x0000000200400000ULL) |
485 | #define QLA82XX_ADDR_OCM1_MAX (0x00000002004fffffULL) | 485 | #define QLA82XX_ADDR_OCM1_MAX (0x00000002004fffffULL) |
486 | #define QLA82XX_ADDR_QDR_NET (0x0000000300000000ULL) | 486 | #define QLA82XX_ADDR_QDR_NET (0x0000000300000000ULL) |
487 | |||
488 | #define QLA82XX_P2_ADDR_QDR_NET_MAX (0x00000003001fffffULL) | ||
489 | #define QLA82XX_P3_ADDR_QDR_NET_MAX (0x0000000303ffffffULL) | 487 | #define QLA82XX_P3_ADDR_QDR_NET_MAX (0x0000000303ffffffULL) |
490 | 488 | ||
491 | #define QLA82XX_PCI_CRBSPACE (unsigned long)0x06000000 | 489 | #define QLA82XX_PCI_CRBSPACE (unsigned long)0x06000000 |
@@ -922,4 +920,256 @@ struct ct6_dsd { | |||
922 | #define M25P_INSTR_DP 0xb9 | 920 | #define M25P_INSTR_DP 0xb9 |
923 | #define M25P_INSTR_RES 0xab | 921 | #define M25P_INSTR_RES 0xab |
924 | 922 | ||
923 | /* Minidump related */ | ||
924 | |||
925 | /* | ||
926 | * Version of the template | ||
927 | * 4 Bytes | ||
928 | * X.Major.Minor.RELEASE | ||
929 | */ | ||
930 | #define QLA82XX_MINIDUMP_VERSION 0x10101 | ||
931 | |||
932 | /* | ||
933 | * Entry Type Defines | ||
934 | */ | ||
935 | #define QLA82XX_RDNOP 0 | ||
936 | #define QLA82XX_RDCRB 1 | ||
937 | #define QLA82XX_RDMUX 2 | ||
938 | #define QLA82XX_QUEUE 3 | ||
939 | #define QLA82XX_BOARD 4 | ||
940 | #define QLA82XX_RDSRE 5 | ||
941 | #define QLA82XX_RDOCM 6 | ||
942 | #define QLA82XX_CACHE 10 | ||
943 | #define QLA82XX_L1DAT 11 | ||
944 | #define QLA82XX_L1INS 12 | ||
945 | #define QLA82XX_L2DTG 21 | ||
946 | #define QLA82XX_L2ITG 22 | ||
947 | #define QLA82XX_L2DAT 23 | ||
948 | #define QLA82XX_L2INS 24 | ||
949 | #define QLA82XX_RDROM 71 | ||
950 | #define QLA82XX_RDMEM 72 | ||
951 | #define QLA82XX_CNTRL 98 | ||
952 | #define QLA82XX_TLHDR 99 | ||
953 | #define QLA82XX_RDEND 255 | ||
954 | |||
955 | /* | ||
956 | * Opcodes for Control Entries. | ||
957 | * These Flags are bit fields. | ||
958 | */ | ||
959 | #define QLA82XX_DBG_OPCODE_WR 0x01 | ||
960 | #define QLA82XX_DBG_OPCODE_RW 0x02 | ||
961 | #define QLA82XX_DBG_OPCODE_AND 0x04 | ||
962 | #define QLA82XX_DBG_OPCODE_OR 0x08 | ||
963 | #define QLA82XX_DBG_OPCODE_POLL 0x10 | ||
964 | #define QLA82XX_DBG_OPCODE_RDSTATE 0x20 | ||
965 | #define QLA82XX_DBG_OPCODE_WRSTATE 0x40 | ||
966 | #define QLA82XX_DBG_OPCODE_MDSTATE 0x80 | ||
967 | |||
968 | /* | ||
969 | * Template Header and Entry Header definitions start here. | ||
970 | */ | ||
971 | |||
972 | /* | ||
973 | * Template Header | ||
974 | * Parts of the template header can be modified by the driver. | ||
975 | * These include the saved_state_array, capture_debug_level, driver_timestamp | ||
976 | */ | ||
977 | |||
978 | #define QLA82XX_DBG_STATE_ARRAY_LEN 16 | ||
979 | #define QLA82XX_DBG_CAP_SIZE_ARRAY_LEN 8 | ||
980 | #define QLA82XX_DBG_RSVD_ARRAY_LEN 8 | ||
981 | |||
982 | /* | ||
983 | * Driver Flags | ||
984 | */ | ||
985 | #define QLA82XX_DBG_SKIPPED_FLAG 0x80 /* driver skipped this entry */ | ||
986 | #define QLA82XX_DEFAULT_CAP_MASK 0xFF /* default capture mask */ | ||
987 | |||
988 | struct qla82xx_md_template_hdr { | ||
989 | uint32_t entry_type; | ||
990 | uint32_t first_entry_offset; | ||
991 | uint32_t size_of_template; | ||
992 | uint32_t capture_debug_level; | ||
993 | |||
994 | uint32_t num_of_entries; | ||
995 | uint32_t version; | ||
996 | uint32_t driver_timestamp; | ||
997 | uint32_t template_checksum; | ||
998 | |||
999 | uint32_t driver_capture_mask; | ||
1000 | uint32_t driver_info[3]; | ||
1001 | |||
1002 | uint32_t saved_state_array[QLA82XX_DBG_STATE_ARRAY_LEN]; | ||
1003 | uint32_t capture_size_array[QLA82XX_DBG_CAP_SIZE_ARRAY_LEN]; | ||
1004 | |||
1005 | /* markers_array used to capture some special locations on board */ | ||
1006 | uint32_t markers_array[QLA82XX_DBG_RSVD_ARRAY_LEN]; | ||
1007 | uint32_t num_of_free_entries; /* For internal use */ | ||
1008 | uint32_t free_entry_offset; /* For internal use */ | ||
1009 | uint32_t total_table_size; /* For internal use */ | ||
1010 | uint32_t bkup_table_offset; /* For internal use */ | ||
1011 | } __packed; | ||
1012 | |||
1013 | /* | ||
1014 | * Entry Header: Common to All Entry Types | ||
1015 | */ | ||
1016 | |||
1017 | /* | ||
1018 | * Driver Code is for driver to write some info about the entry. | ||
1019 | * Currently not used. | ||
1020 | */ | ||
1021 | typedef struct qla82xx_md_entry_hdr { | ||
1022 | uint32_t entry_type; | ||
1023 | uint32_t entry_size; | ||
1024 | uint32_t entry_capture_size; | ||
1025 | struct { | ||
1026 | uint8_t entry_capture_mask; | ||
1027 | uint8_t entry_code; | ||
1028 | uint8_t driver_code; | ||
1029 | uint8_t driver_flags; | ||
1030 | } d_ctrl; | ||
1031 | } __packed qla82xx_md_entry_hdr_t; | ||
1032 | |||
1033 | /* | ||
1034 | * Read CRB entry header | ||
1035 | */ | ||
1036 | struct qla82xx_md_entry_crb { | ||
1037 | qla82xx_md_entry_hdr_t h; | ||
1038 | uint32_t addr; | ||
1039 | struct { | ||
1040 | uint8_t addr_stride; | ||
1041 | uint8_t state_index_a; | ||
1042 | uint16_t poll_timeout; | ||
1043 | } crb_strd; | ||
1044 | |||
1045 | uint32_t data_size; | ||
1046 | uint32_t op_count; | ||
1047 | |||
1048 | struct { | ||
1049 | uint8_t opcode; | ||
1050 | uint8_t state_index_v; | ||
1051 | uint8_t shl; | ||
1052 | uint8_t shr; | ||
1053 | } crb_ctrl; | ||
1054 | |||
1055 | uint32_t value_1; | ||
1056 | uint32_t value_2; | ||
1057 | uint32_t value_3; | ||
1058 | } __packed; | ||
1059 | |||
1060 | /* | ||
1061 | * Cache entry header | ||
1062 | */ | ||
1063 | struct qla82xx_md_entry_cache { | ||
1064 | qla82xx_md_entry_hdr_t h; | ||
1065 | |||
1066 | uint32_t tag_reg_addr; | ||
1067 | struct { | ||
1068 | uint16_t tag_value_stride; | ||
1069 | uint16_t init_tag_value; | ||
1070 | } addr_ctrl; | ||
1071 | |||
1072 | uint32_t data_size; | ||
1073 | uint32_t op_count; | ||
1074 | |||
1075 | uint32_t control_addr; | ||
1076 | struct { | ||
1077 | uint16_t write_value; | ||
1078 | uint8_t poll_mask; | ||
1079 | uint8_t poll_wait; | ||
1080 | } cache_ctrl; | ||
1081 | |||
1082 | uint32_t read_addr; | ||
1083 | struct { | ||
1084 | uint8_t read_addr_stride; | ||
1085 | uint8_t read_addr_cnt; | ||
1086 | uint16_t rsvd_1; | ||
1087 | } read_ctrl; | ||
1088 | } __packed; | ||
1089 | |||
1090 | /* | ||
1091 | * Read OCM | ||
1092 | */ | ||
1093 | struct qla82xx_md_entry_rdocm { | ||
1094 | qla82xx_md_entry_hdr_t h; | ||
1095 | |||
1096 | uint32_t rsvd_0; | ||
1097 | uint32_t rsvd_1; | ||
1098 | uint32_t data_size; | ||
1099 | uint32_t op_count; | ||
1100 | |||
1101 | uint32_t rsvd_2; | ||
1102 | uint32_t rsvd_3; | ||
1103 | uint32_t read_addr; | ||
1104 | uint32_t read_addr_stride; | ||
1105 | uint32_t read_addr_cntrl; | ||
1106 | } __packed; | ||
1107 | |||
1108 | /* | ||
1109 | * Read Memory | ||
1110 | */ | ||
1111 | struct qla82xx_md_entry_rdmem { | ||
1112 | qla82xx_md_entry_hdr_t h; | ||
1113 | uint32_t rsvd[6]; | ||
1114 | uint32_t read_addr; | ||
1115 | uint32_t read_data_size; | ||
1116 | } __packed; | ||
1117 | |||
1118 | /* | ||
1119 | * Read ROM | ||
1120 | */ | ||
1121 | struct qla82xx_md_entry_rdrom { | ||
1122 | qla82xx_md_entry_hdr_t h; | ||
1123 | uint32_t rsvd[6]; | ||
1124 | uint32_t read_addr; | ||
1125 | uint32_t read_data_size; | ||
1126 | } __packed; | ||
1127 | |||
1128 | struct qla82xx_md_entry_mux { | ||
1129 | qla82xx_md_entry_hdr_t h; | ||
1130 | |||
1131 | uint32_t select_addr; | ||
1132 | uint32_t rsvd_0; | ||
1133 | uint32_t data_size; | ||
1134 | uint32_t op_count; | ||
1135 | |||
1136 | uint32_t select_value; | ||
1137 | uint32_t select_value_stride; | ||
1138 | uint32_t read_addr; | ||
1139 | uint32_t rsvd_1; | ||
1140 | } __packed; | ||
1141 | |||
1142 | struct qla82xx_md_entry_queue { | ||
1143 | qla82xx_md_entry_hdr_t h; | ||
1144 | |||
1145 | uint32_t select_addr; | ||
1146 | struct { | ||
1147 | uint16_t queue_id_stride; | ||
1148 | uint16_t rsvd_0; | ||
1149 | } q_strd; | ||
1150 | |||
1151 | uint32_t data_size; | ||
1152 | uint32_t op_count; | ||
1153 | uint32_t rsvd_1; | ||
1154 | uint32_t rsvd_2; | ||
1155 | |||
1156 | uint32_t read_addr; | ||
1157 | struct { | ||
1158 | uint8_t read_addr_stride; | ||
1159 | uint8_t read_addr_cnt; | ||
1160 | uint16_t rsvd_3; | ||
1161 | } rd_strd; | ||
1162 | } __packed; | ||
1163 | |||
1164 | #define MBC_DIAGNOSTIC_MINIDUMP_TEMPLATE 0x129 | ||
1165 | #define RQST_TMPLT_SIZE 0x0 | ||
1166 | #define RQST_TMPLT 0x1 | ||
1167 | #define MD_DIRECT_ROM_WINDOW 0x42110030 | ||
1168 | #define MD_DIRECT_ROM_READ_BASE 0x42150000 | ||
1169 | #define MD_MIU_TEST_AGT_CTRL 0x41000090 | ||
1170 | #define MD_MIU_TEST_AGT_ADDR_LO 0x41000094 | ||
1171 | #define MD_MIU_TEST_AGT_ADDR_HI 0x41000098 | ||
1172 | |||
1173 | static const int MD_MIU_TEST_AGT_RDDATA[] = { 0x410000A8, 0x410000AC, | ||
1174 | 0x410000B8, 0x410000BC }; | ||
925 | #endif | 1175 | #endif |
diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index 4cace3f20c04..e37556ce211f 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c | |||
@@ -160,9 +160,9 @@ MODULE_PARM_DESC(ql2xetsenable, | |||
160 | int ql2xdbwr = 1; | 160 | int ql2xdbwr = 1; |
161 | module_param(ql2xdbwr, int, S_IRUGO); | 161 | module_param(ql2xdbwr, int, S_IRUGO); |
162 | MODULE_PARM_DESC(ql2xdbwr, | 162 | MODULE_PARM_DESC(ql2xdbwr, |
163 | "Option to specify scheme for request queue posting.\n" | 163 | "Option to specify scheme for request queue posting.\n" |
164 | " 0 -- Regular doorbell.\n" | 164 | " 0 -- Regular doorbell.\n" |
165 | " 1 -- CAMRAM doorbell (faster).\n"); | 165 | " 1 -- CAMRAM doorbell (faster).\n"); |
166 | 166 | ||
167 | int ql2xtargetreset = 1; | 167 | int ql2xtargetreset = 1; |
168 | module_param(ql2xtargetreset, int, S_IRUGO); | 168 | module_param(ql2xtargetreset, int, S_IRUGO); |
@@ -185,9 +185,9 @@ MODULE_PARM_DESC(ql2xasynctmfenable, | |||
185 | int ql2xdontresethba; | 185 | int ql2xdontresethba; |
186 | module_param(ql2xdontresethba, int, S_IRUGO); | 186 | module_param(ql2xdontresethba, int, S_IRUGO); |
187 | MODULE_PARM_DESC(ql2xdontresethba, | 187 | MODULE_PARM_DESC(ql2xdontresethba, |
188 | "Option to specify reset behaviour.\n" | 188 | "Option to specify reset behaviour.\n" |
189 | " 0 (Default) -- Reset on failure.\n" | 189 | " 0 (Default) -- Reset on failure.\n" |
190 | " 1 -- Do not reset on failure.\n"); | 190 | " 1 -- Do not reset on failure.\n"); |
191 | 191 | ||
192 | uint ql2xmaxlun = MAX_LUNS; | 192 | uint ql2xmaxlun = MAX_LUNS; |
193 | module_param(ql2xmaxlun, uint, S_IRUGO); | 193 | module_param(ql2xmaxlun, uint, S_IRUGO); |
@@ -195,6 +195,19 @@ MODULE_PARM_DESC(ql2xmaxlun, | |||
195 | "Defines the maximum LU number to register with the SCSI " | 195 | "Defines the maximum LU number to register with the SCSI " |
196 | "midlayer. Default is 65535."); | 196 | "midlayer. Default is 65535."); |
197 | 197 | ||
198 | int ql2xmdcapmask = 0x1F; | ||
199 | module_param(ql2xmdcapmask, int, S_IRUGO); | ||
200 | MODULE_PARM_DESC(ql2xmdcapmask, | ||
201 | "Set the Minidump driver capture mask level. " | ||
202 | "Default is 0x7F - Can be set to 0x3, 0x7, 0xF, 0x1F, 0x7F."); | ||
203 | |||
204 | int ql2xmdenable; | ||
205 | module_param(ql2xmdenable, int, S_IRUGO); | ||
206 | MODULE_PARM_DESC(ql2xmdenable, | ||
207 | "Enable/disable MiniDump. " | ||
208 | "0 (Default) - MiniDump disabled. " | ||
209 | "1 - MiniDump enabled."); | ||
210 | |||
198 | /* | 211 | /* |
199 | * SCSI host template entry points | 212 | * SCSI host template entry points |
200 | */ | 213 | */ |
@@ -2669,6 +2682,8 @@ qla2x00_free_device(scsi_qla_host_t *vha) | |||
2669 | 2682 | ||
2670 | qla2x00_mem_free(ha); | 2683 | qla2x00_mem_free(ha); |
2671 | 2684 | ||
2685 | qla82xx_md_free(vha); | ||
2686 | |||
2672 | qla2x00_free_queues(ha); | 2687 | qla2x00_free_queues(ha); |
2673 | } | 2688 | } |
2674 | 2689 | ||