diff options
| -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 | 92 | ||||
| -rw-r--r-- | drivers/scsi/qla4xxx/ql4_mbx.c | 73 | ||||
| -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 | 22 |
9 files changed, 1293 insertions, 16 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 05484364010e..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 | ||
diff --git a/drivers/scsi/qla4xxx/ql4_mbx.c b/drivers/scsi/qla4xxx/ql4_mbx.c index c7d101eee63c..cab8f665a41f 100644 --- a/drivers/scsi/qla4xxx/ql4_mbx.c +++ b/drivers/scsi/qla4xxx/ql4_mbx.c | |||
| @@ -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 f4ea58ee8673..cd15678f9ada 100644 --- a/drivers/scsi/qla4xxx/ql4_os.c +++ b/drivers/scsi/qla4xxx/ql4_os.c | |||
| @@ -82,6 +82,20 @@ MODULE_PARM_DESC(ql4xsess_recovery_tmo, | |||
| 82 | " Target Session Recovery Timeout.\n" | 82 | " Target Session Recovery Timeout.\n" |
| 83 | "\t\t Default: 120 sec."); | 83 | "\t\t Default: 120 sec."); |
| 84 | 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 | |||
| 85 | 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); |
| 86 | /* | 100 | /* |
| 87 | * SCSI host template entry points | 101 | * SCSI host template entry points |
| @@ -2265,6 +2279,9 @@ static void qla4xxx_mem_free(struct scsi_qla_host *ha) | |||
| 2265 | dma_free_coherent(&ha->pdev->dev, ha->queues_len, ha->queues, | 2279 | dma_free_coherent(&ha->pdev->dev, ha->queues_len, ha->queues, |
| 2266 | ha->queues_dma); | 2280 | ha->queues_dma); |
| 2267 | 2281 | ||
| 2282 | if (ha->fw_dump) | ||
| 2283 | vfree(ha->fw_dump); | ||
| 2284 | |||
| 2268 | ha->queues_len = 0; | 2285 | ha->queues_len = 0; |
| 2269 | ha->queues = NULL; | 2286 | ha->queues = NULL; |
| 2270 | ha->queues_dma = 0; | 2287 | ha->queues_dma = 0; |
| @@ -2274,6 +2291,8 @@ static void qla4xxx_mem_free(struct scsi_qla_host *ha) | |||
| 2274 | ha->response_dma = 0; | 2291 | ha->response_dma = 0; |
| 2275 | ha->shadow_regs = NULL; | 2292 | ha->shadow_regs = NULL; |
| 2276 | ha->shadow_regs_dma = 0; | 2293 | ha->shadow_regs_dma = 0; |
| 2294 | ha->fw_dump = NULL; | ||
| 2295 | ha->fw_dump_size = 0; | ||
| 2277 | 2296 | ||
| 2278 | /* Free srb pool. */ | 2297 | /* Free srb pool. */ |
| 2279 | if (ha->srb_mempool) | 2298 | if (ha->srb_mempool) |
| @@ -5068,6 +5087,8 @@ static int __devinit qla4xxx_probe_adapter(struct pci_dev *pdev, | |||
| 5068 | 5087 | ||
| 5069 | set_bit(AF_INIT_DONE, &ha->flags); | 5088 | set_bit(AF_INIT_DONE, &ha->flags); |
| 5070 | 5089 | ||
| 5090 | qla4_8xxx_alloc_sysfs_attr(ha); | ||
| 5091 | |||
| 5071 | printk(KERN_INFO | 5092 | printk(KERN_INFO |
| 5072 | " QLogic iSCSI HBA Driver version: %s\n" | 5093 | " QLogic iSCSI HBA Driver version: %s\n" |
| 5073 | " 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", |
| @@ -5194,6 +5215,7 @@ static void __devexit qla4xxx_remove_adapter(struct pci_dev *pdev) | |||
| 5194 | iscsi_boot_destroy_kset(ha->boot_kset); | 5215 | iscsi_boot_destroy_kset(ha->boot_kset); |
| 5195 | 5216 | ||
| 5196 | qla4xxx_destroy_fw_ddb_session(ha); | 5217 | qla4xxx_destroy_fw_ddb_session(ha); |
| 5218 | qla4_8xxx_free_sysfs_attr(ha); | ||
| 5197 | 5219 | ||
| 5198 | scsi_remove_host(ha->host); | 5220 | scsi_remove_host(ha->host); |
| 5199 | 5221 | ||
