diff options
Diffstat (limited to 'drivers/scsi/qla4xxx')
-rw-r--r-- | drivers/scsi/qla4xxx/ql4_attr.c | 134 | ||||
-rw-r--r-- | drivers/scsi/qla4xxx/ql4_def.h | 22 | ||||
-rw-r--r-- | drivers/scsi/qla4xxx/ql4_fw.h | 28 | ||||
-rw-r--r-- | drivers/scsi/qla4xxx/ql4_glbl.h | 8 | ||||
-rw-r--r-- | drivers/scsi/qla4xxx/ql4_init.c | 95 | ||||
-rw-r--r-- | drivers/scsi/qla4xxx/ql4_mbx.c | 111 | ||||
-rw-r--r-- | drivers/scsi/qla4xxx/ql4_nx.c | 738 | ||||
-rw-r--r-- | drivers/scsi/qla4xxx/ql4_nx.h | 192 | ||||
-rw-r--r-- | drivers/scsi/qla4xxx/ql4_os.c | 78 | ||||
-rw-r--r-- | drivers/scsi/qla4xxx/ql4_version.h | 2 |
10 files changed, 1370 insertions, 38 deletions
diff --git a/drivers/scsi/qla4xxx/ql4_attr.c b/drivers/scsi/qla4xxx/ql4_attr.c index 0b0a7d42137d..c681b2a355e1 100644 --- a/drivers/scsi/qla4xxx/ql4_attr.c +++ b/drivers/scsi/qla4xxx/ql4_attr.c | |||
@@ -9,6 +9,140 @@ | |||
9 | #include "ql4_glbl.h" | 9 | #include "ql4_glbl.h" |
10 | #include "ql4_dbg.h" | 10 | #include "ql4_dbg.h" |
11 | 11 | ||
12 | static ssize_t | ||
13 | qla4_8xxx_sysfs_read_fw_dump(struct file *filep, struct kobject *kobj, | ||
14 | struct bin_attribute *ba, char *buf, loff_t off, | ||
15 | size_t count) | ||
16 | { | ||
17 | struct scsi_qla_host *ha = to_qla_host(dev_to_shost(container_of(kobj, | ||
18 | struct device, kobj))); | ||
19 | |||
20 | if (!is_qla8022(ha)) | ||
21 | return -EINVAL; | ||
22 | |||
23 | if (!test_bit(AF_82XX_DUMP_READING, &ha->flags)) | ||
24 | return 0; | ||
25 | |||
26 | return memory_read_from_buffer(buf, count, &off, ha->fw_dump, | ||
27 | ha->fw_dump_size); | ||
28 | } | ||
29 | |||
30 | static ssize_t | ||
31 | qla4_8xxx_sysfs_write_fw_dump(struct file *filep, struct kobject *kobj, | ||
32 | struct bin_attribute *ba, char *buf, loff_t off, | ||
33 | size_t count) | ||
34 | { | ||
35 | struct scsi_qla_host *ha = to_qla_host(dev_to_shost(container_of(kobj, | ||
36 | struct device, kobj))); | ||
37 | uint32_t dev_state; | ||
38 | long reading; | ||
39 | int ret = 0; | ||
40 | |||
41 | if (!is_qla8022(ha)) | ||
42 | return -EINVAL; | ||
43 | |||
44 | if (off != 0) | ||
45 | return ret; | ||
46 | |||
47 | buf[1] = 0; | ||
48 | ret = kstrtol(buf, 10, &reading); | ||
49 | if (ret) { | ||
50 | ql4_printk(KERN_ERR, ha, "%s: Invalid input. Return err %d\n", | ||
51 | __func__, ret); | ||
52 | return ret; | ||
53 | } | ||
54 | |||
55 | switch (reading) { | ||
56 | case 0: | ||
57 | /* clear dump collection flags */ | ||
58 | if (test_and_clear_bit(AF_82XX_DUMP_READING, &ha->flags)) { | ||
59 | clear_bit(AF_82XX_FW_DUMPED, &ha->flags); | ||
60 | /* Reload minidump template */ | ||
61 | qla4xxx_alloc_fw_dump(ha); | ||
62 | DEBUG2(ql4_printk(KERN_INFO, ha, | ||
63 | "Firmware template reloaded\n")); | ||
64 | } | ||
65 | break; | ||
66 | case 1: | ||
67 | /* Set flag to read dump */ | ||
68 | if (test_bit(AF_82XX_FW_DUMPED, &ha->flags) && | ||
69 | !test_bit(AF_82XX_DUMP_READING, &ha->flags)) { | ||
70 | set_bit(AF_82XX_DUMP_READING, &ha->flags); | ||
71 | DEBUG2(ql4_printk(KERN_INFO, ha, | ||
72 | "Raw firmware dump ready for read on (%ld).\n", | ||
73 | ha->host_no)); | ||
74 | } | ||
75 | break; | ||
76 | case 2: | ||
77 | /* Reset HBA */ | ||
78 | qla4_8xxx_idc_lock(ha); | ||
79 | dev_state = qla4_8xxx_rd_32(ha, QLA82XX_CRB_DEV_STATE); | ||
80 | if (dev_state == QLA82XX_DEV_READY) { | ||
81 | ql4_printk(KERN_INFO, ha, | ||
82 | "%s: Setting Need reset, reset_owner is 0x%x.\n", | ||
83 | __func__, ha->func_num); | ||
84 | qla4_8xxx_wr_32(ha, QLA82XX_CRB_DEV_STATE, | ||
85 | QLA82XX_DEV_NEED_RESET); | ||
86 | set_bit(AF_82XX_RST_OWNER, &ha->flags); | ||
87 | } else | ||
88 | ql4_printk(KERN_INFO, ha, | ||
89 | "%s: Reset not performed as device state is 0x%x\n", | ||
90 | __func__, dev_state); | ||
91 | |||
92 | qla4_8xxx_idc_unlock(ha); | ||
93 | break; | ||
94 | default: | ||
95 | /* do nothing */ | ||
96 | break; | ||
97 | } | ||
98 | |||
99 | return count; | ||
100 | } | ||
101 | |||
102 | static struct bin_attribute sysfs_fw_dump_attr = { | ||
103 | .attr = { | ||
104 | .name = "fw_dump", | ||
105 | .mode = S_IRUSR | S_IWUSR, | ||
106 | }, | ||
107 | .size = 0, | ||
108 | .read = qla4_8xxx_sysfs_read_fw_dump, | ||
109 | .write = qla4_8xxx_sysfs_write_fw_dump, | ||
110 | }; | ||
111 | |||
112 | static struct sysfs_entry { | ||
113 | char *name; | ||
114 | struct bin_attribute *attr; | ||
115 | } bin_file_entries[] = { | ||
116 | { "fw_dump", &sysfs_fw_dump_attr }, | ||
117 | { NULL }, | ||
118 | }; | ||
119 | |||
120 | void qla4_8xxx_alloc_sysfs_attr(struct scsi_qla_host *ha) | ||
121 | { | ||
122 | struct Scsi_Host *host = ha->host; | ||
123 | struct sysfs_entry *iter; | ||
124 | int ret; | ||
125 | |||
126 | for (iter = bin_file_entries; iter->name; iter++) { | ||
127 | ret = sysfs_create_bin_file(&host->shost_gendev.kobj, | ||
128 | iter->attr); | ||
129 | if (ret) | ||
130 | ql4_printk(KERN_ERR, ha, | ||
131 | "Unable to create sysfs %s binary attribute (%d).\n", | ||
132 | iter->name, ret); | ||
133 | } | ||
134 | } | ||
135 | |||
136 | void qla4_8xxx_free_sysfs_attr(struct scsi_qla_host *ha) | ||
137 | { | ||
138 | struct Scsi_Host *host = ha->host; | ||
139 | struct sysfs_entry *iter; | ||
140 | |||
141 | for (iter = bin_file_entries; iter->name; iter++) | ||
142 | sysfs_remove_bin_file(&host->shost_gendev.kobj, | ||
143 | iter->attr); | ||
144 | } | ||
145 | |||
12 | /* Scsi_Host attributes. */ | 146 | /* Scsi_Host attributes. */ |
13 | static ssize_t | 147 | static ssize_t |
14 | qla4xxx_fw_version_show(struct device *dev, | 148 | qla4xxx_fw_version_show(struct device *dev, |
diff --git a/drivers/scsi/qla4xxx/ql4_def.h b/drivers/scsi/qla4xxx/ql4_def.h index 7f2492e88be7..96a5616a8fda 100644 --- a/drivers/scsi/qla4xxx/ql4_def.h +++ b/drivers/scsi/qla4xxx/ql4_def.h | |||
@@ -398,6 +398,16 @@ struct isp_operations { | |||
398 | int (*get_sys_info) (struct scsi_qla_host *); | 398 | int (*get_sys_info) (struct scsi_qla_host *); |
399 | }; | 399 | }; |
400 | 400 | ||
401 | struct ql4_mdump_size_table { | ||
402 | uint32_t size; | ||
403 | uint32_t size_cmask_02; | ||
404 | uint32_t size_cmask_04; | ||
405 | uint32_t size_cmask_08; | ||
406 | uint32_t size_cmask_10; | ||
407 | uint32_t size_cmask_FF; | ||
408 | uint32_t version; | ||
409 | }; | ||
410 | |||
401 | /*qla4xxx ipaddress configuration details */ | 411 | /*qla4xxx ipaddress configuration details */ |
402 | struct ipaddress_config { | 412 | struct ipaddress_config { |
403 | uint16_t ipv4_options; | 413 | uint16_t ipv4_options; |
@@ -485,6 +495,10 @@ struct scsi_qla_host { | |||
485 | #define AF_EEH_BUSY 20 /* 0x00100000 */ | 495 | #define AF_EEH_BUSY 20 /* 0x00100000 */ |
486 | #define AF_PCI_CHANNEL_IO_PERM_FAILURE 21 /* 0x00200000 */ | 496 | #define AF_PCI_CHANNEL_IO_PERM_FAILURE 21 /* 0x00200000 */ |
487 | #define AF_BUILD_DDB_LIST 22 /* 0x00400000 */ | 497 | #define AF_BUILD_DDB_LIST 22 /* 0x00400000 */ |
498 | #define AF_82XX_FW_DUMPED 24 /* 0x01000000 */ | ||
499 | #define AF_82XX_RST_OWNER 25 /* 0x02000000 */ | ||
500 | #define AF_82XX_DUMP_READING 26 /* 0x04000000 */ | ||
501 | |||
488 | unsigned long dpc_flags; | 502 | unsigned long dpc_flags; |
489 | 503 | ||
490 | #define DPC_RESET_HA 1 /* 0x00000002 */ | 504 | #define DPC_RESET_HA 1 /* 0x00000002 */ |
@@ -662,6 +676,11 @@ struct scsi_qla_host { | |||
662 | 676 | ||
663 | uint32_t nx_dev_init_timeout; | 677 | uint32_t nx_dev_init_timeout; |
664 | uint32_t nx_reset_timeout; | 678 | uint32_t nx_reset_timeout; |
679 | void *fw_dump; | ||
680 | uint32_t fw_dump_size; | ||
681 | uint32_t fw_dump_capture_mask; | ||
682 | void *fw_dump_tmplt_hdr; | ||
683 | uint32_t fw_dump_tmplt_size; | ||
665 | 684 | ||
666 | struct completion mbx_intr_comp; | 685 | struct completion mbx_intr_comp; |
667 | 686 | ||
@@ -936,4 +955,7 @@ static inline int ql4xxx_reset_active(struct scsi_qla_host *ha) | |||
936 | #define PROCESS_ALL_AENS 0 | 955 | #define PROCESS_ALL_AENS 0 |
937 | #define FLUSH_DDB_CHANGED_AENS 1 | 956 | #define FLUSH_DDB_CHANGED_AENS 1 |
938 | 957 | ||
958 | /* Defines for udev events */ | ||
959 | #define QL4_UEVENT_CODE_FW_DUMP 0 | ||
960 | |||
939 | #endif /*_QLA4XXX_H */ | 961 | #endif /*_QLA4XXX_H */ |
diff --git a/drivers/scsi/qla4xxx/ql4_fw.h b/drivers/scsi/qla4xxx/ql4_fw.h index 210cd1d64475..7240948fb929 100644 --- a/drivers/scsi/qla4xxx/ql4_fw.h +++ b/drivers/scsi/qla4xxx/ql4_fw.h | |||
@@ -385,6 +385,11 @@ struct qla_flt_region { | |||
385 | #define MBOX_CMD_GET_IP_ADDR_STATE 0x0091 | 385 | #define MBOX_CMD_GET_IP_ADDR_STATE 0x0091 |
386 | #define MBOX_CMD_SEND_IPV6_ROUTER_SOL 0x0092 | 386 | #define MBOX_CMD_SEND_IPV6_ROUTER_SOL 0x0092 |
387 | #define MBOX_CMD_GET_DB_ENTRY_CURRENT_IP_ADDR 0x0093 | 387 | #define MBOX_CMD_GET_DB_ENTRY_CURRENT_IP_ADDR 0x0093 |
388 | #define MBOX_CMD_MINIDUMP 0x0129 | ||
389 | |||
390 | /* Minidump subcommand */ | ||
391 | #define MINIDUMP_GET_SIZE_SUBCOMMAND 0x00 | ||
392 | #define MINIDUMP_GET_TMPLT_SUBCOMMAND 0x01 | ||
388 | 393 | ||
389 | /* Mailbox 1 */ | 394 | /* Mailbox 1 */ |
390 | #define FW_STATE_READY 0x0000 | 395 | #define FW_STATE_READY 0x0000 |
@@ -1190,4 +1195,27 @@ struct ql_iscsi_stats { | |||
1190 | uint8_t reserved2[264]; /* 0x0308 - 0x040F */ | 1195 | uint8_t reserved2[264]; /* 0x0308 - 0x040F */ |
1191 | }; | 1196 | }; |
1192 | 1197 | ||
1198 | #define QLA82XX_DBG_STATE_ARRAY_LEN 16 | ||
1199 | #define QLA82XX_DBG_CAP_SIZE_ARRAY_LEN 8 | ||
1200 | #define QLA82XX_DBG_RSVD_ARRAY_LEN 8 | ||
1201 | |||
1202 | struct qla4_8xxx_minidump_template_hdr { | ||
1203 | uint32_t entry_type; | ||
1204 | uint32_t first_entry_offset; | ||
1205 | uint32_t size_of_template; | ||
1206 | uint32_t capture_debug_level; | ||
1207 | uint32_t num_of_entries; | ||
1208 | uint32_t version; | ||
1209 | uint32_t driver_timestamp; | ||
1210 | uint32_t checksum; | ||
1211 | |||
1212 | uint32_t driver_capture_mask; | ||
1213 | uint32_t driver_info_word2; | ||
1214 | uint32_t driver_info_word3; | ||
1215 | uint32_t driver_info_word4; | ||
1216 | |||
1217 | uint32_t saved_state_array[QLA82XX_DBG_STATE_ARRAY_LEN]; | ||
1218 | uint32_t capture_size_array[QLA82XX_DBG_CAP_SIZE_ARRAY_LEN]; | ||
1219 | }; | ||
1220 | |||
1193 | #endif /* _QLA4X_FW_H */ | 1221 | #endif /* _QLA4X_FW_H */ |
diff --git a/drivers/scsi/qla4xxx/ql4_glbl.h b/drivers/scsi/qla4xxx/ql4_glbl.h index 910536667cf5..20b49d019043 100644 --- a/drivers/scsi/qla4xxx/ql4_glbl.h +++ b/drivers/scsi/qla4xxx/ql4_glbl.h | |||
@@ -196,10 +196,18 @@ int qla4xxx_bsg_request(struct bsg_job *bsg_job); | |||
196 | int qla4xxx_process_vendor_specific(struct bsg_job *bsg_job); | 196 | int qla4xxx_process_vendor_specific(struct bsg_job *bsg_job); |
197 | 197 | ||
198 | void qla4xxx_arm_relogin_timer(struct ddb_entry *ddb_entry); | 198 | void qla4xxx_arm_relogin_timer(struct ddb_entry *ddb_entry); |
199 | int qla4xxx_get_minidump_template(struct scsi_qla_host *ha, | ||
200 | dma_addr_t phys_addr); | ||
201 | int qla4xxx_req_template_size(struct scsi_qla_host *ha); | ||
202 | void qla4_8xxx_alloc_sysfs_attr(struct scsi_qla_host *ha); | ||
203 | void qla4_8xxx_free_sysfs_attr(struct scsi_qla_host *ha); | ||
204 | void qla4xxx_alloc_fw_dump(struct scsi_qla_host *ha); | ||
199 | 205 | ||
200 | extern int ql4xextended_error_logging; | 206 | extern int ql4xextended_error_logging; |
201 | extern int ql4xdontresethba; | 207 | extern int ql4xdontresethba; |
202 | extern int ql4xenablemsix; | 208 | extern int ql4xenablemsix; |
209 | extern int ql4xmdcapmask; | ||
210 | extern int ql4xenablemd; | ||
203 | 211 | ||
204 | extern struct device_attribute *qla4xxx_host_attrs[]; | 212 | extern struct device_attribute *qla4xxx_host_attrs[]; |
205 | #endif /* _QLA4x_GBL_H */ | 213 | #endif /* _QLA4x_GBL_H */ |
diff --git a/drivers/scsi/qla4xxx/ql4_init.c b/drivers/scsi/qla4xxx/ql4_init.c index 90ee5d8fa731..bf36723b84e1 100644 --- a/drivers/scsi/qla4xxx/ql4_init.c +++ b/drivers/scsi/qla4xxx/ql4_init.c | |||
@@ -277,6 +277,94 @@ qla4xxx_wait_for_ip_config(struct scsi_qla_host *ha) | |||
277 | return ipv4_wait|ipv6_wait; | 277 | return ipv4_wait|ipv6_wait; |
278 | } | 278 | } |
279 | 279 | ||
280 | /** | ||
281 | * qla4xxx_alloc_fw_dump - Allocate memory for minidump data. | ||
282 | * @ha: pointer to host adapter structure. | ||
283 | **/ | ||
284 | void qla4xxx_alloc_fw_dump(struct scsi_qla_host *ha) | ||
285 | { | ||
286 | int status; | ||
287 | uint32_t capture_debug_level; | ||
288 | int hdr_entry_bit, k; | ||
289 | void *md_tmp; | ||
290 | dma_addr_t md_tmp_dma; | ||
291 | struct qla4_8xxx_minidump_template_hdr *md_hdr; | ||
292 | |||
293 | if (ha->fw_dump) { | ||
294 | ql4_printk(KERN_WARNING, ha, | ||
295 | "Firmware dump previously allocated.\n"); | ||
296 | return; | ||
297 | } | ||
298 | |||
299 | status = qla4xxx_req_template_size(ha); | ||
300 | if (status != QLA_SUCCESS) { | ||
301 | ql4_printk(KERN_INFO, ha, | ||
302 | "scsi%ld: Failed to get template size\n", | ||
303 | ha->host_no); | ||
304 | return; | ||
305 | } | ||
306 | |||
307 | clear_bit(AF_82XX_FW_DUMPED, &ha->flags); | ||
308 | |||
309 | /* Allocate memory for saving the template */ | ||
310 | md_tmp = dma_alloc_coherent(&ha->pdev->dev, ha->fw_dump_tmplt_size, | ||
311 | &md_tmp_dma, GFP_KERNEL); | ||
312 | |||
313 | /* Request template */ | ||
314 | status = qla4xxx_get_minidump_template(ha, md_tmp_dma); | ||
315 | if (status != QLA_SUCCESS) { | ||
316 | ql4_printk(KERN_INFO, ha, | ||
317 | "scsi%ld: Failed to get minidump template\n", | ||
318 | ha->host_no); | ||
319 | goto alloc_cleanup; | ||
320 | } | ||
321 | |||
322 | md_hdr = (struct qla4_8xxx_minidump_template_hdr *)md_tmp; | ||
323 | |||
324 | capture_debug_level = md_hdr->capture_debug_level; | ||
325 | |||
326 | /* Get capture mask based on module loadtime setting. */ | ||
327 | if (ql4xmdcapmask >= 0x3 && ql4xmdcapmask <= 0x7F) | ||
328 | ha->fw_dump_capture_mask = ql4xmdcapmask; | ||
329 | else | ||
330 | ha->fw_dump_capture_mask = capture_debug_level; | ||
331 | |||
332 | md_hdr->driver_capture_mask = ha->fw_dump_capture_mask; | ||
333 | |||
334 | DEBUG2(ql4_printk(KERN_INFO, ha, "Minimum num of entries = %d\n", | ||
335 | md_hdr->num_of_entries)); | ||
336 | DEBUG2(ql4_printk(KERN_INFO, ha, "Dump template size = %d\n", | ||
337 | ha->fw_dump_tmplt_size)); | ||
338 | DEBUG2(ql4_printk(KERN_INFO, ha, "Selected Capture mask =0x%x\n", | ||
339 | ha->fw_dump_capture_mask)); | ||
340 | |||
341 | /* Calculate fw_dump_size */ | ||
342 | for (hdr_entry_bit = 0x2, k = 1; (hdr_entry_bit & 0xFF); | ||
343 | hdr_entry_bit <<= 1, k++) { | ||
344 | if (hdr_entry_bit & ha->fw_dump_capture_mask) | ||
345 | ha->fw_dump_size += md_hdr->capture_size_array[k]; | ||
346 | } | ||
347 | |||
348 | /* Total firmware dump size including command header */ | ||
349 | ha->fw_dump_size += ha->fw_dump_tmplt_size; | ||
350 | ha->fw_dump = vmalloc(ha->fw_dump_size); | ||
351 | if (!ha->fw_dump) | ||
352 | goto alloc_cleanup; | ||
353 | |||
354 | DEBUG2(ql4_printk(KERN_INFO, ha, | ||
355 | "Minidump Tempalate Size = 0x%x KB\n", | ||
356 | ha->fw_dump_tmplt_size)); | ||
357 | DEBUG2(ql4_printk(KERN_INFO, ha, | ||
358 | "Total Minidump size = 0x%x KB\n", ha->fw_dump_size)); | ||
359 | |||
360 | memcpy(ha->fw_dump, md_tmp, ha->fw_dump_tmplt_size); | ||
361 | ha->fw_dump_tmplt_hdr = ha->fw_dump; | ||
362 | |||
363 | alloc_cleanup: | ||
364 | dma_free_coherent(&ha->pdev->dev, ha->fw_dump_tmplt_size, | ||
365 | md_tmp, md_tmp_dma); | ||
366 | } | ||
367 | |||
280 | static int qla4xxx_fw_ready(struct scsi_qla_host *ha) | 368 | static int qla4xxx_fw_ready(struct scsi_qla_host *ha) |
281 | { | 369 | { |
282 | uint32_t timeout_count; | 370 | uint32_t timeout_count; |
@@ -445,9 +533,13 @@ static int qla4xxx_init_firmware(struct scsi_qla_host *ha) | |||
445 | "control block\n", ha->host_no, __func__)); | 533 | "control block\n", ha->host_no, __func__)); |
446 | return status; | 534 | return status; |
447 | } | 535 | } |
536 | |||
448 | if (!qla4xxx_fw_ready(ha)) | 537 | if (!qla4xxx_fw_ready(ha)) |
449 | return status; | 538 | return status; |
450 | 539 | ||
540 | if (is_qla8022(ha) && !test_bit(AF_INIT_DONE, &ha->flags)) | ||
541 | qla4xxx_alloc_fw_dump(ha); | ||
542 | |||
451 | return qla4xxx_get_firmware_status(ha); | 543 | return qla4xxx_get_firmware_status(ha); |
452 | } | 544 | } |
453 | 545 | ||
@@ -884,8 +976,8 @@ int qla4xxx_ddb_change(struct scsi_qla_host *ha, uint32_t fw_ddb_index, | |||
884 | switch (state) { | 976 | switch (state) { |
885 | case DDB_DS_SESSION_ACTIVE: | 977 | case DDB_DS_SESSION_ACTIVE: |
886 | case DDB_DS_DISCOVERY: | 978 | case DDB_DS_DISCOVERY: |
887 | ddb_entry->unblock_sess(ddb_entry->sess); | ||
888 | qla4xxx_update_session_conn_param(ha, ddb_entry); | 979 | qla4xxx_update_session_conn_param(ha, ddb_entry); |
980 | ddb_entry->unblock_sess(ddb_entry->sess); | ||
889 | status = QLA_SUCCESS; | 981 | status = QLA_SUCCESS; |
890 | break; | 982 | break; |
891 | case DDB_DS_SESSION_FAILED: | 983 | case DDB_DS_SESSION_FAILED: |
@@ -897,6 +989,7 @@ int qla4xxx_ddb_change(struct scsi_qla_host *ha, uint32_t fw_ddb_index, | |||
897 | } | 989 | } |
898 | break; | 990 | break; |
899 | case DDB_DS_SESSION_ACTIVE: | 991 | case DDB_DS_SESSION_ACTIVE: |
992 | case DDB_DS_DISCOVERY: | ||
900 | switch (state) { | 993 | switch (state) { |
901 | case DDB_DS_SESSION_FAILED: | 994 | case DDB_DS_SESSION_FAILED: |
902 | /* | 995 | /* |
diff --git a/drivers/scsi/qla4xxx/ql4_mbx.c b/drivers/scsi/qla4xxx/ql4_mbx.c index 7ac21dabbf22..cab8f665a41f 100644 --- a/drivers/scsi/qla4xxx/ql4_mbx.c +++ b/drivers/scsi/qla4xxx/ql4_mbx.c | |||
@@ -51,25 +51,6 @@ int qla4xxx_mailbox_command(struct scsi_qla_host *ha, uint8_t inCount, | |||
51 | } | 51 | } |
52 | } | 52 | } |
53 | 53 | ||
54 | if (is_qla8022(ha)) { | ||
55 | if (test_bit(AF_FW_RECOVERY, &ha->flags)) { | ||
56 | DEBUG2(ql4_printk(KERN_WARNING, ha, "scsi%ld: %s: " | ||
57 | "prematurely completing mbx cmd as firmware " | ||
58 | "recovery detected\n", ha->host_no, __func__)); | ||
59 | return status; | ||
60 | } | ||
61 | /* Do not send any mbx cmd if h/w is in failed state*/ | ||
62 | qla4_8xxx_idc_lock(ha); | ||
63 | dev_state = qla4_8xxx_rd_32(ha, QLA82XX_CRB_DEV_STATE); | ||
64 | qla4_8xxx_idc_unlock(ha); | ||
65 | if (dev_state == QLA82XX_DEV_FAILED) { | ||
66 | ql4_printk(KERN_WARNING, ha, "scsi%ld: %s: H/W is in " | ||
67 | "failed state, do not send any mailbox commands\n", | ||
68 | ha->host_no, __func__); | ||
69 | return status; | ||
70 | } | ||
71 | } | ||
72 | |||
73 | if ((is_aer_supported(ha)) && | 54 | if ((is_aer_supported(ha)) && |
74 | (test_bit(AF_PCI_CHANNEL_IO_PERM_FAILURE, &ha->flags))) { | 55 | (test_bit(AF_PCI_CHANNEL_IO_PERM_FAILURE, &ha->flags))) { |
75 | DEBUG2(printk(KERN_WARNING "scsi%ld: %s: Perm failure on EEH, " | 56 | DEBUG2(printk(KERN_WARNING "scsi%ld: %s: Perm failure on EEH, " |
@@ -96,6 +77,25 @@ int qla4xxx_mailbox_command(struct scsi_qla_host *ha, uint8_t inCount, | |||
96 | msleep(10); | 77 | msleep(10); |
97 | } | 78 | } |
98 | 79 | ||
80 | if (is_qla8022(ha)) { | ||
81 | if (test_bit(AF_FW_RECOVERY, &ha->flags)) { | ||
82 | DEBUG2(ql4_printk(KERN_WARNING, ha, | ||
83 | "scsi%ld: %s: prematurely completing mbx cmd as firmware recovery detected\n", | ||
84 | ha->host_no, __func__)); | ||
85 | goto mbox_exit; | ||
86 | } | ||
87 | /* Do not send any mbx cmd if h/w is in failed state*/ | ||
88 | qla4_8xxx_idc_lock(ha); | ||
89 | dev_state = qla4_8xxx_rd_32(ha, QLA82XX_CRB_DEV_STATE); | ||
90 | qla4_8xxx_idc_unlock(ha); | ||
91 | if (dev_state == QLA82XX_DEV_FAILED) { | ||
92 | ql4_printk(KERN_WARNING, ha, | ||
93 | "scsi%ld: %s: H/W is in failed state, do not send any mailbox commands\n", | ||
94 | ha->host_no, __func__); | ||
95 | goto mbox_exit; | ||
96 | } | ||
97 | } | ||
98 | |||
99 | spin_lock_irqsave(&ha->hardware_lock, flags); | 99 | spin_lock_irqsave(&ha->hardware_lock, flags); |
100 | 100 | ||
101 | ha->mbox_status_count = outCount; | 101 | ha->mbox_status_count = outCount; |
@@ -270,6 +270,79 @@ mbox_exit: | |||
270 | return status; | 270 | return status; |
271 | } | 271 | } |
272 | 272 | ||
273 | /** | ||
274 | * qla4xxx_get_minidump_template - Get the firmware template | ||
275 | * @ha: Pointer to host adapter structure. | ||
276 | * @phys_addr: dma address for template | ||
277 | * | ||
278 | * Obtain the minidump template from firmware during initialization | ||
279 | * as it may not be available when minidump is desired. | ||
280 | **/ | ||
281 | int qla4xxx_get_minidump_template(struct scsi_qla_host *ha, | ||
282 | dma_addr_t phys_addr) | ||
283 | { | ||
284 | uint32_t mbox_cmd[MBOX_REG_COUNT]; | ||
285 | uint32_t mbox_sts[MBOX_REG_COUNT]; | ||
286 | int status; | ||
287 | |||
288 | memset(&mbox_cmd, 0, sizeof(mbox_cmd)); | ||
289 | memset(&mbox_sts, 0, sizeof(mbox_sts)); | ||
290 | |||
291 | mbox_cmd[0] = MBOX_CMD_MINIDUMP; | ||
292 | mbox_cmd[1] = MINIDUMP_GET_TMPLT_SUBCOMMAND; | ||
293 | mbox_cmd[2] = LSDW(phys_addr); | ||
294 | mbox_cmd[3] = MSDW(phys_addr); | ||
295 | mbox_cmd[4] = ha->fw_dump_tmplt_size; | ||
296 | mbox_cmd[5] = 0; | ||
297 | |||
298 | status = qla4xxx_mailbox_command(ha, MBOX_REG_COUNT, 2, &mbox_cmd[0], | ||
299 | &mbox_sts[0]); | ||
300 | if (status != QLA_SUCCESS) { | ||
301 | DEBUG2(ql4_printk(KERN_INFO, ha, | ||
302 | "scsi%ld: %s: Cmd = %08X, mbx[0] = 0x%04x, mbx[1] = 0x%04x\n", | ||
303 | ha->host_no, __func__, mbox_cmd[0], | ||
304 | mbox_sts[0], mbox_sts[1])); | ||
305 | } | ||
306 | return status; | ||
307 | } | ||
308 | |||
309 | /** | ||
310 | * qla4xxx_req_template_size - Get minidump template size from firmware. | ||
311 | * @ha: Pointer to host adapter structure. | ||
312 | **/ | ||
313 | int qla4xxx_req_template_size(struct scsi_qla_host *ha) | ||
314 | { | ||
315 | uint32_t mbox_cmd[MBOX_REG_COUNT]; | ||
316 | uint32_t mbox_sts[MBOX_REG_COUNT]; | ||
317 | int status; | ||
318 | |||
319 | memset(&mbox_cmd, 0, sizeof(mbox_cmd)); | ||
320 | memset(&mbox_sts, 0, sizeof(mbox_sts)); | ||
321 | |||
322 | mbox_cmd[0] = MBOX_CMD_MINIDUMP; | ||
323 | mbox_cmd[1] = MINIDUMP_GET_SIZE_SUBCOMMAND; | ||
324 | |||
325 | status = qla4xxx_mailbox_command(ha, MBOX_REG_COUNT, 8, &mbox_cmd[0], | ||
326 | &mbox_sts[0]); | ||
327 | if (status == QLA_SUCCESS) { | ||
328 | ha->fw_dump_tmplt_size = mbox_sts[1]; | ||
329 | DEBUG2(ql4_printk(KERN_INFO, ha, | ||
330 | "%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", | ||
331 | __func__, mbox_sts[0], mbox_sts[1], | ||
332 | mbox_sts[2], mbox_sts[3], mbox_sts[4], | ||
333 | mbox_sts[5], mbox_sts[6], mbox_sts[7])); | ||
334 | if (ha->fw_dump_tmplt_size == 0) | ||
335 | status = QLA_ERROR; | ||
336 | } else { | ||
337 | ql4_printk(KERN_WARNING, ha, | ||
338 | "%s: Error sts[0]=0x%04x, mbx[1]=0x%04x\n", | ||
339 | __func__, mbox_sts[0], mbox_sts[1]); | ||
340 | status = QLA_ERROR; | ||
341 | } | ||
342 | |||
343 | return status; | ||
344 | } | ||
345 | |||
273 | void qla4xxx_mailbox_premature_completion(struct scsi_qla_host *ha) | 346 | void qla4xxx_mailbox_premature_completion(struct scsi_qla_host *ha) |
274 | { | 347 | { |
275 | set_bit(AF_FW_RECOVERY, &ha->flags); | 348 | set_bit(AF_FW_RECOVERY, &ha->flags); |
diff --git a/drivers/scsi/qla4xxx/ql4_nx.c b/drivers/scsi/qla4xxx/ql4_nx.c index e1e46b6dac75..228b67020d2c 100644 --- a/drivers/scsi/qla4xxx/ql4_nx.c +++ b/drivers/scsi/qla4xxx/ql4_nx.c | |||
@@ -7,6 +7,7 @@ | |||
7 | #include <linux/delay.h> | 7 | #include <linux/delay.h> |
8 | #include <linux/io.h> | 8 | #include <linux/io.h> |
9 | #include <linux/pci.h> | 9 | #include <linux/pci.h> |
10 | #include <linux/ratelimit.h> | ||
10 | #include "ql4_def.h" | 11 | #include "ql4_def.h" |
11 | #include "ql4_glbl.h" | 12 | #include "ql4_glbl.h" |
12 | 13 | ||
@@ -420,6 +421,38 @@ qla4_8xxx_rd_32(struct scsi_qla_host *ha, ulong off) | |||
420 | return data; | 421 | return data; |
421 | } | 422 | } |
422 | 423 | ||
424 | /* Minidump related functions */ | ||
425 | static int qla4_8xxx_md_rw_32(struct scsi_qla_host *ha, uint32_t off, | ||
426 | u32 data, uint8_t flag) | ||
427 | { | ||
428 | uint32_t win_read, off_value, rval = QLA_SUCCESS; | ||
429 | |||
430 | off_value = off & 0xFFFF0000; | ||
431 | writel(off_value, (void __iomem *)(CRB_WINDOW_2M + ha->nx_pcibase)); | ||
432 | |||
433 | /* Read back value to make sure write has gone through before trying | ||
434 | * to use it. | ||
435 | */ | ||
436 | win_read = readl((void __iomem *)(CRB_WINDOW_2M + ha->nx_pcibase)); | ||
437 | if (win_read != off_value) { | ||
438 | DEBUG2(ql4_printk(KERN_INFO, ha, | ||
439 | "%s: Written (0x%x) != Read (0x%x), off=0x%x\n", | ||
440 | __func__, off_value, win_read, off)); | ||
441 | return QLA_ERROR; | ||
442 | } | ||
443 | |||
444 | off_value = off & 0x0000FFFF; | ||
445 | |||
446 | if (flag) | ||
447 | writel(data, (void __iomem *)(off_value + CRB_INDIRECT_2M + | ||
448 | ha->nx_pcibase)); | ||
449 | else | ||
450 | rval = readl((void __iomem *)(off_value + CRB_INDIRECT_2M + | ||
451 | ha->nx_pcibase)); | ||
452 | |||
453 | return rval; | ||
454 | } | ||
455 | |||
423 | #define CRB_WIN_LOCK_TIMEOUT 100000000 | 456 | #define CRB_WIN_LOCK_TIMEOUT 100000000 |
424 | 457 | ||
425 | int qla4_8xxx_crb_win_lock(struct scsi_qla_host *ha) | 458 | int qla4_8xxx_crb_win_lock(struct scsi_qla_host *ha) |
@@ -1252,9 +1285,9 @@ qla4_8xxx_pci_mem_read_2M(struct scsi_qla_host *ha, | |||
1252 | } | 1285 | } |
1253 | 1286 | ||
1254 | if (j >= MAX_CTL_CHECK) { | 1287 | if (j >= MAX_CTL_CHECK) { |
1255 | if (printk_ratelimit()) | 1288 | printk_ratelimited(KERN_ERR |
1256 | ql4_printk(KERN_ERR, ha, | 1289 | "%s: failed to read through agent\n", |
1257 | "failed to read through agent\n"); | 1290 | __func__); |
1258 | break; | 1291 | break; |
1259 | } | 1292 | } |
1260 | 1293 | ||
@@ -1390,7 +1423,8 @@ qla4_8xxx_pci_mem_write_2M(struct scsi_qla_host *ha, | |||
1390 | if (j >= MAX_CTL_CHECK) { | 1423 | if (j >= MAX_CTL_CHECK) { |
1391 | if (printk_ratelimit()) | 1424 | if (printk_ratelimit()) |
1392 | ql4_printk(KERN_ERR, ha, | 1425 | ql4_printk(KERN_ERR, ha, |
1393 | "failed to write through agent\n"); | 1426 | "%s: failed to read through agent\n", |
1427 | __func__); | ||
1394 | ret = -1; | 1428 | ret = -1; |
1395 | break; | 1429 | break; |
1396 | } | 1430 | } |
@@ -1462,6 +1496,8 @@ qla4_8xxx_set_drv_active(struct scsi_qla_host *ha) | |||
1462 | 1496 | ||
1463 | drv_active = qla4_8xxx_rd_32(ha, QLA82XX_CRB_DRV_ACTIVE); | 1497 | drv_active = qla4_8xxx_rd_32(ha, QLA82XX_CRB_DRV_ACTIVE); |
1464 | drv_active |= (1 << (ha->func_num * 4)); | 1498 | drv_active |= (1 << (ha->func_num * 4)); |
1499 | ql4_printk(KERN_INFO, ha, "%s(%ld): drv_active: 0x%08x\n", | ||
1500 | __func__, ha->host_no, drv_active); | ||
1465 | qla4_8xxx_wr_32(ha, QLA82XX_CRB_DRV_ACTIVE, drv_active); | 1501 | qla4_8xxx_wr_32(ha, QLA82XX_CRB_DRV_ACTIVE, drv_active); |
1466 | } | 1502 | } |
1467 | 1503 | ||
@@ -1472,6 +1508,8 @@ qla4_8xxx_clear_drv_active(struct scsi_qla_host *ha) | |||
1472 | 1508 | ||
1473 | drv_active = qla4_8xxx_rd_32(ha, QLA82XX_CRB_DRV_ACTIVE); | 1509 | drv_active = qla4_8xxx_rd_32(ha, QLA82XX_CRB_DRV_ACTIVE); |
1474 | drv_active &= ~(1 << (ha->func_num * 4)); | 1510 | drv_active &= ~(1 << (ha->func_num * 4)); |
1511 | ql4_printk(KERN_INFO, ha, "%s(%ld): drv_active: 0x%08x\n", | ||
1512 | __func__, ha->host_no, drv_active); | ||
1475 | qla4_8xxx_wr_32(ha, QLA82XX_CRB_DRV_ACTIVE, drv_active); | 1513 | qla4_8xxx_wr_32(ha, QLA82XX_CRB_DRV_ACTIVE, drv_active); |
1476 | } | 1514 | } |
1477 | 1515 | ||
@@ -1497,6 +1535,8 @@ qla4_8xxx_set_rst_ready(struct scsi_qla_host *ha) | |||
1497 | 1535 | ||
1498 | drv_state = qla4_8xxx_rd_32(ha, QLA82XX_CRB_DRV_STATE); | 1536 | drv_state = qla4_8xxx_rd_32(ha, QLA82XX_CRB_DRV_STATE); |
1499 | drv_state |= (1 << (ha->func_num * 4)); | 1537 | drv_state |= (1 << (ha->func_num * 4)); |
1538 | ql4_printk(KERN_INFO, ha, "%s(%ld): drv_state: 0x%08x\n", | ||
1539 | __func__, ha->host_no, drv_state); | ||
1500 | qla4_8xxx_wr_32(ha, QLA82XX_CRB_DRV_STATE, drv_state); | 1540 | qla4_8xxx_wr_32(ha, QLA82XX_CRB_DRV_STATE, drv_state); |
1501 | } | 1541 | } |
1502 | 1542 | ||
@@ -1507,6 +1547,8 @@ qla4_8xxx_clear_rst_ready(struct scsi_qla_host *ha) | |||
1507 | 1547 | ||
1508 | drv_state = qla4_8xxx_rd_32(ha, QLA82XX_CRB_DRV_STATE); | 1548 | drv_state = qla4_8xxx_rd_32(ha, QLA82XX_CRB_DRV_STATE); |
1509 | drv_state &= ~(1 << (ha->func_num * 4)); | 1549 | drv_state &= ~(1 << (ha->func_num * 4)); |
1550 | ql4_printk(KERN_INFO, ha, "%s(%ld): drv_state: 0x%08x\n", | ||
1551 | __func__, ha->host_no, drv_state); | ||
1510 | qla4_8xxx_wr_32(ha, QLA82XX_CRB_DRV_STATE, drv_state); | 1552 | qla4_8xxx_wr_32(ha, QLA82XX_CRB_DRV_STATE, drv_state); |
1511 | } | 1553 | } |
1512 | 1554 | ||
@@ -1601,6 +1643,629 @@ static void qla4_8xxx_rom_lock_recovery(struct scsi_qla_host *ha) | |||
1601 | qla4_8xxx_rom_unlock(ha); | 1643 | qla4_8xxx_rom_unlock(ha); |
1602 | } | 1644 | } |
1603 | 1645 | ||
1646 | static void qla4_8xxx_minidump_process_rdcrb(struct scsi_qla_host *ha, | ||
1647 | struct qla82xx_minidump_entry_hdr *entry_hdr, | ||
1648 | uint32_t **d_ptr) | ||
1649 | { | ||
1650 | uint32_t r_addr, r_stride, loop_cnt, i, r_value; | ||
1651 | struct qla82xx_minidump_entry_crb *crb_hdr; | ||
1652 | uint32_t *data_ptr = *d_ptr; | ||
1653 | |||
1654 | DEBUG2(ql4_printk(KERN_INFO, ha, "Entering fn: %s\n", __func__)); | ||
1655 | crb_hdr = (struct qla82xx_minidump_entry_crb *)entry_hdr; | ||
1656 | r_addr = crb_hdr->addr; | ||
1657 | r_stride = crb_hdr->crb_strd.addr_stride; | ||
1658 | loop_cnt = crb_hdr->op_count; | ||
1659 | |||
1660 | for (i = 0; i < loop_cnt; i++) { | ||
1661 | r_value = qla4_8xxx_md_rw_32(ha, r_addr, 0, 0); | ||
1662 | *data_ptr++ = cpu_to_le32(r_addr); | ||
1663 | *data_ptr++ = cpu_to_le32(r_value); | ||
1664 | r_addr += r_stride; | ||
1665 | } | ||
1666 | *d_ptr = data_ptr; | ||
1667 | } | ||
1668 | |||
1669 | static int qla4_8xxx_minidump_process_l2tag(struct scsi_qla_host *ha, | ||
1670 | struct qla82xx_minidump_entry_hdr *entry_hdr, | ||
1671 | uint32_t **d_ptr) | ||
1672 | { | ||
1673 | uint32_t addr, r_addr, c_addr, t_r_addr; | ||
1674 | uint32_t i, k, loop_count, t_value, r_cnt, r_value; | ||
1675 | unsigned long p_wait, w_time, p_mask; | ||
1676 | uint32_t c_value_w, c_value_r; | ||
1677 | struct qla82xx_minidump_entry_cache *cache_hdr; | ||
1678 | int rval = QLA_ERROR; | ||
1679 | uint32_t *data_ptr = *d_ptr; | ||
1680 | |||
1681 | DEBUG2(ql4_printk(KERN_INFO, ha, "Entering fn: %s\n", __func__)); | ||
1682 | cache_hdr = (struct qla82xx_minidump_entry_cache *)entry_hdr; | ||
1683 | |||
1684 | loop_count = cache_hdr->op_count; | ||
1685 | r_addr = cache_hdr->read_addr; | ||
1686 | c_addr = cache_hdr->control_addr; | ||
1687 | c_value_w = cache_hdr->cache_ctrl.write_value; | ||
1688 | |||
1689 | t_r_addr = cache_hdr->tag_reg_addr; | ||
1690 | t_value = cache_hdr->addr_ctrl.init_tag_value; | ||
1691 | r_cnt = cache_hdr->read_ctrl.read_addr_cnt; | ||
1692 | p_wait = cache_hdr->cache_ctrl.poll_wait; | ||
1693 | p_mask = cache_hdr->cache_ctrl.poll_mask; | ||
1694 | |||
1695 | for (i = 0; i < loop_count; i++) { | ||
1696 | qla4_8xxx_md_rw_32(ha, t_r_addr, t_value, 1); | ||
1697 | |||
1698 | if (c_value_w) | ||
1699 | qla4_8xxx_md_rw_32(ha, c_addr, c_value_w, 1); | ||
1700 | |||
1701 | if (p_mask) { | ||
1702 | w_time = jiffies + p_wait; | ||
1703 | do { | ||
1704 | c_value_r = qla4_8xxx_md_rw_32(ha, c_addr, | ||
1705 | 0, 0); | ||
1706 | if ((c_value_r & p_mask) == 0) { | ||
1707 | break; | ||
1708 | } else if (time_after_eq(jiffies, w_time)) { | ||
1709 | /* capturing dump failed */ | ||
1710 | return rval; | ||
1711 | } | ||
1712 | } while (1); | ||
1713 | } | ||
1714 | |||
1715 | addr = r_addr; | ||
1716 | for (k = 0; k < r_cnt; k++) { | ||
1717 | r_value = qla4_8xxx_md_rw_32(ha, addr, 0, 0); | ||
1718 | *data_ptr++ = cpu_to_le32(r_value); | ||
1719 | addr += cache_hdr->read_ctrl.read_addr_stride; | ||
1720 | } | ||
1721 | |||
1722 | t_value += cache_hdr->addr_ctrl.tag_value_stride; | ||
1723 | } | ||
1724 | *d_ptr = data_ptr; | ||
1725 | return QLA_SUCCESS; | ||
1726 | } | ||
1727 | |||
1728 | static int qla4_8xxx_minidump_process_control(struct scsi_qla_host *ha, | ||
1729 | struct qla82xx_minidump_entry_hdr *entry_hdr) | ||
1730 | { | ||
1731 | struct qla82xx_minidump_entry_crb *crb_entry; | ||
1732 | uint32_t read_value, opcode, poll_time, addr, index, rval = QLA_SUCCESS; | ||
1733 | uint32_t crb_addr; | ||
1734 | unsigned long wtime; | ||
1735 | struct qla4_8xxx_minidump_template_hdr *tmplt_hdr; | ||
1736 | int i; | ||
1737 | |||
1738 | DEBUG2(ql4_printk(KERN_INFO, ha, "Entering fn: %s\n", __func__)); | ||
1739 | tmplt_hdr = (struct qla4_8xxx_minidump_template_hdr *) | ||
1740 | ha->fw_dump_tmplt_hdr; | ||
1741 | crb_entry = (struct qla82xx_minidump_entry_crb *)entry_hdr; | ||
1742 | |||
1743 | crb_addr = crb_entry->addr; | ||
1744 | for (i = 0; i < crb_entry->op_count; i++) { | ||
1745 | opcode = crb_entry->crb_ctrl.opcode; | ||
1746 | if (opcode & QLA82XX_DBG_OPCODE_WR) { | ||
1747 | qla4_8xxx_md_rw_32(ha, crb_addr, | ||
1748 | crb_entry->value_1, 1); | ||
1749 | opcode &= ~QLA82XX_DBG_OPCODE_WR; | ||
1750 | } | ||
1751 | if (opcode & QLA82XX_DBG_OPCODE_RW) { | ||
1752 | read_value = qla4_8xxx_md_rw_32(ha, crb_addr, 0, 0); | ||
1753 | qla4_8xxx_md_rw_32(ha, crb_addr, read_value, 1); | ||
1754 | opcode &= ~QLA82XX_DBG_OPCODE_RW; | ||
1755 | } | ||
1756 | if (opcode & QLA82XX_DBG_OPCODE_AND) { | ||
1757 | read_value = qla4_8xxx_md_rw_32(ha, crb_addr, 0, 0); | ||
1758 | read_value &= crb_entry->value_2; | ||
1759 | opcode &= ~QLA82XX_DBG_OPCODE_AND; | ||
1760 | if (opcode & QLA82XX_DBG_OPCODE_OR) { | ||
1761 | read_value |= crb_entry->value_3; | ||
1762 | opcode &= ~QLA82XX_DBG_OPCODE_OR; | ||
1763 | } | ||
1764 | qla4_8xxx_md_rw_32(ha, crb_addr, read_value, 1); | ||
1765 | } | ||
1766 | if (opcode & QLA82XX_DBG_OPCODE_OR) { | ||
1767 | read_value = qla4_8xxx_md_rw_32(ha, crb_addr, 0, 0); | ||
1768 | read_value |= crb_entry->value_3; | ||
1769 | qla4_8xxx_md_rw_32(ha, crb_addr, read_value, 1); | ||
1770 | opcode &= ~QLA82XX_DBG_OPCODE_OR; | ||
1771 | } | ||
1772 | if (opcode & QLA82XX_DBG_OPCODE_POLL) { | ||
1773 | poll_time = crb_entry->crb_strd.poll_timeout; | ||
1774 | wtime = jiffies + poll_time; | ||
1775 | read_value = qla4_8xxx_md_rw_32(ha, crb_addr, 0, 0); | ||
1776 | |||
1777 | do { | ||
1778 | if ((read_value & crb_entry->value_2) == | ||
1779 | crb_entry->value_1) | ||
1780 | break; | ||
1781 | else if (time_after_eq(jiffies, wtime)) { | ||
1782 | /* capturing dump failed */ | ||
1783 | rval = QLA_ERROR; | ||
1784 | break; | ||
1785 | } else | ||
1786 | read_value = qla4_8xxx_md_rw_32(ha, | ||
1787 | crb_addr, 0, 0); | ||
1788 | } while (1); | ||
1789 | opcode &= ~QLA82XX_DBG_OPCODE_POLL; | ||
1790 | } | ||
1791 | |||
1792 | if (opcode & QLA82XX_DBG_OPCODE_RDSTATE) { | ||
1793 | if (crb_entry->crb_strd.state_index_a) { | ||
1794 | index = crb_entry->crb_strd.state_index_a; | ||
1795 | addr = tmplt_hdr->saved_state_array[index]; | ||
1796 | } else { | ||
1797 | addr = crb_addr; | ||
1798 | } | ||
1799 | |||
1800 | read_value = qla4_8xxx_md_rw_32(ha, addr, 0, 0); | ||
1801 | index = crb_entry->crb_ctrl.state_index_v; | ||
1802 | tmplt_hdr->saved_state_array[index] = read_value; | ||
1803 | opcode &= ~QLA82XX_DBG_OPCODE_RDSTATE; | ||
1804 | } | ||
1805 | |||
1806 | if (opcode & QLA82XX_DBG_OPCODE_WRSTATE) { | ||
1807 | if (crb_entry->crb_strd.state_index_a) { | ||
1808 | index = crb_entry->crb_strd.state_index_a; | ||
1809 | addr = tmplt_hdr->saved_state_array[index]; | ||
1810 | } else { | ||
1811 | addr = crb_addr; | ||
1812 | } | ||
1813 | |||
1814 | if (crb_entry->crb_ctrl.state_index_v) { | ||
1815 | index = crb_entry->crb_ctrl.state_index_v; | ||
1816 | read_value = | ||
1817 | tmplt_hdr->saved_state_array[index]; | ||
1818 | } else { | ||
1819 | read_value = crb_entry->value_1; | ||
1820 | } | ||
1821 | |||
1822 | qla4_8xxx_md_rw_32(ha, addr, read_value, 1); | ||
1823 | opcode &= ~QLA82XX_DBG_OPCODE_WRSTATE; | ||
1824 | } | ||
1825 | |||
1826 | if (opcode & QLA82XX_DBG_OPCODE_MDSTATE) { | ||
1827 | index = crb_entry->crb_ctrl.state_index_v; | ||
1828 | read_value = tmplt_hdr->saved_state_array[index]; | ||
1829 | read_value <<= crb_entry->crb_ctrl.shl; | ||
1830 | read_value >>= crb_entry->crb_ctrl.shr; | ||
1831 | if (crb_entry->value_2) | ||
1832 | read_value &= crb_entry->value_2; | ||
1833 | read_value |= crb_entry->value_3; | ||
1834 | read_value += crb_entry->value_1; | ||
1835 | tmplt_hdr->saved_state_array[index] = read_value; | ||
1836 | opcode &= ~QLA82XX_DBG_OPCODE_MDSTATE; | ||
1837 | } | ||
1838 | crb_addr += crb_entry->crb_strd.addr_stride; | ||
1839 | } | ||
1840 | DEBUG2(ql4_printk(KERN_INFO, ha, "Leaving fn: %s\n", __func__)); | ||
1841 | return rval; | ||
1842 | } | ||
1843 | |||
1844 | static void qla4_8xxx_minidump_process_rdocm(struct scsi_qla_host *ha, | ||
1845 | struct qla82xx_minidump_entry_hdr *entry_hdr, | ||
1846 | uint32_t **d_ptr) | ||
1847 | { | ||
1848 | uint32_t r_addr, r_stride, loop_cnt, i, r_value; | ||
1849 | struct qla82xx_minidump_entry_rdocm *ocm_hdr; | ||
1850 | uint32_t *data_ptr = *d_ptr; | ||
1851 | |||
1852 | DEBUG2(ql4_printk(KERN_INFO, ha, "Entering fn: %s\n", __func__)); | ||
1853 | ocm_hdr = (struct qla82xx_minidump_entry_rdocm *)entry_hdr; | ||
1854 | r_addr = ocm_hdr->read_addr; | ||
1855 | r_stride = ocm_hdr->read_addr_stride; | ||
1856 | loop_cnt = ocm_hdr->op_count; | ||
1857 | |||
1858 | DEBUG2(ql4_printk(KERN_INFO, ha, | ||
1859 | "[%s]: r_addr: 0x%x, r_stride: 0x%x, loop_cnt: 0x%x\n", | ||
1860 | __func__, r_addr, r_stride, loop_cnt)); | ||
1861 | |||
1862 | for (i = 0; i < loop_cnt; i++) { | ||
1863 | r_value = readl((void __iomem *)(r_addr + ha->nx_pcibase)); | ||
1864 | *data_ptr++ = cpu_to_le32(r_value); | ||
1865 | r_addr += r_stride; | ||
1866 | } | ||
1867 | DEBUG2(ql4_printk(KERN_INFO, ha, "Leaving fn: %s datacount: 0x%lx\n", | ||
1868 | __func__, (loop_cnt * sizeof(uint32_t)))); | ||
1869 | *d_ptr = data_ptr; | ||
1870 | } | ||
1871 | |||
1872 | static void qla4_8xxx_minidump_process_rdmux(struct scsi_qla_host *ha, | ||
1873 | struct qla82xx_minidump_entry_hdr *entry_hdr, | ||
1874 | uint32_t **d_ptr) | ||
1875 | { | ||
1876 | uint32_t r_addr, s_stride, s_addr, s_value, loop_cnt, i, r_value; | ||
1877 | struct qla82xx_minidump_entry_mux *mux_hdr; | ||
1878 | uint32_t *data_ptr = *d_ptr; | ||
1879 | |||
1880 | DEBUG2(ql4_printk(KERN_INFO, ha, "Entering fn: %s\n", __func__)); | ||
1881 | mux_hdr = (struct qla82xx_minidump_entry_mux *)entry_hdr; | ||
1882 | r_addr = mux_hdr->read_addr; | ||
1883 | s_addr = mux_hdr->select_addr; | ||
1884 | s_stride = mux_hdr->select_value_stride; | ||
1885 | s_value = mux_hdr->select_value; | ||
1886 | loop_cnt = mux_hdr->op_count; | ||
1887 | |||
1888 | for (i = 0; i < loop_cnt; i++) { | ||
1889 | qla4_8xxx_md_rw_32(ha, s_addr, s_value, 1); | ||
1890 | r_value = qla4_8xxx_md_rw_32(ha, r_addr, 0, 0); | ||
1891 | *data_ptr++ = cpu_to_le32(s_value); | ||
1892 | *data_ptr++ = cpu_to_le32(r_value); | ||
1893 | s_value += s_stride; | ||
1894 | } | ||
1895 | *d_ptr = data_ptr; | ||
1896 | } | ||
1897 | |||
1898 | static void qla4_8xxx_minidump_process_l1cache(struct scsi_qla_host *ha, | ||
1899 | struct qla82xx_minidump_entry_hdr *entry_hdr, | ||
1900 | uint32_t **d_ptr) | ||
1901 | { | ||
1902 | uint32_t addr, r_addr, c_addr, t_r_addr; | ||
1903 | uint32_t i, k, loop_count, t_value, r_cnt, r_value; | ||
1904 | uint32_t c_value_w; | ||
1905 | struct qla82xx_minidump_entry_cache *cache_hdr; | ||
1906 | uint32_t *data_ptr = *d_ptr; | ||
1907 | |||
1908 | cache_hdr = (struct qla82xx_minidump_entry_cache *)entry_hdr; | ||
1909 | loop_count = cache_hdr->op_count; | ||
1910 | r_addr = cache_hdr->read_addr; | ||
1911 | c_addr = cache_hdr->control_addr; | ||
1912 | c_value_w = cache_hdr->cache_ctrl.write_value; | ||
1913 | |||
1914 | t_r_addr = cache_hdr->tag_reg_addr; | ||
1915 | t_value = cache_hdr->addr_ctrl.init_tag_value; | ||
1916 | r_cnt = cache_hdr->read_ctrl.read_addr_cnt; | ||
1917 | |||
1918 | for (i = 0; i < loop_count; i++) { | ||
1919 | qla4_8xxx_md_rw_32(ha, t_r_addr, t_value, 1); | ||
1920 | qla4_8xxx_md_rw_32(ha, c_addr, c_value_w, 1); | ||
1921 | addr = r_addr; | ||
1922 | for (k = 0; k < r_cnt; k++) { | ||
1923 | r_value = qla4_8xxx_md_rw_32(ha, addr, 0, 0); | ||
1924 | *data_ptr++ = cpu_to_le32(r_value); | ||
1925 | addr += cache_hdr->read_ctrl.read_addr_stride; | ||
1926 | } | ||
1927 | t_value += cache_hdr->addr_ctrl.tag_value_stride; | ||
1928 | } | ||
1929 | *d_ptr = data_ptr; | ||
1930 | } | ||
1931 | |||
1932 | static void qla4_8xxx_minidump_process_queue(struct scsi_qla_host *ha, | ||
1933 | struct qla82xx_minidump_entry_hdr *entry_hdr, | ||
1934 | uint32_t **d_ptr) | ||
1935 | { | ||
1936 | uint32_t s_addr, r_addr; | ||
1937 | uint32_t r_stride, r_value, r_cnt, qid = 0; | ||
1938 | uint32_t i, k, loop_cnt; | ||
1939 | struct qla82xx_minidump_entry_queue *q_hdr; | ||
1940 | uint32_t *data_ptr = *d_ptr; | ||
1941 | |||
1942 | DEBUG2(ql4_printk(KERN_INFO, ha, "Entering fn: %s\n", __func__)); | ||
1943 | q_hdr = (struct qla82xx_minidump_entry_queue *)entry_hdr; | ||
1944 | s_addr = q_hdr->select_addr; | ||
1945 | r_cnt = q_hdr->rd_strd.read_addr_cnt; | ||
1946 | r_stride = q_hdr->rd_strd.read_addr_stride; | ||
1947 | loop_cnt = q_hdr->op_count; | ||
1948 | |||
1949 | for (i = 0; i < loop_cnt; i++) { | ||
1950 | qla4_8xxx_md_rw_32(ha, s_addr, qid, 1); | ||
1951 | r_addr = q_hdr->read_addr; | ||
1952 | for (k = 0; k < r_cnt; k++) { | ||
1953 | r_value = qla4_8xxx_md_rw_32(ha, r_addr, 0, 0); | ||
1954 | *data_ptr++ = cpu_to_le32(r_value); | ||
1955 | r_addr += r_stride; | ||
1956 | } | ||
1957 | qid += q_hdr->q_strd.queue_id_stride; | ||
1958 | } | ||
1959 | *d_ptr = data_ptr; | ||
1960 | } | ||
1961 | |||
1962 | #define MD_DIRECT_ROM_WINDOW 0x42110030 | ||
1963 | #define MD_DIRECT_ROM_READ_BASE 0x42150000 | ||
1964 | |||
1965 | static void qla4_8xxx_minidump_process_rdrom(struct scsi_qla_host *ha, | ||
1966 | struct qla82xx_minidump_entry_hdr *entry_hdr, | ||
1967 | uint32_t **d_ptr) | ||
1968 | { | ||
1969 | uint32_t r_addr, r_value; | ||
1970 | uint32_t i, loop_cnt; | ||
1971 | struct qla82xx_minidump_entry_rdrom *rom_hdr; | ||
1972 | uint32_t *data_ptr = *d_ptr; | ||
1973 | |||
1974 | DEBUG2(ql4_printk(KERN_INFO, ha, "Entering fn: %s\n", __func__)); | ||
1975 | rom_hdr = (struct qla82xx_minidump_entry_rdrom *)entry_hdr; | ||
1976 | r_addr = rom_hdr->read_addr; | ||
1977 | loop_cnt = rom_hdr->read_data_size/sizeof(uint32_t); | ||
1978 | |||
1979 | DEBUG2(ql4_printk(KERN_INFO, ha, | ||
1980 | "[%s]: flash_addr: 0x%x, read_data_size: 0x%x\n", | ||
1981 | __func__, r_addr, loop_cnt)); | ||
1982 | |||
1983 | for (i = 0; i < loop_cnt; i++) { | ||
1984 | qla4_8xxx_md_rw_32(ha, MD_DIRECT_ROM_WINDOW, | ||
1985 | (r_addr & 0xFFFF0000), 1); | ||
1986 | r_value = qla4_8xxx_md_rw_32(ha, | ||
1987 | MD_DIRECT_ROM_READ_BASE + | ||
1988 | (r_addr & 0x0000FFFF), 0, 0); | ||
1989 | *data_ptr++ = cpu_to_le32(r_value); | ||
1990 | r_addr += sizeof(uint32_t); | ||
1991 | } | ||
1992 | *d_ptr = data_ptr; | ||
1993 | } | ||
1994 | |||
1995 | #define MD_MIU_TEST_AGT_CTRL 0x41000090 | ||
1996 | #define MD_MIU_TEST_AGT_ADDR_LO 0x41000094 | ||
1997 | #define MD_MIU_TEST_AGT_ADDR_HI 0x41000098 | ||
1998 | |||
1999 | static int qla4_8xxx_minidump_process_rdmem(struct scsi_qla_host *ha, | ||
2000 | struct qla82xx_minidump_entry_hdr *entry_hdr, | ||
2001 | uint32_t **d_ptr) | ||
2002 | { | ||
2003 | uint32_t r_addr, r_value, r_data; | ||
2004 | uint32_t i, j, loop_cnt; | ||
2005 | struct qla82xx_minidump_entry_rdmem *m_hdr; | ||
2006 | unsigned long flags; | ||
2007 | uint32_t *data_ptr = *d_ptr; | ||
2008 | |||
2009 | DEBUG2(ql4_printk(KERN_INFO, ha, "Entering fn: %s\n", __func__)); | ||
2010 | m_hdr = (struct qla82xx_minidump_entry_rdmem *)entry_hdr; | ||
2011 | r_addr = m_hdr->read_addr; | ||
2012 | loop_cnt = m_hdr->read_data_size/16; | ||
2013 | |||
2014 | DEBUG2(ql4_printk(KERN_INFO, ha, | ||
2015 | "[%s]: Read addr: 0x%x, read_data_size: 0x%x\n", | ||
2016 | __func__, r_addr, m_hdr->read_data_size)); | ||
2017 | |||
2018 | if (r_addr & 0xf) { | ||
2019 | DEBUG2(ql4_printk(KERN_INFO, ha, | ||
2020 | "[%s]: Read addr 0x%x not 16 bytes alligned\n", | ||
2021 | __func__, r_addr)); | ||
2022 | return QLA_ERROR; | ||
2023 | } | ||
2024 | |||
2025 | if (m_hdr->read_data_size % 16) { | ||
2026 | DEBUG2(ql4_printk(KERN_INFO, ha, | ||
2027 | "[%s]: Read data[0x%x] not multiple of 16 bytes\n", | ||
2028 | __func__, m_hdr->read_data_size)); | ||
2029 | return QLA_ERROR; | ||
2030 | } | ||
2031 | |||
2032 | DEBUG2(ql4_printk(KERN_INFO, ha, | ||
2033 | "[%s]: rdmem_addr: 0x%x, read_data_size: 0x%x, loop_cnt: 0x%x\n", | ||
2034 | __func__, r_addr, m_hdr->read_data_size, loop_cnt)); | ||
2035 | |||
2036 | write_lock_irqsave(&ha->hw_lock, flags); | ||
2037 | for (i = 0; i < loop_cnt; i++) { | ||
2038 | qla4_8xxx_md_rw_32(ha, MD_MIU_TEST_AGT_ADDR_LO, r_addr, 1); | ||
2039 | r_value = 0; | ||
2040 | qla4_8xxx_md_rw_32(ha, MD_MIU_TEST_AGT_ADDR_HI, r_value, 1); | ||
2041 | r_value = MIU_TA_CTL_ENABLE; | ||
2042 | qla4_8xxx_md_rw_32(ha, MD_MIU_TEST_AGT_CTRL, r_value, 1); | ||
2043 | r_value = MIU_TA_CTL_START | MIU_TA_CTL_ENABLE; | ||
2044 | qla4_8xxx_md_rw_32(ha, MD_MIU_TEST_AGT_CTRL, r_value, 1); | ||
2045 | |||
2046 | for (j = 0; j < MAX_CTL_CHECK; j++) { | ||
2047 | r_value = qla4_8xxx_md_rw_32(ha, MD_MIU_TEST_AGT_CTRL, | ||
2048 | 0, 0); | ||
2049 | if ((r_value & MIU_TA_CTL_BUSY) == 0) | ||
2050 | break; | ||
2051 | } | ||
2052 | |||
2053 | if (j >= MAX_CTL_CHECK) { | ||
2054 | printk_ratelimited(KERN_ERR | ||
2055 | "%s: failed to read through agent\n", | ||
2056 | __func__); | ||
2057 | write_unlock_irqrestore(&ha->hw_lock, flags); | ||
2058 | return QLA_SUCCESS; | ||
2059 | } | ||
2060 | |||
2061 | for (j = 0; j < 4; j++) { | ||
2062 | r_data = qla4_8xxx_md_rw_32(ha, | ||
2063 | MD_MIU_TEST_AGT_RDDATA[j], | ||
2064 | 0, 0); | ||
2065 | *data_ptr++ = cpu_to_le32(r_data); | ||
2066 | } | ||
2067 | |||
2068 | r_addr += 16; | ||
2069 | } | ||
2070 | write_unlock_irqrestore(&ha->hw_lock, flags); | ||
2071 | |||
2072 | DEBUG2(ql4_printk(KERN_INFO, ha, "Leaving fn: %s datacount: 0x%x\n", | ||
2073 | __func__, (loop_cnt * 16))); | ||
2074 | |||
2075 | *d_ptr = data_ptr; | ||
2076 | return QLA_SUCCESS; | ||
2077 | } | ||
2078 | |||
2079 | static void ql4_8xxx_mark_entry_skipped(struct scsi_qla_host *ha, | ||
2080 | struct qla82xx_minidump_entry_hdr *entry_hdr, | ||
2081 | int index) | ||
2082 | { | ||
2083 | entry_hdr->d_ctrl.driver_flags |= QLA82XX_DBG_SKIPPED_FLAG; | ||
2084 | DEBUG2(ql4_printk(KERN_INFO, ha, | ||
2085 | "scsi(%ld): Skipping entry[%d]: ETYPE[0x%x]-ELEVEL[0x%x]\n", | ||
2086 | ha->host_no, index, entry_hdr->entry_type, | ||
2087 | entry_hdr->d_ctrl.entry_capture_mask)); | ||
2088 | } | ||
2089 | |||
2090 | /** | ||
2091 | * qla82xx_collect_md_data - Retrieve firmware minidump data. | ||
2092 | * @ha: pointer to adapter structure | ||
2093 | **/ | ||
2094 | static int qla4_8xxx_collect_md_data(struct scsi_qla_host *ha) | ||
2095 | { | ||
2096 | int num_entry_hdr = 0; | ||
2097 | struct qla82xx_minidump_entry_hdr *entry_hdr; | ||
2098 | struct qla4_8xxx_minidump_template_hdr *tmplt_hdr; | ||
2099 | uint32_t *data_ptr; | ||
2100 | uint32_t data_collected = 0; | ||
2101 | int i, rval = QLA_ERROR; | ||
2102 | uint64_t now; | ||
2103 | uint32_t timestamp; | ||
2104 | |||
2105 | if (!ha->fw_dump) { | ||
2106 | ql4_printk(KERN_INFO, ha, "%s(%ld) No buffer to dump\n", | ||
2107 | __func__, ha->host_no); | ||
2108 | return rval; | ||
2109 | } | ||
2110 | |||
2111 | tmplt_hdr = (struct qla4_8xxx_minidump_template_hdr *) | ||
2112 | ha->fw_dump_tmplt_hdr; | ||
2113 | data_ptr = (uint32_t *)((uint8_t *)ha->fw_dump + | ||
2114 | ha->fw_dump_tmplt_size); | ||
2115 | data_collected += ha->fw_dump_tmplt_size; | ||
2116 | |||
2117 | num_entry_hdr = tmplt_hdr->num_of_entries; | ||
2118 | ql4_printk(KERN_INFO, ha, "[%s]: starting data ptr: %p\n", | ||
2119 | __func__, data_ptr); | ||
2120 | ql4_printk(KERN_INFO, ha, | ||
2121 | "[%s]: no of entry headers in Template: 0x%x\n", | ||
2122 | __func__, num_entry_hdr); | ||
2123 | ql4_printk(KERN_INFO, ha, "[%s]: Capture Mask obtained: 0x%x\n", | ||
2124 | __func__, ha->fw_dump_capture_mask); | ||
2125 | ql4_printk(KERN_INFO, ha, "[%s]: Total_data_size 0x%x, %d obtained\n", | ||
2126 | __func__, ha->fw_dump_size, ha->fw_dump_size); | ||
2127 | |||
2128 | /* Update current timestamp before taking dump */ | ||
2129 | now = get_jiffies_64(); | ||
2130 | timestamp = (u32)(jiffies_to_msecs(now) / 1000); | ||
2131 | tmplt_hdr->driver_timestamp = timestamp; | ||
2132 | |||
2133 | entry_hdr = (struct qla82xx_minidump_entry_hdr *) | ||
2134 | (((uint8_t *)ha->fw_dump_tmplt_hdr) + | ||
2135 | tmplt_hdr->first_entry_offset); | ||
2136 | |||
2137 | /* Walk through the entry headers - validate/perform required action */ | ||
2138 | for (i = 0; i < num_entry_hdr; i++) { | ||
2139 | if (data_collected >= ha->fw_dump_size) { | ||
2140 | ql4_printk(KERN_INFO, ha, | ||
2141 | "Data collected: [0x%x], Total Dump size: [0x%x]\n", | ||
2142 | data_collected, ha->fw_dump_size); | ||
2143 | return rval; | ||
2144 | } | ||
2145 | |||
2146 | if (!(entry_hdr->d_ctrl.entry_capture_mask & | ||
2147 | ha->fw_dump_capture_mask)) { | ||
2148 | entry_hdr->d_ctrl.driver_flags |= | ||
2149 | QLA82XX_DBG_SKIPPED_FLAG; | ||
2150 | goto skip_nxt_entry; | ||
2151 | } | ||
2152 | |||
2153 | DEBUG2(ql4_printk(KERN_INFO, ha, | ||
2154 | "Data collected: [0x%x], Dump size left:[0x%x]\n", | ||
2155 | data_collected, | ||
2156 | (ha->fw_dump_size - data_collected))); | ||
2157 | |||
2158 | /* Decode the entry type and take required action to capture | ||
2159 | * debug data | ||
2160 | */ | ||
2161 | switch (entry_hdr->entry_type) { | ||
2162 | case QLA82XX_RDEND: | ||
2163 | ql4_8xxx_mark_entry_skipped(ha, entry_hdr, i); | ||
2164 | break; | ||
2165 | case QLA82XX_CNTRL: | ||
2166 | rval = qla4_8xxx_minidump_process_control(ha, | ||
2167 | entry_hdr); | ||
2168 | if (rval != QLA_SUCCESS) { | ||
2169 | ql4_8xxx_mark_entry_skipped(ha, entry_hdr, i); | ||
2170 | goto md_failed; | ||
2171 | } | ||
2172 | break; | ||
2173 | case QLA82XX_RDCRB: | ||
2174 | qla4_8xxx_minidump_process_rdcrb(ha, entry_hdr, | ||
2175 | &data_ptr); | ||
2176 | break; | ||
2177 | case QLA82XX_RDMEM: | ||
2178 | rval = qla4_8xxx_minidump_process_rdmem(ha, entry_hdr, | ||
2179 | &data_ptr); | ||
2180 | if (rval != QLA_SUCCESS) { | ||
2181 | ql4_8xxx_mark_entry_skipped(ha, entry_hdr, i); | ||
2182 | goto md_failed; | ||
2183 | } | ||
2184 | break; | ||
2185 | case QLA82XX_BOARD: | ||
2186 | case QLA82XX_RDROM: | ||
2187 | qla4_8xxx_minidump_process_rdrom(ha, entry_hdr, | ||
2188 | &data_ptr); | ||
2189 | break; | ||
2190 | case QLA82XX_L2DTG: | ||
2191 | case QLA82XX_L2ITG: | ||
2192 | case QLA82XX_L2DAT: | ||
2193 | case QLA82XX_L2INS: | ||
2194 | rval = qla4_8xxx_minidump_process_l2tag(ha, entry_hdr, | ||
2195 | &data_ptr); | ||
2196 | if (rval != QLA_SUCCESS) { | ||
2197 | ql4_8xxx_mark_entry_skipped(ha, entry_hdr, i); | ||
2198 | goto md_failed; | ||
2199 | } | ||
2200 | break; | ||
2201 | case QLA82XX_L1DAT: | ||
2202 | case QLA82XX_L1INS: | ||
2203 | qla4_8xxx_minidump_process_l1cache(ha, entry_hdr, | ||
2204 | &data_ptr); | ||
2205 | break; | ||
2206 | case QLA82XX_RDOCM: | ||
2207 | qla4_8xxx_minidump_process_rdocm(ha, entry_hdr, | ||
2208 | &data_ptr); | ||
2209 | break; | ||
2210 | case QLA82XX_RDMUX: | ||
2211 | qla4_8xxx_minidump_process_rdmux(ha, entry_hdr, | ||
2212 | &data_ptr); | ||
2213 | break; | ||
2214 | case QLA82XX_QUEUE: | ||
2215 | qla4_8xxx_minidump_process_queue(ha, entry_hdr, | ||
2216 | &data_ptr); | ||
2217 | break; | ||
2218 | case QLA82XX_RDNOP: | ||
2219 | default: | ||
2220 | ql4_8xxx_mark_entry_skipped(ha, entry_hdr, i); | ||
2221 | break; | ||
2222 | } | ||
2223 | |||
2224 | data_collected = (uint8_t *)data_ptr - | ||
2225 | ((uint8_t *)((uint8_t *)ha->fw_dump + | ||
2226 | ha->fw_dump_tmplt_size)); | ||
2227 | skip_nxt_entry: | ||
2228 | /* next entry in the template */ | ||
2229 | entry_hdr = (struct qla82xx_minidump_entry_hdr *) | ||
2230 | (((uint8_t *)entry_hdr) + | ||
2231 | entry_hdr->entry_size); | ||
2232 | } | ||
2233 | |||
2234 | if ((data_collected + ha->fw_dump_tmplt_size) != ha->fw_dump_size) { | ||
2235 | ql4_printk(KERN_INFO, ha, | ||
2236 | "Dump data mismatch: Data collected: [0x%x], total_data_size:[0x%x]\n", | ||
2237 | data_collected, ha->fw_dump_size); | ||
2238 | goto md_failed; | ||
2239 | } | ||
2240 | |||
2241 | DEBUG2(ql4_printk(KERN_INFO, ha, "Leaving fn: %s Last entry: 0x%x\n", | ||
2242 | __func__, i)); | ||
2243 | md_failed: | ||
2244 | return rval; | ||
2245 | } | ||
2246 | |||
2247 | /** | ||
2248 | * qla4_8xxx_uevent_emit - Send uevent when the firmware dump is ready. | ||
2249 | * @ha: pointer to adapter structure | ||
2250 | **/ | ||
2251 | static void qla4_8xxx_uevent_emit(struct scsi_qla_host *ha, u32 code) | ||
2252 | { | ||
2253 | char event_string[40]; | ||
2254 | char *envp[] = { event_string, NULL }; | ||
2255 | |||
2256 | switch (code) { | ||
2257 | case QL4_UEVENT_CODE_FW_DUMP: | ||
2258 | snprintf(event_string, sizeof(event_string), "FW_DUMP=%ld", | ||
2259 | ha->host_no); | ||
2260 | break; | ||
2261 | default: | ||
2262 | /*do nothing*/ | ||
2263 | break; | ||
2264 | } | ||
2265 | |||
2266 | kobject_uevent_env(&(&ha->pdev->dev)->kobj, KOBJ_CHANGE, envp); | ||
2267 | } | ||
2268 | |||
1604 | /** | 2269 | /** |
1605 | * qla4_8xxx_device_bootstrap - Initialize device, set DEV_READY, start fw | 2270 | * qla4_8xxx_device_bootstrap - Initialize device, set DEV_READY, start fw |
1606 | * @ha: pointer to adapter structure | 2271 | * @ha: pointer to adapter structure |
@@ -1659,6 +2324,15 @@ dev_initialize: | |||
1659 | qla4_8xxx_wr_32(ha, QLA82XX_CRB_DRV_IDC_VERSION, QLA82XX_IDC_VERSION); | 2324 | qla4_8xxx_wr_32(ha, QLA82XX_CRB_DRV_IDC_VERSION, QLA82XX_IDC_VERSION); |
1660 | 2325 | ||
1661 | qla4_8xxx_idc_unlock(ha); | 2326 | qla4_8xxx_idc_unlock(ha); |
2327 | if (ql4xenablemd && test_bit(AF_FW_RECOVERY, &ha->flags) && | ||
2328 | !test_and_set_bit(AF_82XX_FW_DUMPED, &ha->flags)) { | ||
2329 | if (!qla4_8xxx_collect_md_data(ha)) { | ||
2330 | qla4_8xxx_uevent_emit(ha, QL4_UEVENT_CODE_FW_DUMP); | ||
2331 | } else { | ||
2332 | ql4_printk(KERN_INFO, ha, "Unable to collect minidump\n"); | ||
2333 | clear_bit(AF_82XX_FW_DUMPED, &ha->flags); | ||
2334 | } | ||
2335 | } | ||
1662 | rval = qla4_8xxx_try_start_fw(ha); | 2336 | rval = qla4_8xxx_try_start_fw(ha); |
1663 | qla4_8xxx_idc_lock(ha); | 2337 | qla4_8xxx_idc_lock(ha); |
1664 | 2338 | ||
@@ -1686,6 +2360,7 @@ static void | |||
1686 | qla4_8xxx_need_reset_handler(struct scsi_qla_host *ha) | 2360 | qla4_8xxx_need_reset_handler(struct scsi_qla_host *ha) |
1687 | { | 2361 | { |
1688 | uint32_t dev_state, drv_state, drv_active; | 2362 | uint32_t dev_state, drv_state, drv_active; |
2363 | uint32_t active_mask = 0xFFFFFFFF; | ||
1689 | unsigned long reset_timeout; | 2364 | unsigned long reset_timeout; |
1690 | 2365 | ||
1691 | ql4_printk(KERN_INFO, ha, | 2366 | ql4_printk(KERN_INFO, ha, |
@@ -1697,7 +2372,14 @@ qla4_8xxx_need_reset_handler(struct scsi_qla_host *ha) | |||
1697 | qla4_8xxx_idc_lock(ha); | 2372 | qla4_8xxx_idc_lock(ha); |
1698 | } | 2373 | } |
1699 | 2374 | ||
1700 | qla4_8xxx_set_rst_ready(ha); | 2375 | if (!test_bit(AF_82XX_RST_OWNER, &ha->flags)) { |
2376 | DEBUG2(ql4_printk(KERN_INFO, ha, | ||
2377 | "%s(%ld): reset acknowledged\n", | ||
2378 | __func__, ha->host_no)); | ||
2379 | qla4_8xxx_set_rst_ready(ha); | ||
2380 | } else { | ||
2381 | active_mask = (~(1 << (ha->func_num * 4))); | ||
2382 | } | ||
1701 | 2383 | ||
1702 | /* wait for 10 seconds for reset ack from all functions */ | 2384 | /* wait for 10 seconds for reset ack from all functions */ |
1703 | reset_timeout = jiffies + (ha->nx_reset_timeout * HZ); | 2385 | reset_timeout = jiffies + (ha->nx_reset_timeout * HZ); |
@@ -1709,12 +2391,24 @@ qla4_8xxx_need_reset_handler(struct scsi_qla_host *ha) | |||
1709 | "%s(%ld): drv_state = 0x%x, drv_active = 0x%x\n", | 2391 | "%s(%ld): drv_state = 0x%x, drv_active = 0x%x\n", |
1710 | __func__, ha->host_no, drv_state, drv_active); | 2392 | __func__, ha->host_no, drv_state, drv_active); |
1711 | 2393 | ||
1712 | while (drv_state != drv_active) { | 2394 | while (drv_state != (drv_active & active_mask)) { |
1713 | if (time_after_eq(jiffies, reset_timeout)) { | 2395 | if (time_after_eq(jiffies, reset_timeout)) { |
1714 | printk("%s: RESET TIMEOUT!\n", DRIVER_NAME); | 2396 | ql4_printk(KERN_INFO, ha, |
2397 | "%s: RESET TIMEOUT! drv_state: 0x%08x, drv_active: 0x%08x\n", | ||
2398 | DRIVER_NAME, drv_state, drv_active); | ||
1715 | break; | 2399 | break; |
1716 | } | 2400 | } |
1717 | 2401 | ||
2402 | /* | ||
2403 | * When reset_owner times out, check which functions | ||
2404 | * acked/did not ack | ||
2405 | */ | ||
2406 | if (test_bit(AF_82XX_RST_OWNER, &ha->flags)) { | ||
2407 | ql4_printk(KERN_INFO, ha, | ||
2408 | "%s(%ld): drv_state = 0x%x, drv_active = 0x%x\n", | ||
2409 | __func__, ha->host_no, drv_state, | ||
2410 | drv_active); | ||
2411 | } | ||
1718 | qla4_8xxx_idc_unlock(ha); | 2412 | qla4_8xxx_idc_unlock(ha); |
1719 | msleep(1000); | 2413 | msleep(1000); |
1720 | qla4_8xxx_idc_lock(ha); | 2414 | qla4_8xxx_idc_lock(ha); |
@@ -1723,14 +2417,18 @@ qla4_8xxx_need_reset_handler(struct scsi_qla_host *ha) | |||
1723 | drv_active = qla4_8xxx_rd_32(ha, QLA82XX_CRB_DRV_ACTIVE); | 2417 | drv_active = qla4_8xxx_rd_32(ha, QLA82XX_CRB_DRV_ACTIVE); |
1724 | } | 2418 | } |
1725 | 2419 | ||
2420 | /* Clear RESET OWNER as we are not going to use it any further */ | ||
2421 | clear_bit(AF_82XX_RST_OWNER, &ha->flags); | ||
2422 | |||
1726 | dev_state = qla4_8xxx_rd_32(ha, QLA82XX_CRB_DEV_STATE); | 2423 | dev_state = qla4_8xxx_rd_32(ha, QLA82XX_CRB_DEV_STATE); |
1727 | ql4_printk(KERN_INFO, ha, "3:Device state is 0x%x = %s\n", dev_state, | 2424 | ql4_printk(KERN_INFO, ha, "Device state is 0x%x = %s\n", dev_state, |
1728 | dev_state < MAX_STATES ? qdev_state[dev_state] : "Unknown"); | 2425 | dev_state < MAX_STATES ? qdev_state[dev_state] : "Unknown"); |
1729 | 2426 | ||
1730 | /* Force to DEV_COLD unless someone else is starting a reset */ | 2427 | /* Force to DEV_COLD unless someone else is starting a reset */ |
1731 | if (dev_state != QLA82XX_DEV_INITIALIZING) { | 2428 | if (dev_state != QLA82XX_DEV_INITIALIZING) { |
1732 | ql4_printk(KERN_INFO, ha, "HW State: COLD/RE-INIT\n"); | 2429 | ql4_printk(KERN_INFO, ha, "HW State: COLD/RE-INIT\n"); |
1733 | qla4_8xxx_wr_32(ha, QLA82XX_CRB_DEV_STATE, QLA82XX_DEV_COLD); | 2430 | qla4_8xxx_wr_32(ha, QLA82XX_CRB_DEV_STATE, QLA82XX_DEV_COLD); |
2431 | qla4_8xxx_set_rst_ready(ha); | ||
1734 | } | 2432 | } |
1735 | } | 2433 | } |
1736 | 2434 | ||
@@ -1765,8 +2463,9 @@ int qla4_8xxx_device_state_handler(struct scsi_qla_host *ha) | |||
1765 | } | 2463 | } |
1766 | 2464 | ||
1767 | dev_state = qla4_8xxx_rd_32(ha, QLA82XX_CRB_DEV_STATE); | 2465 | dev_state = qla4_8xxx_rd_32(ha, QLA82XX_CRB_DEV_STATE); |
1768 | ql4_printk(KERN_INFO, ha, "1:Device state is 0x%x = %s\n", dev_state, | 2466 | DEBUG2(ql4_printk(KERN_INFO, ha, "Device state is 0x%x = %s\n", |
1769 | dev_state < MAX_STATES ? qdev_state[dev_state] : "Unknown"); | 2467 | dev_state, dev_state < MAX_STATES ? |
2468 | qdev_state[dev_state] : "Unknown")); | ||
1770 | 2469 | ||
1771 | /* wait for 30 seconds for device to go ready */ | 2470 | /* wait for 30 seconds for device to go ready */ |
1772 | dev_init_timeout = jiffies + (ha->nx_dev_init_timeout * HZ); | 2471 | dev_init_timeout = jiffies + (ha->nx_dev_init_timeout * HZ); |
@@ -1775,15 +2474,19 @@ int qla4_8xxx_device_state_handler(struct scsi_qla_host *ha) | |||
1775 | while (1) { | 2474 | while (1) { |
1776 | 2475 | ||
1777 | if (time_after_eq(jiffies, dev_init_timeout)) { | 2476 | if (time_after_eq(jiffies, dev_init_timeout)) { |
1778 | ql4_printk(KERN_WARNING, ha, "Device init failed!\n"); | 2477 | ql4_printk(KERN_WARNING, ha, |
2478 | "%s: Device Init Failed 0x%x = %s\n", | ||
2479 | DRIVER_NAME, | ||
2480 | dev_state, dev_state < MAX_STATES ? | ||
2481 | qdev_state[dev_state] : "Unknown"); | ||
1779 | qla4_8xxx_wr_32(ha, QLA82XX_CRB_DEV_STATE, | 2482 | qla4_8xxx_wr_32(ha, QLA82XX_CRB_DEV_STATE, |
1780 | QLA82XX_DEV_FAILED); | 2483 | QLA82XX_DEV_FAILED); |
1781 | } | 2484 | } |
1782 | 2485 | ||
1783 | dev_state = qla4_8xxx_rd_32(ha, QLA82XX_CRB_DEV_STATE); | 2486 | dev_state = qla4_8xxx_rd_32(ha, QLA82XX_CRB_DEV_STATE); |
1784 | ql4_printk(KERN_INFO, ha, | 2487 | ql4_printk(KERN_INFO, ha, "Device state is 0x%x = %s\n", |
1785 | "2:Device state is 0x%x = %s\n", dev_state, | 2488 | dev_state, dev_state < MAX_STATES ? |
1786 | dev_state < MAX_STATES ? qdev_state[dev_state] : "Unknown"); | 2489 | qdev_state[dev_state] : "Unknown"); |
1787 | 2490 | ||
1788 | /* NOTE: Make sure idc unlocked upon exit of switch statement */ | 2491 | /* NOTE: Make sure idc unlocked upon exit of switch statement */ |
1789 | switch (dev_state) { | 2492 | switch (dev_state) { |
@@ -2184,6 +2887,7 @@ qla4_8xxx_isp_reset(struct scsi_qla_host *ha) | |||
2184 | ql4_printk(KERN_INFO, ha, "HW State: NEED RESET\n"); | 2887 | ql4_printk(KERN_INFO, ha, "HW State: NEED RESET\n"); |
2185 | qla4_8xxx_wr_32(ha, QLA82XX_CRB_DEV_STATE, | 2888 | qla4_8xxx_wr_32(ha, QLA82XX_CRB_DEV_STATE, |
2186 | QLA82XX_DEV_NEED_RESET); | 2889 | QLA82XX_DEV_NEED_RESET); |
2890 | set_bit(AF_82XX_RST_OWNER, &ha->flags); | ||
2187 | } else | 2891 | } else |
2188 | ql4_printk(KERN_INFO, ha, "HW State: DEVICE INITIALIZING\n"); | 2892 | ql4_printk(KERN_INFO, ha, "HW State: DEVICE INITIALIZING\n"); |
2189 | 2893 | ||
@@ -2195,8 +2899,10 @@ qla4_8xxx_isp_reset(struct scsi_qla_host *ha) | |||
2195 | qla4_8xxx_clear_rst_ready(ha); | 2899 | qla4_8xxx_clear_rst_ready(ha); |
2196 | qla4_8xxx_idc_unlock(ha); | 2900 | qla4_8xxx_idc_unlock(ha); |
2197 | 2901 | ||
2198 | if (rval == QLA_SUCCESS) | 2902 | if (rval == QLA_SUCCESS) { |
2903 | ql4_printk(KERN_INFO, ha, "Clearing AF_RECOVERY in qla4_8xxx_isp_reset\n"); | ||
2199 | clear_bit(AF_FW_RECOVERY, &ha->flags); | 2904 | clear_bit(AF_FW_RECOVERY, &ha->flags); |
2905 | } | ||
2200 | 2906 | ||
2201 | return rval; | 2907 | return rval; |
2202 | } | 2908 | } |
diff --git a/drivers/scsi/qla4xxx/ql4_nx.h b/drivers/scsi/qla4xxx/ql4_nx.h index dc7500e47b8b..30258479f100 100644 --- a/drivers/scsi/qla4xxx/ql4_nx.h +++ b/drivers/scsi/qla4xxx/ql4_nx.h | |||
@@ -792,4 +792,196 @@ struct crb_addr_pair { | |||
792 | #define MIU_TEST_AGT_WRDATA_UPPER_LO (0x0b0) | 792 | #define MIU_TEST_AGT_WRDATA_UPPER_LO (0x0b0) |
793 | #define MIU_TEST_AGT_WRDATA_UPPER_HI (0x0b4) | 793 | #define MIU_TEST_AGT_WRDATA_UPPER_HI (0x0b4) |
794 | 794 | ||
795 | /* Minidump related */ | ||
796 | |||
797 | /* Entry Type Defines */ | ||
798 | #define QLA82XX_RDNOP 0 | ||
799 | #define QLA82XX_RDCRB 1 | ||
800 | #define QLA82XX_RDMUX 2 | ||
801 | #define QLA82XX_QUEUE 3 | ||
802 | #define QLA82XX_BOARD 4 | ||
803 | #define QLA82XX_RDOCM 6 | ||
804 | #define QLA82XX_PREGS 7 | ||
805 | #define QLA82XX_L1DTG 8 | ||
806 | #define QLA82XX_L1ITG 9 | ||
807 | #define QLA82XX_L1DAT 11 | ||
808 | #define QLA82XX_L1INS 12 | ||
809 | #define QLA82XX_L2DTG 21 | ||
810 | #define QLA82XX_L2ITG 22 | ||
811 | #define QLA82XX_L2DAT 23 | ||
812 | #define QLA82XX_L2INS 24 | ||
813 | #define QLA82XX_RDROM 71 | ||
814 | #define QLA82XX_RDMEM 72 | ||
815 | #define QLA82XX_CNTRL 98 | ||
816 | #define QLA82XX_RDEND 255 | ||
817 | |||
818 | /* Opcodes for Control Entries. | ||
819 | * These Flags are bit fields. | ||
820 | */ | ||
821 | #define QLA82XX_DBG_OPCODE_WR 0x01 | ||
822 | #define QLA82XX_DBG_OPCODE_RW 0x02 | ||
823 | #define QLA82XX_DBG_OPCODE_AND 0x04 | ||
824 | #define QLA82XX_DBG_OPCODE_OR 0x08 | ||
825 | #define QLA82XX_DBG_OPCODE_POLL 0x10 | ||
826 | #define QLA82XX_DBG_OPCODE_RDSTATE 0x20 | ||
827 | #define QLA82XX_DBG_OPCODE_WRSTATE 0x40 | ||
828 | #define QLA82XX_DBG_OPCODE_MDSTATE 0x80 | ||
829 | |||
830 | /* Driver Flags */ | ||
831 | #define QLA82XX_DBG_SKIPPED_FLAG 0x80 /* driver skipped this entry */ | ||
832 | #define QLA82XX_DBG_SIZE_ERR_FLAG 0x40 /* Entry vs Capture size | ||
833 | * mismatch */ | ||
834 | |||
835 | /* Driver_code is for driver to write some info about the entry | ||
836 | * currently not used. | ||
837 | */ | ||
838 | struct qla82xx_minidump_entry_hdr { | ||
839 | uint32_t entry_type; | ||
840 | uint32_t entry_size; | ||
841 | uint32_t entry_capture_size; | ||
842 | struct { | ||
843 | uint8_t entry_capture_mask; | ||
844 | uint8_t entry_code; | ||
845 | uint8_t driver_code; | ||
846 | uint8_t driver_flags; | ||
847 | } d_ctrl; | ||
848 | }; | ||
849 | |||
850 | /* Read CRB entry header */ | ||
851 | struct qla82xx_minidump_entry_crb { | ||
852 | struct qla82xx_minidump_entry_hdr h; | ||
853 | uint32_t addr; | ||
854 | struct { | ||
855 | uint8_t addr_stride; | ||
856 | uint8_t state_index_a; | ||
857 | uint16_t poll_timeout; | ||
858 | } crb_strd; | ||
859 | uint32_t data_size; | ||
860 | uint32_t op_count; | ||
861 | |||
862 | struct { | ||
863 | uint8_t opcode; | ||
864 | uint8_t state_index_v; | ||
865 | uint8_t shl; | ||
866 | uint8_t shr; | ||
867 | } crb_ctrl; | ||
868 | |||
869 | uint32_t value_1; | ||
870 | uint32_t value_2; | ||
871 | uint32_t value_3; | ||
872 | }; | ||
873 | |||
874 | struct qla82xx_minidump_entry_cache { | ||
875 | struct qla82xx_minidump_entry_hdr h; | ||
876 | uint32_t tag_reg_addr; | ||
877 | struct { | ||
878 | uint16_t tag_value_stride; | ||
879 | uint16_t init_tag_value; | ||
880 | } addr_ctrl; | ||
881 | uint32_t data_size; | ||
882 | uint32_t op_count; | ||
883 | uint32_t control_addr; | ||
884 | struct { | ||
885 | uint16_t write_value; | ||
886 | uint8_t poll_mask; | ||
887 | uint8_t poll_wait; | ||
888 | } cache_ctrl; | ||
889 | uint32_t read_addr; | ||
890 | struct { | ||
891 | uint8_t read_addr_stride; | ||
892 | uint8_t read_addr_cnt; | ||
893 | uint16_t rsvd_1; | ||
894 | } read_ctrl; | ||
895 | }; | ||
896 | |||
897 | /* Read OCM */ | ||
898 | struct qla82xx_minidump_entry_rdocm { | ||
899 | struct qla82xx_minidump_entry_hdr h; | ||
900 | uint32_t rsvd_0; | ||
901 | uint32_t rsvd_1; | ||
902 | uint32_t data_size; | ||
903 | uint32_t op_count; | ||
904 | uint32_t rsvd_2; | ||
905 | uint32_t rsvd_3; | ||
906 | uint32_t read_addr; | ||
907 | uint32_t read_addr_stride; | ||
908 | }; | ||
909 | |||
910 | /* Read Memory */ | ||
911 | struct qla82xx_minidump_entry_rdmem { | ||
912 | struct qla82xx_minidump_entry_hdr h; | ||
913 | uint32_t rsvd[6]; | ||
914 | uint32_t read_addr; | ||
915 | uint32_t read_data_size; | ||
916 | }; | ||
917 | |||
918 | /* Read ROM */ | ||
919 | struct qla82xx_minidump_entry_rdrom { | ||
920 | struct qla82xx_minidump_entry_hdr h; | ||
921 | uint32_t rsvd[6]; | ||
922 | uint32_t read_addr; | ||
923 | uint32_t read_data_size; | ||
924 | }; | ||
925 | |||
926 | /* Mux entry */ | ||
927 | struct qla82xx_minidump_entry_mux { | ||
928 | struct qla82xx_minidump_entry_hdr h; | ||
929 | uint32_t select_addr; | ||
930 | uint32_t rsvd_0; | ||
931 | uint32_t data_size; | ||
932 | uint32_t op_count; | ||
933 | uint32_t select_value; | ||
934 | uint32_t select_value_stride; | ||
935 | uint32_t read_addr; | ||
936 | uint32_t rsvd_1; | ||
937 | }; | ||
938 | |||
939 | /* Queue entry */ | ||
940 | struct qla82xx_minidump_entry_queue { | ||
941 | struct qla82xx_minidump_entry_hdr h; | ||
942 | uint32_t select_addr; | ||
943 | struct { | ||
944 | uint16_t queue_id_stride; | ||
945 | uint16_t rsvd_0; | ||
946 | } q_strd; | ||
947 | uint32_t data_size; | ||
948 | uint32_t op_count; | ||
949 | uint32_t rsvd_1; | ||
950 | uint32_t rsvd_2; | ||
951 | uint32_t read_addr; | ||
952 | struct { | ||
953 | uint8_t read_addr_stride; | ||
954 | uint8_t read_addr_cnt; | ||
955 | uint16_t rsvd_3; | ||
956 | } rd_strd; | ||
957 | }; | ||
958 | |||
959 | #define QLA82XX_MINIDUMP_OCM0_SIZE (256 * 1024) | ||
960 | #define QLA82XX_MINIDUMP_L1C_SIZE (256 * 1024) | ||
961 | #define QLA82XX_MINIDUMP_L2C_SIZE 1572864 | ||
962 | #define QLA82XX_MINIDUMP_COMMON_STR_SIZE 0 | ||
963 | #define QLA82XX_MINIDUMP_FCOE_STR_SIZE 0 | ||
964 | #define QLA82XX_MINIDUMP_MEM_SIZE 0 | ||
965 | #define QLA82XX_MAX_ENTRY_HDR 4 | ||
966 | |||
967 | struct qla82xx_minidump { | ||
968 | uint32_t md_ocm0_data[QLA82XX_MINIDUMP_OCM0_SIZE]; | ||
969 | uint32_t md_l1c_data[QLA82XX_MINIDUMP_L1C_SIZE]; | ||
970 | uint32_t md_l2c_data[QLA82XX_MINIDUMP_L2C_SIZE]; | ||
971 | uint32_t md_cs_data[QLA82XX_MINIDUMP_COMMON_STR_SIZE]; | ||
972 | uint32_t md_fcoes_data[QLA82XX_MINIDUMP_FCOE_STR_SIZE]; | ||
973 | uint32_t md_mem_data[QLA82XX_MINIDUMP_MEM_SIZE]; | ||
974 | }; | ||
975 | |||
976 | #define MBC_DIAGNOSTIC_MINIDUMP_TEMPLATE 0x129 | ||
977 | #define RQST_TMPLT_SIZE 0x0 | ||
978 | #define RQST_TMPLT 0x1 | ||
979 | #define MD_DIRECT_ROM_WINDOW 0x42110030 | ||
980 | #define MD_DIRECT_ROM_READ_BASE 0x42150000 | ||
981 | #define MD_MIU_TEST_AGT_CTRL 0x41000090 | ||
982 | #define MD_MIU_TEST_AGT_ADDR_LO 0x41000094 | ||
983 | #define MD_MIU_TEST_AGT_ADDR_HI 0x41000098 | ||
984 | |||
985 | static const int MD_MIU_TEST_AGT_RDDATA[] = { 0x410000A8, | ||
986 | 0x410000AC, 0x410000B8, 0x410000BC }; | ||
795 | #endif | 987 | #endif |
diff --git a/drivers/scsi/qla4xxx/ql4_os.c b/drivers/scsi/qla4xxx/ql4_os.c index ee47820c30a6..cd15678f9ada 100644 --- a/drivers/scsi/qla4xxx/ql4_os.c +++ b/drivers/scsi/qla4xxx/ql4_os.c | |||
@@ -68,12 +68,34 @@ MODULE_PARM_DESC(ql4xmaxqdepth, | |||
68 | " Maximum queue depth to report for target devices.\n" | 68 | " Maximum queue depth to report for target devices.\n" |
69 | "\t\t Default: 32."); | 69 | "\t\t Default: 32."); |
70 | 70 | ||
71 | static int ql4xqfulltracking = 1; | ||
72 | module_param(ql4xqfulltracking, int, S_IRUGO | S_IWUSR); | ||
73 | MODULE_PARM_DESC(ql4xqfulltracking, | ||
74 | " Enable or disable dynamic tracking and adjustment of\n" | ||
75 | "\t\t scsi device queue depth.\n" | ||
76 | "\t\t 0 - Disable.\n" | ||
77 | "\t\t 1 - Enable. (Default)"); | ||
78 | |||
71 | static int ql4xsess_recovery_tmo = QL4_SESS_RECOVERY_TMO; | 79 | static int ql4xsess_recovery_tmo = QL4_SESS_RECOVERY_TMO; |
72 | module_param(ql4xsess_recovery_tmo, int, S_IRUGO); | 80 | module_param(ql4xsess_recovery_tmo, int, S_IRUGO); |
73 | MODULE_PARM_DESC(ql4xsess_recovery_tmo, | 81 | MODULE_PARM_DESC(ql4xsess_recovery_tmo, |
74 | " Target Session Recovery Timeout.\n" | 82 | " Target Session Recovery Timeout.\n" |
75 | "\t\t Default: 120 sec."); | 83 | "\t\t Default: 120 sec."); |
76 | 84 | ||
85 | int ql4xmdcapmask = 0x1F; | ||
86 | module_param(ql4xmdcapmask, int, S_IRUGO); | ||
87 | MODULE_PARM_DESC(ql4xmdcapmask, | ||
88 | " Set the Minidump driver capture mask level.\n" | ||
89 | "\t\t Default is 0x1F.\n" | ||
90 | "\t\t Can be set to 0x3, 0x7, 0xF, 0x1F, 0x3F, 0x7F"); | ||
91 | |||
92 | int ql4xenablemd = 1; | ||
93 | module_param(ql4xenablemd, int, S_IRUGO | S_IWUSR); | ||
94 | MODULE_PARM_DESC(ql4xenablemd, | ||
95 | " Set to enable minidump.\n" | ||
96 | "\t\t 0 - disable minidump\n" | ||
97 | "\t\t 1 - enable minidump (Default)"); | ||
98 | |||
77 | static int qla4xxx_wait_for_hba_online(struct scsi_qla_host *ha); | 99 | static int qla4xxx_wait_for_hba_online(struct scsi_qla_host *ha); |
78 | /* | 100 | /* |
79 | * SCSI host template entry points | 101 | * SCSI host template entry points |
@@ -140,6 +162,8 @@ static int qla4xxx_slave_configure(struct scsi_device *device); | |||
140 | static void qla4xxx_slave_destroy(struct scsi_device *sdev); | 162 | static void qla4xxx_slave_destroy(struct scsi_device *sdev); |
141 | static umode_t ql4_attr_is_visible(int param_type, int param); | 163 | static umode_t ql4_attr_is_visible(int param_type, int param); |
142 | static int qla4xxx_host_reset(struct Scsi_Host *shost, int reset_type); | 164 | static int qla4xxx_host_reset(struct Scsi_Host *shost, int reset_type); |
165 | static int qla4xxx_change_queue_depth(struct scsi_device *sdev, int qdepth, | ||
166 | int reason); | ||
143 | 167 | ||
144 | static struct qla4_8xxx_legacy_intr_set legacy_intr[] = | 168 | static struct qla4_8xxx_legacy_intr_set legacy_intr[] = |
145 | QLA82XX_LEGACY_INTR_CONFIG; | 169 | QLA82XX_LEGACY_INTR_CONFIG; |
@@ -159,6 +183,7 @@ static struct scsi_host_template qla4xxx_driver_template = { | |||
159 | .slave_configure = qla4xxx_slave_configure, | 183 | .slave_configure = qla4xxx_slave_configure, |
160 | .slave_alloc = qla4xxx_slave_alloc, | 184 | .slave_alloc = qla4xxx_slave_alloc, |
161 | .slave_destroy = qla4xxx_slave_destroy, | 185 | .slave_destroy = qla4xxx_slave_destroy, |
186 | .change_queue_depth = qla4xxx_change_queue_depth, | ||
162 | 187 | ||
163 | .this_id = -1, | 188 | .this_id = -1, |
164 | .cmd_per_lun = 3, | 189 | .cmd_per_lun = 3, |
@@ -1555,19 +1580,53 @@ static void qla4xxx_session_destroy(struct iscsi_cls_session *cls_sess) | |||
1555 | struct iscsi_session *sess; | 1580 | struct iscsi_session *sess; |
1556 | struct ddb_entry *ddb_entry; | 1581 | struct ddb_entry *ddb_entry; |
1557 | struct scsi_qla_host *ha; | 1582 | struct scsi_qla_host *ha; |
1558 | unsigned long flags; | 1583 | unsigned long flags, wtime; |
1584 | struct dev_db_entry *fw_ddb_entry = NULL; | ||
1585 | dma_addr_t fw_ddb_entry_dma; | ||
1586 | uint32_t ddb_state; | ||
1587 | int ret; | ||
1559 | 1588 | ||
1560 | DEBUG2(printk(KERN_INFO "Func: %s\n", __func__)); | 1589 | DEBUG2(printk(KERN_INFO "Func: %s\n", __func__)); |
1561 | sess = cls_sess->dd_data; | 1590 | sess = cls_sess->dd_data; |
1562 | ddb_entry = sess->dd_data; | 1591 | ddb_entry = sess->dd_data; |
1563 | ha = ddb_entry->ha; | 1592 | ha = ddb_entry->ha; |
1564 | 1593 | ||
1594 | fw_ddb_entry = dma_alloc_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry), | ||
1595 | &fw_ddb_entry_dma, GFP_KERNEL); | ||
1596 | if (!fw_ddb_entry) { | ||
1597 | ql4_printk(KERN_ERR, ha, | ||
1598 | "%s: Unable to allocate dma buffer\n", __func__); | ||
1599 | goto destroy_session; | ||
1600 | } | ||
1601 | |||
1602 | wtime = jiffies + (HZ * LOGOUT_TOV); | ||
1603 | do { | ||
1604 | ret = qla4xxx_get_fwddb_entry(ha, ddb_entry->fw_ddb_index, | ||
1605 | fw_ddb_entry, fw_ddb_entry_dma, | ||
1606 | NULL, NULL, &ddb_state, NULL, | ||
1607 | NULL, NULL); | ||
1608 | if (ret == QLA_ERROR) | ||
1609 | goto destroy_session; | ||
1610 | |||
1611 | if ((ddb_state == DDB_DS_NO_CONNECTION_ACTIVE) || | ||
1612 | (ddb_state == DDB_DS_SESSION_FAILED)) | ||
1613 | goto destroy_session; | ||
1614 | |||
1615 | schedule_timeout_uninterruptible(HZ); | ||
1616 | } while ((time_after(wtime, jiffies))); | ||
1617 | |||
1618 | destroy_session: | ||
1565 | qla4xxx_clear_ddb_entry(ha, ddb_entry->fw_ddb_index); | 1619 | qla4xxx_clear_ddb_entry(ha, ddb_entry->fw_ddb_index); |
1566 | 1620 | ||
1567 | spin_lock_irqsave(&ha->hardware_lock, flags); | 1621 | spin_lock_irqsave(&ha->hardware_lock, flags); |
1568 | qla4xxx_free_ddb(ha, ddb_entry); | 1622 | qla4xxx_free_ddb(ha, ddb_entry); |
1569 | spin_unlock_irqrestore(&ha->hardware_lock, flags); | 1623 | spin_unlock_irqrestore(&ha->hardware_lock, flags); |
1624 | |||
1570 | iscsi_session_teardown(cls_sess); | 1625 | iscsi_session_teardown(cls_sess); |
1626 | |||
1627 | if (fw_ddb_entry) | ||
1628 | dma_free_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry), | ||
1629 | fw_ddb_entry, fw_ddb_entry_dma); | ||
1571 | } | 1630 | } |
1572 | 1631 | ||
1573 | static struct iscsi_cls_conn * | 1632 | static struct iscsi_cls_conn * |
@@ -2220,6 +2279,9 @@ static void qla4xxx_mem_free(struct scsi_qla_host *ha) | |||
2220 | dma_free_coherent(&ha->pdev->dev, ha->queues_len, ha->queues, | 2279 | dma_free_coherent(&ha->pdev->dev, ha->queues_len, ha->queues, |
2221 | ha->queues_dma); | 2280 | ha->queues_dma); |
2222 | 2281 | ||
2282 | if (ha->fw_dump) | ||
2283 | vfree(ha->fw_dump); | ||
2284 | |||
2223 | ha->queues_len = 0; | 2285 | ha->queues_len = 0; |
2224 | ha->queues = NULL; | 2286 | ha->queues = NULL; |
2225 | ha->queues_dma = 0; | 2287 | ha->queues_dma = 0; |
@@ -2229,6 +2291,8 @@ static void qla4xxx_mem_free(struct scsi_qla_host *ha) | |||
2229 | ha->response_dma = 0; | 2291 | ha->response_dma = 0; |
2230 | ha->shadow_regs = NULL; | 2292 | ha->shadow_regs = NULL; |
2231 | ha->shadow_regs_dma = 0; | 2293 | ha->shadow_regs_dma = 0; |
2294 | ha->fw_dump = NULL; | ||
2295 | ha->fw_dump_size = 0; | ||
2232 | 2296 | ||
2233 | /* Free srb pool. */ | 2297 | /* Free srb pool. */ |
2234 | if (ha->srb_mempool) | 2298 | if (ha->srb_mempool) |
@@ -5023,6 +5087,8 @@ static int __devinit qla4xxx_probe_adapter(struct pci_dev *pdev, | |||
5023 | 5087 | ||
5024 | set_bit(AF_INIT_DONE, &ha->flags); | 5088 | set_bit(AF_INIT_DONE, &ha->flags); |
5025 | 5089 | ||
5090 | qla4_8xxx_alloc_sysfs_attr(ha); | ||
5091 | |||
5026 | printk(KERN_INFO | 5092 | printk(KERN_INFO |
5027 | " QLogic iSCSI HBA Driver version: %s\n" | 5093 | " QLogic iSCSI HBA Driver version: %s\n" |
5028 | " QLogic ISP%04x @ %s, host#=%ld, fw=%02d.%02d.%02d.%02d\n", | 5094 | " QLogic ISP%04x @ %s, host#=%ld, fw=%02d.%02d.%02d.%02d\n", |
@@ -5149,6 +5215,7 @@ static void __devexit qla4xxx_remove_adapter(struct pci_dev *pdev) | |||
5149 | iscsi_boot_destroy_kset(ha->boot_kset); | 5215 | iscsi_boot_destroy_kset(ha->boot_kset); |
5150 | 5216 | ||
5151 | qla4xxx_destroy_fw_ddb_session(ha); | 5217 | qla4xxx_destroy_fw_ddb_session(ha); |
5218 | qla4_8xxx_free_sysfs_attr(ha); | ||
5152 | 5219 | ||
5153 | scsi_remove_host(ha->host); | 5220 | scsi_remove_host(ha->host); |
5154 | 5221 | ||
@@ -5217,6 +5284,15 @@ static void qla4xxx_slave_destroy(struct scsi_device *sdev) | |||
5217 | scsi_deactivate_tcq(sdev, 1); | 5284 | scsi_deactivate_tcq(sdev, 1); |
5218 | } | 5285 | } |
5219 | 5286 | ||
5287 | static int qla4xxx_change_queue_depth(struct scsi_device *sdev, int qdepth, | ||
5288 | int reason) | ||
5289 | { | ||
5290 | if (!ql4xqfulltracking) | ||
5291 | return -EOPNOTSUPP; | ||
5292 | |||
5293 | return iscsi_change_queue_depth(sdev, qdepth, reason); | ||
5294 | } | ||
5295 | |||
5220 | /** | 5296 | /** |
5221 | * qla4xxx_del_from_active_array - returns an active srb | 5297 | * qla4xxx_del_from_active_array - returns an active srb |
5222 | * @ha: Pointer to host adapter structure. | 5298 | * @ha: Pointer to host adapter structure. |
diff --git a/drivers/scsi/qla4xxx/ql4_version.h b/drivers/scsi/qla4xxx/ql4_version.h index 97b30c108e36..cc1cc3518b87 100644 --- a/drivers/scsi/qla4xxx/ql4_version.h +++ b/drivers/scsi/qla4xxx/ql4_version.h | |||
@@ -5,4 +5,4 @@ | |||
5 | * See LICENSE.qla4xxx for copyright and licensing details. | 5 | * See LICENSE.qla4xxx for copyright and licensing details. |
6 | */ | 6 | */ |
7 | 7 | ||
8 | #define QLA4XXX_DRIVER_VERSION "5.02.00-k16" | 8 | #define QLA4XXX_DRIVER_VERSION "5.02.00-k17" |