18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * QLogic Fibre Channel HBA Driver 48c2ecf20Sopenharmony_ci * Copyright (c) 2003-2014 QLogic Corporation 58c2ecf20Sopenharmony_ci */ 68c2ecf20Sopenharmony_ci 78c2ecf20Sopenharmony_ci#include <linux/vmalloc.h> 88c2ecf20Sopenharmony_ci#include <linux/delay.h> 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci#include "qla_def.h" 118c2ecf20Sopenharmony_ci#include "qla_gbl.h" 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_ci#define TIMEOUT_100_MS 100 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_cistatic const uint32_t qla8044_reg_tbl[] = { 168c2ecf20Sopenharmony_ci QLA8044_PEG_HALT_STATUS1, 178c2ecf20Sopenharmony_ci QLA8044_PEG_HALT_STATUS2, 188c2ecf20Sopenharmony_ci QLA8044_PEG_ALIVE_COUNTER, 198c2ecf20Sopenharmony_ci QLA8044_CRB_DRV_ACTIVE, 208c2ecf20Sopenharmony_ci QLA8044_CRB_DEV_STATE, 218c2ecf20Sopenharmony_ci QLA8044_CRB_DRV_STATE, 228c2ecf20Sopenharmony_ci QLA8044_CRB_DRV_SCRATCH, 238c2ecf20Sopenharmony_ci QLA8044_CRB_DEV_PART_INFO1, 248c2ecf20Sopenharmony_ci QLA8044_CRB_IDC_VER_MAJOR, 258c2ecf20Sopenharmony_ci QLA8044_FW_VER_MAJOR, 268c2ecf20Sopenharmony_ci QLA8044_FW_VER_MINOR, 278c2ecf20Sopenharmony_ci QLA8044_FW_VER_SUB, 288c2ecf20Sopenharmony_ci QLA8044_CMDPEG_STATE, 298c2ecf20Sopenharmony_ci QLA8044_ASIC_TEMP, 308c2ecf20Sopenharmony_ci}; 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci/* 8044 Flash Read/Write functions */ 338c2ecf20Sopenharmony_ciuint32_t 348c2ecf20Sopenharmony_ciqla8044_rd_reg(struct qla_hw_data *ha, ulong addr) 358c2ecf20Sopenharmony_ci{ 368c2ecf20Sopenharmony_ci return readl((void __iomem *) (ha->nx_pcibase + addr)); 378c2ecf20Sopenharmony_ci} 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_civoid 408c2ecf20Sopenharmony_ciqla8044_wr_reg(struct qla_hw_data *ha, ulong addr, uint32_t val) 418c2ecf20Sopenharmony_ci{ 428c2ecf20Sopenharmony_ci writel(val, (void __iomem *)((ha)->nx_pcibase + addr)); 438c2ecf20Sopenharmony_ci} 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ciint 468c2ecf20Sopenharmony_ciqla8044_rd_direct(struct scsi_qla_host *vha, 478c2ecf20Sopenharmony_ci const uint32_t crb_reg) 488c2ecf20Sopenharmony_ci{ 498c2ecf20Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_ci if (crb_reg < CRB_REG_INDEX_MAX) 528c2ecf20Sopenharmony_ci return qla8044_rd_reg(ha, qla8044_reg_tbl[crb_reg]); 538c2ecf20Sopenharmony_ci else 548c2ecf20Sopenharmony_ci return QLA_FUNCTION_FAILED; 558c2ecf20Sopenharmony_ci} 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_civoid 588c2ecf20Sopenharmony_ciqla8044_wr_direct(struct scsi_qla_host *vha, 598c2ecf20Sopenharmony_ci const uint32_t crb_reg, 608c2ecf20Sopenharmony_ci const uint32_t value) 618c2ecf20Sopenharmony_ci{ 628c2ecf20Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci if (crb_reg < CRB_REG_INDEX_MAX) 658c2ecf20Sopenharmony_ci qla8044_wr_reg(ha, qla8044_reg_tbl[crb_reg], value); 668c2ecf20Sopenharmony_ci} 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_cistatic int 698c2ecf20Sopenharmony_ciqla8044_set_win_base(scsi_qla_host_t *vha, uint32_t addr) 708c2ecf20Sopenharmony_ci{ 718c2ecf20Sopenharmony_ci uint32_t val; 728c2ecf20Sopenharmony_ci int ret_val = QLA_SUCCESS; 738c2ecf20Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ci qla8044_wr_reg(ha, QLA8044_CRB_WIN_FUNC(ha->portnum), addr); 768c2ecf20Sopenharmony_ci val = qla8044_rd_reg(ha, QLA8044_CRB_WIN_FUNC(ha->portnum)); 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ci if (val != addr) { 798c2ecf20Sopenharmony_ci ql_log(ql_log_warn, vha, 0xb087, 808c2ecf20Sopenharmony_ci "%s: Failed to set register window : " 818c2ecf20Sopenharmony_ci "addr written 0x%x, read 0x%x!\n", 828c2ecf20Sopenharmony_ci __func__, addr, val); 838c2ecf20Sopenharmony_ci ret_val = QLA_FUNCTION_FAILED; 848c2ecf20Sopenharmony_ci } 858c2ecf20Sopenharmony_ci return ret_val; 868c2ecf20Sopenharmony_ci} 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_cistatic int 898c2ecf20Sopenharmony_ciqla8044_rd_reg_indirect(scsi_qla_host_t *vha, uint32_t addr, uint32_t *data) 908c2ecf20Sopenharmony_ci{ 918c2ecf20Sopenharmony_ci int ret_val = QLA_SUCCESS; 928c2ecf20Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci ret_val = qla8044_set_win_base(vha, addr); 958c2ecf20Sopenharmony_ci if (!ret_val) 968c2ecf20Sopenharmony_ci *data = qla8044_rd_reg(ha, QLA8044_WILDCARD); 978c2ecf20Sopenharmony_ci else 988c2ecf20Sopenharmony_ci ql_log(ql_log_warn, vha, 0xb088, 998c2ecf20Sopenharmony_ci "%s: failed read of addr 0x%x!\n", __func__, addr); 1008c2ecf20Sopenharmony_ci return ret_val; 1018c2ecf20Sopenharmony_ci} 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_cistatic int 1048c2ecf20Sopenharmony_ciqla8044_wr_reg_indirect(scsi_qla_host_t *vha, uint32_t addr, uint32_t data) 1058c2ecf20Sopenharmony_ci{ 1068c2ecf20Sopenharmony_ci int ret_val = QLA_SUCCESS; 1078c2ecf20Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ci ret_val = qla8044_set_win_base(vha, addr); 1108c2ecf20Sopenharmony_ci if (!ret_val) 1118c2ecf20Sopenharmony_ci qla8044_wr_reg(ha, QLA8044_WILDCARD, data); 1128c2ecf20Sopenharmony_ci else 1138c2ecf20Sopenharmony_ci ql_log(ql_log_warn, vha, 0xb089, 1148c2ecf20Sopenharmony_ci "%s: failed wrt to addr 0x%x, data 0x%x\n", 1158c2ecf20Sopenharmony_ci __func__, addr, data); 1168c2ecf20Sopenharmony_ci return ret_val; 1178c2ecf20Sopenharmony_ci} 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_ci/* 1208c2ecf20Sopenharmony_ci * qla8044_read_write_crb_reg - Read from raddr and write value to waddr. 1218c2ecf20Sopenharmony_ci * 1228c2ecf20Sopenharmony_ci * @ha : Pointer to adapter structure 1238c2ecf20Sopenharmony_ci * @raddr : CRB address to read from 1248c2ecf20Sopenharmony_ci * @waddr : CRB address to write to 1258c2ecf20Sopenharmony_ci * 1268c2ecf20Sopenharmony_ci */ 1278c2ecf20Sopenharmony_cistatic void 1288c2ecf20Sopenharmony_ciqla8044_read_write_crb_reg(struct scsi_qla_host *vha, 1298c2ecf20Sopenharmony_ci uint32_t raddr, uint32_t waddr) 1308c2ecf20Sopenharmony_ci{ 1318c2ecf20Sopenharmony_ci uint32_t value; 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci qla8044_rd_reg_indirect(vha, raddr, &value); 1348c2ecf20Sopenharmony_ci qla8044_wr_reg_indirect(vha, waddr, value); 1358c2ecf20Sopenharmony_ci} 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_cistatic int 1388c2ecf20Sopenharmony_ciqla8044_poll_wait_for_ready(struct scsi_qla_host *vha, uint32_t addr1, 1398c2ecf20Sopenharmony_ci uint32_t mask) 1408c2ecf20Sopenharmony_ci{ 1418c2ecf20Sopenharmony_ci unsigned long timeout; 1428c2ecf20Sopenharmony_ci uint32_t temp; 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_ci /* jiffies after 100ms */ 1458c2ecf20Sopenharmony_ci timeout = jiffies + msecs_to_jiffies(TIMEOUT_100_MS); 1468c2ecf20Sopenharmony_ci do { 1478c2ecf20Sopenharmony_ci qla8044_rd_reg_indirect(vha, addr1, &temp); 1488c2ecf20Sopenharmony_ci if ((temp & mask) != 0) 1498c2ecf20Sopenharmony_ci break; 1508c2ecf20Sopenharmony_ci if (time_after_eq(jiffies, timeout)) { 1518c2ecf20Sopenharmony_ci ql_log(ql_log_warn, vha, 0xb151, 1528c2ecf20Sopenharmony_ci "Error in processing rdmdio entry\n"); 1538c2ecf20Sopenharmony_ci return -1; 1548c2ecf20Sopenharmony_ci } 1558c2ecf20Sopenharmony_ci } while (1); 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci return 0; 1588c2ecf20Sopenharmony_ci} 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_cistatic uint32_t 1618c2ecf20Sopenharmony_ciqla8044_ipmdio_rd_reg(struct scsi_qla_host *vha, 1628c2ecf20Sopenharmony_ci uint32_t addr1, uint32_t addr3, uint32_t mask, uint32_t addr) 1638c2ecf20Sopenharmony_ci{ 1648c2ecf20Sopenharmony_ci uint32_t temp; 1658c2ecf20Sopenharmony_ci int ret = 0; 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_ci ret = qla8044_poll_wait_for_ready(vha, addr1, mask); 1688c2ecf20Sopenharmony_ci if (ret == -1) 1698c2ecf20Sopenharmony_ci return -1; 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_ci temp = (0x40000000 | addr); 1728c2ecf20Sopenharmony_ci qla8044_wr_reg_indirect(vha, addr1, temp); 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_ci ret = qla8044_poll_wait_for_ready(vha, addr1, mask); 1758c2ecf20Sopenharmony_ci if (ret == -1) 1768c2ecf20Sopenharmony_ci return 0; 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_ci qla8044_rd_reg_indirect(vha, addr3, &ret); 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_ci return ret; 1818c2ecf20Sopenharmony_ci} 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_cistatic int 1858c2ecf20Sopenharmony_ciqla8044_poll_wait_ipmdio_bus_idle(struct scsi_qla_host *vha, 1868c2ecf20Sopenharmony_ci uint32_t addr1, uint32_t addr2, uint32_t addr3, uint32_t mask) 1878c2ecf20Sopenharmony_ci{ 1888c2ecf20Sopenharmony_ci unsigned long timeout; 1898c2ecf20Sopenharmony_ci uint32_t temp; 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_ci /* jiffies after 100 msecs */ 1928c2ecf20Sopenharmony_ci timeout = jiffies + msecs_to_jiffies(TIMEOUT_100_MS); 1938c2ecf20Sopenharmony_ci do { 1948c2ecf20Sopenharmony_ci temp = qla8044_ipmdio_rd_reg(vha, addr1, addr3, mask, addr2); 1958c2ecf20Sopenharmony_ci if ((temp & 0x1) != 1) 1968c2ecf20Sopenharmony_ci break; 1978c2ecf20Sopenharmony_ci if (time_after_eq(jiffies, timeout)) { 1988c2ecf20Sopenharmony_ci ql_log(ql_log_warn, vha, 0xb152, 1998c2ecf20Sopenharmony_ci "Error in processing mdiobus idle\n"); 2008c2ecf20Sopenharmony_ci return -1; 2018c2ecf20Sopenharmony_ci } 2028c2ecf20Sopenharmony_ci } while (1); 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_ci return 0; 2058c2ecf20Sopenharmony_ci} 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_cistatic int 2088c2ecf20Sopenharmony_ciqla8044_ipmdio_wr_reg(struct scsi_qla_host *vha, uint32_t addr1, 2098c2ecf20Sopenharmony_ci uint32_t addr3, uint32_t mask, uint32_t addr, uint32_t value) 2108c2ecf20Sopenharmony_ci{ 2118c2ecf20Sopenharmony_ci int ret = 0; 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ci ret = qla8044_poll_wait_for_ready(vha, addr1, mask); 2148c2ecf20Sopenharmony_ci if (ret == -1) 2158c2ecf20Sopenharmony_ci return -1; 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_ci qla8044_wr_reg_indirect(vha, addr3, value); 2188c2ecf20Sopenharmony_ci qla8044_wr_reg_indirect(vha, addr1, addr); 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_ci ret = qla8044_poll_wait_for_ready(vha, addr1, mask); 2218c2ecf20Sopenharmony_ci if (ret == -1) 2228c2ecf20Sopenharmony_ci return -1; 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_ci return 0; 2258c2ecf20Sopenharmony_ci} 2268c2ecf20Sopenharmony_ci/* 2278c2ecf20Sopenharmony_ci * qla8044_rmw_crb_reg - Read value from raddr, AND with test_mask, 2288c2ecf20Sopenharmony_ci * Shift Left,Right/OR/XOR with values RMW header and write value to waddr. 2298c2ecf20Sopenharmony_ci * 2308c2ecf20Sopenharmony_ci * @vha : Pointer to adapter structure 2318c2ecf20Sopenharmony_ci * @raddr : CRB address to read from 2328c2ecf20Sopenharmony_ci * @waddr : CRB address to write to 2338c2ecf20Sopenharmony_ci * @p_rmw_hdr : header with shift/or/xor values. 2348c2ecf20Sopenharmony_ci * 2358c2ecf20Sopenharmony_ci */ 2368c2ecf20Sopenharmony_cistatic void 2378c2ecf20Sopenharmony_ciqla8044_rmw_crb_reg(struct scsi_qla_host *vha, 2388c2ecf20Sopenharmony_ci uint32_t raddr, uint32_t waddr, struct qla8044_rmw *p_rmw_hdr) 2398c2ecf20Sopenharmony_ci{ 2408c2ecf20Sopenharmony_ci uint32_t value; 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ci if (p_rmw_hdr->index_a) 2438c2ecf20Sopenharmony_ci value = vha->reset_tmplt.array[p_rmw_hdr->index_a]; 2448c2ecf20Sopenharmony_ci else 2458c2ecf20Sopenharmony_ci qla8044_rd_reg_indirect(vha, raddr, &value); 2468c2ecf20Sopenharmony_ci value &= p_rmw_hdr->test_mask; 2478c2ecf20Sopenharmony_ci value <<= p_rmw_hdr->shl; 2488c2ecf20Sopenharmony_ci value >>= p_rmw_hdr->shr; 2498c2ecf20Sopenharmony_ci value |= p_rmw_hdr->or_value; 2508c2ecf20Sopenharmony_ci value ^= p_rmw_hdr->xor_value; 2518c2ecf20Sopenharmony_ci qla8044_wr_reg_indirect(vha, waddr, value); 2528c2ecf20Sopenharmony_ci return; 2538c2ecf20Sopenharmony_ci} 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_cistatic inline void 2568c2ecf20Sopenharmony_ciqla8044_set_qsnt_ready(struct scsi_qla_host *vha) 2578c2ecf20Sopenharmony_ci{ 2588c2ecf20Sopenharmony_ci uint32_t qsnt_state; 2598c2ecf20Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_ci qsnt_state = qla8044_rd_direct(vha, QLA8044_CRB_DRV_STATE_INDEX); 2628c2ecf20Sopenharmony_ci qsnt_state |= (1 << ha->portnum); 2638c2ecf20Sopenharmony_ci qla8044_wr_direct(vha, QLA8044_CRB_DRV_STATE_INDEX, qsnt_state); 2648c2ecf20Sopenharmony_ci ql_log(ql_log_info, vha, 0xb08e, "%s(%ld): qsnt_state: 0x%08x\n", 2658c2ecf20Sopenharmony_ci __func__, vha->host_no, qsnt_state); 2668c2ecf20Sopenharmony_ci} 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_civoid 2698c2ecf20Sopenharmony_ciqla8044_clear_qsnt_ready(struct scsi_qla_host *vha) 2708c2ecf20Sopenharmony_ci{ 2718c2ecf20Sopenharmony_ci uint32_t qsnt_state; 2728c2ecf20Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_ci qsnt_state = qla8044_rd_direct(vha, QLA8044_CRB_DRV_STATE_INDEX); 2758c2ecf20Sopenharmony_ci qsnt_state &= ~(1 << ha->portnum); 2768c2ecf20Sopenharmony_ci qla8044_wr_direct(vha, QLA8044_CRB_DRV_STATE_INDEX, qsnt_state); 2778c2ecf20Sopenharmony_ci ql_log(ql_log_info, vha, 0xb08f, "%s(%ld): qsnt_state: 0x%08x\n", 2788c2ecf20Sopenharmony_ci __func__, vha->host_no, qsnt_state); 2798c2ecf20Sopenharmony_ci} 2808c2ecf20Sopenharmony_ci 2818c2ecf20Sopenharmony_ci/** 2828c2ecf20Sopenharmony_ci * qla8044_lock_recovery - Recovers the idc_lock. 2838c2ecf20Sopenharmony_ci * @vha : Pointer to adapter structure 2848c2ecf20Sopenharmony_ci * 2858c2ecf20Sopenharmony_ci * Lock Recovery Register 2868c2ecf20Sopenharmony_ci * 5-2 Lock recovery owner: Function ID of driver doing lock recovery, 2878c2ecf20Sopenharmony_ci * valid if bits 1..0 are set by driver doing lock recovery. 2888c2ecf20Sopenharmony_ci * 1-0 1 - Driver intends to force unlock the IDC lock. 2898c2ecf20Sopenharmony_ci * 2 - Driver is moving forward to unlock the IDC lock. Driver clears 2908c2ecf20Sopenharmony_ci * this field after force unlocking the IDC lock. 2918c2ecf20Sopenharmony_ci * 2928c2ecf20Sopenharmony_ci * Lock Recovery process 2938c2ecf20Sopenharmony_ci * a. Read the IDC_LOCK_RECOVERY register. If the value in bits 1..0 is 2948c2ecf20Sopenharmony_ci * greater than 0, then wait for the other driver to unlock otherwise 2958c2ecf20Sopenharmony_ci * move to the next step. 2968c2ecf20Sopenharmony_ci * b. Indicate intent to force-unlock by writing 1h to the IDC_LOCK_RECOVERY 2978c2ecf20Sopenharmony_ci * register bits 1..0 and also set the function# in bits 5..2. 2988c2ecf20Sopenharmony_ci * c. Read the IDC_LOCK_RECOVERY register again after a delay of 200ms. 2998c2ecf20Sopenharmony_ci * Wait for the other driver to perform lock recovery if the function 3008c2ecf20Sopenharmony_ci * number in bits 5..2 has changed, otherwise move to the next step. 3018c2ecf20Sopenharmony_ci * d. Write a value of 2h to the IDC_LOCK_RECOVERY register bits 1..0 3028c2ecf20Sopenharmony_ci * leaving your function# in bits 5..2. 3038c2ecf20Sopenharmony_ci * e. Force unlock using the DRIVER_UNLOCK register and immediately clear 3048c2ecf20Sopenharmony_ci * the IDC_LOCK_RECOVERY bits 5..0 by writing 0. 3058c2ecf20Sopenharmony_ci **/ 3068c2ecf20Sopenharmony_cistatic int 3078c2ecf20Sopenharmony_ciqla8044_lock_recovery(struct scsi_qla_host *vha) 3088c2ecf20Sopenharmony_ci{ 3098c2ecf20Sopenharmony_ci uint32_t lock = 0, lockid; 3108c2ecf20Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_ci lockid = qla8044_rd_reg(ha, QLA8044_DRV_LOCKRECOVERY); 3138c2ecf20Sopenharmony_ci 3148c2ecf20Sopenharmony_ci /* Check for other Recovery in progress, go wait */ 3158c2ecf20Sopenharmony_ci if ((lockid & IDC_LOCK_RECOVERY_STATE_MASK) != 0) 3168c2ecf20Sopenharmony_ci return QLA_FUNCTION_FAILED; 3178c2ecf20Sopenharmony_ci 3188c2ecf20Sopenharmony_ci /* Intent to Recover */ 3198c2ecf20Sopenharmony_ci qla8044_wr_reg(ha, QLA8044_DRV_LOCKRECOVERY, 3208c2ecf20Sopenharmony_ci (ha->portnum << 3218c2ecf20Sopenharmony_ci IDC_LOCK_RECOVERY_STATE_SHIFT_BITS) | INTENT_TO_RECOVER); 3228c2ecf20Sopenharmony_ci msleep(200); 3238c2ecf20Sopenharmony_ci 3248c2ecf20Sopenharmony_ci /* Check Intent to Recover is advertised */ 3258c2ecf20Sopenharmony_ci lockid = qla8044_rd_reg(ha, QLA8044_DRV_LOCKRECOVERY); 3268c2ecf20Sopenharmony_ci if ((lockid & IDC_LOCK_RECOVERY_OWNER_MASK) != (ha->portnum << 3278c2ecf20Sopenharmony_ci IDC_LOCK_RECOVERY_STATE_SHIFT_BITS)) 3288c2ecf20Sopenharmony_ci return QLA_FUNCTION_FAILED; 3298c2ecf20Sopenharmony_ci 3308c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_p3p, vha, 0xb08B, "%s:%d: IDC Lock recovery initiated\n" 3318c2ecf20Sopenharmony_ci , __func__, ha->portnum); 3328c2ecf20Sopenharmony_ci 3338c2ecf20Sopenharmony_ci /* Proceed to Recover */ 3348c2ecf20Sopenharmony_ci qla8044_wr_reg(ha, QLA8044_DRV_LOCKRECOVERY, 3358c2ecf20Sopenharmony_ci (ha->portnum << IDC_LOCK_RECOVERY_STATE_SHIFT_BITS) | 3368c2ecf20Sopenharmony_ci PROCEED_TO_RECOVER); 3378c2ecf20Sopenharmony_ci 3388c2ecf20Sopenharmony_ci /* Force Unlock() */ 3398c2ecf20Sopenharmony_ci qla8044_wr_reg(ha, QLA8044_DRV_LOCK_ID, 0xFF); 3408c2ecf20Sopenharmony_ci qla8044_rd_reg(ha, QLA8044_DRV_UNLOCK); 3418c2ecf20Sopenharmony_ci 3428c2ecf20Sopenharmony_ci /* Clear bits 0-5 in IDC_RECOVERY register*/ 3438c2ecf20Sopenharmony_ci qla8044_wr_reg(ha, QLA8044_DRV_LOCKRECOVERY, 0); 3448c2ecf20Sopenharmony_ci 3458c2ecf20Sopenharmony_ci /* Get lock() */ 3468c2ecf20Sopenharmony_ci lock = qla8044_rd_reg(ha, QLA8044_DRV_LOCK); 3478c2ecf20Sopenharmony_ci if (lock) { 3488c2ecf20Sopenharmony_ci lockid = qla8044_rd_reg(ha, QLA8044_DRV_LOCK_ID); 3498c2ecf20Sopenharmony_ci lockid = ((lockid + (1 << 8)) & ~0xFF) | ha->portnum; 3508c2ecf20Sopenharmony_ci qla8044_wr_reg(ha, QLA8044_DRV_LOCK_ID, lockid); 3518c2ecf20Sopenharmony_ci return QLA_SUCCESS; 3528c2ecf20Sopenharmony_ci } else 3538c2ecf20Sopenharmony_ci return QLA_FUNCTION_FAILED; 3548c2ecf20Sopenharmony_ci} 3558c2ecf20Sopenharmony_ci 3568c2ecf20Sopenharmony_ciint 3578c2ecf20Sopenharmony_ciqla8044_idc_lock(struct qla_hw_data *ha) 3588c2ecf20Sopenharmony_ci{ 3598c2ecf20Sopenharmony_ci uint32_t ret_val = QLA_SUCCESS, timeout = 0, status = 0; 3608c2ecf20Sopenharmony_ci uint32_t lock_id, lock_cnt, func_num, tmo_owner = 0, first_owner = 0; 3618c2ecf20Sopenharmony_ci scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev); 3628c2ecf20Sopenharmony_ci 3638c2ecf20Sopenharmony_ci while (status == 0) { 3648c2ecf20Sopenharmony_ci /* acquire semaphore5 from PCI HW block */ 3658c2ecf20Sopenharmony_ci status = qla8044_rd_reg(ha, QLA8044_DRV_LOCK); 3668c2ecf20Sopenharmony_ci 3678c2ecf20Sopenharmony_ci if (status) { 3688c2ecf20Sopenharmony_ci /* Increment Counter (8-31) and update func_num (0-7) on 3698c2ecf20Sopenharmony_ci * getting a successful lock */ 3708c2ecf20Sopenharmony_ci lock_id = qla8044_rd_reg(ha, QLA8044_DRV_LOCK_ID); 3718c2ecf20Sopenharmony_ci lock_id = ((lock_id + (1 << 8)) & ~0xFF) | ha->portnum; 3728c2ecf20Sopenharmony_ci qla8044_wr_reg(ha, QLA8044_DRV_LOCK_ID, lock_id); 3738c2ecf20Sopenharmony_ci break; 3748c2ecf20Sopenharmony_ci } 3758c2ecf20Sopenharmony_ci 3768c2ecf20Sopenharmony_ci if (timeout == 0) 3778c2ecf20Sopenharmony_ci first_owner = qla8044_rd_reg(ha, QLA8044_DRV_LOCK_ID); 3788c2ecf20Sopenharmony_ci 3798c2ecf20Sopenharmony_ci if (++timeout >= 3808c2ecf20Sopenharmony_ci (QLA8044_DRV_LOCK_TIMEOUT / QLA8044_DRV_LOCK_MSLEEP)) { 3818c2ecf20Sopenharmony_ci tmo_owner = qla8044_rd_reg(ha, QLA8044_DRV_LOCK_ID); 3828c2ecf20Sopenharmony_ci func_num = tmo_owner & 0xFF; 3838c2ecf20Sopenharmony_ci lock_cnt = tmo_owner >> 8; 3848c2ecf20Sopenharmony_ci ql_log(ql_log_warn, vha, 0xb114, 3858c2ecf20Sopenharmony_ci "%s: Lock by func %d failed after 2s, lock held " 3868c2ecf20Sopenharmony_ci "by func %d, lock count %d, first_owner %d\n", 3878c2ecf20Sopenharmony_ci __func__, ha->portnum, func_num, lock_cnt, 3888c2ecf20Sopenharmony_ci (first_owner & 0xFF)); 3898c2ecf20Sopenharmony_ci if (first_owner != tmo_owner) { 3908c2ecf20Sopenharmony_ci /* Some other driver got lock, 3918c2ecf20Sopenharmony_ci * OR same driver got lock again (counter 3928c2ecf20Sopenharmony_ci * value changed), when we were waiting for 3938c2ecf20Sopenharmony_ci * lock. Retry for another 2 sec */ 3948c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_p3p, vha, 0xb115, 3958c2ecf20Sopenharmony_ci "%s: %d: IDC lock failed\n", 3968c2ecf20Sopenharmony_ci __func__, ha->portnum); 3978c2ecf20Sopenharmony_ci timeout = 0; 3988c2ecf20Sopenharmony_ci } else { 3998c2ecf20Sopenharmony_ci /* Same driver holding lock > 2sec. 4008c2ecf20Sopenharmony_ci * Force Recovery */ 4018c2ecf20Sopenharmony_ci if (qla8044_lock_recovery(vha) == QLA_SUCCESS) { 4028c2ecf20Sopenharmony_ci /* Recovered and got lock */ 4038c2ecf20Sopenharmony_ci ret_val = QLA_SUCCESS; 4048c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_p3p, vha, 0xb116, 4058c2ecf20Sopenharmony_ci "%s:IDC lock Recovery by %d" 4068c2ecf20Sopenharmony_ci "successful...\n", __func__, 4078c2ecf20Sopenharmony_ci ha->portnum); 4088c2ecf20Sopenharmony_ci } 4098c2ecf20Sopenharmony_ci /* Recovery Failed, some other function 4108c2ecf20Sopenharmony_ci * has the lock, wait for 2secs 4118c2ecf20Sopenharmony_ci * and retry 4128c2ecf20Sopenharmony_ci */ 4138c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_p3p, vha, 0xb08a, 4148c2ecf20Sopenharmony_ci "%s: IDC lock Recovery by %d " 4158c2ecf20Sopenharmony_ci "failed, Retrying timeout\n", __func__, 4168c2ecf20Sopenharmony_ci ha->portnum); 4178c2ecf20Sopenharmony_ci timeout = 0; 4188c2ecf20Sopenharmony_ci } 4198c2ecf20Sopenharmony_ci } 4208c2ecf20Sopenharmony_ci msleep(QLA8044_DRV_LOCK_MSLEEP); 4218c2ecf20Sopenharmony_ci } 4228c2ecf20Sopenharmony_ci return ret_val; 4238c2ecf20Sopenharmony_ci} 4248c2ecf20Sopenharmony_ci 4258c2ecf20Sopenharmony_civoid 4268c2ecf20Sopenharmony_ciqla8044_idc_unlock(struct qla_hw_data *ha) 4278c2ecf20Sopenharmony_ci{ 4288c2ecf20Sopenharmony_ci int id; 4298c2ecf20Sopenharmony_ci scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev); 4308c2ecf20Sopenharmony_ci 4318c2ecf20Sopenharmony_ci id = qla8044_rd_reg(ha, QLA8044_DRV_LOCK_ID); 4328c2ecf20Sopenharmony_ci 4338c2ecf20Sopenharmony_ci if ((id & 0xFF) != ha->portnum) { 4348c2ecf20Sopenharmony_ci ql_log(ql_log_warn, vha, 0xb118, 4358c2ecf20Sopenharmony_ci "%s: IDC Unlock by %d failed, lock owner is %d!\n", 4368c2ecf20Sopenharmony_ci __func__, ha->portnum, (id & 0xFF)); 4378c2ecf20Sopenharmony_ci return; 4388c2ecf20Sopenharmony_ci } 4398c2ecf20Sopenharmony_ci 4408c2ecf20Sopenharmony_ci /* Keep lock counter value, update the ha->func_num to 0xFF */ 4418c2ecf20Sopenharmony_ci qla8044_wr_reg(ha, QLA8044_DRV_LOCK_ID, (id | 0xFF)); 4428c2ecf20Sopenharmony_ci qla8044_rd_reg(ha, QLA8044_DRV_UNLOCK); 4438c2ecf20Sopenharmony_ci} 4448c2ecf20Sopenharmony_ci 4458c2ecf20Sopenharmony_ci/* 8044 Flash Lock/Unlock functions */ 4468c2ecf20Sopenharmony_cistatic int 4478c2ecf20Sopenharmony_ciqla8044_flash_lock(scsi_qla_host_t *vha) 4488c2ecf20Sopenharmony_ci{ 4498c2ecf20Sopenharmony_ci int lock_owner; 4508c2ecf20Sopenharmony_ci int timeout = 0; 4518c2ecf20Sopenharmony_ci uint32_t lock_status = 0; 4528c2ecf20Sopenharmony_ci int ret_val = QLA_SUCCESS; 4538c2ecf20Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 4548c2ecf20Sopenharmony_ci 4558c2ecf20Sopenharmony_ci while (lock_status == 0) { 4568c2ecf20Sopenharmony_ci lock_status = qla8044_rd_reg(ha, QLA8044_FLASH_LOCK); 4578c2ecf20Sopenharmony_ci if (lock_status) 4588c2ecf20Sopenharmony_ci break; 4598c2ecf20Sopenharmony_ci 4608c2ecf20Sopenharmony_ci if (++timeout >= QLA8044_FLASH_LOCK_TIMEOUT / 20) { 4618c2ecf20Sopenharmony_ci lock_owner = qla8044_rd_reg(ha, 4628c2ecf20Sopenharmony_ci QLA8044_FLASH_LOCK_ID); 4638c2ecf20Sopenharmony_ci ql_log(ql_log_warn, vha, 0xb113, 4648c2ecf20Sopenharmony_ci "%s: Simultaneous flash access by following ports, active port = %d: accessing port = %d", 4658c2ecf20Sopenharmony_ci __func__, ha->portnum, lock_owner); 4668c2ecf20Sopenharmony_ci ret_val = QLA_FUNCTION_FAILED; 4678c2ecf20Sopenharmony_ci break; 4688c2ecf20Sopenharmony_ci } 4698c2ecf20Sopenharmony_ci msleep(20); 4708c2ecf20Sopenharmony_ci } 4718c2ecf20Sopenharmony_ci qla8044_wr_reg(ha, QLA8044_FLASH_LOCK_ID, ha->portnum); 4728c2ecf20Sopenharmony_ci return ret_val; 4738c2ecf20Sopenharmony_ci} 4748c2ecf20Sopenharmony_ci 4758c2ecf20Sopenharmony_cistatic void 4768c2ecf20Sopenharmony_ciqla8044_flash_unlock(scsi_qla_host_t *vha) 4778c2ecf20Sopenharmony_ci{ 4788c2ecf20Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 4798c2ecf20Sopenharmony_ci 4808c2ecf20Sopenharmony_ci /* Reading FLASH_UNLOCK register unlocks the Flash */ 4818c2ecf20Sopenharmony_ci qla8044_wr_reg(ha, QLA8044_FLASH_LOCK_ID, 0xFF); 4828c2ecf20Sopenharmony_ci qla8044_rd_reg(ha, QLA8044_FLASH_UNLOCK); 4838c2ecf20Sopenharmony_ci} 4848c2ecf20Sopenharmony_ci 4858c2ecf20Sopenharmony_ci 4868c2ecf20Sopenharmony_cistatic 4878c2ecf20Sopenharmony_civoid qla8044_flash_lock_recovery(struct scsi_qla_host *vha) 4888c2ecf20Sopenharmony_ci{ 4898c2ecf20Sopenharmony_ci 4908c2ecf20Sopenharmony_ci if (qla8044_flash_lock(vha)) { 4918c2ecf20Sopenharmony_ci /* Someone else is holding the lock. */ 4928c2ecf20Sopenharmony_ci ql_log(ql_log_warn, vha, 0xb120, "Resetting flash_lock\n"); 4938c2ecf20Sopenharmony_ci } 4948c2ecf20Sopenharmony_ci 4958c2ecf20Sopenharmony_ci /* 4968c2ecf20Sopenharmony_ci * Either we got the lock, or someone 4978c2ecf20Sopenharmony_ci * else died while holding it. 4988c2ecf20Sopenharmony_ci * In either case, unlock. 4998c2ecf20Sopenharmony_ci */ 5008c2ecf20Sopenharmony_ci qla8044_flash_unlock(vha); 5018c2ecf20Sopenharmony_ci} 5028c2ecf20Sopenharmony_ci 5038c2ecf20Sopenharmony_ci/* 5048c2ecf20Sopenharmony_ci * Address and length are byte address 5058c2ecf20Sopenharmony_ci */ 5068c2ecf20Sopenharmony_cistatic int 5078c2ecf20Sopenharmony_ciqla8044_read_flash_data(scsi_qla_host_t *vha, uint8_t *p_data, 5088c2ecf20Sopenharmony_ci uint32_t flash_addr, int u32_word_count) 5098c2ecf20Sopenharmony_ci{ 5108c2ecf20Sopenharmony_ci int i, ret_val = QLA_SUCCESS; 5118c2ecf20Sopenharmony_ci uint32_t u32_word; 5128c2ecf20Sopenharmony_ci 5138c2ecf20Sopenharmony_ci if (qla8044_flash_lock(vha) != QLA_SUCCESS) { 5148c2ecf20Sopenharmony_ci ret_val = QLA_FUNCTION_FAILED; 5158c2ecf20Sopenharmony_ci goto exit_lock_error; 5168c2ecf20Sopenharmony_ci } 5178c2ecf20Sopenharmony_ci 5188c2ecf20Sopenharmony_ci if (flash_addr & 0x03) { 5198c2ecf20Sopenharmony_ci ql_log(ql_log_warn, vha, 0xb117, 5208c2ecf20Sopenharmony_ci "%s: Illegal addr = 0x%x\n", __func__, flash_addr); 5218c2ecf20Sopenharmony_ci ret_val = QLA_FUNCTION_FAILED; 5228c2ecf20Sopenharmony_ci goto exit_flash_read; 5238c2ecf20Sopenharmony_ci } 5248c2ecf20Sopenharmony_ci 5258c2ecf20Sopenharmony_ci for (i = 0; i < u32_word_count; i++) { 5268c2ecf20Sopenharmony_ci if (qla8044_wr_reg_indirect(vha, QLA8044_FLASH_DIRECT_WINDOW, 5278c2ecf20Sopenharmony_ci (flash_addr & 0xFFFF0000))) { 5288c2ecf20Sopenharmony_ci ql_log(ql_log_warn, vha, 0xb119, 5298c2ecf20Sopenharmony_ci "%s: failed to write addr 0x%x to " 5308c2ecf20Sopenharmony_ci "FLASH_DIRECT_WINDOW\n! ", 5318c2ecf20Sopenharmony_ci __func__, flash_addr); 5328c2ecf20Sopenharmony_ci ret_val = QLA_FUNCTION_FAILED; 5338c2ecf20Sopenharmony_ci goto exit_flash_read; 5348c2ecf20Sopenharmony_ci } 5358c2ecf20Sopenharmony_ci 5368c2ecf20Sopenharmony_ci ret_val = qla8044_rd_reg_indirect(vha, 5378c2ecf20Sopenharmony_ci QLA8044_FLASH_DIRECT_DATA(flash_addr), 5388c2ecf20Sopenharmony_ci &u32_word); 5398c2ecf20Sopenharmony_ci if (ret_val != QLA_SUCCESS) { 5408c2ecf20Sopenharmony_ci ql_log(ql_log_warn, vha, 0xb08c, 5418c2ecf20Sopenharmony_ci "%s: failed to read addr 0x%x!\n", 5428c2ecf20Sopenharmony_ci __func__, flash_addr); 5438c2ecf20Sopenharmony_ci goto exit_flash_read; 5448c2ecf20Sopenharmony_ci } 5458c2ecf20Sopenharmony_ci 5468c2ecf20Sopenharmony_ci *(uint32_t *)p_data = u32_word; 5478c2ecf20Sopenharmony_ci p_data = p_data + 4; 5488c2ecf20Sopenharmony_ci flash_addr = flash_addr + 4; 5498c2ecf20Sopenharmony_ci } 5508c2ecf20Sopenharmony_ci 5518c2ecf20Sopenharmony_ciexit_flash_read: 5528c2ecf20Sopenharmony_ci qla8044_flash_unlock(vha); 5538c2ecf20Sopenharmony_ci 5548c2ecf20Sopenharmony_ciexit_lock_error: 5558c2ecf20Sopenharmony_ci return ret_val; 5568c2ecf20Sopenharmony_ci} 5578c2ecf20Sopenharmony_ci 5588c2ecf20Sopenharmony_ci/* 5598c2ecf20Sopenharmony_ci * Address and length are byte address 5608c2ecf20Sopenharmony_ci */ 5618c2ecf20Sopenharmony_civoid * 5628c2ecf20Sopenharmony_ciqla8044_read_optrom_data(struct scsi_qla_host *vha, void *buf, 5638c2ecf20Sopenharmony_ci uint32_t offset, uint32_t length) 5648c2ecf20Sopenharmony_ci{ 5658c2ecf20Sopenharmony_ci scsi_block_requests(vha->host); 5668c2ecf20Sopenharmony_ci if (qla8044_read_flash_data(vha, buf, offset, length / 4) 5678c2ecf20Sopenharmony_ci != QLA_SUCCESS) { 5688c2ecf20Sopenharmony_ci ql_log(ql_log_warn, vha, 0xb08d, 5698c2ecf20Sopenharmony_ci "%s: Failed to read from flash\n", 5708c2ecf20Sopenharmony_ci __func__); 5718c2ecf20Sopenharmony_ci } 5728c2ecf20Sopenharmony_ci scsi_unblock_requests(vha->host); 5738c2ecf20Sopenharmony_ci return buf; 5748c2ecf20Sopenharmony_ci} 5758c2ecf20Sopenharmony_ci 5768c2ecf20Sopenharmony_cistatic inline int 5778c2ecf20Sopenharmony_ciqla8044_need_reset(struct scsi_qla_host *vha) 5788c2ecf20Sopenharmony_ci{ 5798c2ecf20Sopenharmony_ci uint32_t drv_state, drv_active; 5808c2ecf20Sopenharmony_ci int rval; 5818c2ecf20Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 5828c2ecf20Sopenharmony_ci 5838c2ecf20Sopenharmony_ci drv_active = qla8044_rd_direct(vha, QLA8044_CRB_DRV_ACTIVE_INDEX); 5848c2ecf20Sopenharmony_ci drv_state = qla8044_rd_direct(vha, QLA8044_CRB_DRV_STATE_INDEX); 5858c2ecf20Sopenharmony_ci 5868c2ecf20Sopenharmony_ci rval = drv_state & (1 << ha->portnum); 5878c2ecf20Sopenharmony_ci 5888c2ecf20Sopenharmony_ci if (ha->flags.eeh_busy && drv_active) 5898c2ecf20Sopenharmony_ci rval = 1; 5908c2ecf20Sopenharmony_ci return rval; 5918c2ecf20Sopenharmony_ci} 5928c2ecf20Sopenharmony_ci 5938c2ecf20Sopenharmony_ci/* 5948c2ecf20Sopenharmony_ci * qla8044_write_list - Write the value (p_entry->arg2) to address specified 5958c2ecf20Sopenharmony_ci * by p_entry->arg1 for all entries in header with delay of p_hdr->delay between 5968c2ecf20Sopenharmony_ci * entries. 5978c2ecf20Sopenharmony_ci * 5988c2ecf20Sopenharmony_ci * @vha : Pointer to adapter structure 5998c2ecf20Sopenharmony_ci * @p_hdr : reset_entry header for WRITE_LIST opcode. 6008c2ecf20Sopenharmony_ci * 6018c2ecf20Sopenharmony_ci */ 6028c2ecf20Sopenharmony_cistatic void 6038c2ecf20Sopenharmony_ciqla8044_write_list(struct scsi_qla_host *vha, 6048c2ecf20Sopenharmony_ci struct qla8044_reset_entry_hdr *p_hdr) 6058c2ecf20Sopenharmony_ci{ 6068c2ecf20Sopenharmony_ci struct qla8044_entry *p_entry; 6078c2ecf20Sopenharmony_ci uint32_t i; 6088c2ecf20Sopenharmony_ci 6098c2ecf20Sopenharmony_ci p_entry = (struct qla8044_entry *)((char *)p_hdr + 6108c2ecf20Sopenharmony_ci sizeof(struct qla8044_reset_entry_hdr)); 6118c2ecf20Sopenharmony_ci 6128c2ecf20Sopenharmony_ci for (i = 0; i < p_hdr->count; i++, p_entry++) { 6138c2ecf20Sopenharmony_ci qla8044_wr_reg_indirect(vha, p_entry->arg1, p_entry->arg2); 6148c2ecf20Sopenharmony_ci if (p_hdr->delay) 6158c2ecf20Sopenharmony_ci udelay((uint32_t)(p_hdr->delay)); 6168c2ecf20Sopenharmony_ci } 6178c2ecf20Sopenharmony_ci} 6188c2ecf20Sopenharmony_ci 6198c2ecf20Sopenharmony_ci/* 6208c2ecf20Sopenharmony_ci * qla8044_read_write_list - Read from address specified by p_entry->arg1, 6218c2ecf20Sopenharmony_ci * write value read to address specified by p_entry->arg2, for all entries in 6228c2ecf20Sopenharmony_ci * header with delay of p_hdr->delay between entries. 6238c2ecf20Sopenharmony_ci * 6248c2ecf20Sopenharmony_ci * @vha : Pointer to adapter structure 6258c2ecf20Sopenharmony_ci * @p_hdr : reset_entry header for READ_WRITE_LIST opcode. 6268c2ecf20Sopenharmony_ci * 6278c2ecf20Sopenharmony_ci */ 6288c2ecf20Sopenharmony_cistatic void 6298c2ecf20Sopenharmony_ciqla8044_read_write_list(struct scsi_qla_host *vha, 6308c2ecf20Sopenharmony_ci struct qla8044_reset_entry_hdr *p_hdr) 6318c2ecf20Sopenharmony_ci{ 6328c2ecf20Sopenharmony_ci struct qla8044_entry *p_entry; 6338c2ecf20Sopenharmony_ci uint32_t i; 6348c2ecf20Sopenharmony_ci 6358c2ecf20Sopenharmony_ci p_entry = (struct qla8044_entry *)((char *)p_hdr + 6368c2ecf20Sopenharmony_ci sizeof(struct qla8044_reset_entry_hdr)); 6378c2ecf20Sopenharmony_ci 6388c2ecf20Sopenharmony_ci for (i = 0; i < p_hdr->count; i++, p_entry++) { 6398c2ecf20Sopenharmony_ci qla8044_read_write_crb_reg(vha, p_entry->arg1, 6408c2ecf20Sopenharmony_ci p_entry->arg2); 6418c2ecf20Sopenharmony_ci if (p_hdr->delay) 6428c2ecf20Sopenharmony_ci udelay((uint32_t)(p_hdr->delay)); 6438c2ecf20Sopenharmony_ci } 6448c2ecf20Sopenharmony_ci} 6458c2ecf20Sopenharmony_ci 6468c2ecf20Sopenharmony_ci/* 6478c2ecf20Sopenharmony_ci * qla8044_poll_reg - Poll the given CRB addr for duration msecs till 6488c2ecf20Sopenharmony_ci * value read ANDed with test_mask is equal to test_result. 6498c2ecf20Sopenharmony_ci * 6508c2ecf20Sopenharmony_ci * @ha : Pointer to adapter structure 6518c2ecf20Sopenharmony_ci * @addr : CRB register address 6528c2ecf20Sopenharmony_ci * @duration : Poll for total of "duration" msecs 6538c2ecf20Sopenharmony_ci * @test_mask : Mask value read with "test_mask" 6548c2ecf20Sopenharmony_ci * @test_result : Compare (value&test_mask) with test_result. 6558c2ecf20Sopenharmony_ci * 6568c2ecf20Sopenharmony_ci * Return Value - QLA_SUCCESS/QLA_FUNCTION_FAILED 6578c2ecf20Sopenharmony_ci */ 6588c2ecf20Sopenharmony_cistatic int 6598c2ecf20Sopenharmony_ciqla8044_poll_reg(struct scsi_qla_host *vha, uint32_t addr, 6608c2ecf20Sopenharmony_ci int duration, uint32_t test_mask, uint32_t test_result) 6618c2ecf20Sopenharmony_ci{ 6628c2ecf20Sopenharmony_ci uint32_t value = 0; 6638c2ecf20Sopenharmony_ci int timeout_error; 6648c2ecf20Sopenharmony_ci uint8_t retries; 6658c2ecf20Sopenharmony_ci int ret_val = QLA_SUCCESS; 6668c2ecf20Sopenharmony_ci 6678c2ecf20Sopenharmony_ci ret_val = qla8044_rd_reg_indirect(vha, addr, &value); 6688c2ecf20Sopenharmony_ci if (ret_val == QLA_FUNCTION_FAILED) { 6698c2ecf20Sopenharmony_ci timeout_error = 1; 6708c2ecf20Sopenharmony_ci goto exit_poll_reg; 6718c2ecf20Sopenharmony_ci } 6728c2ecf20Sopenharmony_ci 6738c2ecf20Sopenharmony_ci /* poll every 1/10 of the total duration */ 6748c2ecf20Sopenharmony_ci retries = duration/10; 6758c2ecf20Sopenharmony_ci 6768c2ecf20Sopenharmony_ci do { 6778c2ecf20Sopenharmony_ci if ((value & test_mask) != test_result) { 6788c2ecf20Sopenharmony_ci timeout_error = 1; 6798c2ecf20Sopenharmony_ci msleep(duration/10); 6808c2ecf20Sopenharmony_ci ret_val = qla8044_rd_reg_indirect(vha, addr, &value); 6818c2ecf20Sopenharmony_ci if (ret_val == QLA_FUNCTION_FAILED) { 6828c2ecf20Sopenharmony_ci timeout_error = 1; 6838c2ecf20Sopenharmony_ci goto exit_poll_reg; 6848c2ecf20Sopenharmony_ci } 6858c2ecf20Sopenharmony_ci } else { 6868c2ecf20Sopenharmony_ci timeout_error = 0; 6878c2ecf20Sopenharmony_ci break; 6888c2ecf20Sopenharmony_ci } 6898c2ecf20Sopenharmony_ci } while (retries--); 6908c2ecf20Sopenharmony_ci 6918c2ecf20Sopenharmony_ciexit_poll_reg: 6928c2ecf20Sopenharmony_ci if (timeout_error) { 6938c2ecf20Sopenharmony_ci vha->reset_tmplt.seq_error++; 6948c2ecf20Sopenharmony_ci ql_log(ql_log_fatal, vha, 0xb090, 6958c2ecf20Sopenharmony_ci "%s: Poll Failed: 0x%08x 0x%08x 0x%08x\n", 6968c2ecf20Sopenharmony_ci __func__, value, test_mask, test_result); 6978c2ecf20Sopenharmony_ci } 6988c2ecf20Sopenharmony_ci 6998c2ecf20Sopenharmony_ci return timeout_error; 7008c2ecf20Sopenharmony_ci} 7018c2ecf20Sopenharmony_ci 7028c2ecf20Sopenharmony_ci/* 7038c2ecf20Sopenharmony_ci * qla8044_poll_list - For all entries in the POLL_LIST header, poll read CRB 7048c2ecf20Sopenharmony_ci * register specified by p_entry->arg1 and compare (value AND test_mask) with 7058c2ecf20Sopenharmony_ci * test_result to validate it. Wait for p_hdr->delay between processing entries. 7068c2ecf20Sopenharmony_ci * 7078c2ecf20Sopenharmony_ci * @ha : Pointer to adapter structure 7088c2ecf20Sopenharmony_ci * @p_hdr : reset_entry header for POLL_LIST opcode. 7098c2ecf20Sopenharmony_ci * 7108c2ecf20Sopenharmony_ci */ 7118c2ecf20Sopenharmony_cistatic void 7128c2ecf20Sopenharmony_ciqla8044_poll_list(struct scsi_qla_host *vha, 7138c2ecf20Sopenharmony_ci struct qla8044_reset_entry_hdr *p_hdr) 7148c2ecf20Sopenharmony_ci{ 7158c2ecf20Sopenharmony_ci long delay; 7168c2ecf20Sopenharmony_ci struct qla8044_entry *p_entry; 7178c2ecf20Sopenharmony_ci struct qla8044_poll *p_poll; 7188c2ecf20Sopenharmony_ci uint32_t i; 7198c2ecf20Sopenharmony_ci uint32_t value; 7208c2ecf20Sopenharmony_ci 7218c2ecf20Sopenharmony_ci p_poll = (struct qla8044_poll *) 7228c2ecf20Sopenharmony_ci ((char *)p_hdr + sizeof(struct qla8044_reset_entry_hdr)); 7238c2ecf20Sopenharmony_ci 7248c2ecf20Sopenharmony_ci /* Entries start after 8 byte qla8044_poll, poll header contains 7258c2ecf20Sopenharmony_ci * the test_mask, test_value. 7268c2ecf20Sopenharmony_ci */ 7278c2ecf20Sopenharmony_ci p_entry = (struct qla8044_entry *)((char *)p_poll + 7288c2ecf20Sopenharmony_ci sizeof(struct qla8044_poll)); 7298c2ecf20Sopenharmony_ci 7308c2ecf20Sopenharmony_ci delay = (long)p_hdr->delay; 7318c2ecf20Sopenharmony_ci 7328c2ecf20Sopenharmony_ci if (!delay) { 7338c2ecf20Sopenharmony_ci for (i = 0; i < p_hdr->count; i++, p_entry++) 7348c2ecf20Sopenharmony_ci qla8044_poll_reg(vha, p_entry->arg1, 7358c2ecf20Sopenharmony_ci delay, p_poll->test_mask, p_poll->test_value); 7368c2ecf20Sopenharmony_ci } else { 7378c2ecf20Sopenharmony_ci for (i = 0; i < p_hdr->count; i++, p_entry++) { 7388c2ecf20Sopenharmony_ci if (delay) { 7398c2ecf20Sopenharmony_ci if (qla8044_poll_reg(vha, 7408c2ecf20Sopenharmony_ci p_entry->arg1, delay, 7418c2ecf20Sopenharmony_ci p_poll->test_mask, 7428c2ecf20Sopenharmony_ci p_poll->test_value)) { 7438c2ecf20Sopenharmony_ci /*If 7448c2ecf20Sopenharmony_ci * (data_read&test_mask != test_value) 7458c2ecf20Sopenharmony_ci * read TIMEOUT_ADDR (arg1) and 7468c2ecf20Sopenharmony_ci * ADDR (arg2) registers 7478c2ecf20Sopenharmony_ci */ 7488c2ecf20Sopenharmony_ci qla8044_rd_reg_indirect(vha, 7498c2ecf20Sopenharmony_ci p_entry->arg1, &value); 7508c2ecf20Sopenharmony_ci qla8044_rd_reg_indirect(vha, 7518c2ecf20Sopenharmony_ci p_entry->arg2, &value); 7528c2ecf20Sopenharmony_ci } 7538c2ecf20Sopenharmony_ci } 7548c2ecf20Sopenharmony_ci } 7558c2ecf20Sopenharmony_ci } 7568c2ecf20Sopenharmony_ci} 7578c2ecf20Sopenharmony_ci 7588c2ecf20Sopenharmony_ci/* 7598c2ecf20Sopenharmony_ci * qla8044_poll_write_list - Write dr_value, ar_value to dr_addr/ar_addr, 7608c2ecf20Sopenharmony_ci * read ar_addr, if (value& test_mask != test_mask) re-read till timeout 7618c2ecf20Sopenharmony_ci * expires. 7628c2ecf20Sopenharmony_ci * 7638c2ecf20Sopenharmony_ci * @vha : Pointer to adapter structure 7648c2ecf20Sopenharmony_ci * @p_hdr : reset entry header for POLL_WRITE_LIST opcode. 7658c2ecf20Sopenharmony_ci * 7668c2ecf20Sopenharmony_ci */ 7678c2ecf20Sopenharmony_cistatic void 7688c2ecf20Sopenharmony_ciqla8044_poll_write_list(struct scsi_qla_host *vha, 7698c2ecf20Sopenharmony_ci struct qla8044_reset_entry_hdr *p_hdr) 7708c2ecf20Sopenharmony_ci{ 7718c2ecf20Sopenharmony_ci long delay; 7728c2ecf20Sopenharmony_ci struct qla8044_quad_entry *p_entry; 7738c2ecf20Sopenharmony_ci struct qla8044_poll *p_poll; 7748c2ecf20Sopenharmony_ci uint32_t i; 7758c2ecf20Sopenharmony_ci 7768c2ecf20Sopenharmony_ci p_poll = (struct qla8044_poll *)((char *)p_hdr + 7778c2ecf20Sopenharmony_ci sizeof(struct qla8044_reset_entry_hdr)); 7788c2ecf20Sopenharmony_ci 7798c2ecf20Sopenharmony_ci p_entry = (struct qla8044_quad_entry *)((char *)p_poll + 7808c2ecf20Sopenharmony_ci sizeof(struct qla8044_poll)); 7818c2ecf20Sopenharmony_ci 7828c2ecf20Sopenharmony_ci delay = (long)p_hdr->delay; 7838c2ecf20Sopenharmony_ci 7848c2ecf20Sopenharmony_ci for (i = 0; i < p_hdr->count; i++, p_entry++) { 7858c2ecf20Sopenharmony_ci qla8044_wr_reg_indirect(vha, 7868c2ecf20Sopenharmony_ci p_entry->dr_addr, p_entry->dr_value); 7878c2ecf20Sopenharmony_ci qla8044_wr_reg_indirect(vha, 7888c2ecf20Sopenharmony_ci p_entry->ar_addr, p_entry->ar_value); 7898c2ecf20Sopenharmony_ci if (delay) { 7908c2ecf20Sopenharmony_ci if (qla8044_poll_reg(vha, 7918c2ecf20Sopenharmony_ci p_entry->ar_addr, delay, 7928c2ecf20Sopenharmony_ci p_poll->test_mask, 7938c2ecf20Sopenharmony_ci p_poll->test_value)) { 7948c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_p3p, vha, 0xb091, 7958c2ecf20Sopenharmony_ci "%s: Timeout Error: poll list, ", 7968c2ecf20Sopenharmony_ci __func__); 7978c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_p3p, vha, 0xb092, 7988c2ecf20Sopenharmony_ci "item_num %d, entry_num %d\n", i, 7998c2ecf20Sopenharmony_ci vha->reset_tmplt.seq_index); 8008c2ecf20Sopenharmony_ci } 8018c2ecf20Sopenharmony_ci } 8028c2ecf20Sopenharmony_ci } 8038c2ecf20Sopenharmony_ci} 8048c2ecf20Sopenharmony_ci 8058c2ecf20Sopenharmony_ci/* 8068c2ecf20Sopenharmony_ci * qla8044_read_modify_write - Read value from p_entry->arg1, modify the 8078c2ecf20Sopenharmony_ci * value, write value to p_entry->arg2. Process entries with p_hdr->delay 8088c2ecf20Sopenharmony_ci * between entries. 8098c2ecf20Sopenharmony_ci * 8108c2ecf20Sopenharmony_ci * @vha : Pointer to adapter structure 8118c2ecf20Sopenharmony_ci * @p_hdr : header with shift/or/xor values. 8128c2ecf20Sopenharmony_ci * 8138c2ecf20Sopenharmony_ci */ 8148c2ecf20Sopenharmony_cistatic void 8158c2ecf20Sopenharmony_ciqla8044_read_modify_write(struct scsi_qla_host *vha, 8168c2ecf20Sopenharmony_ci struct qla8044_reset_entry_hdr *p_hdr) 8178c2ecf20Sopenharmony_ci{ 8188c2ecf20Sopenharmony_ci struct qla8044_entry *p_entry; 8198c2ecf20Sopenharmony_ci struct qla8044_rmw *p_rmw_hdr; 8208c2ecf20Sopenharmony_ci uint32_t i; 8218c2ecf20Sopenharmony_ci 8228c2ecf20Sopenharmony_ci p_rmw_hdr = (struct qla8044_rmw *)((char *)p_hdr + 8238c2ecf20Sopenharmony_ci sizeof(struct qla8044_reset_entry_hdr)); 8248c2ecf20Sopenharmony_ci 8258c2ecf20Sopenharmony_ci p_entry = (struct qla8044_entry *)((char *)p_rmw_hdr + 8268c2ecf20Sopenharmony_ci sizeof(struct qla8044_rmw)); 8278c2ecf20Sopenharmony_ci 8288c2ecf20Sopenharmony_ci for (i = 0; i < p_hdr->count; i++, p_entry++) { 8298c2ecf20Sopenharmony_ci qla8044_rmw_crb_reg(vha, p_entry->arg1, 8308c2ecf20Sopenharmony_ci p_entry->arg2, p_rmw_hdr); 8318c2ecf20Sopenharmony_ci if (p_hdr->delay) 8328c2ecf20Sopenharmony_ci udelay((uint32_t)(p_hdr->delay)); 8338c2ecf20Sopenharmony_ci } 8348c2ecf20Sopenharmony_ci} 8358c2ecf20Sopenharmony_ci 8368c2ecf20Sopenharmony_ci/* 8378c2ecf20Sopenharmony_ci * qla8044_pause - Wait for p_hdr->delay msecs, called between processing 8388c2ecf20Sopenharmony_ci * two entries of a sequence. 8398c2ecf20Sopenharmony_ci * 8408c2ecf20Sopenharmony_ci * @vha : Pointer to adapter structure 8418c2ecf20Sopenharmony_ci * @p_hdr : Common reset entry header. 8428c2ecf20Sopenharmony_ci * 8438c2ecf20Sopenharmony_ci */ 8448c2ecf20Sopenharmony_cistatic 8458c2ecf20Sopenharmony_civoid qla8044_pause(struct scsi_qla_host *vha, 8468c2ecf20Sopenharmony_ci struct qla8044_reset_entry_hdr *p_hdr) 8478c2ecf20Sopenharmony_ci{ 8488c2ecf20Sopenharmony_ci if (p_hdr->delay) 8498c2ecf20Sopenharmony_ci mdelay((uint32_t)((long)p_hdr->delay)); 8508c2ecf20Sopenharmony_ci} 8518c2ecf20Sopenharmony_ci 8528c2ecf20Sopenharmony_ci/* 8538c2ecf20Sopenharmony_ci * qla8044_template_end - Indicates end of reset sequence processing. 8548c2ecf20Sopenharmony_ci * 8558c2ecf20Sopenharmony_ci * @vha : Pointer to adapter structure 8568c2ecf20Sopenharmony_ci * @p_hdr : Common reset entry header. 8578c2ecf20Sopenharmony_ci * 8588c2ecf20Sopenharmony_ci */ 8598c2ecf20Sopenharmony_cistatic void 8608c2ecf20Sopenharmony_ciqla8044_template_end(struct scsi_qla_host *vha, 8618c2ecf20Sopenharmony_ci struct qla8044_reset_entry_hdr *p_hdr) 8628c2ecf20Sopenharmony_ci{ 8638c2ecf20Sopenharmony_ci vha->reset_tmplt.template_end = 1; 8648c2ecf20Sopenharmony_ci 8658c2ecf20Sopenharmony_ci if (vha->reset_tmplt.seq_error == 0) { 8668c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_p3p, vha, 0xb093, 8678c2ecf20Sopenharmony_ci "%s: Reset sequence completed SUCCESSFULLY.\n", __func__); 8688c2ecf20Sopenharmony_ci } else { 8698c2ecf20Sopenharmony_ci ql_log(ql_log_fatal, vha, 0xb094, 8708c2ecf20Sopenharmony_ci "%s: Reset sequence completed with some timeout " 8718c2ecf20Sopenharmony_ci "errors.\n", __func__); 8728c2ecf20Sopenharmony_ci } 8738c2ecf20Sopenharmony_ci} 8748c2ecf20Sopenharmony_ci 8758c2ecf20Sopenharmony_ci/* 8768c2ecf20Sopenharmony_ci * qla8044_poll_read_list - Write ar_value to ar_addr register, read ar_addr, 8778c2ecf20Sopenharmony_ci * if (value & test_mask != test_value) re-read till timeout value expires, 8788c2ecf20Sopenharmony_ci * read dr_addr register and assign to reset_tmplt.array. 8798c2ecf20Sopenharmony_ci * 8808c2ecf20Sopenharmony_ci * @vha : Pointer to adapter structure 8818c2ecf20Sopenharmony_ci * @p_hdr : Common reset entry header. 8828c2ecf20Sopenharmony_ci * 8838c2ecf20Sopenharmony_ci */ 8848c2ecf20Sopenharmony_cistatic void 8858c2ecf20Sopenharmony_ciqla8044_poll_read_list(struct scsi_qla_host *vha, 8868c2ecf20Sopenharmony_ci struct qla8044_reset_entry_hdr *p_hdr) 8878c2ecf20Sopenharmony_ci{ 8888c2ecf20Sopenharmony_ci long delay; 8898c2ecf20Sopenharmony_ci int index; 8908c2ecf20Sopenharmony_ci struct qla8044_quad_entry *p_entry; 8918c2ecf20Sopenharmony_ci struct qla8044_poll *p_poll; 8928c2ecf20Sopenharmony_ci uint32_t i; 8938c2ecf20Sopenharmony_ci uint32_t value; 8948c2ecf20Sopenharmony_ci 8958c2ecf20Sopenharmony_ci p_poll = (struct qla8044_poll *) 8968c2ecf20Sopenharmony_ci ((char *)p_hdr + sizeof(struct qla8044_reset_entry_hdr)); 8978c2ecf20Sopenharmony_ci 8988c2ecf20Sopenharmony_ci p_entry = (struct qla8044_quad_entry *) 8998c2ecf20Sopenharmony_ci ((char *)p_poll + sizeof(struct qla8044_poll)); 9008c2ecf20Sopenharmony_ci 9018c2ecf20Sopenharmony_ci delay = (long)p_hdr->delay; 9028c2ecf20Sopenharmony_ci 9038c2ecf20Sopenharmony_ci for (i = 0; i < p_hdr->count; i++, p_entry++) { 9048c2ecf20Sopenharmony_ci qla8044_wr_reg_indirect(vha, p_entry->ar_addr, 9058c2ecf20Sopenharmony_ci p_entry->ar_value); 9068c2ecf20Sopenharmony_ci if (delay) { 9078c2ecf20Sopenharmony_ci if (qla8044_poll_reg(vha, p_entry->ar_addr, delay, 9088c2ecf20Sopenharmony_ci p_poll->test_mask, p_poll->test_value)) { 9098c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_p3p, vha, 0xb095, 9108c2ecf20Sopenharmony_ci "%s: Timeout Error: poll " 9118c2ecf20Sopenharmony_ci "list, ", __func__); 9128c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_p3p, vha, 0xb096, 9138c2ecf20Sopenharmony_ci "Item_num %d, " 9148c2ecf20Sopenharmony_ci "entry_num %d\n", i, 9158c2ecf20Sopenharmony_ci vha->reset_tmplt.seq_index); 9168c2ecf20Sopenharmony_ci } else { 9178c2ecf20Sopenharmony_ci index = vha->reset_tmplt.array_index; 9188c2ecf20Sopenharmony_ci qla8044_rd_reg_indirect(vha, 9198c2ecf20Sopenharmony_ci p_entry->dr_addr, &value); 9208c2ecf20Sopenharmony_ci vha->reset_tmplt.array[index++] = value; 9218c2ecf20Sopenharmony_ci if (index == QLA8044_MAX_RESET_SEQ_ENTRIES) 9228c2ecf20Sopenharmony_ci vha->reset_tmplt.array_index = 1; 9238c2ecf20Sopenharmony_ci } 9248c2ecf20Sopenharmony_ci } 9258c2ecf20Sopenharmony_ci } 9268c2ecf20Sopenharmony_ci} 9278c2ecf20Sopenharmony_ci 9288c2ecf20Sopenharmony_ci/* 9298c2ecf20Sopenharmony_ci * qla8031_process_reset_template - Process all entries in reset template 9308c2ecf20Sopenharmony_ci * till entry with SEQ_END opcode, which indicates end of the reset template 9318c2ecf20Sopenharmony_ci * processing. Each entry has a Reset Entry header, entry opcode/command, with 9328c2ecf20Sopenharmony_ci * size of the entry, number of entries in sub-sequence and delay in microsecs 9338c2ecf20Sopenharmony_ci * or timeout in millisecs. 9348c2ecf20Sopenharmony_ci * 9358c2ecf20Sopenharmony_ci * @ha : Pointer to adapter structure 9368c2ecf20Sopenharmony_ci * @p_buff : Common reset entry header. 9378c2ecf20Sopenharmony_ci * 9388c2ecf20Sopenharmony_ci */ 9398c2ecf20Sopenharmony_cistatic void 9408c2ecf20Sopenharmony_ciqla8044_process_reset_template(struct scsi_qla_host *vha, 9418c2ecf20Sopenharmony_ci char *p_buff) 9428c2ecf20Sopenharmony_ci{ 9438c2ecf20Sopenharmony_ci int index, entries; 9448c2ecf20Sopenharmony_ci struct qla8044_reset_entry_hdr *p_hdr; 9458c2ecf20Sopenharmony_ci char *p_entry = p_buff; 9468c2ecf20Sopenharmony_ci 9478c2ecf20Sopenharmony_ci vha->reset_tmplt.seq_end = 0; 9488c2ecf20Sopenharmony_ci vha->reset_tmplt.template_end = 0; 9498c2ecf20Sopenharmony_ci entries = vha->reset_tmplt.hdr->entries; 9508c2ecf20Sopenharmony_ci index = vha->reset_tmplt.seq_index; 9518c2ecf20Sopenharmony_ci 9528c2ecf20Sopenharmony_ci for (; (!vha->reset_tmplt.seq_end) && (index < entries); index++) { 9538c2ecf20Sopenharmony_ci p_hdr = (struct qla8044_reset_entry_hdr *)p_entry; 9548c2ecf20Sopenharmony_ci switch (p_hdr->cmd) { 9558c2ecf20Sopenharmony_ci case OPCODE_NOP: 9568c2ecf20Sopenharmony_ci break; 9578c2ecf20Sopenharmony_ci case OPCODE_WRITE_LIST: 9588c2ecf20Sopenharmony_ci qla8044_write_list(vha, p_hdr); 9598c2ecf20Sopenharmony_ci break; 9608c2ecf20Sopenharmony_ci case OPCODE_READ_WRITE_LIST: 9618c2ecf20Sopenharmony_ci qla8044_read_write_list(vha, p_hdr); 9628c2ecf20Sopenharmony_ci break; 9638c2ecf20Sopenharmony_ci case OPCODE_POLL_LIST: 9648c2ecf20Sopenharmony_ci qla8044_poll_list(vha, p_hdr); 9658c2ecf20Sopenharmony_ci break; 9668c2ecf20Sopenharmony_ci case OPCODE_POLL_WRITE_LIST: 9678c2ecf20Sopenharmony_ci qla8044_poll_write_list(vha, p_hdr); 9688c2ecf20Sopenharmony_ci break; 9698c2ecf20Sopenharmony_ci case OPCODE_READ_MODIFY_WRITE: 9708c2ecf20Sopenharmony_ci qla8044_read_modify_write(vha, p_hdr); 9718c2ecf20Sopenharmony_ci break; 9728c2ecf20Sopenharmony_ci case OPCODE_SEQ_PAUSE: 9738c2ecf20Sopenharmony_ci qla8044_pause(vha, p_hdr); 9748c2ecf20Sopenharmony_ci break; 9758c2ecf20Sopenharmony_ci case OPCODE_SEQ_END: 9768c2ecf20Sopenharmony_ci vha->reset_tmplt.seq_end = 1; 9778c2ecf20Sopenharmony_ci break; 9788c2ecf20Sopenharmony_ci case OPCODE_TMPL_END: 9798c2ecf20Sopenharmony_ci qla8044_template_end(vha, p_hdr); 9808c2ecf20Sopenharmony_ci break; 9818c2ecf20Sopenharmony_ci case OPCODE_POLL_READ_LIST: 9828c2ecf20Sopenharmony_ci qla8044_poll_read_list(vha, p_hdr); 9838c2ecf20Sopenharmony_ci break; 9848c2ecf20Sopenharmony_ci default: 9858c2ecf20Sopenharmony_ci ql_log(ql_log_fatal, vha, 0xb097, 9868c2ecf20Sopenharmony_ci "%s: Unknown command ==> 0x%04x on " 9878c2ecf20Sopenharmony_ci "entry = %d\n", __func__, p_hdr->cmd, index); 9888c2ecf20Sopenharmony_ci break; 9898c2ecf20Sopenharmony_ci } 9908c2ecf20Sopenharmony_ci /* 9918c2ecf20Sopenharmony_ci *Set pointer to next entry in the sequence. 9928c2ecf20Sopenharmony_ci */ 9938c2ecf20Sopenharmony_ci p_entry += p_hdr->size; 9948c2ecf20Sopenharmony_ci } 9958c2ecf20Sopenharmony_ci vha->reset_tmplt.seq_index = index; 9968c2ecf20Sopenharmony_ci} 9978c2ecf20Sopenharmony_ci 9988c2ecf20Sopenharmony_cistatic void 9998c2ecf20Sopenharmony_ciqla8044_process_init_seq(struct scsi_qla_host *vha) 10008c2ecf20Sopenharmony_ci{ 10018c2ecf20Sopenharmony_ci qla8044_process_reset_template(vha, 10028c2ecf20Sopenharmony_ci vha->reset_tmplt.init_offset); 10038c2ecf20Sopenharmony_ci if (vha->reset_tmplt.seq_end != 1) 10048c2ecf20Sopenharmony_ci ql_log(ql_log_fatal, vha, 0xb098, 10058c2ecf20Sopenharmony_ci "%s: Abrupt INIT Sub-Sequence end.\n", 10068c2ecf20Sopenharmony_ci __func__); 10078c2ecf20Sopenharmony_ci} 10088c2ecf20Sopenharmony_ci 10098c2ecf20Sopenharmony_cistatic void 10108c2ecf20Sopenharmony_ciqla8044_process_stop_seq(struct scsi_qla_host *vha) 10118c2ecf20Sopenharmony_ci{ 10128c2ecf20Sopenharmony_ci vha->reset_tmplt.seq_index = 0; 10138c2ecf20Sopenharmony_ci qla8044_process_reset_template(vha, vha->reset_tmplt.stop_offset); 10148c2ecf20Sopenharmony_ci if (vha->reset_tmplt.seq_end != 1) 10158c2ecf20Sopenharmony_ci ql_log(ql_log_fatal, vha, 0xb099, 10168c2ecf20Sopenharmony_ci "%s: Abrupt STOP Sub-Sequence end.\n", __func__); 10178c2ecf20Sopenharmony_ci} 10188c2ecf20Sopenharmony_ci 10198c2ecf20Sopenharmony_cistatic void 10208c2ecf20Sopenharmony_ciqla8044_process_start_seq(struct scsi_qla_host *vha) 10218c2ecf20Sopenharmony_ci{ 10228c2ecf20Sopenharmony_ci qla8044_process_reset_template(vha, vha->reset_tmplt.start_offset); 10238c2ecf20Sopenharmony_ci if (vha->reset_tmplt.template_end != 1) 10248c2ecf20Sopenharmony_ci ql_log(ql_log_fatal, vha, 0xb09a, 10258c2ecf20Sopenharmony_ci "%s: Abrupt START Sub-Sequence end.\n", 10268c2ecf20Sopenharmony_ci __func__); 10278c2ecf20Sopenharmony_ci} 10288c2ecf20Sopenharmony_ci 10298c2ecf20Sopenharmony_cistatic int 10308c2ecf20Sopenharmony_ciqla8044_lockless_flash_read_u32(struct scsi_qla_host *vha, 10318c2ecf20Sopenharmony_ci uint32_t flash_addr, uint8_t *p_data, int u32_word_count) 10328c2ecf20Sopenharmony_ci{ 10338c2ecf20Sopenharmony_ci uint32_t i; 10348c2ecf20Sopenharmony_ci uint32_t u32_word; 10358c2ecf20Sopenharmony_ci uint32_t flash_offset; 10368c2ecf20Sopenharmony_ci uint32_t addr = flash_addr; 10378c2ecf20Sopenharmony_ci int ret_val = QLA_SUCCESS; 10388c2ecf20Sopenharmony_ci 10398c2ecf20Sopenharmony_ci flash_offset = addr & (QLA8044_FLASH_SECTOR_SIZE - 1); 10408c2ecf20Sopenharmony_ci 10418c2ecf20Sopenharmony_ci if (addr & 0x3) { 10428c2ecf20Sopenharmony_ci ql_log(ql_log_fatal, vha, 0xb09b, "%s: Illegal addr = 0x%x\n", 10438c2ecf20Sopenharmony_ci __func__, addr); 10448c2ecf20Sopenharmony_ci ret_val = QLA_FUNCTION_FAILED; 10458c2ecf20Sopenharmony_ci goto exit_lockless_read; 10468c2ecf20Sopenharmony_ci } 10478c2ecf20Sopenharmony_ci 10488c2ecf20Sopenharmony_ci ret_val = qla8044_wr_reg_indirect(vha, 10498c2ecf20Sopenharmony_ci QLA8044_FLASH_DIRECT_WINDOW, (addr)); 10508c2ecf20Sopenharmony_ci 10518c2ecf20Sopenharmony_ci if (ret_val != QLA_SUCCESS) { 10528c2ecf20Sopenharmony_ci ql_log(ql_log_fatal, vha, 0xb09c, 10538c2ecf20Sopenharmony_ci "%s: failed to write addr 0x%x to FLASH_DIRECT_WINDOW!\n", 10548c2ecf20Sopenharmony_ci __func__, addr); 10558c2ecf20Sopenharmony_ci goto exit_lockless_read; 10568c2ecf20Sopenharmony_ci } 10578c2ecf20Sopenharmony_ci 10588c2ecf20Sopenharmony_ci /* Check if data is spread across multiple sectors */ 10598c2ecf20Sopenharmony_ci if ((flash_offset + (u32_word_count * sizeof(uint32_t))) > 10608c2ecf20Sopenharmony_ci (QLA8044_FLASH_SECTOR_SIZE - 1)) { 10618c2ecf20Sopenharmony_ci /* Multi sector read */ 10628c2ecf20Sopenharmony_ci for (i = 0; i < u32_word_count; i++) { 10638c2ecf20Sopenharmony_ci ret_val = qla8044_rd_reg_indirect(vha, 10648c2ecf20Sopenharmony_ci QLA8044_FLASH_DIRECT_DATA(addr), &u32_word); 10658c2ecf20Sopenharmony_ci if (ret_val != QLA_SUCCESS) { 10668c2ecf20Sopenharmony_ci ql_log(ql_log_fatal, vha, 0xb09d, 10678c2ecf20Sopenharmony_ci "%s: failed to read addr 0x%x!\n", 10688c2ecf20Sopenharmony_ci __func__, addr); 10698c2ecf20Sopenharmony_ci goto exit_lockless_read; 10708c2ecf20Sopenharmony_ci } 10718c2ecf20Sopenharmony_ci *(uint32_t *)p_data = u32_word; 10728c2ecf20Sopenharmony_ci p_data = p_data + 4; 10738c2ecf20Sopenharmony_ci addr = addr + 4; 10748c2ecf20Sopenharmony_ci flash_offset = flash_offset + 4; 10758c2ecf20Sopenharmony_ci if (flash_offset > (QLA8044_FLASH_SECTOR_SIZE - 1)) { 10768c2ecf20Sopenharmony_ci /* This write is needed once for each sector */ 10778c2ecf20Sopenharmony_ci ret_val = qla8044_wr_reg_indirect(vha, 10788c2ecf20Sopenharmony_ci QLA8044_FLASH_DIRECT_WINDOW, (addr)); 10798c2ecf20Sopenharmony_ci if (ret_val != QLA_SUCCESS) { 10808c2ecf20Sopenharmony_ci ql_log(ql_log_fatal, vha, 0xb09f, 10818c2ecf20Sopenharmony_ci "%s: failed to write addr " 10828c2ecf20Sopenharmony_ci "0x%x to FLASH_DIRECT_WINDOW!\n", 10838c2ecf20Sopenharmony_ci __func__, addr); 10848c2ecf20Sopenharmony_ci goto exit_lockless_read; 10858c2ecf20Sopenharmony_ci } 10868c2ecf20Sopenharmony_ci flash_offset = 0; 10878c2ecf20Sopenharmony_ci } 10888c2ecf20Sopenharmony_ci } 10898c2ecf20Sopenharmony_ci } else { 10908c2ecf20Sopenharmony_ci /* Single sector read */ 10918c2ecf20Sopenharmony_ci for (i = 0; i < u32_word_count; i++) { 10928c2ecf20Sopenharmony_ci ret_val = qla8044_rd_reg_indirect(vha, 10938c2ecf20Sopenharmony_ci QLA8044_FLASH_DIRECT_DATA(addr), &u32_word); 10948c2ecf20Sopenharmony_ci if (ret_val != QLA_SUCCESS) { 10958c2ecf20Sopenharmony_ci ql_log(ql_log_fatal, vha, 0xb0a0, 10968c2ecf20Sopenharmony_ci "%s: failed to read addr 0x%x!\n", 10978c2ecf20Sopenharmony_ci __func__, addr); 10988c2ecf20Sopenharmony_ci goto exit_lockless_read; 10998c2ecf20Sopenharmony_ci } 11008c2ecf20Sopenharmony_ci *(uint32_t *)p_data = u32_word; 11018c2ecf20Sopenharmony_ci p_data = p_data + 4; 11028c2ecf20Sopenharmony_ci addr = addr + 4; 11038c2ecf20Sopenharmony_ci } 11048c2ecf20Sopenharmony_ci } 11058c2ecf20Sopenharmony_ci 11068c2ecf20Sopenharmony_ciexit_lockless_read: 11078c2ecf20Sopenharmony_ci return ret_val; 11088c2ecf20Sopenharmony_ci} 11098c2ecf20Sopenharmony_ci 11108c2ecf20Sopenharmony_ci/* 11118c2ecf20Sopenharmony_ci * qla8044_ms_mem_write_128b - Writes data to MS/off-chip memory 11128c2ecf20Sopenharmony_ci * 11138c2ecf20Sopenharmony_ci * @vha : Pointer to adapter structure 11148c2ecf20Sopenharmony_ci * addr : Flash address to write to 11158c2ecf20Sopenharmony_ci * data : Data to be written 11168c2ecf20Sopenharmony_ci * count : word_count to be written 11178c2ecf20Sopenharmony_ci * 11188c2ecf20Sopenharmony_ci * Return Value - QLA_SUCCESS/QLA_FUNCTION_FAILED 11198c2ecf20Sopenharmony_ci */ 11208c2ecf20Sopenharmony_cistatic int 11218c2ecf20Sopenharmony_ciqla8044_ms_mem_write_128b(struct scsi_qla_host *vha, 11228c2ecf20Sopenharmony_ci uint64_t addr, uint32_t *data, uint32_t count) 11238c2ecf20Sopenharmony_ci{ 11248c2ecf20Sopenharmony_ci int i, j, ret_val = QLA_SUCCESS; 11258c2ecf20Sopenharmony_ci uint32_t agt_ctrl; 11268c2ecf20Sopenharmony_ci unsigned long flags; 11278c2ecf20Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 11288c2ecf20Sopenharmony_ci 11298c2ecf20Sopenharmony_ci /* Only 128-bit aligned access */ 11308c2ecf20Sopenharmony_ci if (addr & 0xF) { 11318c2ecf20Sopenharmony_ci ret_val = QLA_FUNCTION_FAILED; 11328c2ecf20Sopenharmony_ci goto exit_ms_mem_write; 11338c2ecf20Sopenharmony_ci } 11348c2ecf20Sopenharmony_ci write_lock_irqsave(&ha->hw_lock, flags); 11358c2ecf20Sopenharmony_ci 11368c2ecf20Sopenharmony_ci /* Write address */ 11378c2ecf20Sopenharmony_ci ret_val = qla8044_wr_reg_indirect(vha, MD_MIU_TEST_AGT_ADDR_HI, 0); 11388c2ecf20Sopenharmony_ci if (ret_val == QLA_FUNCTION_FAILED) { 11398c2ecf20Sopenharmony_ci ql_log(ql_log_fatal, vha, 0xb0a1, 11408c2ecf20Sopenharmony_ci "%s: write to AGT_ADDR_HI failed!\n", __func__); 11418c2ecf20Sopenharmony_ci goto exit_ms_mem_write_unlock; 11428c2ecf20Sopenharmony_ci } 11438c2ecf20Sopenharmony_ci 11448c2ecf20Sopenharmony_ci for (i = 0; i < count; i++, addr += 16) { 11458c2ecf20Sopenharmony_ci if (!((addr_in_range(addr, QLA8044_ADDR_QDR_NET, 11468c2ecf20Sopenharmony_ci QLA8044_ADDR_QDR_NET_MAX)) || 11478c2ecf20Sopenharmony_ci (addr_in_range(addr, QLA8044_ADDR_DDR_NET, 11488c2ecf20Sopenharmony_ci QLA8044_ADDR_DDR_NET_MAX)))) { 11498c2ecf20Sopenharmony_ci ret_val = QLA_FUNCTION_FAILED; 11508c2ecf20Sopenharmony_ci goto exit_ms_mem_write_unlock; 11518c2ecf20Sopenharmony_ci } 11528c2ecf20Sopenharmony_ci 11538c2ecf20Sopenharmony_ci ret_val = qla8044_wr_reg_indirect(vha, 11548c2ecf20Sopenharmony_ci MD_MIU_TEST_AGT_ADDR_LO, addr); 11558c2ecf20Sopenharmony_ci 11568c2ecf20Sopenharmony_ci /* Write data */ 11578c2ecf20Sopenharmony_ci ret_val += qla8044_wr_reg_indirect(vha, 11588c2ecf20Sopenharmony_ci MD_MIU_TEST_AGT_WRDATA_LO, *data++); 11598c2ecf20Sopenharmony_ci ret_val += qla8044_wr_reg_indirect(vha, 11608c2ecf20Sopenharmony_ci MD_MIU_TEST_AGT_WRDATA_HI, *data++); 11618c2ecf20Sopenharmony_ci ret_val += qla8044_wr_reg_indirect(vha, 11628c2ecf20Sopenharmony_ci MD_MIU_TEST_AGT_WRDATA_ULO, *data++); 11638c2ecf20Sopenharmony_ci ret_val += qla8044_wr_reg_indirect(vha, 11648c2ecf20Sopenharmony_ci MD_MIU_TEST_AGT_WRDATA_UHI, *data++); 11658c2ecf20Sopenharmony_ci if (ret_val == QLA_FUNCTION_FAILED) { 11668c2ecf20Sopenharmony_ci ql_log(ql_log_fatal, vha, 0xb0a2, 11678c2ecf20Sopenharmony_ci "%s: write to AGT_WRDATA failed!\n", 11688c2ecf20Sopenharmony_ci __func__); 11698c2ecf20Sopenharmony_ci goto exit_ms_mem_write_unlock; 11708c2ecf20Sopenharmony_ci } 11718c2ecf20Sopenharmony_ci 11728c2ecf20Sopenharmony_ci /* Check write status */ 11738c2ecf20Sopenharmony_ci ret_val = qla8044_wr_reg_indirect(vha, MD_MIU_TEST_AGT_CTRL, 11748c2ecf20Sopenharmony_ci MIU_TA_CTL_WRITE_ENABLE); 11758c2ecf20Sopenharmony_ci ret_val += qla8044_wr_reg_indirect(vha, MD_MIU_TEST_AGT_CTRL, 11768c2ecf20Sopenharmony_ci MIU_TA_CTL_WRITE_START); 11778c2ecf20Sopenharmony_ci if (ret_val == QLA_FUNCTION_FAILED) { 11788c2ecf20Sopenharmony_ci ql_log(ql_log_fatal, vha, 0xb0a3, 11798c2ecf20Sopenharmony_ci "%s: write to AGT_CTRL failed!\n", __func__); 11808c2ecf20Sopenharmony_ci goto exit_ms_mem_write_unlock; 11818c2ecf20Sopenharmony_ci } 11828c2ecf20Sopenharmony_ci 11838c2ecf20Sopenharmony_ci for (j = 0; j < MAX_CTL_CHECK; j++) { 11848c2ecf20Sopenharmony_ci ret_val = qla8044_rd_reg_indirect(vha, 11858c2ecf20Sopenharmony_ci MD_MIU_TEST_AGT_CTRL, &agt_ctrl); 11868c2ecf20Sopenharmony_ci if (ret_val == QLA_FUNCTION_FAILED) { 11878c2ecf20Sopenharmony_ci ql_log(ql_log_fatal, vha, 0xb0a4, 11888c2ecf20Sopenharmony_ci "%s: failed to read " 11898c2ecf20Sopenharmony_ci "MD_MIU_TEST_AGT_CTRL!\n", __func__); 11908c2ecf20Sopenharmony_ci goto exit_ms_mem_write_unlock; 11918c2ecf20Sopenharmony_ci } 11928c2ecf20Sopenharmony_ci if ((agt_ctrl & MIU_TA_CTL_BUSY) == 0) 11938c2ecf20Sopenharmony_ci break; 11948c2ecf20Sopenharmony_ci } 11958c2ecf20Sopenharmony_ci 11968c2ecf20Sopenharmony_ci /* Status check failed */ 11978c2ecf20Sopenharmony_ci if (j >= MAX_CTL_CHECK) { 11988c2ecf20Sopenharmony_ci ql_log(ql_log_fatal, vha, 0xb0a5, 11998c2ecf20Sopenharmony_ci "%s: MS memory write failed!\n", 12008c2ecf20Sopenharmony_ci __func__); 12018c2ecf20Sopenharmony_ci ret_val = QLA_FUNCTION_FAILED; 12028c2ecf20Sopenharmony_ci goto exit_ms_mem_write_unlock; 12038c2ecf20Sopenharmony_ci } 12048c2ecf20Sopenharmony_ci } 12058c2ecf20Sopenharmony_ci 12068c2ecf20Sopenharmony_ciexit_ms_mem_write_unlock: 12078c2ecf20Sopenharmony_ci write_unlock_irqrestore(&ha->hw_lock, flags); 12088c2ecf20Sopenharmony_ci 12098c2ecf20Sopenharmony_ciexit_ms_mem_write: 12108c2ecf20Sopenharmony_ci return ret_val; 12118c2ecf20Sopenharmony_ci} 12128c2ecf20Sopenharmony_ci 12138c2ecf20Sopenharmony_cistatic int 12148c2ecf20Sopenharmony_ciqla8044_copy_bootloader(struct scsi_qla_host *vha) 12158c2ecf20Sopenharmony_ci{ 12168c2ecf20Sopenharmony_ci uint8_t *p_cache; 12178c2ecf20Sopenharmony_ci uint32_t src, count, size; 12188c2ecf20Sopenharmony_ci uint64_t dest; 12198c2ecf20Sopenharmony_ci int ret_val = QLA_SUCCESS; 12208c2ecf20Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 12218c2ecf20Sopenharmony_ci 12228c2ecf20Sopenharmony_ci src = QLA8044_BOOTLOADER_FLASH_ADDR; 12238c2ecf20Sopenharmony_ci dest = qla8044_rd_reg(ha, QLA8044_BOOTLOADER_ADDR); 12248c2ecf20Sopenharmony_ci size = qla8044_rd_reg(ha, QLA8044_BOOTLOADER_SIZE); 12258c2ecf20Sopenharmony_ci 12268c2ecf20Sopenharmony_ci /* 128 bit alignment check */ 12278c2ecf20Sopenharmony_ci if (size & 0xF) 12288c2ecf20Sopenharmony_ci size = (size + 16) & ~0xF; 12298c2ecf20Sopenharmony_ci 12308c2ecf20Sopenharmony_ci /* 16 byte count */ 12318c2ecf20Sopenharmony_ci count = size/16; 12328c2ecf20Sopenharmony_ci 12338c2ecf20Sopenharmony_ci p_cache = vmalloc(size); 12348c2ecf20Sopenharmony_ci if (p_cache == NULL) { 12358c2ecf20Sopenharmony_ci ql_log(ql_log_fatal, vha, 0xb0a6, 12368c2ecf20Sopenharmony_ci "%s: Failed to allocate memory for " 12378c2ecf20Sopenharmony_ci "boot loader cache\n", __func__); 12388c2ecf20Sopenharmony_ci ret_val = QLA_FUNCTION_FAILED; 12398c2ecf20Sopenharmony_ci goto exit_copy_bootloader; 12408c2ecf20Sopenharmony_ci } 12418c2ecf20Sopenharmony_ci 12428c2ecf20Sopenharmony_ci ret_val = qla8044_lockless_flash_read_u32(vha, src, 12438c2ecf20Sopenharmony_ci p_cache, size/sizeof(uint32_t)); 12448c2ecf20Sopenharmony_ci if (ret_val == QLA_FUNCTION_FAILED) { 12458c2ecf20Sopenharmony_ci ql_log(ql_log_fatal, vha, 0xb0a7, 12468c2ecf20Sopenharmony_ci "%s: Error reading F/W from flash!!!\n", __func__); 12478c2ecf20Sopenharmony_ci goto exit_copy_error; 12488c2ecf20Sopenharmony_ci } 12498c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_p3p, vha, 0xb0a8, "%s: Read F/W from flash!\n", 12508c2ecf20Sopenharmony_ci __func__); 12518c2ecf20Sopenharmony_ci 12528c2ecf20Sopenharmony_ci /* 128 bit/16 byte write to MS memory */ 12538c2ecf20Sopenharmony_ci ret_val = qla8044_ms_mem_write_128b(vha, dest, 12548c2ecf20Sopenharmony_ci (uint32_t *)p_cache, count); 12558c2ecf20Sopenharmony_ci if (ret_val == QLA_FUNCTION_FAILED) { 12568c2ecf20Sopenharmony_ci ql_log(ql_log_fatal, vha, 0xb0a9, 12578c2ecf20Sopenharmony_ci "%s: Error writing F/W to MS !!!\n", __func__); 12588c2ecf20Sopenharmony_ci goto exit_copy_error; 12598c2ecf20Sopenharmony_ci } 12608c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_p3p, vha, 0xb0aa, 12618c2ecf20Sopenharmony_ci "%s: Wrote F/W (size %d) to MS !!!\n", 12628c2ecf20Sopenharmony_ci __func__, size); 12638c2ecf20Sopenharmony_ci 12648c2ecf20Sopenharmony_ciexit_copy_error: 12658c2ecf20Sopenharmony_ci vfree(p_cache); 12668c2ecf20Sopenharmony_ci 12678c2ecf20Sopenharmony_ciexit_copy_bootloader: 12688c2ecf20Sopenharmony_ci return ret_val; 12698c2ecf20Sopenharmony_ci} 12708c2ecf20Sopenharmony_ci 12718c2ecf20Sopenharmony_cistatic int 12728c2ecf20Sopenharmony_ciqla8044_restart(struct scsi_qla_host *vha) 12738c2ecf20Sopenharmony_ci{ 12748c2ecf20Sopenharmony_ci int ret_val = QLA_SUCCESS; 12758c2ecf20Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 12768c2ecf20Sopenharmony_ci 12778c2ecf20Sopenharmony_ci qla8044_process_stop_seq(vha); 12788c2ecf20Sopenharmony_ci 12798c2ecf20Sopenharmony_ci /* Collect minidump */ 12808c2ecf20Sopenharmony_ci if (ql2xmdenable) 12818c2ecf20Sopenharmony_ci qla8044_get_minidump(vha); 12828c2ecf20Sopenharmony_ci else 12838c2ecf20Sopenharmony_ci ql_log(ql_log_fatal, vha, 0xb14c, 12848c2ecf20Sopenharmony_ci "Minidump disabled.\n"); 12858c2ecf20Sopenharmony_ci 12868c2ecf20Sopenharmony_ci qla8044_process_init_seq(vha); 12878c2ecf20Sopenharmony_ci 12888c2ecf20Sopenharmony_ci if (qla8044_copy_bootloader(vha)) { 12898c2ecf20Sopenharmony_ci ql_log(ql_log_fatal, vha, 0xb0ab, 12908c2ecf20Sopenharmony_ci "%s: Copy bootloader, firmware restart failed!\n", 12918c2ecf20Sopenharmony_ci __func__); 12928c2ecf20Sopenharmony_ci ret_val = QLA_FUNCTION_FAILED; 12938c2ecf20Sopenharmony_ci goto exit_restart; 12948c2ecf20Sopenharmony_ci } 12958c2ecf20Sopenharmony_ci 12968c2ecf20Sopenharmony_ci /* 12978c2ecf20Sopenharmony_ci * Loads F/W from flash 12988c2ecf20Sopenharmony_ci */ 12998c2ecf20Sopenharmony_ci qla8044_wr_reg(ha, QLA8044_FW_IMAGE_VALID, QLA8044_BOOT_FROM_FLASH); 13008c2ecf20Sopenharmony_ci 13018c2ecf20Sopenharmony_ci qla8044_process_start_seq(vha); 13028c2ecf20Sopenharmony_ci 13038c2ecf20Sopenharmony_ciexit_restart: 13048c2ecf20Sopenharmony_ci return ret_val; 13058c2ecf20Sopenharmony_ci} 13068c2ecf20Sopenharmony_ci 13078c2ecf20Sopenharmony_ci/* 13088c2ecf20Sopenharmony_ci * qla8044_check_cmd_peg_status - Check peg status to see if Peg is 13098c2ecf20Sopenharmony_ci * initialized. 13108c2ecf20Sopenharmony_ci * 13118c2ecf20Sopenharmony_ci * @ha : Pointer to adapter structure 13128c2ecf20Sopenharmony_ci * 13138c2ecf20Sopenharmony_ci * Return Value - QLA_SUCCESS/QLA_FUNCTION_FAILED 13148c2ecf20Sopenharmony_ci */ 13158c2ecf20Sopenharmony_cistatic int 13168c2ecf20Sopenharmony_ciqla8044_check_cmd_peg_status(struct scsi_qla_host *vha) 13178c2ecf20Sopenharmony_ci{ 13188c2ecf20Sopenharmony_ci uint32_t val, ret_val = QLA_FUNCTION_FAILED; 13198c2ecf20Sopenharmony_ci int retries = CRB_CMDPEG_CHECK_RETRY_COUNT; 13208c2ecf20Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 13218c2ecf20Sopenharmony_ci 13228c2ecf20Sopenharmony_ci do { 13238c2ecf20Sopenharmony_ci val = qla8044_rd_reg(ha, QLA8044_CMDPEG_STATE); 13248c2ecf20Sopenharmony_ci if (val == PHAN_INITIALIZE_COMPLETE) { 13258c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_p3p, vha, 0xb0ac, 13268c2ecf20Sopenharmony_ci "%s: Command Peg initialization " 13278c2ecf20Sopenharmony_ci "complete! state=0x%x\n", __func__, val); 13288c2ecf20Sopenharmony_ci ret_val = QLA_SUCCESS; 13298c2ecf20Sopenharmony_ci break; 13308c2ecf20Sopenharmony_ci } 13318c2ecf20Sopenharmony_ci msleep(CRB_CMDPEG_CHECK_DELAY); 13328c2ecf20Sopenharmony_ci } while (--retries); 13338c2ecf20Sopenharmony_ci 13348c2ecf20Sopenharmony_ci return ret_val; 13358c2ecf20Sopenharmony_ci} 13368c2ecf20Sopenharmony_ci 13378c2ecf20Sopenharmony_cistatic int 13388c2ecf20Sopenharmony_ciqla8044_start_firmware(struct scsi_qla_host *vha) 13398c2ecf20Sopenharmony_ci{ 13408c2ecf20Sopenharmony_ci int ret_val = QLA_SUCCESS; 13418c2ecf20Sopenharmony_ci 13428c2ecf20Sopenharmony_ci if (qla8044_restart(vha)) { 13438c2ecf20Sopenharmony_ci ql_log(ql_log_fatal, vha, 0xb0ad, 13448c2ecf20Sopenharmony_ci "%s: Restart Error!!!, Need Reset!!!\n", 13458c2ecf20Sopenharmony_ci __func__); 13468c2ecf20Sopenharmony_ci ret_val = QLA_FUNCTION_FAILED; 13478c2ecf20Sopenharmony_ci goto exit_start_fw; 13488c2ecf20Sopenharmony_ci } else 13498c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_p3p, vha, 0xb0af, 13508c2ecf20Sopenharmony_ci "%s: Restart done!\n", __func__); 13518c2ecf20Sopenharmony_ci 13528c2ecf20Sopenharmony_ci ret_val = qla8044_check_cmd_peg_status(vha); 13538c2ecf20Sopenharmony_ci if (ret_val) { 13548c2ecf20Sopenharmony_ci ql_log(ql_log_fatal, vha, 0xb0b0, 13558c2ecf20Sopenharmony_ci "%s: Peg not initialized!\n", __func__); 13568c2ecf20Sopenharmony_ci ret_val = QLA_FUNCTION_FAILED; 13578c2ecf20Sopenharmony_ci } 13588c2ecf20Sopenharmony_ci 13598c2ecf20Sopenharmony_ciexit_start_fw: 13608c2ecf20Sopenharmony_ci return ret_val; 13618c2ecf20Sopenharmony_ci} 13628c2ecf20Sopenharmony_ci 13638c2ecf20Sopenharmony_civoid 13648c2ecf20Sopenharmony_ciqla8044_clear_drv_active(struct qla_hw_data *ha) 13658c2ecf20Sopenharmony_ci{ 13668c2ecf20Sopenharmony_ci uint32_t drv_active; 13678c2ecf20Sopenharmony_ci struct scsi_qla_host *vha = pci_get_drvdata(ha->pdev); 13688c2ecf20Sopenharmony_ci 13698c2ecf20Sopenharmony_ci drv_active = qla8044_rd_direct(vha, QLA8044_CRB_DRV_ACTIVE_INDEX); 13708c2ecf20Sopenharmony_ci drv_active &= ~(1 << (ha->portnum)); 13718c2ecf20Sopenharmony_ci 13728c2ecf20Sopenharmony_ci ql_log(ql_log_info, vha, 0xb0b1, 13738c2ecf20Sopenharmony_ci "%s(%ld): drv_active: 0x%08x\n", 13748c2ecf20Sopenharmony_ci __func__, vha->host_no, drv_active); 13758c2ecf20Sopenharmony_ci 13768c2ecf20Sopenharmony_ci qla8044_wr_direct(vha, QLA8044_CRB_DRV_ACTIVE_INDEX, drv_active); 13778c2ecf20Sopenharmony_ci} 13788c2ecf20Sopenharmony_ci 13798c2ecf20Sopenharmony_ci/* 13808c2ecf20Sopenharmony_ci * qla8044_device_bootstrap - Initialize device, set DEV_READY, start fw 13818c2ecf20Sopenharmony_ci * @ha: pointer to adapter structure 13828c2ecf20Sopenharmony_ci * 13838c2ecf20Sopenharmony_ci * Note: IDC lock must be held upon entry 13848c2ecf20Sopenharmony_ci **/ 13858c2ecf20Sopenharmony_cistatic int 13868c2ecf20Sopenharmony_ciqla8044_device_bootstrap(struct scsi_qla_host *vha) 13878c2ecf20Sopenharmony_ci{ 13888c2ecf20Sopenharmony_ci int rval = QLA_FUNCTION_FAILED; 13898c2ecf20Sopenharmony_ci int i; 13908c2ecf20Sopenharmony_ci uint32_t old_count = 0, count = 0; 13918c2ecf20Sopenharmony_ci int need_reset = 0; 13928c2ecf20Sopenharmony_ci uint32_t idc_ctrl; 13938c2ecf20Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 13948c2ecf20Sopenharmony_ci 13958c2ecf20Sopenharmony_ci need_reset = qla8044_need_reset(vha); 13968c2ecf20Sopenharmony_ci 13978c2ecf20Sopenharmony_ci if (!need_reset) { 13988c2ecf20Sopenharmony_ci old_count = qla8044_rd_direct(vha, 13998c2ecf20Sopenharmony_ci QLA8044_PEG_ALIVE_COUNTER_INDEX); 14008c2ecf20Sopenharmony_ci 14018c2ecf20Sopenharmony_ci for (i = 0; i < 10; i++) { 14028c2ecf20Sopenharmony_ci msleep(200); 14038c2ecf20Sopenharmony_ci 14048c2ecf20Sopenharmony_ci count = qla8044_rd_direct(vha, 14058c2ecf20Sopenharmony_ci QLA8044_PEG_ALIVE_COUNTER_INDEX); 14068c2ecf20Sopenharmony_ci if (count != old_count) { 14078c2ecf20Sopenharmony_ci rval = QLA_SUCCESS; 14088c2ecf20Sopenharmony_ci goto dev_ready; 14098c2ecf20Sopenharmony_ci } 14108c2ecf20Sopenharmony_ci } 14118c2ecf20Sopenharmony_ci qla8044_flash_lock_recovery(vha); 14128c2ecf20Sopenharmony_ci } else { 14138c2ecf20Sopenharmony_ci /* We are trying to perform a recovery here. */ 14148c2ecf20Sopenharmony_ci if (ha->flags.isp82xx_fw_hung) 14158c2ecf20Sopenharmony_ci qla8044_flash_lock_recovery(vha); 14168c2ecf20Sopenharmony_ci } 14178c2ecf20Sopenharmony_ci 14188c2ecf20Sopenharmony_ci /* set to DEV_INITIALIZING */ 14198c2ecf20Sopenharmony_ci ql_log(ql_log_info, vha, 0xb0b2, 14208c2ecf20Sopenharmony_ci "%s: HW State: INITIALIZING\n", __func__); 14218c2ecf20Sopenharmony_ci qla8044_wr_direct(vha, QLA8044_CRB_DEV_STATE_INDEX, 14228c2ecf20Sopenharmony_ci QLA8XXX_DEV_INITIALIZING); 14238c2ecf20Sopenharmony_ci 14248c2ecf20Sopenharmony_ci qla8044_idc_unlock(ha); 14258c2ecf20Sopenharmony_ci rval = qla8044_start_firmware(vha); 14268c2ecf20Sopenharmony_ci qla8044_idc_lock(ha); 14278c2ecf20Sopenharmony_ci 14288c2ecf20Sopenharmony_ci if (rval != QLA_SUCCESS) { 14298c2ecf20Sopenharmony_ci ql_log(ql_log_info, vha, 0xb0b3, 14308c2ecf20Sopenharmony_ci "%s: HW State: FAILED\n", __func__); 14318c2ecf20Sopenharmony_ci qla8044_clear_drv_active(ha); 14328c2ecf20Sopenharmony_ci qla8044_wr_direct(vha, QLA8044_CRB_DEV_STATE_INDEX, 14338c2ecf20Sopenharmony_ci QLA8XXX_DEV_FAILED); 14348c2ecf20Sopenharmony_ci return rval; 14358c2ecf20Sopenharmony_ci } 14368c2ecf20Sopenharmony_ci 14378c2ecf20Sopenharmony_ci /* For ISP8044, If IDC_CTRL GRACEFUL_RESET_BIT1 is set , reset it after 14388c2ecf20Sopenharmony_ci * device goes to INIT state. */ 14398c2ecf20Sopenharmony_ci idc_ctrl = qla8044_rd_reg(ha, QLA8044_IDC_DRV_CTRL); 14408c2ecf20Sopenharmony_ci if (idc_ctrl & GRACEFUL_RESET_BIT1) { 14418c2ecf20Sopenharmony_ci qla8044_wr_reg(ha, QLA8044_IDC_DRV_CTRL, 14428c2ecf20Sopenharmony_ci (idc_ctrl & ~GRACEFUL_RESET_BIT1)); 14438c2ecf20Sopenharmony_ci ha->fw_dumped = false; 14448c2ecf20Sopenharmony_ci } 14458c2ecf20Sopenharmony_ci 14468c2ecf20Sopenharmony_cidev_ready: 14478c2ecf20Sopenharmony_ci ql_log(ql_log_info, vha, 0xb0b4, 14488c2ecf20Sopenharmony_ci "%s: HW State: READY\n", __func__); 14498c2ecf20Sopenharmony_ci qla8044_wr_direct(vha, QLA8044_CRB_DEV_STATE_INDEX, QLA8XXX_DEV_READY); 14508c2ecf20Sopenharmony_ci 14518c2ecf20Sopenharmony_ci return rval; 14528c2ecf20Sopenharmony_ci} 14538c2ecf20Sopenharmony_ci 14548c2ecf20Sopenharmony_ci/*-------------------------Reset Sequence Functions-----------------------*/ 14558c2ecf20Sopenharmony_cistatic void 14568c2ecf20Sopenharmony_ciqla8044_dump_reset_seq_hdr(struct scsi_qla_host *vha) 14578c2ecf20Sopenharmony_ci{ 14588c2ecf20Sopenharmony_ci u8 *phdr; 14598c2ecf20Sopenharmony_ci 14608c2ecf20Sopenharmony_ci if (!vha->reset_tmplt.buff) { 14618c2ecf20Sopenharmony_ci ql_log(ql_log_fatal, vha, 0xb0b5, 14628c2ecf20Sopenharmony_ci "%s: Error Invalid reset_seq_template\n", __func__); 14638c2ecf20Sopenharmony_ci return; 14648c2ecf20Sopenharmony_ci } 14658c2ecf20Sopenharmony_ci 14668c2ecf20Sopenharmony_ci phdr = vha->reset_tmplt.buff; 14678c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_p3p, vha, 0xb0b6, 14688c2ecf20Sopenharmony_ci "Reset Template :\n\t0x%X 0x%X 0x%X 0x%X" 14698c2ecf20Sopenharmony_ci "0x%X 0x%X 0x%X 0x%X 0x%X 0x%X\n" 14708c2ecf20Sopenharmony_ci "\t0x%X 0x%X 0x%X 0x%X 0x%X 0x%X\n\n", 14718c2ecf20Sopenharmony_ci *phdr, *(phdr+1), *(phdr+2), *(phdr+3), *(phdr+4), 14728c2ecf20Sopenharmony_ci *(phdr+5), *(phdr+6), *(phdr+7), *(phdr + 8), 14738c2ecf20Sopenharmony_ci *(phdr+9), *(phdr+10), *(phdr+11), *(phdr+12), 14748c2ecf20Sopenharmony_ci *(phdr+13), *(phdr+14), *(phdr+15)); 14758c2ecf20Sopenharmony_ci} 14768c2ecf20Sopenharmony_ci 14778c2ecf20Sopenharmony_ci/* 14788c2ecf20Sopenharmony_ci * qla8044_reset_seq_checksum_test - Validate Reset Sequence template. 14798c2ecf20Sopenharmony_ci * 14808c2ecf20Sopenharmony_ci * @ha : Pointer to adapter structure 14818c2ecf20Sopenharmony_ci * 14828c2ecf20Sopenharmony_ci * Return Value - QLA_SUCCESS/QLA_FUNCTION_FAILED 14838c2ecf20Sopenharmony_ci */ 14848c2ecf20Sopenharmony_cistatic int 14858c2ecf20Sopenharmony_ciqla8044_reset_seq_checksum_test(struct scsi_qla_host *vha) 14868c2ecf20Sopenharmony_ci{ 14878c2ecf20Sopenharmony_ci uint32_t sum = 0; 14888c2ecf20Sopenharmony_ci uint16_t *buff = (uint16_t *)vha->reset_tmplt.buff; 14898c2ecf20Sopenharmony_ci int u16_count = vha->reset_tmplt.hdr->size / sizeof(uint16_t); 14908c2ecf20Sopenharmony_ci 14918c2ecf20Sopenharmony_ci while (u16_count-- > 0) 14928c2ecf20Sopenharmony_ci sum += *buff++; 14938c2ecf20Sopenharmony_ci 14948c2ecf20Sopenharmony_ci while (sum >> 16) 14958c2ecf20Sopenharmony_ci sum = (sum & 0xFFFF) + (sum >> 16); 14968c2ecf20Sopenharmony_ci 14978c2ecf20Sopenharmony_ci /* checksum of 0 indicates a valid template */ 14988c2ecf20Sopenharmony_ci if (~sum) { 14998c2ecf20Sopenharmony_ci return QLA_SUCCESS; 15008c2ecf20Sopenharmony_ci } else { 15018c2ecf20Sopenharmony_ci ql_log(ql_log_fatal, vha, 0xb0b7, 15028c2ecf20Sopenharmony_ci "%s: Reset seq checksum failed\n", __func__); 15038c2ecf20Sopenharmony_ci return QLA_FUNCTION_FAILED; 15048c2ecf20Sopenharmony_ci } 15058c2ecf20Sopenharmony_ci} 15068c2ecf20Sopenharmony_ci 15078c2ecf20Sopenharmony_ci/* 15088c2ecf20Sopenharmony_ci * qla8044_read_reset_template - Read Reset Template from Flash, validate 15098c2ecf20Sopenharmony_ci * the template and store offsets of stop/start/init offsets in ha->reset_tmplt. 15108c2ecf20Sopenharmony_ci * 15118c2ecf20Sopenharmony_ci * @ha : Pointer to adapter structure 15128c2ecf20Sopenharmony_ci */ 15138c2ecf20Sopenharmony_civoid 15148c2ecf20Sopenharmony_ciqla8044_read_reset_template(struct scsi_qla_host *vha) 15158c2ecf20Sopenharmony_ci{ 15168c2ecf20Sopenharmony_ci uint8_t *p_buff; 15178c2ecf20Sopenharmony_ci uint32_t addr, tmplt_hdr_def_size, tmplt_hdr_size; 15188c2ecf20Sopenharmony_ci 15198c2ecf20Sopenharmony_ci vha->reset_tmplt.seq_error = 0; 15208c2ecf20Sopenharmony_ci vha->reset_tmplt.buff = vmalloc(QLA8044_RESTART_TEMPLATE_SIZE); 15218c2ecf20Sopenharmony_ci if (vha->reset_tmplt.buff == NULL) { 15228c2ecf20Sopenharmony_ci ql_log(ql_log_fatal, vha, 0xb0b8, 15238c2ecf20Sopenharmony_ci "%s: Failed to allocate reset template resources\n", 15248c2ecf20Sopenharmony_ci __func__); 15258c2ecf20Sopenharmony_ci goto exit_read_reset_template; 15268c2ecf20Sopenharmony_ci } 15278c2ecf20Sopenharmony_ci 15288c2ecf20Sopenharmony_ci p_buff = vha->reset_tmplt.buff; 15298c2ecf20Sopenharmony_ci addr = QLA8044_RESET_TEMPLATE_ADDR; 15308c2ecf20Sopenharmony_ci 15318c2ecf20Sopenharmony_ci tmplt_hdr_def_size = 15328c2ecf20Sopenharmony_ci sizeof(struct qla8044_reset_template_hdr) / sizeof(uint32_t); 15338c2ecf20Sopenharmony_ci 15348c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_p3p, vha, 0xb0b9, 15358c2ecf20Sopenharmony_ci "%s: Read template hdr size %d from Flash\n", 15368c2ecf20Sopenharmony_ci __func__, tmplt_hdr_def_size); 15378c2ecf20Sopenharmony_ci 15388c2ecf20Sopenharmony_ci /* Copy template header from flash */ 15398c2ecf20Sopenharmony_ci if (qla8044_read_flash_data(vha, p_buff, addr, tmplt_hdr_def_size)) { 15408c2ecf20Sopenharmony_ci ql_log(ql_log_fatal, vha, 0xb0ba, 15418c2ecf20Sopenharmony_ci "%s: Failed to read reset template\n", __func__); 15428c2ecf20Sopenharmony_ci goto exit_read_template_error; 15438c2ecf20Sopenharmony_ci } 15448c2ecf20Sopenharmony_ci 15458c2ecf20Sopenharmony_ci vha->reset_tmplt.hdr = 15468c2ecf20Sopenharmony_ci (struct qla8044_reset_template_hdr *) vha->reset_tmplt.buff; 15478c2ecf20Sopenharmony_ci 15488c2ecf20Sopenharmony_ci /* Validate the template header size and signature */ 15498c2ecf20Sopenharmony_ci tmplt_hdr_size = vha->reset_tmplt.hdr->hdr_size/sizeof(uint32_t); 15508c2ecf20Sopenharmony_ci if ((tmplt_hdr_size != tmplt_hdr_def_size) || 15518c2ecf20Sopenharmony_ci (vha->reset_tmplt.hdr->signature != RESET_TMPLT_HDR_SIGNATURE)) { 15528c2ecf20Sopenharmony_ci ql_log(ql_log_fatal, vha, 0xb0bb, 15538c2ecf20Sopenharmony_ci "%s: Template Header size invalid %d " 15548c2ecf20Sopenharmony_ci "tmplt_hdr_def_size %d!!!\n", __func__, 15558c2ecf20Sopenharmony_ci tmplt_hdr_size, tmplt_hdr_def_size); 15568c2ecf20Sopenharmony_ci goto exit_read_template_error; 15578c2ecf20Sopenharmony_ci } 15588c2ecf20Sopenharmony_ci 15598c2ecf20Sopenharmony_ci addr = QLA8044_RESET_TEMPLATE_ADDR + vha->reset_tmplt.hdr->hdr_size; 15608c2ecf20Sopenharmony_ci p_buff = vha->reset_tmplt.buff + vha->reset_tmplt.hdr->hdr_size; 15618c2ecf20Sopenharmony_ci tmplt_hdr_def_size = (vha->reset_tmplt.hdr->size - 15628c2ecf20Sopenharmony_ci vha->reset_tmplt.hdr->hdr_size)/sizeof(uint32_t); 15638c2ecf20Sopenharmony_ci 15648c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_p3p, vha, 0xb0bc, 15658c2ecf20Sopenharmony_ci "%s: Read rest of the template size %d\n", 15668c2ecf20Sopenharmony_ci __func__, vha->reset_tmplt.hdr->size); 15678c2ecf20Sopenharmony_ci 15688c2ecf20Sopenharmony_ci /* Copy rest of the template */ 15698c2ecf20Sopenharmony_ci if (qla8044_read_flash_data(vha, p_buff, addr, tmplt_hdr_def_size)) { 15708c2ecf20Sopenharmony_ci ql_log(ql_log_fatal, vha, 0xb0bd, 15718c2ecf20Sopenharmony_ci "%s: Failed to read reset template\n", __func__); 15728c2ecf20Sopenharmony_ci goto exit_read_template_error; 15738c2ecf20Sopenharmony_ci } 15748c2ecf20Sopenharmony_ci 15758c2ecf20Sopenharmony_ci /* Integrity check */ 15768c2ecf20Sopenharmony_ci if (qla8044_reset_seq_checksum_test(vha)) { 15778c2ecf20Sopenharmony_ci ql_log(ql_log_fatal, vha, 0xb0be, 15788c2ecf20Sopenharmony_ci "%s: Reset Seq checksum failed!\n", __func__); 15798c2ecf20Sopenharmony_ci goto exit_read_template_error; 15808c2ecf20Sopenharmony_ci } 15818c2ecf20Sopenharmony_ci 15828c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_p3p, vha, 0xb0bf, 15838c2ecf20Sopenharmony_ci "%s: Reset Seq checksum passed! Get stop, " 15848c2ecf20Sopenharmony_ci "start and init seq offsets\n", __func__); 15858c2ecf20Sopenharmony_ci 15868c2ecf20Sopenharmony_ci /* Get STOP, START, INIT sequence offsets */ 15878c2ecf20Sopenharmony_ci vha->reset_tmplt.init_offset = vha->reset_tmplt.buff + 15888c2ecf20Sopenharmony_ci vha->reset_tmplt.hdr->init_seq_offset; 15898c2ecf20Sopenharmony_ci 15908c2ecf20Sopenharmony_ci vha->reset_tmplt.start_offset = vha->reset_tmplt.buff + 15918c2ecf20Sopenharmony_ci vha->reset_tmplt.hdr->start_seq_offset; 15928c2ecf20Sopenharmony_ci 15938c2ecf20Sopenharmony_ci vha->reset_tmplt.stop_offset = vha->reset_tmplt.buff + 15948c2ecf20Sopenharmony_ci vha->reset_tmplt.hdr->hdr_size; 15958c2ecf20Sopenharmony_ci 15968c2ecf20Sopenharmony_ci qla8044_dump_reset_seq_hdr(vha); 15978c2ecf20Sopenharmony_ci 15988c2ecf20Sopenharmony_ci goto exit_read_reset_template; 15998c2ecf20Sopenharmony_ci 16008c2ecf20Sopenharmony_ciexit_read_template_error: 16018c2ecf20Sopenharmony_ci vfree(vha->reset_tmplt.buff); 16028c2ecf20Sopenharmony_ci 16038c2ecf20Sopenharmony_ciexit_read_reset_template: 16048c2ecf20Sopenharmony_ci return; 16058c2ecf20Sopenharmony_ci} 16068c2ecf20Sopenharmony_ci 16078c2ecf20Sopenharmony_civoid 16088c2ecf20Sopenharmony_ciqla8044_set_idc_dontreset(struct scsi_qla_host *vha) 16098c2ecf20Sopenharmony_ci{ 16108c2ecf20Sopenharmony_ci uint32_t idc_ctrl; 16118c2ecf20Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 16128c2ecf20Sopenharmony_ci 16138c2ecf20Sopenharmony_ci idc_ctrl = qla8044_rd_reg(ha, QLA8044_IDC_DRV_CTRL); 16148c2ecf20Sopenharmony_ci idc_ctrl |= DONTRESET_BIT0; 16158c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_p3p, vha, 0xb0c0, 16168c2ecf20Sopenharmony_ci "%s: idc_ctrl = %d\n", __func__, idc_ctrl); 16178c2ecf20Sopenharmony_ci qla8044_wr_reg(ha, QLA8044_IDC_DRV_CTRL, idc_ctrl); 16188c2ecf20Sopenharmony_ci} 16198c2ecf20Sopenharmony_ci 16208c2ecf20Sopenharmony_cistatic inline void 16218c2ecf20Sopenharmony_ciqla8044_set_rst_ready(struct scsi_qla_host *vha) 16228c2ecf20Sopenharmony_ci{ 16238c2ecf20Sopenharmony_ci uint32_t drv_state; 16248c2ecf20Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 16258c2ecf20Sopenharmony_ci 16268c2ecf20Sopenharmony_ci drv_state = qla8044_rd_direct(vha, QLA8044_CRB_DRV_STATE_INDEX); 16278c2ecf20Sopenharmony_ci 16288c2ecf20Sopenharmony_ci /* For ISP8044, drv_active register has 1 bit per function, 16298c2ecf20Sopenharmony_ci * shift 1 by func_num to set a bit for the function.*/ 16308c2ecf20Sopenharmony_ci drv_state |= (1 << ha->portnum); 16318c2ecf20Sopenharmony_ci 16328c2ecf20Sopenharmony_ci ql_log(ql_log_info, vha, 0xb0c1, 16338c2ecf20Sopenharmony_ci "%s(%ld): drv_state: 0x%08x\n", 16348c2ecf20Sopenharmony_ci __func__, vha->host_no, drv_state); 16358c2ecf20Sopenharmony_ci qla8044_wr_direct(vha, QLA8044_CRB_DRV_STATE_INDEX, drv_state); 16368c2ecf20Sopenharmony_ci} 16378c2ecf20Sopenharmony_ci 16388c2ecf20Sopenharmony_ci/** 16398c2ecf20Sopenharmony_ci * qla8044_need_reset_handler - Code to start reset sequence 16408c2ecf20Sopenharmony_ci * @vha: pointer to adapter structure 16418c2ecf20Sopenharmony_ci * 16428c2ecf20Sopenharmony_ci * Note: IDC lock must be held upon entry 16438c2ecf20Sopenharmony_ci */ 16448c2ecf20Sopenharmony_cistatic void 16458c2ecf20Sopenharmony_ciqla8044_need_reset_handler(struct scsi_qla_host *vha) 16468c2ecf20Sopenharmony_ci{ 16478c2ecf20Sopenharmony_ci uint32_t dev_state = 0, drv_state, drv_active; 16488c2ecf20Sopenharmony_ci unsigned long reset_timeout; 16498c2ecf20Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 16508c2ecf20Sopenharmony_ci 16518c2ecf20Sopenharmony_ci ql_log(ql_log_fatal, vha, 0xb0c2, 16528c2ecf20Sopenharmony_ci "%s: Performing ISP error recovery\n", __func__); 16538c2ecf20Sopenharmony_ci 16548c2ecf20Sopenharmony_ci if (vha->flags.online) { 16558c2ecf20Sopenharmony_ci qla8044_idc_unlock(ha); 16568c2ecf20Sopenharmony_ci qla2x00_abort_isp_cleanup(vha); 16578c2ecf20Sopenharmony_ci ha->isp_ops->get_flash_version(vha, vha->req->ring); 16588c2ecf20Sopenharmony_ci ha->isp_ops->nvram_config(vha); 16598c2ecf20Sopenharmony_ci qla8044_idc_lock(ha); 16608c2ecf20Sopenharmony_ci } 16618c2ecf20Sopenharmony_ci 16628c2ecf20Sopenharmony_ci dev_state = qla8044_rd_direct(vha, 16638c2ecf20Sopenharmony_ci QLA8044_CRB_DEV_STATE_INDEX); 16648c2ecf20Sopenharmony_ci drv_state = qla8044_rd_direct(vha, 16658c2ecf20Sopenharmony_ci QLA8044_CRB_DRV_STATE_INDEX); 16668c2ecf20Sopenharmony_ci drv_active = qla8044_rd_direct(vha, 16678c2ecf20Sopenharmony_ci QLA8044_CRB_DRV_ACTIVE_INDEX); 16688c2ecf20Sopenharmony_ci 16698c2ecf20Sopenharmony_ci ql_log(ql_log_info, vha, 0xb0c5, 16708c2ecf20Sopenharmony_ci "%s(%ld): drv_state = 0x%x, drv_active = 0x%x dev_state = 0x%x\n", 16718c2ecf20Sopenharmony_ci __func__, vha->host_no, drv_state, drv_active, dev_state); 16728c2ecf20Sopenharmony_ci 16738c2ecf20Sopenharmony_ci qla8044_set_rst_ready(vha); 16748c2ecf20Sopenharmony_ci 16758c2ecf20Sopenharmony_ci /* wait for 10 seconds for reset ack from all functions */ 16768c2ecf20Sopenharmony_ci reset_timeout = jiffies + (ha->fcoe_reset_timeout * HZ); 16778c2ecf20Sopenharmony_ci 16788c2ecf20Sopenharmony_ci do { 16798c2ecf20Sopenharmony_ci if (time_after_eq(jiffies, reset_timeout)) { 16808c2ecf20Sopenharmony_ci ql_log(ql_log_info, vha, 0xb0c4, 16818c2ecf20Sopenharmony_ci "%s: Function %d: Reset Ack Timeout!, drv_state: 0x%08x, drv_active: 0x%08x\n", 16828c2ecf20Sopenharmony_ci __func__, ha->portnum, drv_state, drv_active); 16838c2ecf20Sopenharmony_ci break; 16848c2ecf20Sopenharmony_ci } 16858c2ecf20Sopenharmony_ci 16868c2ecf20Sopenharmony_ci qla8044_idc_unlock(ha); 16878c2ecf20Sopenharmony_ci msleep(1000); 16888c2ecf20Sopenharmony_ci qla8044_idc_lock(ha); 16898c2ecf20Sopenharmony_ci 16908c2ecf20Sopenharmony_ci dev_state = qla8044_rd_direct(vha, 16918c2ecf20Sopenharmony_ci QLA8044_CRB_DEV_STATE_INDEX); 16928c2ecf20Sopenharmony_ci drv_state = qla8044_rd_direct(vha, 16938c2ecf20Sopenharmony_ci QLA8044_CRB_DRV_STATE_INDEX); 16948c2ecf20Sopenharmony_ci drv_active = qla8044_rd_direct(vha, 16958c2ecf20Sopenharmony_ci QLA8044_CRB_DRV_ACTIVE_INDEX); 16968c2ecf20Sopenharmony_ci } while (((drv_state & drv_active) != drv_active) && 16978c2ecf20Sopenharmony_ci (dev_state == QLA8XXX_DEV_NEED_RESET)); 16988c2ecf20Sopenharmony_ci 16998c2ecf20Sopenharmony_ci /* Remove IDC participation of functions not acknowledging */ 17008c2ecf20Sopenharmony_ci if (drv_state != drv_active) { 17018c2ecf20Sopenharmony_ci ql_log(ql_log_info, vha, 0xb0c7, 17028c2ecf20Sopenharmony_ci "%s(%ld): Function %d turning off drv_active of non-acking function 0x%x\n", 17038c2ecf20Sopenharmony_ci __func__, vha->host_no, ha->portnum, 17048c2ecf20Sopenharmony_ci (drv_active ^ drv_state)); 17058c2ecf20Sopenharmony_ci drv_active = drv_active & drv_state; 17068c2ecf20Sopenharmony_ci qla8044_wr_direct(vha, QLA8044_CRB_DRV_ACTIVE_INDEX, 17078c2ecf20Sopenharmony_ci drv_active); 17088c2ecf20Sopenharmony_ci } else { 17098c2ecf20Sopenharmony_ci /* 17108c2ecf20Sopenharmony_ci * Reset owner should execute reset recovery, 17118c2ecf20Sopenharmony_ci * if all functions acknowledged 17128c2ecf20Sopenharmony_ci */ 17138c2ecf20Sopenharmony_ci if ((ha->flags.nic_core_reset_owner) && 17148c2ecf20Sopenharmony_ci (dev_state == QLA8XXX_DEV_NEED_RESET)) { 17158c2ecf20Sopenharmony_ci ha->flags.nic_core_reset_owner = 0; 17168c2ecf20Sopenharmony_ci qla8044_device_bootstrap(vha); 17178c2ecf20Sopenharmony_ci return; 17188c2ecf20Sopenharmony_ci } 17198c2ecf20Sopenharmony_ci } 17208c2ecf20Sopenharmony_ci 17218c2ecf20Sopenharmony_ci /* Exit if non active function */ 17228c2ecf20Sopenharmony_ci if (!(drv_active & (1 << ha->portnum))) { 17238c2ecf20Sopenharmony_ci ha->flags.nic_core_reset_owner = 0; 17248c2ecf20Sopenharmony_ci return; 17258c2ecf20Sopenharmony_ci } 17268c2ecf20Sopenharmony_ci 17278c2ecf20Sopenharmony_ci /* 17288c2ecf20Sopenharmony_ci * Execute Reset Recovery if Reset Owner or Function 7 17298c2ecf20Sopenharmony_ci * is the only active function 17308c2ecf20Sopenharmony_ci */ 17318c2ecf20Sopenharmony_ci if (ha->flags.nic_core_reset_owner || 17328c2ecf20Sopenharmony_ci ((drv_state & drv_active) == QLA8044_FUN7_ACTIVE_INDEX)) { 17338c2ecf20Sopenharmony_ci ha->flags.nic_core_reset_owner = 0; 17348c2ecf20Sopenharmony_ci qla8044_device_bootstrap(vha); 17358c2ecf20Sopenharmony_ci } 17368c2ecf20Sopenharmony_ci} 17378c2ecf20Sopenharmony_ci 17388c2ecf20Sopenharmony_cistatic void 17398c2ecf20Sopenharmony_ciqla8044_set_drv_active(struct scsi_qla_host *vha) 17408c2ecf20Sopenharmony_ci{ 17418c2ecf20Sopenharmony_ci uint32_t drv_active; 17428c2ecf20Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 17438c2ecf20Sopenharmony_ci 17448c2ecf20Sopenharmony_ci drv_active = qla8044_rd_direct(vha, QLA8044_CRB_DRV_ACTIVE_INDEX); 17458c2ecf20Sopenharmony_ci 17468c2ecf20Sopenharmony_ci /* For ISP8044, drv_active register has 1 bit per function, 17478c2ecf20Sopenharmony_ci * shift 1 by func_num to set a bit for the function.*/ 17488c2ecf20Sopenharmony_ci drv_active |= (1 << ha->portnum); 17498c2ecf20Sopenharmony_ci 17508c2ecf20Sopenharmony_ci ql_log(ql_log_info, vha, 0xb0c8, 17518c2ecf20Sopenharmony_ci "%s(%ld): drv_active: 0x%08x\n", 17528c2ecf20Sopenharmony_ci __func__, vha->host_no, drv_active); 17538c2ecf20Sopenharmony_ci qla8044_wr_direct(vha, QLA8044_CRB_DRV_ACTIVE_INDEX, drv_active); 17548c2ecf20Sopenharmony_ci} 17558c2ecf20Sopenharmony_ci 17568c2ecf20Sopenharmony_cistatic int 17578c2ecf20Sopenharmony_ciqla8044_check_drv_active(struct scsi_qla_host *vha) 17588c2ecf20Sopenharmony_ci{ 17598c2ecf20Sopenharmony_ci uint32_t drv_active; 17608c2ecf20Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 17618c2ecf20Sopenharmony_ci 17628c2ecf20Sopenharmony_ci drv_active = qla8044_rd_direct(vha, QLA8044_CRB_DRV_ACTIVE_INDEX); 17638c2ecf20Sopenharmony_ci if (drv_active & (1 << ha->portnum)) 17648c2ecf20Sopenharmony_ci return QLA_SUCCESS; 17658c2ecf20Sopenharmony_ci else 17668c2ecf20Sopenharmony_ci return QLA_TEST_FAILED; 17678c2ecf20Sopenharmony_ci} 17688c2ecf20Sopenharmony_ci 17698c2ecf20Sopenharmony_cistatic void 17708c2ecf20Sopenharmony_ciqla8044_clear_idc_dontreset(struct scsi_qla_host *vha) 17718c2ecf20Sopenharmony_ci{ 17728c2ecf20Sopenharmony_ci uint32_t idc_ctrl; 17738c2ecf20Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 17748c2ecf20Sopenharmony_ci 17758c2ecf20Sopenharmony_ci idc_ctrl = qla8044_rd_reg(ha, QLA8044_IDC_DRV_CTRL); 17768c2ecf20Sopenharmony_ci idc_ctrl &= ~DONTRESET_BIT0; 17778c2ecf20Sopenharmony_ci ql_log(ql_log_info, vha, 0xb0c9, 17788c2ecf20Sopenharmony_ci "%s: idc_ctrl = %d\n", __func__, 17798c2ecf20Sopenharmony_ci idc_ctrl); 17808c2ecf20Sopenharmony_ci qla8044_wr_reg(ha, QLA8044_IDC_DRV_CTRL, idc_ctrl); 17818c2ecf20Sopenharmony_ci} 17828c2ecf20Sopenharmony_ci 17838c2ecf20Sopenharmony_cistatic int 17848c2ecf20Sopenharmony_ciqla8044_set_idc_ver(struct scsi_qla_host *vha) 17858c2ecf20Sopenharmony_ci{ 17868c2ecf20Sopenharmony_ci int idc_ver; 17878c2ecf20Sopenharmony_ci uint32_t drv_active; 17888c2ecf20Sopenharmony_ci int rval = QLA_SUCCESS; 17898c2ecf20Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 17908c2ecf20Sopenharmony_ci 17918c2ecf20Sopenharmony_ci drv_active = qla8044_rd_direct(vha, QLA8044_CRB_DRV_ACTIVE_INDEX); 17928c2ecf20Sopenharmony_ci if (drv_active == (1 << ha->portnum)) { 17938c2ecf20Sopenharmony_ci idc_ver = qla8044_rd_direct(vha, 17948c2ecf20Sopenharmony_ci QLA8044_CRB_DRV_IDC_VERSION_INDEX); 17958c2ecf20Sopenharmony_ci idc_ver &= (~0xFF); 17968c2ecf20Sopenharmony_ci idc_ver |= QLA8044_IDC_VER_MAJ_VALUE; 17978c2ecf20Sopenharmony_ci qla8044_wr_direct(vha, QLA8044_CRB_DRV_IDC_VERSION_INDEX, 17988c2ecf20Sopenharmony_ci idc_ver); 17998c2ecf20Sopenharmony_ci ql_log(ql_log_info, vha, 0xb0ca, 18008c2ecf20Sopenharmony_ci "%s: IDC version updated to %d\n", 18018c2ecf20Sopenharmony_ci __func__, idc_ver); 18028c2ecf20Sopenharmony_ci } else { 18038c2ecf20Sopenharmony_ci idc_ver = qla8044_rd_direct(vha, 18048c2ecf20Sopenharmony_ci QLA8044_CRB_DRV_IDC_VERSION_INDEX); 18058c2ecf20Sopenharmony_ci idc_ver &= 0xFF; 18068c2ecf20Sopenharmony_ci if (QLA8044_IDC_VER_MAJ_VALUE != idc_ver) { 18078c2ecf20Sopenharmony_ci ql_log(ql_log_info, vha, 0xb0cb, 18088c2ecf20Sopenharmony_ci "%s: qla4xxx driver IDC version %d " 18098c2ecf20Sopenharmony_ci "is not compatible with IDC version %d " 18108c2ecf20Sopenharmony_ci "of other drivers!\n", 18118c2ecf20Sopenharmony_ci __func__, QLA8044_IDC_VER_MAJ_VALUE, 18128c2ecf20Sopenharmony_ci idc_ver); 18138c2ecf20Sopenharmony_ci rval = QLA_FUNCTION_FAILED; 18148c2ecf20Sopenharmony_ci goto exit_set_idc_ver; 18158c2ecf20Sopenharmony_ci } 18168c2ecf20Sopenharmony_ci } 18178c2ecf20Sopenharmony_ci 18188c2ecf20Sopenharmony_ci /* Update IDC_MINOR_VERSION */ 18198c2ecf20Sopenharmony_ci idc_ver = qla8044_rd_reg(ha, QLA8044_CRB_IDC_VER_MINOR); 18208c2ecf20Sopenharmony_ci idc_ver &= ~(0x03 << (ha->portnum * 2)); 18218c2ecf20Sopenharmony_ci idc_ver |= (QLA8044_IDC_VER_MIN_VALUE << (ha->portnum * 2)); 18228c2ecf20Sopenharmony_ci qla8044_wr_reg(ha, QLA8044_CRB_IDC_VER_MINOR, idc_ver); 18238c2ecf20Sopenharmony_ci 18248c2ecf20Sopenharmony_ciexit_set_idc_ver: 18258c2ecf20Sopenharmony_ci return rval; 18268c2ecf20Sopenharmony_ci} 18278c2ecf20Sopenharmony_ci 18288c2ecf20Sopenharmony_cistatic int 18298c2ecf20Sopenharmony_ciqla8044_update_idc_reg(struct scsi_qla_host *vha) 18308c2ecf20Sopenharmony_ci{ 18318c2ecf20Sopenharmony_ci uint32_t drv_active; 18328c2ecf20Sopenharmony_ci int rval = QLA_SUCCESS; 18338c2ecf20Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 18348c2ecf20Sopenharmony_ci 18358c2ecf20Sopenharmony_ci if (vha->flags.init_done) 18368c2ecf20Sopenharmony_ci goto exit_update_idc_reg; 18378c2ecf20Sopenharmony_ci 18388c2ecf20Sopenharmony_ci qla8044_idc_lock(ha); 18398c2ecf20Sopenharmony_ci qla8044_set_drv_active(vha); 18408c2ecf20Sopenharmony_ci 18418c2ecf20Sopenharmony_ci drv_active = qla8044_rd_direct(vha, 18428c2ecf20Sopenharmony_ci QLA8044_CRB_DRV_ACTIVE_INDEX); 18438c2ecf20Sopenharmony_ci 18448c2ecf20Sopenharmony_ci /* If we are the first driver to load and 18458c2ecf20Sopenharmony_ci * ql2xdontresethba is not set, clear IDC_CTRL BIT0. */ 18468c2ecf20Sopenharmony_ci if ((drv_active == (1 << ha->portnum)) && !ql2xdontresethba) 18478c2ecf20Sopenharmony_ci qla8044_clear_idc_dontreset(vha); 18488c2ecf20Sopenharmony_ci 18498c2ecf20Sopenharmony_ci rval = qla8044_set_idc_ver(vha); 18508c2ecf20Sopenharmony_ci if (rval == QLA_FUNCTION_FAILED) 18518c2ecf20Sopenharmony_ci qla8044_clear_drv_active(ha); 18528c2ecf20Sopenharmony_ci qla8044_idc_unlock(ha); 18538c2ecf20Sopenharmony_ci 18548c2ecf20Sopenharmony_ciexit_update_idc_reg: 18558c2ecf20Sopenharmony_ci return rval; 18568c2ecf20Sopenharmony_ci} 18578c2ecf20Sopenharmony_ci 18588c2ecf20Sopenharmony_ci/** 18598c2ecf20Sopenharmony_ci * qla8044_need_qsnt_handler - Code to start qsnt 18608c2ecf20Sopenharmony_ci * @vha: pointer to adapter structure 18618c2ecf20Sopenharmony_ci */ 18628c2ecf20Sopenharmony_cistatic void 18638c2ecf20Sopenharmony_ciqla8044_need_qsnt_handler(struct scsi_qla_host *vha) 18648c2ecf20Sopenharmony_ci{ 18658c2ecf20Sopenharmony_ci unsigned long qsnt_timeout; 18668c2ecf20Sopenharmony_ci uint32_t drv_state, drv_active, dev_state; 18678c2ecf20Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 18688c2ecf20Sopenharmony_ci 18698c2ecf20Sopenharmony_ci if (vha->flags.online) 18708c2ecf20Sopenharmony_ci qla2x00_quiesce_io(vha); 18718c2ecf20Sopenharmony_ci else 18728c2ecf20Sopenharmony_ci return; 18738c2ecf20Sopenharmony_ci 18748c2ecf20Sopenharmony_ci qla8044_set_qsnt_ready(vha); 18758c2ecf20Sopenharmony_ci 18768c2ecf20Sopenharmony_ci /* Wait for 30 secs for all functions to ack qsnt mode */ 18778c2ecf20Sopenharmony_ci qsnt_timeout = jiffies + (QSNT_ACK_TOV * HZ); 18788c2ecf20Sopenharmony_ci drv_state = qla8044_rd_direct(vha, QLA8044_CRB_DRV_STATE_INDEX); 18798c2ecf20Sopenharmony_ci drv_active = qla8044_rd_direct(vha, QLA8044_CRB_DRV_ACTIVE_INDEX); 18808c2ecf20Sopenharmony_ci 18818c2ecf20Sopenharmony_ci /* Shift drv_active by 1 to match drv_state. As quiescent ready bit 18828c2ecf20Sopenharmony_ci position is at bit 1 and drv active is at bit 0 */ 18838c2ecf20Sopenharmony_ci drv_active = drv_active << 1; 18848c2ecf20Sopenharmony_ci 18858c2ecf20Sopenharmony_ci while (drv_state != drv_active) { 18868c2ecf20Sopenharmony_ci if (time_after_eq(jiffies, qsnt_timeout)) { 18878c2ecf20Sopenharmony_ci /* Other functions did not ack, changing state to 18888c2ecf20Sopenharmony_ci * DEV_READY 18898c2ecf20Sopenharmony_ci */ 18908c2ecf20Sopenharmony_ci clear_bit(ISP_QUIESCE_NEEDED, &vha->dpc_flags); 18918c2ecf20Sopenharmony_ci qla8044_wr_direct(vha, QLA8044_CRB_DEV_STATE_INDEX, 18928c2ecf20Sopenharmony_ci QLA8XXX_DEV_READY); 18938c2ecf20Sopenharmony_ci qla8044_clear_qsnt_ready(vha); 18948c2ecf20Sopenharmony_ci ql_log(ql_log_info, vha, 0xb0cc, 18958c2ecf20Sopenharmony_ci "Timeout waiting for quiescent ack!!!\n"); 18968c2ecf20Sopenharmony_ci return; 18978c2ecf20Sopenharmony_ci } 18988c2ecf20Sopenharmony_ci qla8044_idc_unlock(ha); 18998c2ecf20Sopenharmony_ci msleep(1000); 19008c2ecf20Sopenharmony_ci qla8044_idc_lock(ha); 19018c2ecf20Sopenharmony_ci 19028c2ecf20Sopenharmony_ci drv_state = qla8044_rd_direct(vha, 19038c2ecf20Sopenharmony_ci QLA8044_CRB_DRV_STATE_INDEX); 19048c2ecf20Sopenharmony_ci drv_active = qla8044_rd_direct(vha, 19058c2ecf20Sopenharmony_ci QLA8044_CRB_DRV_ACTIVE_INDEX); 19068c2ecf20Sopenharmony_ci drv_active = drv_active << 1; 19078c2ecf20Sopenharmony_ci } 19088c2ecf20Sopenharmony_ci 19098c2ecf20Sopenharmony_ci /* All functions have Acked. Set quiescent state */ 19108c2ecf20Sopenharmony_ci dev_state = qla8044_rd_direct(vha, QLA8044_CRB_DEV_STATE_INDEX); 19118c2ecf20Sopenharmony_ci 19128c2ecf20Sopenharmony_ci if (dev_state == QLA8XXX_DEV_NEED_QUIESCENT) { 19138c2ecf20Sopenharmony_ci qla8044_wr_direct(vha, QLA8044_CRB_DEV_STATE_INDEX, 19148c2ecf20Sopenharmony_ci QLA8XXX_DEV_QUIESCENT); 19158c2ecf20Sopenharmony_ci ql_log(ql_log_info, vha, 0xb0cd, 19168c2ecf20Sopenharmony_ci "%s: HW State: QUIESCENT\n", __func__); 19178c2ecf20Sopenharmony_ci } 19188c2ecf20Sopenharmony_ci} 19198c2ecf20Sopenharmony_ci 19208c2ecf20Sopenharmony_ci/* 19218c2ecf20Sopenharmony_ci * qla8044_device_state_handler - Adapter state machine 19228c2ecf20Sopenharmony_ci * @ha: pointer to host adapter structure. 19238c2ecf20Sopenharmony_ci * 19248c2ecf20Sopenharmony_ci * Note: IDC lock must be UNLOCKED upon entry 19258c2ecf20Sopenharmony_ci **/ 19268c2ecf20Sopenharmony_ciint 19278c2ecf20Sopenharmony_ciqla8044_device_state_handler(struct scsi_qla_host *vha) 19288c2ecf20Sopenharmony_ci{ 19298c2ecf20Sopenharmony_ci uint32_t dev_state; 19308c2ecf20Sopenharmony_ci int rval = QLA_SUCCESS; 19318c2ecf20Sopenharmony_ci unsigned long dev_init_timeout; 19328c2ecf20Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 19338c2ecf20Sopenharmony_ci 19348c2ecf20Sopenharmony_ci rval = qla8044_update_idc_reg(vha); 19358c2ecf20Sopenharmony_ci if (rval == QLA_FUNCTION_FAILED) 19368c2ecf20Sopenharmony_ci goto exit_error; 19378c2ecf20Sopenharmony_ci 19388c2ecf20Sopenharmony_ci dev_state = qla8044_rd_direct(vha, QLA8044_CRB_DEV_STATE_INDEX); 19398c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_p3p, vha, 0xb0ce, 19408c2ecf20Sopenharmony_ci "Device state is 0x%x = %s\n", 19418c2ecf20Sopenharmony_ci dev_state, dev_state < MAX_STATES ? 19428c2ecf20Sopenharmony_ci qdev_state(dev_state) : "Unknown"); 19438c2ecf20Sopenharmony_ci 19448c2ecf20Sopenharmony_ci /* wait for 30 seconds for device to go ready */ 19458c2ecf20Sopenharmony_ci dev_init_timeout = jiffies + (ha->fcoe_dev_init_timeout * HZ); 19468c2ecf20Sopenharmony_ci 19478c2ecf20Sopenharmony_ci qla8044_idc_lock(ha); 19488c2ecf20Sopenharmony_ci 19498c2ecf20Sopenharmony_ci while (1) { 19508c2ecf20Sopenharmony_ci if (time_after_eq(jiffies, dev_init_timeout)) { 19518c2ecf20Sopenharmony_ci if (qla8044_check_drv_active(vha) == QLA_SUCCESS) { 19528c2ecf20Sopenharmony_ci ql_log(ql_log_warn, vha, 0xb0cf, 19538c2ecf20Sopenharmony_ci "%s: Device Init Failed 0x%x = %s\n", 19548c2ecf20Sopenharmony_ci QLA2XXX_DRIVER_NAME, dev_state, 19558c2ecf20Sopenharmony_ci dev_state < MAX_STATES ? 19568c2ecf20Sopenharmony_ci qdev_state(dev_state) : "Unknown"); 19578c2ecf20Sopenharmony_ci qla8044_wr_direct(vha, 19588c2ecf20Sopenharmony_ci QLA8044_CRB_DEV_STATE_INDEX, 19598c2ecf20Sopenharmony_ci QLA8XXX_DEV_FAILED); 19608c2ecf20Sopenharmony_ci } 19618c2ecf20Sopenharmony_ci } 19628c2ecf20Sopenharmony_ci 19638c2ecf20Sopenharmony_ci dev_state = qla8044_rd_direct(vha, QLA8044_CRB_DEV_STATE_INDEX); 19648c2ecf20Sopenharmony_ci ql_log(ql_log_info, vha, 0xb0d0, 19658c2ecf20Sopenharmony_ci "Device state is 0x%x = %s\n", 19668c2ecf20Sopenharmony_ci dev_state, dev_state < MAX_STATES ? 19678c2ecf20Sopenharmony_ci qdev_state(dev_state) : "Unknown"); 19688c2ecf20Sopenharmony_ci 19698c2ecf20Sopenharmony_ci /* NOTE: Make sure idc unlocked upon exit of switch statement */ 19708c2ecf20Sopenharmony_ci switch (dev_state) { 19718c2ecf20Sopenharmony_ci case QLA8XXX_DEV_READY: 19728c2ecf20Sopenharmony_ci ha->flags.nic_core_reset_owner = 0; 19738c2ecf20Sopenharmony_ci goto exit; 19748c2ecf20Sopenharmony_ci case QLA8XXX_DEV_COLD: 19758c2ecf20Sopenharmony_ci rval = qla8044_device_bootstrap(vha); 19768c2ecf20Sopenharmony_ci break; 19778c2ecf20Sopenharmony_ci case QLA8XXX_DEV_INITIALIZING: 19788c2ecf20Sopenharmony_ci qla8044_idc_unlock(ha); 19798c2ecf20Sopenharmony_ci msleep(1000); 19808c2ecf20Sopenharmony_ci qla8044_idc_lock(ha); 19818c2ecf20Sopenharmony_ci break; 19828c2ecf20Sopenharmony_ci case QLA8XXX_DEV_NEED_RESET: 19838c2ecf20Sopenharmony_ci /* For ISP8044, if NEED_RESET is set by any driver, 19848c2ecf20Sopenharmony_ci * it should be honored, irrespective of IDC_CTRL 19858c2ecf20Sopenharmony_ci * DONTRESET_BIT0 */ 19868c2ecf20Sopenharmony_ci qla8044_need_reset_handler(vha); 19878c2ecf20Sopenharmony_ci break; 19888c2ecf20Sopenharmony_ci case QLA8XXX_DEV_NEED_QUIESCENT: 19898c2ecf20Sopenharmony_ci /* idc locked/unlocked in handler */ 19908c2ecf20Sopenharmony_ci qla8044_need_qsnt_handler(vha); 19918c2ecf20Sopenharmony_ci 19928c2ecf20Sopenharmony_ci /* Reset the init timeout after qsnt handler */ 19938c2ecf20Sopenharmony_ci dev_init_timeout = jiffies + 19948c2ecf20Sopenharmony_ci (ha->fcoe_reset_timeout * HZ); 19958c2ecf20Sopenharmony_ci break; 19968c2ecf20Sopenharmony_ci case QLA8XXX_DEV_QUIESCENT: 19978c2ecf20Sopenharmony_ci ql_log(ql_log_info, vha, 0xb0d1, 19988c2ecf20Sopenharmony_ci "HW State: QUIESCENT\n"); 19998c2ecf20Sopenharmony_ci 20008c2ecf20Sopenharmony_ci qla8044_idc_unlock(ha); 20018c2ecf20Sopenharmony_ci msleep(1000); 20028c2ecf20Sopenharmony_ci qla8044_idc_lock(ha); 20038c2ecf20Sopenharmony_ci 20048c2ecf20Sopenharmony_ci /* Reset the init timeout after qsnt handler */ 20058c2ecf20Sopenharmony_ci dev_init_timeout = jiffies + 20068c2ecf20Sopenharmony_ci (ha->fcoe_reset_timeout * HZ); 20078c2ecf20Sopenharmony_ci break; 20088c2ecf20Sopenharmony_ci case QLA8XXX_DEV_FAILED: 20098c2ecf20Sopenharmony_ci ha->flags.nic_core_reset_owner = 0; 20108c2ecf20Sopenharmony_ci qla8044_idc_unlock(ha); 20118c2ecf20Sopenharmony_ci qla8xxx_dev_failed_handler(vha); 20128c2ecf20Sopenharmony_ci rval = QLA_FUNCTION_FAILED; 20138c2ecf20Sopenharmony_ci qla8044_idc_lock(ha); 20148c2ecf20Sopenharmony_ci goto exit; 20158c2ecf20Sopenharmony_ci default: 20168c2ecf20Sopenharmony_ci qla8044_idc_unlock(ha); 20178c2ecf20Sopenharmony_ci qla8xxx_dev_failed_handler(vha); 20188c2ecf20Sopenharmony_ci rval = QLA_FUNCTION_FAILED; 20198c2ecf20Sopenharmony_ci qla8044_idc_lock(ha); 20208c2ecf20Sopenharmony_ci goto exit; 20218c2ecf20Sopenharmony_ci } 20228c2ecf20Sopenharmony_ci } 20238c2ecf20Sopenharmony_ciexit: 20248c2ecf20Sopenharmony_ci qla8044_idc_unlock(ha); 20258c2ecf20Sopenharmony_ci 20268c2ecf20Sopenharmony_ciexit_error: 20278c2ecf20Sopenharmony_ci return rval; 20288c2ecf20Sopenharmony_ci} 20298c2ecf20Sopenharmony_ci 20308c2ecf20Sopenharmony_ci/** 20318c2ecf20Sopenharmony_ci * qla4_8xxx_check_temp - Check the ISP82XX temperature. 20328c2ecf20Sopenharmony_ci * @vha: adapter block pointer. 20338c2ecf20Sopenharmony_ci * 20348c2ecf20Sopenharmony_ci * Note: The caller should not hold the idc lock. 20358c2ecf20Sopenharmony_ci */ 20368c2ecf20Sopenharmony_cistatic int 20378c2ecf20Sopenharmony_ciqla8044_check_temp(struct scsi_qla_host *vha) 20388c2ecf20Sopenharmony_ci{ 20398c2ecf20Sopenharmony_ci uint32_t temp, temp_state, temp_val; 20408c2ecf20Sopenharmony_ci int status = QLA_SUCCESS; 20418c2ecf20Sopenharmony_ci 20428c2ecf20Sopenharmony_ci temp = qla8044_rd_direct(vha, QLA8044_CRB_TEMP_STATE_INDEX); 20438c2ecf20Sopenharmony_ci temp_state = qla82xx_get_temp_state(temp); 20448c2ecf20Sopenharmony_ci temp_val = qla82xx_get_temp_val(temp); 20458c2ecf20Sopenharmony_ci 20468c2ecf20Sopenharmony_ci if (temp_state == QLA82XX_TEMP_PANIC) { 20478c2ecf20Sopenharmony_ci ql_log(ql_log_warn, vha, 0xb0d2, 20488c2ecf20Sopenharmony_ci "Device temperature %d degrees C" 20498c2ecf20Sopenharmony_ci " exceeds maximum allowed. Hardware has been shut" 20508c2ecf20Sopenharmony_ci " down\n", temp_val); 20518c2ecf20Sopenharmony_ci status = QLA_FUNCTION_FAILED; 20528c2ecf20Sopenharmony_ci return status; 20538c2ecf20Sopenharmony_ci } else if (temp_state == QLA82XX_TEMP_WARN) { 20548c2ecf20Sopenharmony_ci ql_log(ql_log_warn, vha, 0xb0d3, 20558c2ecf20Sopenharmony_ci "Device temperature %d" 20568c2ecf20Sopenharmony_ci " degrees C exceeds operating range." 20578c2ecf20Sopenharmony_ci " Immediate action needed.\n", temp_val); 20588c2ecf20Sopenharmony_ci } 20598c2ecf20Sopenharmony_ci return 0; 20608c2ecf20Sopenharmony_ci} 20618c2ecf20Sopenharmony_ci 20628c2ecf20Sopenharmony_ciint qla8044_read_temperature(scsi_qla_host_t *vha) 20638c2ecf20Sopenharmony_ci{ 20648c2ecf20Sopenharmony_ci uint32_t temp; 20658c2ecf20Sopenharmony_ci 20668c2ecf20Sopenharmony_ci temp = qla8044_rd_direct(vha, QLA8044_CRB_TEMP_STATE_INDEX); 20678c2ecf20Sopenharmony_ci return qla82xx_get_temp_val(temp); 20688c2ecf20Sopenharmony_ci} 20698c2ecf20Sopenharmony_ci 20708c2ecf20Sopenharmony_ci/** 20718c2ecf20Sopenharmony_ci * qla8044_check_fw_alive - Check firmware health 20728c2ecf20Sopenharmony_ci * @vha: Pointer to host adapter structure. 20738c2ecf20Sopenharmony_ci * 20748c2ecf20Sopenharmony_ci * Context: Interrupt 20758c2ecf20Sopenharmony_ci */ 20768c2ecf20Sopenharmony_ciint 20778c2ecf20Sopenharmony_ciqla8044_check_fw_alive(struct scsi_qla_host *vha) 20788c2ecf20Sopenharmony_ci{ 20798c2ecf20Sopenharmony_ci uint32_t fw_heartbeat_counter; 20808c2ecf20Sopenharmony_ci uint32_t halt_status1, halt_status2; 20818c2ecf20Sopenharmony_ci int status = QLA_SUCCESS; 20828c2ecf20Sopenharmony_ci 20838c2ecf20Sopenharmony_ci fw_heartbeat_counter = qla8044_rd_direct(vha, 20848c2ecf20Sopenharmony_ci QLA8044_PEG_ALIVE_COUNTER_INDEX); 20858c2ecf20Sopenharmony_ci 20868c2ecf20Sopenharmony_ci /* If PEG_ALIVE_COUNTER is 0xffffffff, AER/EEH is in progress, ignore */ 20878c2ecf20Sopenharmony_ci if (fw_heartbeat_counter == 0xffffffff) { 20888c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_p3p, vha, 0xb0d4, 20898c2ecf20Sopenharmony_ci "scsi%ld: %s: Device in frozen " 20908c2ecf20Sopenharmony_ci "state, QLA82XX_PEG_ALIVE_COUNTER is 0xffffffff\n", 20918c2ecf20Sopenharmony_ci vha->host_no, __func__); 20928c2ecf20Sopenharmony_ci return status; 20938c2ecf20Sopenharmony_ci } 20948c2ecf20Sopenharmony_ci 20958c2ecf20Sopenharmony_ci if (vha->fw_heartbeat_counter == fw_heartbeat_counter) { 20968c2ecf20Sopenharmony_ci vha->seconds_since_last_heartbeat++; 20978c2ecf20Sopenharmony_ci /* FW not alive after 2 seconds */ 20988c2ecf20Sopenharmony_ci if (vha->seconds_since_last_heartbeat == 2) { 20998c2ecf20Sopenharmony_ci vha->seconds_since_last_heartbeat = 0; 21008c2ecf20Sopenharmony_ci halt_status1 = qla8044_rd_direct(vha, 21018c2ecf20Sopenharmony_ci QLA8044_PEG_HALT_STATUS1_INDEX); 21028c2ecf20Sopenharmony_ci halt_status2 = qla8044_rd_direct(vha, 21038c2ecf20Sopenharmony_ci QLA8044_PEG_HALT_STATUS2_INDEX); 21048c2ecf20Sopenharmony_ci 21058c2ecf20Sopenharmony_ci ql_log(ql_log_info, vha, 0xb0d5, 21068c2ecf20Sopenharmony_ci "scsi(%ld): %s, ISP8044 " 21078c2ecf20Sopenharmony_ci "Dumping hw/fw registers:\n" 21088c2ecf20Sopenharmony_ci " PEG_HALT_STATUS1: 0x%x, " 21098c2ecf20Sopenharmony_ci "PEG_HALT_STATUS2: 0x%x,\n", 21108c2ecf20Sopenharmony_ci vha->host_no, __func__, halt_status1, 21118c2ecf20Sopenharmony_ci halt_status2); 21128c2ecf20Sopenharmony_ci status = QLA_FUNCTION_FAILED; 21138c2ecf20Sopenharmony_ci } 21148c2ecf20Sopenharmony_ci } else 21158c2ecf20Sopenharmony_ci vha->seconds_since_last_heartbeat = 0; 21168c2ecf20Sopenharmony_ci 21178c2ecf20Sopenharmony_ci vha->fw_heartbeat_counter = fw_heartbeat_counter; 21188c2ecf20Sopenharmony_ci return status; 21198c2ecf20Sopenharmony_ci} 21208c2ecf20Sopenharmony_ci 21218c2ecf20Sopenharmony_civoid 21228c2ecf20Sopenharmony_ciqla8044_watchdog(struct scsi_qla_host *vha) 21238c2ecf20Sopenharmony_ci{ 21248c2ecf20Sopenharmony_ci uint32_t dev_state, halt_status; 21258c2ecf20Sopenharmony_ci int halt_status_unrecoverable = 0; 21268c2ecf20Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 21278c2ecf20Sopenharmony_ci 21288c2ecf20Sopenharmony_ci /* don't poll if reset is going on or FW hang in quiescent state */ 21298c2ecf20Sopenharmony_ci if (!(test_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags) || 21308c2ecf20Sopenharmony_ci test_bit(FCOE_CTX_RESET_NEEDED, &vha->dpc_flags))) { 21318c2ecf20Sopenharmony_ci dev_state = qla8044_rd_direct(vha, QLA8044_CRB_DEV_STATE_INDEX); 21328c2ecf20Sopenharmony_ci 21338c2ecf20Sopenharmony_ci if (qla8044_check_fw_alive(vha)) { 21348c2ecf20Sopenharmony_ci ha->flags.isp82xx_fw_hung = 1; 21358c2ecf20Sopenharmony_ci ql_log(ql_log_warn, vha, 0xb10a, 21368c2ecf20Sopenharmony_ci "Firmware hung.\n"); 21378c2ecf20Sopenharmony_ci qla82xx_clear_pending_mbx(vha); 21388c2ecf20Sopenharmony_ci } 21398c2ecf20Sopenharmony_ci 21408c2ecf20Sopenharmony_ci if (qla8044_check_temp(vha)) { 21418c2ecf20Sopenharmony_ci set_bit(ISP_UNRECOVERABLE, &vha->dpc_flags); 21428c2ecf20Sopenharmony_ci ha->flags.isp82xx_fw_hung = 1; 21438c2ecf20Sopenharmony_ci qla2xxx_wake_dpc(vha); 21448c2ecf20Sopenharmony_ci } else if (dev_state == QLA8XXX_DEV_NEED_RESET && 21458c2ecf20Sopenharmony_ci !test_bit(ISP_ABORT_NEEDED, &vha->dpc_flags)) { 21468c2ecf20Sopenharmony_ci ql_log(ql_log_info, vha, 0xb0d6, 21478c2ecf20Sopenharmony_ci "%s: HW State: NEED RESET!\n", 21488c2ecf20Sopenharmony_ci __func__); 21498c2ecf20Sopenharmony_ci set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags); 21508c2ecf20Sopenharmony_ci qla2xxx_wake_dpc(vha); 21518c2ecf20Sopenharmony_ci } else if (dev_state == QLA8XXX_DEV_NEED_QUIESCENT && 21528c2ecf20Sopenharmony_ci !test_bit(ISP_QUIESCE_NEEDED, &vha->dpc_flags)) { 21538c2ecf20Sopenharmony_ci ql_log(ql_log_info, vha, 0xb0d7, 21548c2ecf20Sopenharmony_ci "%s: HW State: NEED QUIES detected!\n", 21558c2ecf20Sopenharmony_ci __func__); 21568c2ecf20Sopenharmony_ci set_bit(ISP_QUIESCE_NEEDED, &vha->dpc_flags); 21578c2ecf20Sopenharmony_ci qla2xxx_wake_dpc(vha); 21588c2ecf20Sopenharmony_ci } else { 21598c2ecf20Sopenharmony_ci /* Check firmware health */ 21608c2ecf20Sopenharmony_ci if (ha->flags.isp82xx_fw_hung) { 21618c2ecf20Sopenharmony_ci halt_status = qla8044_rd_direct(vha, 21628c2ecf20Sopenharmony_ci QLA8044_PEG_HALT_STATUS1_INDEX); 21638c2ecf20Sopenharmony_ci if (halt_status & 21648c2ecf20Sopenharmony_ci QLA8044_HALT_STATUS_FW_RESET) { 21658c2ecf20Sopenharmony_ci ql_log(ql_log_fatal, vha, 21668c2ecf20Sopenharmony_ci 0xb0d8, "%s: Firmware " 21678c2ecf20Sopenharmony_ci "error detected device " 21688c2ecf20Sopenharmony_ci "is being reset\n", 21698c2ecf20Sopenharmony_ci __func__); 21708c2ecf20Sopenharmony_ci } else if (halt_status & 21718c2ecf20Sopenharmony_ci QLA8044_HALT_STATUS_UNRECOVERABLE) { 21728c2ecf20Sopenharmony_ci halt_status_unrecoverable = 1; 21738c2ecf20Sopenharmony_ci } 21748c2ecf20Sopenharmony_ci 21758c2ecf20Sopenharmony_ci /* Since we cannot change dev_state in interrupt 21768c2ecf20Sopenharmony_ci * context, set appropriate DPC flag then wakeup 21778c2ecf20Sopenharmony_ci * DPC */ 21788c2ecf20Sopenharmony_ci if (halt_status_unrecoverable) { 21798c2ecf20Sopenharmony_ci set_bit(ISP_UNRECOVERABLE, 21808c2ecf20Sopenharmony_ci &vha->dpc_flags); 21818c2ecf20Sopenharmony_ci } else { 21828c2ecf20Sopenharmony_ci if (dev_state == 21838c2ecf20Sopenharmony_ci QLA8XXX_DEV_QUIESCENT) { 21848c2ecf20Sopenharmony_ci set_bit(FCOE_CTX_RESET_NEEDED, 21858c2ecf20Sopenharmony_ci &vha->dpc_flags); 21868c2ecf20Sopenharmony_ci ql_log(ql_log_info, vha, 0xb0d9, 21878c2ecf20Sopenharmony_ci "%s: FW CONTEXT Reset " 21888c2ecf20Sopenharmony_ci "needed!\n", __func__); 21898c2ecf20Sopenharmony_ci } else { 21908c2ecf20Sopenharmony_ci ql_log(ql_log_info, vha, 21918c2ecf20Sopenharmony_ci 0xb0da, "%s: " 21928c2ecf20Sopenharmony_ci "detect abort needed\n", 21938c2ecf20Sopenharmony_ci __func__); 21948c2ecf20Sopenharmony_ci set_bit(ISP_ABORT_NEEDED, 21958c2ecf20Sopenharmony_ci &vha->dpc_flags); 21968c2ecf20Sopenharmony_ci } 21978c2ecf20Sopenharmony_ci } 21988c2ecf20Sopenharmony_ci qla2xxx_wake_dpc(vha); 21998c2ecf20Sopenharmony_ci } 22008c2ecf20Sopenharmony_ci } 22018c2ecf20Sopenharmony_ci 22028c2ecf20Sopenharmony_ci } 22038c2ecf20Sopenharmony_ci} 22048c2ecf20Sopenharmony_ci 22058c2ecf20Sopenharmony_cistatic int 22068c2ecf20Sopenharmony_ciqla8044_minidump_process_control(struct scsi_qla_host *vha, 22078c2ecf20Sopenharmony_ci struct qla8044_minidump_entry_hdr *entry_hdr) 22088c2ecf20Sopenharmony_ci{ 22098c2ecf20Sopenharmony_ci struct qla8044_minidump_entry_crb *crb_entry; 22108c2ecf20Sopenharmony_ci uint32_t read_value, opcode, poll_time, addr, index; 22118c2ecf20Sopenharmony_ci uint32_t crb_addr, rval = QLA_SUCCESS; 22128c2ecf20Sopenharmony_ci unsigned long wtime; 22138c2ecf20Sopenharmony_ci struct qla8044_minidump_template_hdr *tmplt_hdr; 22148c2ecf20Sopenharmony_ci int i; 22158c2ecf20Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 22168c2ecf20Sopenharmony_ci 22178c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_p3p, vha, 0xb0dd, "Entering fn: %s\n", __func__); 22188c2ecf20Sopenharmony_ci tmplt_hdr = (struct qla8044_minidump_template_hdr *) 22198c2ecf20Sopenharmony_ci ha->md_tmplt_hdr; 22208c2ecf20Sopenharmony_ci crb_entry = (struct qla8044_minidump_entry_crb *)entry_hdr; 22218c2ecf20Sopenharmony_ci 22228c2ecf20Sopenharmony_ci crb_addr = crb_entry->addr; 22238c2ecf20Sopenharmony_ci for (i = 0; i < crb_entry->op_count; i++) { 22248c2ecf20Sopenharmony_ci opcode = crb_entry->crb_ctrl.opcode; 22258c2ecf20Sopenharmony_ci 22268c2ecf20Sopenharmony_ci if (opcode & QLA82XX_DBG_OPCODE_WR) { 22278c2ecf20Sopenharmony_ci qla8044_wr_reg_indirect(vha, crb_addr, 22288c2ecf20Sopenharmony_ci crb_entry->value_1); 22298c2ecf20Sopenharmony_ci opcode &= ~QLA82XX_DBG_OPCODE_WR; 22308c2ecf20Sopenharmony_ci } 22318c2ecf20Sopenharmony_ci 22328c2ecf20Sopenharmony_ci if (opcode & QLA82XX_DBG_OPCODE_RW) { 22338c2ecf20Sopenharmony_ci qla8044_rd_reg_indirect(vha, crb_addr, &read_value); 22348c2ecf20Sopenharmony_ci qla8044_wr_reg_indirect(vha, crb_addr, read_value); 22358c2ecf20Sopenharmony_ci opcode &= ~QLA82XX_DBG_OPCODE_RW; 22368c2ecf20Sopenharmony_ci } 22378c2ecf20Sopenharmony_ci 22388c2ecf20Sopenharmony_ci if (opcode & QLA82XX_DBG_OPCODE_AND) { 22398c2ecf20Sopenharmony_ci qla8044_rd_reg_indirect(vha, crb_addr, &read_value); 22408c2ecf20Sopenharmony_ci read_value &= crb_entry->value_2; 22418c2ecf20Sopenharmony_ci opcode &= ~QLA82XX_DBG_OPCODE_AND; 22428c2ecf20Sopenharmony_ci if (opcode & QLA82XX_DBG_OPCODE_OR) { 22438c2ecf20Sopenharmony_ci read_value |= crb_entry->value_3; 22448c2ecf20Sopenharmony_ci opcode &= ~QLA82XX_DBG_OPCODE_OR; 22458c2ecf20Sopenharmony_ci } 22468c2ecf20Sopenharmony_ci qla8044_wr_reg_indirect(vha, crb_addr, read_value); 22478c2ecf20Sopenharmony_ci } 22488c2ecf20Sopenharmony_ci if (opcode & QLA82XX_DBG_OPCODE_OR) { 22498c2ecf20Sopenharmony_ci qla8044_rd_reg_indirect(vha, crb_addr, &read_value); 22508c2ecf20Sopenharmony_ci read_value |= crb_entry->value_3; 22518c2ecf20Sopenharmony_ci qla8044_wr_reg_indirect(vha, crb_addr, read_value); 22528c2ecf20Sopenharmony_ci opcode &= ~QLA82XX_DBG_OPCODE_OR; 22538c2ecf20Sopenharmony_ci } 22548c2ecf20Sopenharmony_ci if (opcode & QLA82XX_DBG_OPCODE_POLL) { 22558c2ecf20Sopenharmony_ci poll_time = crb_entry->crb_strd.poll_timeout; 22568c2ecf20Sopenharmony_ci wtime = jiffies + poll_time; 22578c2ecf20Sopenharmony_ci qla8044_rd_reg_indirect(vha, crb_addr, &read_value); 22588c2ecf20Sopenharmony_ci 22598c2ecf20Sopenharmony_ci do { 22608c2ecf20Sopenharmony_ci if ((read_value & crb_entry->value_2) == 22618c2ecf20Sopenharmony_ci crb_entry->value_1) { 22628c2ecf20Sopenharmony_ci break; 22638c2ecf20Sopenharmony_ci } else if (time_after_eq(jiffies, wtime)) { 22648c2ecf20Sopenharmony_ci /* capturing dump failed */ 22658c2ecf20Sopenharmony_ci rval = QLA_FUNCTION_FAILED; 22668c2ecf20Sopenharmony_ci break; 22678c2ecf20Sopenharmony_ci } else { 22688c2ecf20Sopenharmony_ci qla8044_rd_reg_indirect(vha, 22698c2ecf20Sopenharmony_ci crb_addr, &read_value); 22708c2ecf20Sopenharmony_ci } 22718c2ecf20Sopenharmony_ci } while (1); 22728c2ecf20Sopenharmony_ci opcode &= ~QLA82XX_DBG_OPCODE_POLL; 22738c2ecf20Sopenharmony_ci } 22748c2ecf20Sopenharmony_ci 22758c2ecf20Sopenharmony_ci if (opcode & QLA82XX_DBG_OPCODE_RDSTATE) { 22768c2ecf20Sopenharmony_ci if (crb_entry->crb_strd.state_index_a) { 22778c2ecf20Sopenharmony_ci index = crb_entry->crb_strd.state_index_a; 22788c2ecf20Sopenharmony_ci addr = tmplt_hdr->saved_state_array[index]; 22798c2ecf20Sopenharmony_ci } else { 22808c2ecf20Sopenharmony_ci addr = crb_addr; 22818c2ecf20Sopenharmony_ci } 22828c2ecf20Sopenharmony_ci 22838c2ecf20Sopenharmony_ci qla8044_rd_reg_indirect(vha, addr, &read_value); 22848c2ecf20Sopenharmony_ci index = crb_entry->crb_ctrl.state_index_v; 22858c2ecf20Sopenharmony_ci tmplt_hdr->saved_state_array[index] = read_value; 22868c2ecf20Sopenharmony_ci opcode &= ~QLA82XX_DBG_OPCODE_RDSTATE; 22878c2ecf20Sopenharmony_ci } 22888c2ecf20Sopenharmony_ci 22898c2ecf20Sopenharmony_ci if (opcode & QLA82XX_DBG_OPCODE_WRSTATE) { 22908c2ecf20Sopenharmony_ci if (crb_entry->crb_strd.state_index_a) { 22918c2ecf20Sopenharmony_ci index = crb_entry->crb_strd.state_index_a; 22928c2ecf20Sopenharmony_ci addr = tmplt_hdr->saved_state_array[index]; 22938c2ecf20Sopenharmony_ci } else { 22948c2ecf20Sopenharmony_ci addr = crb_addr; 22958c2ecf20Sopenharmony_ci } 22968c2ecf20Sopenharmony_ci 22978c2ecf20Sopenharmony_ci if (crb_entry->crb_ctrl.state_index_v) { 22988c2ecf20Sopenharmony_ci index = crb_entry->crb_ctrl.state_index_v; 22998c2ecf20Sopenharmony_ci read_value = 23008c2ecf20Sopenharmony_ci tmplt_hdr->saved_state_array[index]; 23018c2ecf20Sopenharmony_ci } else { 23028c2ecf20Sopenharmony_ci read_value = crb_entry->value_1; 23038c2ecf20Sopenharmony_ci } 23048c2ecf20Sopenharmony_ci 23058c2ecf20Sopenharmony_ci qla8044_wr_reg_indirect(vha, addr, read_value); 23068c2ecf20Sopenharmony_ci opcode &= ~QLA82XX_DBG_OPCODE_WRSTATE; 23078c2ecf20Sopenharmony_ci } 23088c2ecf20Sopenharmony_ci 23098c2ecf20Sopenharmony_ci if (opcode & QLA82XX_DBG_OPCODE_MDSTATE) { 23108c2ecf20Sopenharmony_ci index = crb_entry->crb_ctrl.state_index_v; 23118c2ecf20Sopenharmony_ci read_value = tmplt_hdr->saved_state_array[index]; 23128c2ecf20Sopenharmony_ci read_value <<= crb_entry->crb_ctrl.shl; 23138c2ecf20Sopenharmony_ci read_value >>= crb_entry->crb_ctrl.shr; 23148c2ecf20Sopenharmony_ci if (crb_entry->value_2) 23158c2ecf20Sopenharmony_ci read_value &= crb_entry->value_2; 23168c2ecf20Sopenharmony_ci read_value |= crb_entry->value_3; 23178c2ecf20Sopenharmony_ci read_value += crb_entry->value_1; 23188c2ecf20Sopenharmony_ci tmplt_hdr->saved_state_array[index] = read_value; 23198c2ecf20Sopenharmony_ci opcode &= ~QLA82XX_DBG_OPCODE_MDSTATE; 23208c2ecf20Sopenharmony_ci } 23218c2ecf20Sopenharmony_ci crb_addr += crb_entry->crb_strd.addr_stride; 23228c2ecf20Sopenharmony_ci } 23238c2ecf20Sopenharmony_ci return rval; 23248c2ecf20Sopenharmony_ci} 23258c2ecf20Sopenharmony_ci 23268c2ecf20Sopenharmony_cistatic void 23278c2ecf20Sopenharmony_ciqla8044_minidump_process_rdcrb(struct scsi_qla_host *vha, 23288c2ecf20Sopenharmony_ci struct qla8044_minidump_entry_hdr *entry_hdr, uint32_t **d_ptr) 23298c2ecf20Sopenharmony_ci{ 23308c2ecf20Sopenharmony_ci uint32_t r_addr, r_stride, loop_cnt, i, r_value; 23318c2ecf20Sopenharmony_ci struct qla8044_minidump_entry_crb *crb_hdr; 23328c2ecf20Sopenharmony_ci uint32_t *data_ptr = *d_ptr; 23338c2ecf20Sopenharmony_ci 23348c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_p3p, vha, 0xb0de, "Entering fn: %s\n", __func__); 23358c2ecf20Sopenharmony_ci crb_hdr = (struct qla8044_minidump_entry_crb *)entry_hdr; 23368c2ecf20Sopenharmony_ci r_addr = crb_hdr->addr; 23378c2ecf20Sopenharmony_ci r_stride = crb_hdr->crb_strd.addr_stride; 23388c2ecf20Sopenharmony_ci loop_cnt = crb_hdr->op_count; 23398c2ecf20Sopenharmony_ci 23408c2ecf20Sopenharmony_ci for (i = 0; i < loop_cnt; i++) { 23418c2ecf20Sopenharmony_ci qla8044_rd_reg_indirect(vha, r_addr, &r_value); 23428c2ecf20Sopenharmony_ci *data_ptr++ = r_addr; 23438c2ecf20Sopenharmony_ci *data_ptr++ = r_value; 23448c2ecf20Sopenharmony_ci r_addr += r_stride; 23458c2ecf20Sopenharmony_ci } 23468c2ecf20Sopenharmony_ci *d_ptr = data_ptr; 23478c2ecf20Sopenharmony_ci} 23488c2ecf20Sopenharmony_ci 23498c2ecf20Sopenharmony_cistatic int 23508c2ecf20Sopenharmony_ciqla8044_minidump_process_rdmem(struct scsi_qla_host *vha, 23518c2ecf20Sopenharmony_ci struct qla8044_minidump_entry_hdr *entry_hdr, uint32_t **d_ptr) 23528c2ecf20Sopenharmony_ci{ 23538c2ecf20Sopenharmony_ci uint32_t r_addr, r_value, r_data; 23548c2ecf20Sopenharmony_ci uint32_t i, j, loop_cnt; 23558c2ecf20Sopenharmony_ci struct qla8044_minidump_entry_rdmem *m_hdr; 23568c2ecf20Sopenharmony_ci unsigned long flags; 23578c2ecf20Sopenharmony_ci uint32_t *data_ptr = *d_ptr; 23588c2ecf20Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 23598c2ecf20Sopenharmony_ci 23608c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_p3p, vha, 0xb0df, "Entering fn: %s\n", __func__); 23618c2ecf20Sopenharmony_ci m_hdr = (struct qla8044_minidump_entry_rdmem *)entry_hdr; 23628c2ecf20Sopenharmony_ci r_addr = m_hdr->read_addr; 23638c2ecf20Sopenharmony_ci loop_cnt = m_hdr->read_data_size/16; 23648c2ecf20Sopenharmony_ci 23658c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_p3p, vha, 0xb0f0, 23668c2ecf20Sopenharmony_ci "[%s]: Read addr: 0x%x, read_data_size: 0x%x\n", 23678c2ecf20Sopenharmony_ci __func__, r_addr, m_hdr->read_data_size); 23688c2ecf20Sopenharmony_ci 23698c2ecf20Sopenharmony_ci if (r_addr & 0xf) { 23708c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_p3p, vha, 0xb0f1, 23718c2ecf20Sopenharmony_ci "[%s]: Read addr 0x%x not 16 bytes aligned\n", 23728c2ecf20Sopenharmony_ci __func__, r_addr); 23738c2ecf20Sopenharmony_ci return QLA_FUNCTION_FAILED; 23748c2ecf20Sopenharmony_ci } 23758c2ecf20Sopenharmony_ci 23768c2ecf20Sopenharmony_ci if (m_hdr->read_data_size % 16) { 23778c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_p3p, vha, 0xb0f2, 23788c2ecf20Sopenharmony_ci "[%s]: Read data[0x%x] not multiple of 16 bytes\n", 23798c2ecf20Sopenharmony_ci __func__, m_hdr->read_data_size); 23808c2ecf20Sopenharmony_ci return QLA_FUNCTION_FAILED; 23818c2ecf20Sopenharmony_ci } 23828c2ecf20Sopenharmony_ci 23838c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_p3p, vha, 0xb0f3, 23848c2ecf20Sopenharmony_ci "[%s]: rdmem_addr: 0x%x, read_data_size: 0x%x, loop_cnt: 0x%x\n", 23858c2ecf20Sopenharmony_ci __func__, r_addr, m_hdr->read_data_size, loop_cnt); 23868c2ecf20Sopenharmony_ci 23878c2ecf20Sopenharmony_ci write_lock_irqsave(&ha->hw_lock, flags); 23888c2ecf20Sopenharmony_ci for (i = 0; i < loop_cnt; i++) { 23898c2ecf20Sopenharmony_ci qla8044_wr_reg_indirect(vha, MD_MIU_TEST_AGT_ADDR_LO, r_addr); 23908c2ecf20Sopenharmony_ci r_value = 0; 23918c2ecf20Sopenharmony_ci qla8044_wr_reg_indirect(vha, MD_MIU_TEST_AGT_ADDR_HI, r_value); 23928c2ecf20Sopenharmony_ci r_value = MIU_TA_CTL_ENABLE; 23938c2ecf20Sopenharmony_ci qla8044_wr_reg_indirect(vha, MD_MIU_TEST_AGT_CTRL, r_value); 23948c2ecf20Sopenharmony_ci r_value = MIU_TA_CTL_START_ENABLE; 23958c2ecf20Sopenharmony_ci qla8044_wr_reg_indirect(vha, MD_MIU_TEST_AGT_CTRL, r_value); 23968c2ecf20Sopenharmony_ci 23978c2ecf20Sopenharmony_ci for (j = 0; j < MAX_CTL_CHECK; j++) { 23988c2ecf20Sopenharmony_ci qla8044_rd_reg_indirect(vha, MD_MIU_TEST_AGT_CTRL, 23998c2ecf20Sopenharmony_ci &r_value); 24008c2ecf20Sopenharmony_ci if ((r_value & MIU_TA_CTL_BUSY) == 0) 24018c2ecf20Sopenharmony_ci break; 24028c2ecf20Sopenharmony_ci } 24038c2ecf20Sopenharmony_ci 24048c2ecf20Sopenharmony_ci if (j >= MAX_CTL_CHECK) { 24058c2ecf20Sopenharmony_ci write_unlock_irqrestore(&ha->hw_lock, flags); 24068c2ecf20Sopenharmony_ci return QLA_SUCCESS; 24078c2ecf20Sopenharmony_ci } 24088c2ecf20Sopenharmony_ci 24098c2ecf20Sopenharmony_ci for (j = 0; j < 4; j++) { 24108c2ecf20Sopenharmony_ci qla8044_rd_reg_indirect(vha, MD_MIU_TEST_AGT_RDDATA[j], 24118c2ecf20Sopenharmony_ci &r_data); 24128c2ecf20Sopenharmony_ci *data_ptr++ = r_data; 24138c2ecf20Sopenharmony_ci } 24148c2ecf20Sopenharmony_ci 24158c2ecf20Sopenharmony_ci r_addr += 16; 24168c2ecf20Sopenharmony_ci } 24178c2ecf20Sopenharmony_ci write_unlock_irqrestore(&ha->hw_lock, flags); 24188c2ecf20Sopenharmony_ci 24198c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_p3p, vha, 0xb0f4, 24208c2ecf20Sopenharmony_ci "Leaving fn: %s datacount: 0x%x\n", 24218c2ecf20Sopenharmony_ci __func__, (loop_cnt * 16)); 24228c2ecf20Sopenharmony_ci 24238c2ecf20Sopenharmony_ci *d_ptr = data_ptr; 24248c2ecf20Sopenharmony_ci return QLA_SUCCESS; 24258c2ecf20Sopenharmony_ci} 24268c2ecf20Sopenharmony_ci 24278c2ecf20Sopenharmony_ci/* ISP83xx flash read for _RDROM _BOARD */ 24288c2ecf20Sopenharmony_cistatic uint32_t 24298c2ecf20Sopenharmony_ciqla8044_minidump_process_rdrom(struct scsi_qla_host *vha, 24308c2ecf20Sopenharmony_ci struct qla8044_minidump_entry_hdr *entry_hdr, uint32_t **d_ptr) 24318c2ecf20Sopenharmony_ci{ 24328c2ecf20Sopenharmony_ci uint32_t fl_addr, u32_count, rval; 24338c2ecf20Sopenharmony_ci struct qla8044_minidump_entry_rdrom *rom_hdr; 24348c2ecf20Sopenharmony_ci uint32_t *data_ptr = *d_ptr; 24358c2ecf20Sopenharmony_ci 24368c2ecf20Sopenharmony_ci rom_hdr = (struct qla8044_minidump_entry_rdrom *)entry_hdr; 24378c2ecf20Sopenharmony_ci fl_addr = rom_hdr->read_addr; 24388c2ecf20Sopenharmony_ci u32_count = (rom_hdr->read_data_size)/sizeof(uint32_t); 24398c2ecf20Sopenharmony_ci 24408c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_p3p, vha, 0xb0f5, "[%s]: fl_addr: 0x%x, count: 0x%x\n", 24418c2ecf20Sopenharmony_ci __func__, fl_addr, u32_count); 24428c2ecf20Sopenharmony_ci 24438c2ecf20Sopenharmony_ci rval = qla8044_lockless_flash_read_u32(vha, fl_addr, 24448c2ecf20Sopenharmony_ci (u8 *)(data_ptr), u32_count); 24458c2ecf20Sopenharmony_ci 24468c2ecf20Sopenharmony_ci if (rval != QLA_SUCCESS) { 24478c2ecf20Sopenharmony_ci ql_log(ql_log_fatal, vha, 0xb0f6, 24488c2ecf20Sopenharmony_ci "%s: Flash Read Error,Count=%d\n", __func__, u32_count); 24498c2ecf20Sopenharmony_ci return QLA_FUNCTION_FAILED; 24508c2ecf20Sopenharmony_ci } else { 24518c2ecf20Sopenharmony_ci data_ptr += u32_count; 24528c2ecf20Sopenharmony_ci *d_ptr = data_ptr; 24538c2ecf20Sopenharmony_ci return QLA_SUCCESS; 24548c2ecf20Sopenharmony_ci } 24558c2ecf20Sopenharmony_ci} 24568c2ecf20Sopenharmony_ci 24578c2ecf20Sopenharmony_cistatic void 24588c2ecf20Sopenharmony_ciqla8044_mark_entry_skipped(struct scsi_qla_host *vha, 24598c2ecf20Sopenharmony_ci struct qla8044_minidump_entry_hdr *entry_hdr, int index) 24608c2ecf20Sopenharmony_ci{ 24618c2ecf20Sopenharmony_ci entry_hdr->d_ctrl.driver_flags |= QLA82XX_DBG_SKIPPED_FLAG; 24628c2ecf20Sopenharmony_ci 24638c2ecf20Sopenharmony_ci ql_log(ql_log_info, vha, 0xb0f7, 24648c2ecf20Sopenharmony_ci "scsi(%ld): Skipping entry[%d]: ETYPE[0x%x]-ELEVEL[0x%x]\n", 24658c2ecf20Sopenharmony_ci vha->host_no, index, entry_hdr->entry_type, 24668c2ecf20Sopenharmony_ci entry_hdr->d_ctrl.entry_capture_mask); 24678c2ecf20Sopenharmony_ci} 24688c2ecf20Sopenharmony_ci 24698c2ecf20Sopenharmony_cistatic int 24708c2ecf20Sopenharmony_ciqla8044_minidump_process_l2tag(struct scsi_qla_host *vha, 24718c2ecf20Sopenharmony_ci struct qla8044_minidump_entry_hdr *entry_hdr, 24728c2ecf20Sopenharmony_ci uint32_t **d_ptr) 24738c2ecf20Sopenharmony_ci{ 24748c2ecf20Sopenharmony_ci uint32_t addr, r_addr, c_addr, t_r_addr; 24758c2ecf20Sopenharmony_ci uint32_t i, k, loop_count, t_value, r_cnt, r_value; 24768c2ecf20Sopenharmony_ci unsigned long p_wait, w_time, p_mask; 24778c2ecf20Sopenharmony_ci uint32_t c_value_w, c_value_r; 24788c2ecf20Sopenharmony_ci struct qla8044_minidump_entry_cache *cache_hdr; 24798c2ecf20Sopenharmony_ci int rval = QLA_FUNCTION_FAILED; 24808c2ecf20Sopenharmony_ci uint32_t *data_ptr = *d_ptr; 24818c2ecf20Sopenharmony_ci 24828c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_p3p, vha, 0xb0f8, "Entering fn: %s\n", __func__); 24838c2ecf20Sopenharmony_ci cache_hdr = (struct qla8044_minidump_entry_cache *)entry_hdr; 24848c2ecf20Sopenharmony_ci 24858c2ecf20Sopenharmony_ci loop_count = cache_hdr->op_count; 24868c2ecf20Sopenharmony_ci r_addr = cache_hdr->read_addr; 24878c2ecf20Sopenharmony_ci c_addr = cache_hdr->control_addr; 24888c2ecf20Sopenharmony_ci c_value_w = cache_hdr->cache_ctrl.write_value; 24898c2ecf20Sopenharmony_ci 24908c2ecf20Sopenharmony_ci t_r_addr = cache_hdr->tag_reg_addr; 24918c2ecf20Sopenharmony_ci t_value = cache_hdr->addr_ctrl.init_tag_value; 24928c2ecf20Sopenharmony_ci r_cnt = cache_hdr->read_ctrl.read_addr_cnt; 24938c2ecf20Sopenharmony_ci p_wait = cache_hdr->cache_ctrl.poll_wait; 24948c2ecf20Sopenharmony_ci p_mask = cache_hdr->cache_ctrl.poll_mask; 24958c2ecf20Sopenharmony_ci 24968c2ecf20Sopenharmony_ci for (i = 0; i < loop_count; i++) { 24978c2ecf20Sopenharmony_ci qla8044_wr_reg_indirect(vha, t_r_addr, t_value); 24988c2ecf20Sopenharmony_ci if (c_value_w) 24998c2ecf20Sopenharmony_ci qla8044_wr_reg_indirect(vha, c_addr, c_value_w); 25008c2ecf20Sopenharmony_ci 25018c2ecf20Sopenharmony_ci if (p_mask) { 25028c2ecf20Sopenharmony_ci w_time = jiffies + p_wait; 25038c2ecf20Sopenharmony_ci do { 25048c2ecf20Sopenharmony_ci qla8044_rd_reg_indirect(vha, c_addr, 25058c2ecf20Sopenharmony_ci &c_value_r); 25068c2ecf20Sopenharmony_ci if ((c_value_r & p_mask) == 0) { 25078c2ecf20Sopenharmony_ci break; 25088c2ecf20Sopenharmony_ci } else if (time_after_eq(jiffies, w_time)) { 25098c2ecf20Sopenharmony_ci /* capturing dump failed */ 25108c2ecf20Sopenharmony_ci return rval; 25118c2ecf20Sopenharmony_ci } 25128c2ecf20Sopenharmony_ci } while (1); 25138c2ecf20Sopenharmony_ci } 25148c2ecf20Sopenharmony_ci 25158c2ecf20Sopenharmony_ci addr = r_addr; 25168c2ecf20Sopenharmony_ci for (k = 0; k < r_cnt; k++) { 25178c2ecf20Sopenharmony_ci qla8044_rd_reg_indirect(vha, addr, &r_value); 25188c2ecf20Sopenharmony_ci *data_ptr++ = r_value; 25198c2ecf20Sopenharmony_ci addr += cache_hdr->read_ctrl.read_addr_stride; 25208c2ecf20Sopenharmony_ci } 25218c2ecf20Sopenharmony_ci t_value += cache_hdr->addr_ctrl.tag_value_stride; 25228c2ecf20Sopenharmony_ci } 25238c2ecf20Sopenharmony_ci *d_ptr = data_ptr; 25248c2ecf20Sopenharmony_ci return QLA_SUCCESS; 25258c2ecf20Sopenharmony_ci} 25268c2ecf20Sopenharmony_ci 25278c2ecf20Sopenharmony_cistatic void 25288c2ecf20Sopenharmony_ciqla8044_minidump_process_l1cache(struct scsi_qla_host *vha, 25298c2ecf20Sopenharmony_ci struct qla8044_minidump_entry_hdr *entry_hdr, uint32_t **d_ptr) 25308c2ecf20Sopenharmony_ci{ 25318c2ecf20Sopenharmony_ci uint32_t addr, r_addr, c_addr, t_r_addr; 25328c2ecf20Sopenharmony_ci uint32_t i, k, loop_count, t_value, r_cnt, r_value; 25338c2ecf20Sopenharmony_ci uint32_t c_value_w; 25348c2ecf20Sopenharmony_ci struct qla8044_minidump_entry_cache *cache_hdr; 25358c2ecf20Sopenharmony_ci uint32_t *data_ptr = *d_ptr; 25368c2ecf20Sopenharmony_ci 25378c2ecf20Sopenharmony_ci cache_hdr = (struct qla8044_minidump_entry_cache *)entry_hdr; 25388c2ecf20Sopenharmony_ci loop_count = cache_hdr->op_count; 25398c2ecf20Sopenharmony_ci r_addr = cache_hdr->read_addr; 25408c2ecf20Sopenharmony_ci c_addr = cache_hdr->control_addr; 25418c2ecf20Sopenharmony_ci c_value_w = cache_hdr->cache_ctrl.write_value; 25428c2ecf20Sopenharmony_ci 25438c2ecf20Sopenharmony_ci t_r_addr = cache_hdr->tag_reg_addr; 25448c2ecf20Sopenharmony_ci t_value = cache_hdr->addr_ctrl.init_tag_value; 25458c2ecf20Sopenharmony_ci r_cnt = cache_hdr->read_ctrl.read_addr_cnt; 25468c2ecf20Sopenharmony_ci 25478c2ecf20Sopenharmony_ci for (i = 0; i < loop_count; i++) { 25488c2ecf20Sopenharmony_ci qla8044_wr_reg_indirect(vha, t_r_addr, t_value); 25498c2ecf20Sopenharmony_ci qla8044_wr_reg_indirect(vha, c_addr, c_value_w); 25508c2ecf20Sopenharmony_ci addr = r_addr; 25518c2ecf20Sopenharmony_ci for (k = 0; k < r_cnt; k++) { 25528c2ecf20Sopenharmony_ci qla8044_rd_reg_indirect(vha, addr, &r_value); 25538c2ecf20Sopenharmony_ci *data_ptr++ = r_value; 25548c2ecf20Sopenharmony_ci addr += cache_hdr->read_ctrl.read_addr_stride; 25558c2ecf20Sopenharmony_ci } 25568c2ecf20Sopenharmony_ci t_value += cache_hdr->addr_ctrl.tag_value_stride; 25578c2ecf20Sopenharmony_ci } 25588c2ecf20Sopenharmony_ci *d_ptr = data_ptr; 25598c2ecf20Sopenharmony_ci} 25608c2ecf20Sopenharmony_ci 25618c2ecf20Sopenharmony_cistatic void 25628c2ecf20Sopenharmony_ciqla8044_minidump_process_rdocm(struct scsi_qla_host *vha, 25638c2ecf20Sopenharmony_ci struct qla8044_minidump_entry_hdr *entry_hdr, uint32_t **d_ptr) 25648c2ecf20Sopenharmony_ci{ 25658c2ecf20Sopenharmony_ci uint32_t r_addr, r_stride, loop_cnt, i, r_value; 25668c2ecf20Sopenharmony_ci struct qla8044_minidump_entry_rdocm *ocm_hdr; 25678c2ecf20Sopenharmony_ci uint32_t *data_ptr = *d_ptr; 25688c2ecf20Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 25698c2ecf20Sopenharmony_ci 25708c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_p3p, vha, 0xb0f9, "Entering fn: %s\n", __func__); 25718c2ecf20Sopenharmony_ci 25728c2ecf20Sopenharmony_ci ocm_hdr = (struct qla8044_minidump_entry_rdocm *)entry_hdr; 25738c2ecf20Sopenharmony_ci r_addr = ocm_hdr->read_addr; 25748c2ecf20Sopenharmony_ci r_stride = ocm_hdr->read_addr_stride; 25758c2ecf20Sopenharmony_ci loop_cnt = ocm_hdr->op_count; 25768c2ecf20Sopenharmony_ci 25778c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_p3p, vha, 0xb0fa, 25788c2ecf20Sopenharmony_ci "[%s]: r_addr: 0x%x, r_stride: 0x%x, loop_cnt: 0x%x\n", 25798c2ecf20Sopenharmony_ci __func__, r_addr, r_stride, loop_cnt); 25808c2ecf20Sopenharmony_ci 25818c2ecf20Sopenharmony_ci for (i = 0; i < loop_cnt; i++) { 25828c2ecf20Sopenharmony_ci r_value = readl((void __iomem *)(r_addr + ha->nx_pcibase)); 25838c2ecf20Sopenharmony_ci *data_ptr++ = r_value; 25848c2ecf20Sopenharmony_ci r_addr += r_stride; 25858c2ecf20Sopenharmony_ci } 25868c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_p3p, vha, 0xb0fb, "Leaving fn: %s datacount: 0x%lx\n", 25878c2ecf20Sopenharmony_ci __func__, (long unsigned int) (loop_cnt * sizeof(uint32_t))); 25888c2ecf20Sopenharmony_ci 25898c2ecf20Sopenharmony_ci *d_ptr = data_ptr; 25908c2ecf20Sopenharmony_ci} 25918c2ecf20Sopenharmony_ci 25928c2ecf20Sopenharmony_cistatic void 25938c2ecf20Sopenharmony_ciqla8044_minidump_process_rdmux(struct scsi_qla_host *vha, 25948c2ecf20Sopenharmony_ci struct qla8044_minidump_entry_hdr *entry_hdr, 25958c2ecf20Sopenharmony_ci uint32_t **d_ptr) 25968c2ecf20Sopenharmony_ci{ 25978c2ecf20Sopenharmony_ci uint32_t r_addr, s_stride, s_addr, s_value, loop_cnt, i, r_value; 25988c2ecf20Sopenharmony_ci struct qla8044_minidump_entry_mux *mux_hdr; 25998c2ecf20Sopenharmony_ci uint32_t *data_ptr = *d_ptr; 26008c2ecf20Sopenharmony_ci 26018c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_p3p, vha, 0xb0fc, "Entering fn: %s\n", __func__); 26028c2ecf20Sopenharmony_ci 26038c2ecf20Sopenharmony_ci mux_hdr = (struct qla8044_minidump_entry_mux *)entry_hdr; 26048c2ecf20Sopenharmony_ci r_addr = mux_hdr->read_addr; 26058c2ecf20Sopenharmony_ci s_addr = mux_hdr->select_addr; 26068c2ecf20Sopenharmony_ci s_stride = mux_hdr->select_value_stride; 26078c2ecf20Sopenharmony_ci s_value = mux_hdr->select_value; 26088c2ecf20Sopenharmony_ci loop_cnt = mux_hdr->op_count; 26098c2ecf20Sopenharmony_ci 26108c2ecf20Sopenharmony_ci for (i = 0; i < loop_cnt; i++) { 26118c2ecf20Sopenharmony_ci qla8044_wr_reg_indirect(vha, s_addr, s_value); 26128c2ecf20Sopenharmony_ci qla8044_rd_reg_indirect(vha, r_addr, &r_value); 26138c2ecf20Sopenharmony_ci *data_ptr++ = s_value; 26148c2ecf20Sopenharmony_ci *data_ptr++ = r_value; 26158c2ecf20Sopenharmony_ci s_value += s_stride; 26168c2ecf20Sopenharmony_ci } 26178c2ecf20Sopenharmony_ci *d_ptr = data_ptr; 26188c2ecf20Sopenharmony_ci} 26198c2ecf20Sopenharmony_ci 26208c2ecf20Sopenharmony_cistatic void 26218c2ecf20Sopenharmony_ciqla8044_minidump_process_queue(struct scsi_qla_host *vha, 26228c2ecf20Sopenharmony_ci struct qla8044_minidump_entry_hdr *entry_hdr, 26238c2ecf20Sopenharmony_ci uint32_t **d_ptr) 26248c2ecf20Sopenharmony_ci{ 26258c2ecf20Sopenharmony_ci uint32_t s_addr, r_addr; 26268c2ecf20Sopenharmony_ci uint32_t r_stride, r_value, r_cnt, qid = 0; 26278c2ecf20Sopenharmony_ci uint32_t i, k, loop_cnt; 26288c2ecf20Sopenharmony_ci struct qla8044_minidump_entry_queue *q_hdr; 26298c2ecf20Sopenharmony_ci uint32_t *data_ptr = *d_ptr; 26308c2ecf20Sopenharmony_ci 26318c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_p3p, vha, 0xb0fd, "Entering fn: %s\n", __func__); 26328c2ecf20Sopenharmony_ci q_hdr = (struct qla8044_minidump_entry_queue *)entry_hdr; 26338c2ecf20Sopenharmony_ci s_addr = q_hdr->select_addr; 26348c2ecf20Sopenharmony_ci r_cnt = q_hdr->rd_strd.read_addr_cnt; 26358c2ecf20Sopenharmony_ci r_stride = q_hdr->rd_strd.read_addr_stride; 26368c2ecf20Sopenharmony_ci loop_cnt = q_hdr->op_count; 26378c2ecf20Sopenharmony_ci 26388c2ecf20Sopenharmony_ci for (i = 0; i < loop_cnt; i++) { 26398c2ecf20Sopenharmony_ci qla8044_wr_reg_indirect(vha, s_addr, qid); 26408c2ecf20Sopenharmony_ci r_addr = q_hdr->read_addr; 26418c2ecf20Sopenharmony_ci for (k = 0; k < r_cnt; k++) { 26428c2ecf20Sopenharmony_ci qla8044_rd_reg_indirect(vha, r_addr, &r_value); 26438c2ecf20Sopenharmony_ci *data_ptr++ = r_value; 26448c2ecf20Sopenharmony_ci r_addr += r_stride; 26458c2ecf20Sopenharmony_ci } 26468c2ecf20Sopenharmony_ci qid += q_hdr->q_strd.queue_id_stride; 26478c2ecf20Sopenharmony_ci } 26488c2ecf20Sopenharmony_ci *d_ptr = data_ptr; 26498c2ecf20Sopenharmony_ci} 26508c2ecf20Sopenharmony_ci 26518c2ecf20Sopenharmony_ci/* ISP83xx functions to process new minidump entries... */ 26528c2ecf20Sopenharmony_cistatic uint32_t 26538c2ecf20Sopenharmony_ciqla8044_minidump_process_pollrd(struct scsi_qla_host *vha, 26548c2ecf20Sopenharmony_ci struct qla8044_minidump_entry_hdr *entry_hdr, 26558c2ecf20Sopenharmony_ci uint32_t **d_ptr) 26568c2ecf20Sopenharmony_ci{ 26578c2ecf20Sopenharmony_ci uint32_t r_addr, s_addr, s_value, r_value, poll_wait, poll_mask; 26588c2ecf20Sopenharmony_ci uint16_t s_stride, i; 26598c2ecf20Sopenharmony_ci struct qla8044_minidump_entry_pollrd *pollrd_hdr; 26608c2ecf20Sopenharmony_ci uint32_t *data_ptr = *d_ptr; 26618c2ecf20Sopenharmony_ci 26628c2ecf20Sopenharmony_ci pollrd_hdr = (struct qla8044_minidump_entry_pollrd *) entry_hdr; 26638c2ecf20Sopenharmony_ci s_addr = pollrd_hdr->select_addr; 26648c2ecf20Sopenharmony_ci r_addr = pollrd_hdr->read_addr; 26658c2ecf20Sopenharmony_ci s_value = pollrd_hdr->select_value; 26668c2ecf20Sopenharmony_ci s_stride = pollrd_hdr->select_value_stride; 26678c2ecf20Sopenharmony_ci 26688c2ecf20Sopenharmony_ci poll_wait = pollrd_hdr->poll_wait; 26698c2ecf20Sopenharmony_ci poll_mask = pollrd_hdr->poll_mask; 26708c2ecf20Sopenharmony_ci 26718c2ecf20Sopenharmony_ci for (i = 0; i < pollrd_hdr->op_count; i++) { 26728c2ecf20Sopenharmony_ci qla8044_wr_reg_indirect(vha, s_addr, s_value); 26738c2ecf20Sopenharmony_ci poll_wait = pollrd_hdr->poll_wait; 26748c2ecf20Sopenharmony_ci while (1) { 26758c2ecf20Sopenharmony_ci qla8044_rd_reg_indirect(vha, s_addr, &r_value); 26768c2ecf20Sopenharmony_ci if ((r_value & poll_mask) != 0) { 26778c2ecf20Sopenharmony_ci break; 26788c2ecf20Sopenharmony_ci } else { 26798c2ecf20Sopenharmony_ci usleep_range(1000, 1100); 26808c2ecf20Sopenharmony_ci if (--poll_wait == 0) { 26818c2ecf20Sopenharmony_ci ql_log(ql_log_fatal, vha, 0xb0fe, 26828c2ecf20Sopenharmony_ci "%s: TIMEOUT\n", __func__); 26838c2ecf20Sopenharmony_ci goto error; 26848c2ecf20Sopenharmony_ci } 26858c2ecf20Sopenharmony_ci } 26868c2ecf20Sopenharmony_ci } 26878c2ecf20Sopenharmony_ci qla8044_rd_reg_indirect(vha, r_addr, &r_value); 26888c2ecf20Sopenharmony_ci *data_ptr++ = s_value; 26898c2ecf20Sopenharmony_ci *data_ptr++ = r_value; 26908c2ecf20Sopenharmony_ci 26918c2ecf20Sopenharmony_ci s_value += s_stride; 26928c2ecf20Sopenharmony_ci } 26938c2ecf20Sopenharmony_ci *d_ptr = data_ptr; 26948c2ecf20Sopenharmony_ci return QLA_SUCCESS; 26958c2ecf20Sopenharmony_ci 26968c2ecf20Sopenharmony_cierror: 26978c2ecf20Sopenharmony_ci return QLA_FUNCTION_FAILED; 26988c2ecf20Sopenharmony_ci} 26998c2ecf20Sopenharmony_ci 27008c2ecf20Sopenharmony_cistatic void 27018c2ecf20Sopenharmony_ciqla8044_minidump_process_rdmux2(struct scsi_qla_host *vha, 27028c2ecf20Sopenharmony_ci struct qla8044_minidump_entry_hdr *entry_hdr, uint32_t **d_ptr) 27038c2ecf20Sopenharmony_ci{ 27048c2ecf20Sopenharmony_ci uint32_t sel_val1, sel_val2, t_sel_val, data, i; 27058c2ecf20Sopenharmony_ci uint32_t sel_addr1, sel_addr2, sel_val_mask, read_addr; 27068c2ecf20Sopenharmony_ci struct qla8044_minidump_entry_rdmux2 *rdmux2_hdr; 27078c2ecf20Sopenharmony_ci uint32_t *data_ptr = *d_ptr; 27088c2ecf20Sopenharmony_ci 27098c2ecf20Sopenharmony_ci rdmux2_hdr = (struct qla8044_minidump_entry_rdmux2 *) entry_hdr; 27108c2ecf20Sopenharmony_ci sel_val1 = rdmux2_hdr->select_value_1; 27118c2ecf20Sopenharmony_ci sel_val2 = rdmux2_hdr->select_value_2; 27128c2ecf20Sopenharmony_ci sel_addr1 = rdmux2_hdr->select_addr_1; 27138c2ecf20Sopenharmony_ci sel_addr2 = rdmux2_hdr->select_addr_2; 27148c2ecf20Sopenharmony_ci sel_val_mask = rdmux2_hdr->select_value_mask; 27158c2ecf20Sopenharmony_ci read_addr = rdmux2_hdr->read_addr; 27168c2ecf20Sopenharmony_ci 27178c2ecf20Sopenharmony_ci for (i = 0; i < rdmux2_hdr->op_count; i++) { 27188c2ecf20Sopenharmony_ci qla8044_wr_reg_indirect(vha, sel_addr1, sel_val1); 27198c2ecf20Sopenharmony_ci t_sel_val = sel_val1 & sel_val_mask; 27208c2ecf20Sopenharmony_ci *data_ptr++ = t_sel_val; 27218c2ecf20Sopenharmony_ci 27228c2ecf20Sopenharmony_ci qla8044_wr_reg_indirect(vha, sel_addr2, t_sel_val); 27238c2ecf20Sopenharmony_ci qla8044_rd_reg_indirect(vha, read_addr, &data); 27248c2ecf20Sopenharmony_ci 27258c2ecf20Sopenharmony_ci *data_ptr++ = data; 27268c2ecf20Sopenharmony_ci 27278c2ecf20Sopenharmony_ci qla8044_wr_reg_indirect(vha, sel_addr1, sel_val2); 27288c2ecf20Sopenharmony_ci t_sel_val = sel_val2 & sel_val_mask; 27298c2ecf20Sopenharmony_ci *data_ptr++ = t_sel_val; 27308c2ecf20Sopenharmony_ci 27318c2ecf20Sopenharmony_ci qla8044_wr_reg_indirect(vha, sel_addr2, t_sel_val); 27328c2ecf20Sopenharmony_ci qla8044_rd_reg_indirect(vha, read_addr, &data); 27338c2ecf20Sopenharmony_ci 27348c2ecf20Sopenharmony_ci *data_ptr++ = data; 27358c2ecf20Sopenharmony_ci 27368c2ecf20Sopenharmony_ci sel_val1 += rdmux2_hdr->select_value_stride; 27378c2ecf20Sopenharmony_ci sel_val2 += rdmux2_hdr->select_value_stride; 27388c2ecf20Sopenharmony_ci } 27398c2ecf20Sopenharmony_ci 27408c2ecf20Sopenharmony_ci *d_ptr = data_ptr; 27418c2ecf20Sopenharmony_ci} 27428c2ecf20Sopenharmony_ci 27438c2ecf20Sopenharmony_cistatic uint32_t 27448c2ecf20Sopenharmony_ciqla8044_minidump_process_pollrdmwr(struct scsi_qla_host *vha, 27458c2ecf20Sopenharmony_ci struct qla8044_minidump_entry_hdr *entry_hdr, 27468c2ecf20Sopenharmony_ci uint32_t **d_ptr) 27478c2ecf20Sopenharmony_ci{ 27488c2ecf20Sopenharmony_ci uint32_t poll_wait, poll_mask, r_value, data; 27498c2ecf20Sopenharmony_ci uint32_t addr_1, addr_2, value_1, value_2; 27508c2ecf20Sopenharmony_ci struct qla8044_minidump_entry_pollrdmwr *poll_hdr; 27518c2ecf20Sopenharmony_ci uint32_t *data_ptr = *d_ptr; 27528c2ecf20Sopenharmony_ci 27538c2ecf20Sopenharmony_ci poll_hdr = (struct qla8044_minidump_entry_pollrdmwr *) entry_hdr; 27548c2ecf20Sopenharmony_ci addr_1 = poll_hdr->addr_1; 27558c2ecf20Sopenharmony_ci addr_2 = poll_hdr->addr_2; 27568c2ecf20Sopenharmony_ci value_1 = poll_hdr->value_1; 27578c2ecf20Sopenharmony_ci value_2 = poll_hdr->value_2; 27588c2ecf20Sopenharmony_ci poll_mask = poll_hdr->poll_mask; 27598c2ecf20Sopenharmony_ci 27608c2ecf20Sopenharmony_ci qla8044_wr_reg_indirect(vha, addr_1, value_1); 27618c2ecf20Sopenharmony_ci 27628c2ecf20Sopenharmony_ci poll_wait = poll_hdr->poll_wait; 27638c2ecf20Sopenharmony_ci while (1) { 27648c2ecf20Sopenharmony_ci qla8044_rd_reg_indirect(vha, addr_1, &r_value); 27658c2ecf20Sopenharmony_ci 27668c2ecf20Sopenharmony_ci if ((r_value & poll_mask) != 0) { 27678c2ecf20Sopenharmony_ci break; 27688c2ecf20Sopenharmony_ci } else { 27698c2ecf20Sopenharmony_ci usleep_range(1000, 1100); 27708c2ecf20Sopenharmony_ci if (--poll_wait == 0) { 27718c2ecf20Sopenharmony_ci ql_log(ql_log_fatal, vha, 0xb0ff, 27728c2ecf20Sopenharmony_ci "%s: TIMEOUT\n", __func__); 27738c2ecf20Sopenharmony_ci goto error; 27748c2ecf20Sopenharmony_ci } 27758c2ecf20Sopenharmony_ci } 27768c2ecf20Sopenharmony_ci } 27778c2ecf20Sopenharmony_ci 27788c2ecf20Sopenharmony_ci qla8044_rd_reg_indirect(vha, addr_2, &data); 27798c2ecf20Sopenharmony_ci data &= poll_hdr->modify_mask; 27808c2ecf20Sopenharmony_ci qla8044_wr_reg_indirect(vha, addr_2, data); 27818c2ecf20Sopenharmony_ci qla8044_wr_reg_indirect(vha, addr_1, value_2); 27828c2ecf20Sopenharmony_ci 27838c2ecf20Sopenharmony_ci poll_wait = poll_hdr->poll_wait; 27848c2ecf20Sopenharmony_ci while (1) { 27858c2ecf20Sopenharmony_ci qla8044_rd_reg_indirect(vha, addr_1, &r_value); 27868c2ecf20Sopenharmony_ci 27878c2ecf20Sopenharmony_ci if ((r_value & poll_mask) != 0) { 27888c2ecf20Sopenharmony_ci break; 27898c2ecf20Sopenharmony_ci } else { 27908c2ecf20Sopenharmony_ci usleep_range(1000, 1100); 27918c2ecf20Sopenharmony_ci if (--poll_wait == 0) { 27928c2ecf20Sopenharmony_ci ql_log(ql_log_fatal, vha, 0xb100, 27938c2ecf20Sopenharmony_ci "%s: TIMEOUT2\n", __func__); 27948c2ecf20Sopenharmony_ci goto error; 27958c2ecf20Sopenharmony_ci } 27968c2ecf20Sopenharmony_ci } 27978c2ecf20Sopenharmony_ci } 27988c2ecf20Sopenharmony_ci 27998c2ecf20Sopenharmony_ci *data_ptr++ = addr_2; 28008c2ecf20Sopenharmony_ci *data_ptr++ = data; 28018c2ecf20Sopenharmony_ci 28028c2ecf20Sopenharmony_ci *d_ptr = data_ptr; 28038c2ecf20Sopenharmony_ci 28048c2ecf20Sopenharmony_ci return QLA_SUCCESS; 28058c2ecf20Sopenharmony_ci 28068c2ecf20Sopenharmony_cierror: 28078c2ecf20Sopenharmony_ci return QLA_FUNCTION_FAILED; 28088c2ecf20Sopenharmony_ci} 28098c2ecf20Sopenharmony_ci 28108c2ecf20Sopenharmony_ci#define ISP8044_PEX_DMA_ENGINE_INDEX 8 28118c2ecf20Sopenharmony_ci#define ISP8044_PEX_DMA_BASE_ADDRESS 0x77320000 28128c2ecf20Sopenharmony_ci#define ISP8044_PEX_DMA_NUM_OFFSET 0x10000UL 28138c2ecf20Sopenharmony_ci#define ISP8044_PEX_DMA_CMD_ADDR_LOW 0x0 28148c2ecf20Sopenharmony_ci#define ISP8044_PEX_DMA_CMD_ADDR_HIGH 0x04 28158c2ecf20Sopenharmony_ci#define ISP8044_PEX_DMA_CMD_STS_AND_CNTRL 0x08 28168c2ecf20Sopenharmony_ci 28178c2ecf20Sopenharmony_ci#define ISP8044_PEX_DMA_READ_SIZE (16 * 1024) 28188c2ecf20Sopenharmony_ci#define ISP8044_PEX_DMA_MAX_WAIT (100 * 100) /* Max wait of 100 msecs */ 28198c2ecf20Sopenharmony_ci 28208c2ecf20Sopenharmony_cistatic int 28218c2ecf20Sopenharmony_ciqla8044_check_dma_engine_state(struct scsi_qla_host *vha) 28228c2ecf20Sopenharmony_ci{ 28238c2ecf20Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 28248c2ecf20Sopenharmony_ci int rval = QLA_SUCCESS; 28258c2ecf20Sopenharmony_ci uint32_t dma_eng_num = 0, cmd_sts_and_cntrl = 0; 28268c2ecf20Sopenharmony_ci uint64_t dma_base_addr = 0; 28278c2ecf20Sopenharmony_ci struct qla8044_minidump_template_hdr *tmplt_hdr = NULL; 28288c2ecf20Sopenharmony_ci 28298c2ecf20Sopenharmony_ci tmplt_hdr = ha->md_tmplt_hdr; 28308c2ecf20Sopenharmony_ci dma_eng_num = 28318c2ecf20Sopenharmony_ci tmplt_hdr->saved_state_array[ISP8044_PEX_DMA_ENGINE_INDEX]; 28328c2ecf20Sopenharmony_ci dma_base_addr = ISP8044_PEX_DMA_BASE_ADDRESS + 28338c2ecf20Sopenharmony_ci (dma_eng_num * ISP8044_PEX_DMA_NUM_OFFSET); 28348c2ecf20Sopenharmony_ci 28358c2ecf20Sopenharmony_ci /* Read the pex-dma's command-status-and-control register. */ 28368c2ecf20Sopenharmony_ci rval = qla8044_rd_reg_indirect(vha, 28378c2ecf20Sopenharmony_ci (dma_base_addr + ISP8044_PEX_DMA_CMD_STS_AND_CNTRL), 28388c2ecf20Sopenharmony_ci &cmd_sts_and_cntrl); 28398c2ecf20Sopenharmony_ci if (rval) 28408c2ecf20Sopenharmony_ci return QLA_FUNCTION_FAILED; 28418c2ecf20Sopenharmony_ci 28428c2ecf20Sopenharmony_ci /* Check if requested pex-dma engine is available. */ 28438c2ecf20Sopenharmony_ci if (cmd_sts_and_cntrl & BIT_31) 28448c2ecf20Sopenharmony_ci return QLA_SUCCESS; 28458c2ecf20Sopenharmony_ci 28468c2ecf20Sopenharmony_ci return QLA_FUNCTION_FAILED; 28478c2ecf20Sopenharmony_ci} 28488c2ecf20Sopenharmony_ci 28498c2ecf20Sopenharmony_cistatic int 28508c2ecf20Sopenharmony_ciqla8044_start_pex_dma(struct scsi_qla_host *vha, 28518c2ecf20Sopenharmony_ci struct qla8044_minidump_entry_rdmem_pex_dma *m_hdr) 28528c2ecf20Sopenharmony_ci{ 28538c2ecf20Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 28548c2ecf20Sopenharmony_ci int rval = QLA_SUCCESS, wait = 0; 28558c2ecf20Sopenharmony_ci uint32_t dma_eng_num = 0, cmd_sts_and_cntrl = 0; 28568c2ecf20Sopenharmony_ci uint64_t dma_base_addr = 0; 28578c2ecf20Sopenharmony_ci struct qla8044_minidump_template_hdr *tmplt_hdr = NULL; 28588c2ecf20Sopenharmony_ci 28598c2ecf20Sopenharmony_ci tmplt_hdr = ha->md_tmplt_hdr; 28608c2ecf20Sopenharmony_ci dma_eng_num = 28618c2ecf20Sopenharmony_ci tmplt_hdr->saved_state_array[ISP8044_PEX_DMA_ENGINE_INDEX]; 28628c2ecf20Sopenharmony_ci dma_base_addr = ISP8044_PEX_DMA_BASE_ADDRESS + 28638c2ecf20Sopenharmony_ci (dma_eng_num * ISP8044_PEX_DMA_NUM_OFFSET); 28648c2ecf20Sopenharmony_ci 28658c2ecf20Sopenharmony_ci rval = qla8044_wr_reg_indirect(vha, 28668c2ecf20Sopenharmony_ci dma_base_addr + ISP8044_PEX_DMA_CMD_ADDR_LOW, 28678c2ecf20Sopenharmony_ci m_hdr->desc_card_addr); 28688c2ecf20Sopenharmony_ci if (rval) 28698c2ecf20Sopenharmony_ci goto error_exit; 28708c2ecf20Sopenharmony_ci 28718c2ecf20Sopenharmony_ci rval = qla8044_wr_reg_indirect(vha, 28728c2ecf20Sopenharmony_ci dma_base_addr + ISP8044_PEX_DMA_CMD_ADDR_HIGH, 0); 28738c2ecf20Sopenharmony_ci if (rval) 28748c2ecf20Sopenharmony_ci goto error_exit; 28758c2ecf20Sopenharmony_ci 28768c2ecf20Sopenharmony_ci rval = qla8044_wr_reg_indirect(vha, 28778c2ecf20Sopenharmony_ci dma_base_addr + ISP8044_PEX_DMA_CMD_STS_AND_CNTRL, 28788c2ecf20Sopenharmony_ci m_hdr->start_dma_cmd); 28798c2ecf20Sopenharmony_ci if (rval) 28808c2ecf20Sopenharmony_ci goto error_exit; 28818c2ecf20Sopenharmony_ci 28828c2ecf20Sopenharmony_ci /* Wait for dma operation to complete. */ 28838c2ecf20Sopenharmony_ci for (wait = 0; wait < ISP8044_PEX_DMA_MAX_WAIT; wait++) { 28848c2ecf20Sopenharmony_ci rval = qla8044_rd_reg_indirect(vha, 28858c2ecf20Sopenharmony_ci (dma_base_addr + ISP8044_PEX_DMA_CMD_STS_AND_CNTRL), 28868c2ecf20Sopenharmony_ci &cmd_sts_and_cntrl); 28878c2ecf20Sopenharmony_ci if (rval) 28888c2ecf20Sopenharmony_ci goto error_exit; 28898c2ecf20Sopenharmony_ci 28908c2ecf20Sopenharmony_ci if ((cmd_sts_and_cntrl & BIT_1) == 0) 28918c2ecf20Sopenharmony_ci break; 28928c2ecf20Sopenharmony_ci 28938c2ecf20Sopenharmony_ci udelay(10); 28948c2ecf20Sopenharmony_ci } 28958c2ecf20Sopenharmony_ci 28968c2ecf20Sopenharmony_ci /* Wait a max of 100 ms, otherwise fallback to rdmem entry read */ 28978c2ecf20Sopenharmony_ci if (wait >= ISP8044_PEX_DMA_MAX_WAIT) { 28988c2ecf20Sopenharmony_ci rval = QLA_FUNCTION_FAILED; 28998c2ecf20Sopenharmony_ci goto error_exit; 29008c2ecf20Sopenharmony_ci } 29018c2ecf20Sopenharmony_ci 29028c2ecf20Sopenharmony_cierror_exit: 29038c2ecf20Sopenharmony_ci return rval; 29048c2ecf20Sopenharmony_ci} 29058c2ecf20Sopenharmony_ci 29068c2ecf20Sopenharmony_cistatic int 29078c2ecf20Sopenharmony_ciqla8044_minidump_pex_dma_read(struct scsi_qla_host *vha, 29088c2ecf20Sopenharmony_ci struct qla8044_minidump_entry_hdr *entry_hdr, uint32_t **d_ptr) 29098c2ecf20Sopenharmony_ci{ 29108c2ecf20Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 29118c2ecf20Sopenharmony_ci int rval = QLA_SUCCESS; 29128c2ecf20Sopenharmony_ci struct qla8044_minidump_entry_rdmem_pex_dma *m_hdr = NULL; 29138c2ecf20Sopenharmony_ci uint32_t chunk_size, read_size; 29148c2ecf20Sopenharmony_ci uint8_t *data_ptr = (uint8_t *)*d_ptr; 29158c2ecf20Sopenharmony_ci void *rdmem_buffer = NULL; 29168c2ecf20Sopenharmony_ci dma_addr_t rdmem_dma; 29178c2ecf20Sopenharmony_ci struct qla8044_pex_dma_descriptor dma_desc; 29188c2ecf20Sopenharmony_ci 29198c2ecf20Sopenharmony_ci rval = qla8044_check_dma_engine_state(vha); 29208c2ecf20Sopenharmony_ci if (rval != QLA_SUCCESS) { 29218c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_p3p, vha, 0xb147, 29228c2ecf20Sopenharmony_ci "DMA engine not available. Fallback to rdmem-read.\n"); 29238c2ecf20Sopenharmony_ci return QLA_FUNCTION_FAILED; 29248c2ecf20Sopenharmony_ci } 29258c2ecf20Sopenharmony_ci 29268c2ecf20Sopenharmony_ci m_hdr = (void *)entry_hdr; 29278c2ecf20Sopenharmony_ci 29288c2ecf20Sopenharmony_ci rdmem_buffer = dma_alloc_coherent(&ha->pdev->dev, 29298c2ecf20Sopenharmony_ci ISP8044_PEX_DMA_READ_SIZE, &rdmem_dma, GFP_KERNEL); 29308c2ecf20Sopenharmony_ci if (!rdmem_buffer) { 29318c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_p3p, vha, 0xb148, 29328c2ecf20Sopenharmony_ci "Unable to allocate rdmem dma buffer\n"); 29338c2ecf20Sopenharmony_ci return QLA_FUNCTION_FAILED; 29348c2ecf20Sopenharmony_ci } 29358c2ecf20Sopenharmony_ci 29368c2ecf20Sopenharmony_ci /* Prepare pex-dma descriptor to be written to MS memory. */ 29378c2ecf20Sopenharmony_ci /* dma-desc-cmd layout: 29388c2ecf20Sopenharmony_ci * 0-3: dma-desc-cmd 0-3 29398c2ecf20Sopenharmony_ci * 4-7: pcid function number 29408c2ecf20Sopenharmony_ci * 8-15: dma-desc-cmd 8-15 29418c2ecf20Sopenharmony_ci * dma_bus_addr: dma buffer address 29428c2ecf20Sopenharmony_ci * cmd.read_data_size: amount of data-chunk to be read. 29438c2ecf20Sopenharmony_ci */ 29448c2ecf20Sopenharmony_ci dma_desc.cmd.dma_desc_cmd = (m_hdr->dma_desc_cmd & 0xff0f); 29458c2ecf20Sopenharmony_ci dma_desc.cmd.dma_desc_cmd |= 29468c2ecf20Sopenharmony_ci ((PCI_FUNC(ha->pdev->devfn) & 0xf) << 0x4); 29478c2ecf20Sopenharmony_ci 29488c2ecf20Sopenharmony_ci dma_desc.dma_bus_addr = rdmem_dma; 29498c2ecf20Sopenharmony_ci dma_desc.cmd.read_data_size = chunk_size = ISP8044_PEX_DMA_READ_SIZE; 29508c2ecf20Sopenharmony_ci read_size = 0; 29518c2ecf20Sopenharmony_ci 29528c2ecf20Sopenharmony_ci /* 29538c2ecf20Sopenharmony_ci * Perform rdmem operation using pex-dma. 29548c2ecf20Sopenharmony_ci * Prepare dma in chunks of ISP8044_PEX_DMA_READ_SIZE. 29558c2ecf20Sopenharmony_ci */ 29568c2ecf20Sopenharmony_ci while (read_size < m_hdr->read_data_size) { 29578c2ecf20Sopenharmony_ci if (m_hdr->read_data_size - read_size < 29588c2ecf20Sopenharmony_ci ISP8044_PEX_DMA_READ_SIZE) { 29598c2ecf20Sopenharmony_ci chunk_size = (m_hdr->read_data_size - read_size); 29608c2ecf20Sopenharmony_ci dma_desc.cmd.read_data_size = chunk_size; 29618c2ecf20Sopenharmony_ci } 29628c2ecf20Sopenharmony_ci 29638c2ecf20Sopenharmony_ci dma_desc.src_addr = m_hdr->read_addr + read_size; 29648c2ecf20Sopenharmony_ci 29658c2ecf20Sopenharmony_ci /* Prepare: Write pex-dma descriptor to MS memory. */ 29668c2ecf20Sopenharmony_ci rval = qla8044_ms_mem_write_128b(vha, 29678c2ecf20Sopenharmony_ci m_hdr->desc_card_addr, (uint32_t *)&dma_desc, 29688c2ecf20Sopenharmony_ci (sizeof(struct qla8044_pex_dma_descriptor)/16)); 29698c2ecf20Sopenharmony_ci if (rval) { 29708c2ecf20Sopenharmony_ci ql_log(ql_log_warn, vha, 0xb14a, 29718c2ecf20Sopenharmony_ci "%s: Error writing rdmem-dma-init to MS !!!\n", 29728c2ecf20Sopenharmony_ci __func__); 29738c2ecf20Sopenharmony_ci goto error_exit; 29748c2ecf20Sopenharmony_ci } 29758c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_p3p, vha, 0xb14b, 29768c2ecf20Sopenharmony_ci "%s: Dma-descriptor: Instruct for rdmem dma " 29778c2ecf20Sopenharmony_ci "(chunk_size 0x%x).\n", __func__, chunk_size); 29788c2ecf20Sopenharmony_ci 29798c2ecf20Sopenharmony_ci /* Execute: Start pex-dma operation. */ 29808c2ecf20Sopenharmony_ci rval = qla8044_start_pex_dma(vha, m_hdr); 29818c2ecf20Sopenharmony_ci if (rval) 29828c2ecf20Sopenharmony_ci goto error_exit; 29838c2ecf20Sopenharmony_ci 29848c2ecf20Sopenharmony_ci memcpy(data_ptr, rdmem_buffer, chunk_size); 29858c2ecf20Sopenharmony_ci data_ptr += chunk_size; 29868c2ecf20Sopenharmony_ci read_size += chunk_size; 29878c2ecf20Sopenharmony_ci } 29888c2ecf20Sopenharmony_ci 29898c2ecf20Sopenharmony_ci *d_ptr = (uint32_t *)data_ptr; 29908c2ecf20Sopenharmony_ci 29918c2ecf20Sopenharmony_cierror_exit: 29928c2ecf20Sopenharmony_ci if (rdmem_buffer) 29938c2ecf20Sopenharmony_ci dma_free_coherent(&ha->pdev->dev, ISP8044_PEX_DMA_READ_SIZE, 29948c2ecf20Sopenharmony_ci rdmem_buffer, rdmem_dma); 29958c2ecf20Sopenharmony_ci 29968c2ecf20Sopenharmony_ci return rval; 29978c2ecf20Sopenharmony_ci} 29988c2ecf20Sopenharmony_ci 29998c2ecf20Sopenharmony_cistatic uint32_t 30008c2ecf20Sopenharmony_ciqla8044_minidump_process_rddfe(struct scsi_qla_host *vha, 30018c2ecf20Sopenharmony_ci struct qla8044_minidump_entry_hdr *entry_hdr, uint32_t **d_ptr) 30028c2ecf20Sopenharmony_ci{ 30038c2ecf20Sopenharmony_ci int loop_cnt; 30048c2ecf20Sopenharmony_ci uint32_t addr1, addr2, value, data, temp, wrVal; 30058c2ecf20Sopenharmony_ci uint8_t stride, stride2; 30068c2ecf20Sopenharmony_ci uint16_t count; 30078c2ecf20Sopenharmony_ci uint32_t poll, mask, modify_mask; 30088c2ecf20Sopenharmony_ci uint32_t wait_count = 0; 30098c2ecf20Sopenharmony_ci uint32_t *data_ptr = *d_ptr; 30108c2ecf20Sopenharmony_ci struct qla8044_minidump_entry_rddfe *rddfe; 30118c2ecf20Sopenharmony_ci 30128c2ecf20Sopenharmony_ci rddfe = (struct qla8044_minidump_entry_rddfe *) entry_hdr; 30138c2ecf20Sopenharmony_ci 30148c2ecf20Sopenharmony_ci addr1 = rddfe->addr_1; 30158c2ecf20Sopenharmony_ci value = rddfe->value; 30168c2ecf20Sopenharmony_ci stride = rddfe->stride; 30178c2ecf20Sopenharmony_ci stride2 = rddfe->stride2; 30188c2ecf20Sopenharmony_ci count = rddfe->count; 30198c2ecf20Sopenharmony_ci 30208c2ecf20Sopenharmony_ci poll = rddfe->poll; 30218c2ecf20Sopenharmony_ci mask = rddfe->mask; 30228c2ecf20Sopenharmony_ci modify_mask = rddfe->modify_mask; 30238c2ecf20Sopenharmony_ci 30248c2ecf20Sopenharmony_ci addr2 = addr1 + stride; 30258c2ecf20Sopenharmony_ci 30268c2ecf20Sopenharmony_ci for (loop_cnt = 0x0; loop_cnt < count; loop_cnt++) { 30278c2ecf20Sopenharmony_ci qla8044_wr_reg_indirect(vha, addr1, (0x40000000 | value)); 30288c2ecf20Sopenharmony_ci 30298c2ecf20Sopenharmony_ci wait_count = 0; 30308c2ecf20Sopenharmony_ci while (wait_count < poll) { 30318c2ecf20Sopenharmony_ci qla8044_rd_reg_indirect(vha, addr1, &temp); 30328c2ecf20Sopenharmony_ci if ((temp & mask) != 0) 30338c2ecf20Sopenharmony_ci break; 30348c2ecf20Sopenharmony_ci wait_count++; 30358c2ecf20Sopenharmony_ci } 30368c2ecf20Sopenharmony_ci 30378c2ecf20Sopenharmony_ci if (wait_count == poll) { 30388c2ecf20Sopenharmony_ci ql_log(ql_log_warn, vha, 0xb153, 30398c2ecf20Sopenharmony_ci "%s: TIMEOUT\n", __func__); 30408c2ecf20Sopenharmony_ci goto error; 30418c2ecf20Sopenharmony_ci } else { 30428c2ecf20Sopenharmony_ci qla8044_rd_reg_indirect(vha, addr2, &temp); 30438c2ecf20Sopenharmony_ci temp = temp & modify_mask; 30448c2ecf20Sopenharmony_ci temp = (temp | ((loop_cnt << 16) | loop_cnt)); 30458c2ecf20Sopenharmony_ci wrVal = ((temp << 16) | temp); 30468c2ecf20Sopenharmony_ci 30478c2ecf20Sopenharmony_ci qla8044_wr_reg_indirect(vha, addr2, wrVal); 30488c2ecf20Sopenharmony_ci qla8044_wr_reg_indirect(vha, addr1, value); 30498c2ecf20Sopenharmony_ci 30508c2ecf20Sopenharmony_ci wait_count = 0; 30518c2ecf20Sopenharmony_ci while (wait_count < poll) { 30528c2ecf20Sopenharmony_ci qla8044_rd_reg_indirect(vha, addr1, &temp); 30538c2ecf20Sopenharmony_ci if ((temp & mask) != 0) 30548c2ecf20Sopenharmony_ci break; 30558c2ecf20Sopenharmony_ci wait_count++; 30568c2ecf20Sopenharmony_ci } 30578c2ecf20Sopenharmony_ci if (wait_count == poll) { 30588c2ecf20Sopenharmony_ci ql_log(ql_log_warn, vha, 0xb154, 30598c2ecf20Sopenharmony_ci "%s: TIMEOUT\n", __func__); 30608c2ecf20Sopenharmony_ci goto error; 30618c2ecf20Sopenharmony_ci } 30628c2ecf20Sopenharmony_ci 30638c2ecf20Sopenharmony_ci qla8044_wr_reg_indirect(vha, addr1, 30648c2ecf20Sopenharmony_ci ((0x40000000 | value) + stride2)); 30658c2ecf20Sopenharmony_ci wait_count = 0; 30668c2ecf20Sopenharmony_ci while (wait_count < poll) { 30678c2ecf20Sopenharmony_ci qla8044_rd_reg_indirect(vha, addr1, &temp); 30688c2ecf20Sopenharmony_ci if ((temp & mask) != 0) 30698c2ecf20Sopenharmony_ci break; 30708c2ecf20Sopenharmony_ci wait_count++; 30718c2ecf20Sopenharmony_ci } 30728c2ecf20Sopenharmony_ci 30738c2ecf20Sopenharmony_ci if (wait_count == poll) { 30748c2ecf20Sopenharmony_ci ql_log(ql_log_warn, vha, 0xb155, 30758c2ecf20Sopenharmony_ci "%s: TIMEOUT\n", __func__); 30768c2ecf20Sopenharmony_ci goto error; 30778c2ecf20Sopenharmony_ci } 30788c2ecf20Sopenharmony_ci 30798c2ecf20Sopenharmony_ci qla8044_rd_reg_indirect(vha, addr2, &data); 30808c2ecf20Sopenharmony_ci 30818c2ecf20Sopenharmony_ci *data_ptr++ = wrVal; 30828c2ecf20Sopenharmony_ci *data_ptr++ = data; 30838c2ecf20Sopenharmony_ci } 30848c2ecf20Sopenharmony_ci 30858c2ecf20Sopenharmony_ci } 30868c2ecf20Sopenharmony_ci 30878c2ecf20Sopenharmony_ci *d_ptr = data_ptr; 30888c2ecf20Sopenharmony_ci return QLA_SUCCESS; 30898c2ecf20Sopenharmony_ci 30908c2ecf20Sopenharmony_cierror: 30918c2ecf20Sopenharmony_ci return -1; 30928c2ecf20Sopenharmony_ci 30938c2ecf20Sopenharmony_ci} 30948c2ecf20Sopenharmony_ci 30958c2ecf20Sopenharmony_cistatic uint32_t 30968c2ecf20Sopenharmony_ciqla8044_minidump_process_rdmdio(struct scsi_qla_host *vha, 30978c2ecf20Sopenharmony_ci struct qla8044_minidump_entry_hdr *entry_hdr, uint32_t **d_ptr) 30988c2ecf20Sopenharmony_ci{ 30998c2ecf20Sopenharmony_ci int ret = 0; 31008c2ecf20Sopenharmony_ci uint32_t addr1, addr2, value1, value2, data, selVal; 31018c2ecf20Sopenharmony_ci uint8_t stride1, stride2; 31028c2ecf20Sopenharmony_ci uint32_t addr3, addr4, addr5, addr6, addr7; 31038c2ecf20Sopenharmony_ci uint16_t count, loop_cnt; 31048c2ecf20Sopenharmony_ci uint32_t mask; 31058c2ecf20Sopenharmony_ci uint32_t *data_ptr = *d_ptr; 31068c2ecf20Sopenharmony_ci 31078c2ecf20Sopenharmony_ci struct qla8044_minidump_entry_rdmdio *rdmdio; 31088c2ecf20Sopenharmony_ci 31098c2ecf20Sopenharmony_ci rdmdio = (struct qla8044_minidump_entry_rdmdio *) entry_hdr; 31108c2ecf20Sopenharmony_ci 31118c2ecf20Sopenharmony_ci addr1 = rdmdio->addr_1; 31128c2ecf20Sopenharmony_ci addr2 = rdmdio->addr_2; 31138c2ecf20Sopenharmony_ci value1 = rdmdio->value_1; 31148c2ecf20Sopenharmony_ci stride1 = rdmdio->stride_1; 31158c2ecf20Sopenharmony_ci stride2 = rdmdio->stride_2; 31168c2ecf20Sopenharmony_ci count = rdmdio->count; 31178c2ecf20Sopenharmony_ci 31188c2ecf20Sopenharmony_ci mask = rdmdio->mask; 31198c2ecf20Sopenharmony_ci value2 = rdmdio->value_2; 31208c2ecf20Sopenharmony_ci 31218c2ecf20Sopenharmony_ci addr3 = addr1 + stride1; 31228c2ecf20Sopenharmony_ci 31238c2ecf20Sopenharmony_ci for (loop_cnt = 0; loop_cnt < count; loop_cnt++) { 31248c2ecf20Sopenharmony_ci ret = qla8044_poll_wait_ipmdio_bus_idle(vha, addr1, addr2, 31258c2ecf20Sopenharmony_ci addr3, mask); 31268c2ecf20Sopenharmony_ci if (ret == -1) 31278c2ecf20Sopenharmony_ci goto error; 31288c2ecf20Sopenharmony_ci 31298c2ecf20Sopenharmony_ci addr4 = addr2 - stride1; 31308c2ecf20Sopenharmony_ci ret = qla8044_ipmdio_wr_reg(vha, addr1, addr3, mask, addr4, 31318c2ecf20Sopenharmony_ci value2); 31328c2ecf20Sopenharmony_ci if (ret == -1) 31338c2ecf20Sopenharmony_ci goto error; 31348c2ecf20Sopenharmony_ci 31358c2ecf20Sopenharmony_ci addr5 = addr2 - (2 * stride1); 31368c2ecf20Sopenharmony_ci ret = qla8044_ipmdio_wr_reg(vha, addr1, addr3, mask, addr5, 31378c2ecf20Sopenharmony_ci value1); 31388c2ecf20Sopenharmony_ci if (ret == -1) 31398c2ecf20Sopenharmony_ci goto error; 31408c2ecf20Sopenharmony_ci 31418c2ecf20Sopenharmony_ci addr6 = addr2 - (3 * stride1); 31428c2ecf20Sopenharmony_ci ret = qla8044_ipmdio_wr_reg(vha, addr1, addr3, mask, 31438c2ecf20Sopenharmony_ci addr6, 0x2); 31448c2ecf20Sopenharmony_ci if (ret == -1) 31458c2ecf20Sopenharmony_ci goto error; 31468c2ecf20Sopenharmony_ci 31478c2ecf20Sopenharmony_ci ret = qla8044_poll_wait_ipmdio_bus_idle(vha, addr1, addr2, 31488c2ecf20Sopenharmony_ci addr3, mask); 31498c2ecf20Sopenharmony_ci if (ret == -1) 31508c2ecf20Sopenharmony_ci goto error; 31518c2ecf20Sopenharmony_ci 31528c2ecf20Sopenharmony_ci addr7 = addr2 - (4 * stride1); 31538c2ecf20Sopenharmony_ci data = qla8044_ipmdio_rd_reg(vha, addr1, addr3, mask, addr7); 31548c2ecf20Sopenharmony_ci if (data == -1) 31558c2ecf20Sopenharmony_ci goto error; 31568c2ecf20Sopenharmony_ci 31578c2ecf20Sopenharmony_ci selVal = (value2 << 18) | (value1 << 2) | 2; 31588c2ecf20Sopenharmony_ci 31598c2ecf20Sopenharmony_ci stride2 = rdmdio->stride_2; 31608c2ecf20Sopenharmony_ci *data_ptr++ = selVal; 31618c2ecf20Sopenharmony_ci *data_ptr++ = data; 31628c2ecf20Sopenharmony_ci 31638c2ecf20Sopenharmony_ci value1 = value1 + stride2; 31648c2ecf20Sopenharmony_ci *d_ptr = data_ptr; 31658c2ecf20Sopenharmony_ci } 31668c2ecf20Sopenharmony_ci 31678c2ecf20Sopenharmony_ci return 0; 31688c2ecf20Sopenharmony_ci 31698c2ecf20Sopenharmony_cierror: 31708c2ecf20Sopenharmony_ci return -1; 31718c2ecf20Sopenharmony_ci} 31728c2ecf20Sopenharmony_ci 31738c2ecf20Sopenharmony_cistatic uint32_t qla8044_minidump_process_pollwr(struct scsi_qla_host *vha, 31748c2ecf20Sopenharmony_ci struct qla8044_minidump_entry_hdr *entry_hdr, uint32_t **d_ptr) 31758c2ecf20Sopenharmony_ci{ 31768c2ecf20Sopenharmony_ci uint32_t addr1, addr2, value1, value2, poll, r_value; 31778c2ecf20Sopenharmony_ci uint32_t wait_count = 0; 31788c2ecf20Sopenharmony_ci struct qla8044_minidump_entry_pollwr *pollwr_hdr; 31798c2ecf20Sopenharmony_ci 31808c2ecf20Sopenharmony_ci pollwr_hdr = (struct qla8044_minidump_entry_pollwr *)entry_hdr; 31818c2ecf20Sopenharmony_ci addr1 = pollwr_hdr->addr_1; 31828c2ecf20Sopenharmony_ci addr2 = pollwr_hdr->addr_2; 31838c2ecf20Sopenharmony_ci value1 = pollwr_hdr->value_1; 31848c2ecf20Sopenharmony_ci value2 = pollwr_hdr->value_2; 31858c2ecf20Sopenharmony_ci 31868c2ecf20Sopenharmony_ci poll = pollwr_hdr->poll; 31878c2ecf20Sopenharmony_ci 31888c2ecf20Sopenharmony_ci while (wait_count < poll) { 31898c2ecf20Sopenharmony_ci qla8044_rd_reg_indirect(vha, addr1, &r_value); 31908c2ecf20Sopenharmony_ci 31918c2ecf20Sopenharmony_ci if ((r_value & poll) != 0) 31928c2ecf20Sopenharmony_ci break; 31938c2ecf20Sopenharmony_ci wait_count++; 31948c2ecf20Sopenharmony_ci } 31958c2ecf20Sopenharmony_ci 31968c2ecf20Sopenharmony_ci if (wait_count == poll) { 31978c2ecf20Sopenharmony_ci ql_log(ql_log_warn, vha, 0xb156, "%s: TIMEOUT\n", __func__); 31988c2ecf20Sopenharmony_ci goto error; 31998c2ecf20Sopenharmony_ci } 32008c2ecf20Sopenharmony_ci 32018c2ecf20Sopenharmony_ci qla8044_wr_reg_indirect(vha, addr2, value2); 32028c2ecf20Sopenharmony_ci qla8044_wr_reg_indirect(vha, addr1, value1); 32038c2ecf20Sopenharmony_ci 32048c2ecf20Sopenharmony_ci wait_count = 0; 32058c2ecf20Sopenharmony_ci while (wait_count < poll) { 32068c2ecf20Sopenharmony_ci qla8044_rd_reg_indirect(vha, addr1, &r_value); 32078c2ecf20Sopenharmony_ci 32088c2ecf20Sopenharmony_ci if ((r_value & poll) != 0) 32098c2ecf20Sopenharmony_ci break; 32108c2ecf20Sopenharmony_ci wait_count++; 32118c2ecf20Sopenharmony_ci } 32128c2ecf20Sopenharmony_ci 32138c2ecf20Sopenharmony_ci return QLA_SUCCESS; 32148c2ecf20Sopenharmony_ci 32158c2ecf20Sopenharmony_cierror: 32168c2ecf20Sopenharmony_ci return -1; 32178c2ecf20Sopenharmony_ci} 32188c2ecf20Sopenharmony_ci 32198c2ecf20Sopenharmony_ci/* 32208c2ecf20Sopenharmony_ci * 32218c2ecf20Sopenharmony_ci * qla8044_collect_md_data - Retrieve firmware minidump data. 32228c2ecf20Sopenharmony_ci * @ha: pointer to adapter structure 32238c2ecf20Sopenharmony_ci **/ 32248c2ecf20Sopenharmony_ciint 32258c2ecf20Sopenharmony_ciqla8044_collect_md_data(struct scsi_qla_host *vha) 32268c2ecf20Sopenharmony_ci{ 32278c2ecf20Sopenharmony_ci int num_entry_hdr = 0; 32288c2ecf20Sopenharmony_ci struct qla8044_minidump_entry_hdr *entry_hdr; 32298c2ecf20Sopenharmony_ci struct qla8044_minidump_template_hdr *tmplt_hdr; 32308c2ecf20Sopenharmony_ci uint32_t *data_ptr; 32318c2ecf20Sopenharmony_ci uint32_t data_collected = 0, f_capture_mask; 32328c2ecf20Sopenharmony_ci int i, rval = QLA_FUNCTION_FAILED; 32338c2ecf20Sopenharmony_ci uint64_t now; 32348c2ecf20Sopenharmony_ci uint32_t timestamp, idc_control; 32358c2ecf20Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 32368c2ecf20Sopenharmony_ci 32378c2ecf20Sopenharmony_ci if (!ha->md_dump) { 32388c2ecf20Sopenharmony_ci ql_log(ql_log_info, vha, 0xb101, 32398c2ecf20Sopenharmony_ci "%s(%ld) No buffer to dump\n", 32408c2ecf20Sopenharmony_ci __func__, vha->host_no); 32418c2ecf20Sopenharmony_ci return rval; 32428c2ecf20Sopenharmony_ci } 32438c2ecf20Sopenharmony_ci 32448c2ecf20Sopenharmony_ci if (ha->fw_dumped) { 32458c2ecf20Sopenharmony_ci ql_log(ql_log_warn, vha, 0xb10d, 32468c2ecf20Sopenharmony_ci "Firmware has been previously dumped (%p) " 32478c2ecf20Sopenharmony_ci "-- ignoring request.\n", ha->fw_dump); 32488c2ecf20Sopenharmony_ci goto md_failed; 32498c2ecf20Sopenharmony_ci } 32508c2ecf20Sopenharmony_ci 32518c2ecf20Sopenharmony_ci ha->fw_dumped = false; 32528c2ecf20Sopenharmony_ci 32538c2ecf20Sopenharmony_ci if (!ha->md_tmplt_hdr || !ha->md_dump) { 32548c2ecf20Sopenharmony_ci ql_log(ql_log_warn, vha, 0xb10e, 32558c2ecf20Sopenharmony_ci "Memory not allocated for minidump capture\n"); 32568c2ecf20Sopenharmony_ci goto md_failed; 32578c2ecf20Sopenharmony_ci } 32588c2ecf20Sopenharmony_ci 32598c2ecf20Sopenharmony_ci qla8044_idc_lock(ha); 32608c2ecf20Sopenharmony_ci idc_control = qla8044_rd_reg(ha, QLA8044_IDC_DRV_CTRL); 32618c2ecf20Sopenharmony_ci if (idc_control & GRACEFUL_RESET_BIT1) { 32628c2ecf20Sopenharmony_ci ql_log(ql_log_warn, vha, 0xb112, 32638c2ecf20Sopenharmony_ci "Forced reset from application, " 32648c2ecf20Sopenharmony_ci "ignore minidump capture\n"); 32658c2ecf20Sopenharmony_ci qla8044_wr_reg(ha, QLA8044_IDC_DRV_CTRL, 32668c2ecf20Sopenharmony_ci (idc_control & ~GRACEFUL_RESET_BIT1)); 32678c2ecf20Sopenharmony_ci qla8044_idc_unlock(ha); 32688c2ecf20Sopenharmony_ci 32698c2ecf20Sopenharmony_ci goto md_failed; 32708c2ecf20Sopenharmony_ci } 32718c2ecf20Sopenharmony_ci qla8044_idc_unlock(ha); 32728c2ecf20Sopenharmony_ci 32738c2ecf20Sopenharmony_ci if (qla82xx_validate_template_chksum(vha)) { 32748c2ecf20Sopenharmony_ci ql_log(ql_log_info, vha, 0xb109, 32758c2ecf20Sopenharmony_ci "Template checksum validation error\n"); 32768c2ecf20Sopenharmony_ci goto md_failed; 32778c2ecf20Sopenharmony_ci } 32788c2ecf20Sopenharmony_ci 32798c2ecf20Sopenharmony_ci tmplt_hdr = (struct qla8044_minidump_template_hdr *) 32808c2ecf20Sopenharmony_ci ha->md_tmplt_hdr; 32818c2ecf20Sopenharmony_ci data_ptr = (uint32_t *)((uint8_t *)ha->md_dump); 32828c2ecf20Sopenharmony_ci num_entry_hdr = tmplt_hdr->num_of_entries; 32838c2ecf20Sopenharmony_ci 32848c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_p3p, vha, 0xb11a, 32858c2ecf20Sopenharmony_ci "Capture Mask obtained: 0x%x\n", tmplt_hdr->capture_debug_level); 32868c2ecf20Sopenharmony_ci 32878c2ecf20Sopenharmony_ci f_capture_mask = tmplt_hdr->capture_debug_level & 0xFF; 32888c2ecf20Sopenharmony_ci 32898c2ecf20Sopenharmony_ci /* Validate whether required debug level is set */ 32908c2ecf20Sopenharmony_ci if ((f_capture_mask & 0x3) != 0x3) { 32918c2ecf20Sopenharmony_ci ql_log(ql_log_warn, vha, 0xb10f, 32928c2ecf20Sopenharmony_ci "Minimum required capture mask[0x%x] level not set\n", 32938c2ecf20Sopenharmony_ci f_capture_mask); 32948c2ecf20Sopenharmony_ci 32958c2ecf20Sopenharmony_ci } 32968c2ecf20Sopenharmony_ci tmplt_hdr->driver_capture_mask = ql2xmdcapmask; 32978c2ecf20Sopenharmony_ci ql_log(ql_log_info, vha, 0xb102, 32988c2ecf20Sopenharmony_ci "[%s]: starting data ptr: %p\n", 32998c2ecf20Sopenharmony_ci __func__, data_ptr); 33008c2ecf20Sopenharmony_ci ql_log(ql_log_info, vha, 0xb10b, 33018c2ecf20Sopenharmony_ci "[%s]: no of entry headers in Template: 0x%x\n", 33028c2ecf20Sopenharmony_ci __func__, num_entry_hdr); 33038c2ecf20Sopenharmony_ci ql_log(ql_log_info, vha, 0xb10c, 33048c2ecf20Sopenharmony_ci "[%s]: Total_data_size 0x%x, %d obtained\n", 33058c2ecf20Sopenharmony_ci __func__, ha->md_dump_size, ha->md_dump_size); 33068c2ecf20Sopenharmony_ci 33078c2ecf20Sopenharmony_ci /* Update current timestamp before taking dump */ 33088c2ecf20Sopenharmony_ci now = get_jiffies_64(); 33098c2ecf20Sopenharmony_ci timestamp = (u32)(jiffies_to_msecs(now) / 1000); 33108c2ecf20Sopenharmony_ci tmplt_hdr->driver_timestamp = timestamp; 33118c2ecf20Sopenharmony_ci 33128c2ecf20Sopenharmony_ci entry_hdr = (struct qla8044_minidump_entry_hdr *) 33138c2ecf20Sopenharmony_ci (((uint8_t *)ha->md_tmplt_hdr) + tmplt_hdr->first_entry_offset); 33148c2ecf20Sopenharmony_ci tmplt_hdr->saved_state_array[QLA8044_SS_OCM_WNDREG_INDEX] = 33158c2ecf20Sopenharmony_ci tmplt_hdr->ocm_window_reg[ha->portnum]; 33168c2ecf20Sopenharmony_ci 33178c2ecf20Sopenharmony_ci /* Walk through the entry headers - validate/perform required action */ 33188c2ecf20Sopenharmony_ci for (i = 0; i < num_entry_hdr; i++) { 33198c2ecf20Sopenharmony_ci if (data_collected > ha->md_dump_size) { 33208c2ecf20Sopenharmony_ci ql_log(ql_log_info, vha, 0xb103, 33218c2ecf20Sopenharmony_ci "Data collected: [0x%x], " 33228c2ecf20Sopenharmony_ci "Total Dump size: [0x%x]\n", 33238c2ecf20Sopenharmony_ci data_collected, ha->md_dump_size); 33248c2ecf20Sopenharmony_ci return rval; 33258c2ecf20Sopenharmony_ci } 33268c2ecf20Sopenharmony_ci 33278c2ecf20Sopenharmony_ci if (!(entry_hdr->d_ctrl.entry_capture_mask & 33288c2ecf20Sopenharmony_ci ql2xmdcapmask)) { 33298c2ecf20Sopenharmony_ci entry_hdr->d_ctrl.driver_flags |= 33308c2ecf20Sopenharmony_ci QLA82XX_DBG_SKIPPED_FLAG; 33318c2ecf20Sopenharmony_ci goto skip_nxt_entry; 33328c2ecf20Sopenharmony_ci } 33338c2ecf20Sopenharmony_ci 33348c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_p3p, vha, 0xb104, 33358c2ecf20Sopenharmony_ci "Data collected: [0x%x], Dump size left:[0x%x]\n", 33368c2ecf20Sopenharmony_ci data_collected, 33378c2ecf20Sopenharmony_ci (ha->md_dump_size - data_collected)); 33388c2ecf20Sopenharmony_ci 33398c2ecf20Sopenharmony_ci /* Decode the entry type and take required action to capture 33408c2ecf20Sopenharmony_ci * debug data 33418c2ecf20Sopenharmony_ci */ 33428c2ecf20Sopenharmony_ci switch (entry_hdr->entry_type) { 33438c2ecf20Sopenharmony_ci case QLA82XX_RDEND: 33448c2ecf20Sopenharmony_ci qla8044_mark_entry_skipped(vha, entry_hdr, i); 33458c2ecf20Sopenharmony_ci break; 33468c2ecf20Sopenharmony_ci case QLA82XX_CNTRL: 33478c2ecf20Sopenharmony_ci rval = qla8044_minidump_process_control(vha, 33488c2ecf20Sopenharmony_ci entry_hdr); 33498c2ecf20Sopenharmony_ci if (rval != QLA_SUCCESS) { 33508c2ecf20Sopenharmony_ci qla8044_mark_entry_skipped(vha, entry_hdr, i); 33518c2ecf20Sopenharmony_ci goto md_failed; 33528c2ecf20Sopenharmony_ci } 33538c2ecf20Sopenharmony_ci break; 33548c2ecf20Sopenharmony_ci case QLA82XX_RDCRB: 33558c2ecf20Sopenharmony_ci qla8044_minidump_process_rdcrb(vha, 33568c2ecf20Sopenharmony_ci entry_hdr, &data_ptr); 33578c2ecf20Sopenharmony_ci break; 33588c2ecf20Sopenharmony_ci case QLA82XX_RDMEM: 33598c2ecf20Sopenharmony_ci rval = qla8044_minidump_pex_dma_read(vha, 33608c2ecf20Sopenharmony_ci entry_hdr, &data_ptr); 33618c2ecf20Sopenharmony_ci if (rval != QLA_SUCCESS) { 33628c2ecf20Sopenharmony_ci rval = qla8044_minidump_process_rdmem(vha, 33638c2ecf20Sopenharmony_ci entry_hdr, &data_ptr); 33648c2ecf20Sopenharmony_ci if (rval != QLA_SUCCESS) { 33658c2ecf20Sopenharmony_ci qla8044_mark_entry_skipped(vha, 33668c2ecf20Sopenharmony_ci entry_hdr, i); 33678c2ecf20Sopenharmony_ci goto md_failed; 33688c2ecf20Sopenharmony_ci } 33698c2ecf20Sopenharmony_ci } 33708c2ecf20Sopenharmony_ci break; 33718c2ecf20Sopenharmony_ci case QLA82XX_BOARD: 33728c2ecf20Sopenharmony_ci case QLA82XX_RDROM: 33738c2ecf20Sopenharmony_ci rval = qla8044_minidump_process_rdrom(vha, 33748c2ecf20Sopenharmony_ci entry_hdr, &data_ptr); 33758c2ecf20Sopenharmony_ci if (rval != QLA_SUCCESS) { 33768c2ecf20Sopenharmony_ci qla8044_mark_entry_skipped(vha, 33778c2ecf20Sopenharmony_ci entry_hdr, i); 33788c2ecf20Sopenharmony_ci } 33798c2ecf20Sopenharmony_ci break; 33808c2ecf20Sopenharmony_ci case QLA82XX_L2DTG: 33818c2ecf20Sopenharmony_ci case QLA82XX_L2ITG: 33828c2ecf20Sopenharmony_ci case QLA82XX_L2DAT: 33838c2ecf20Sopenharmony_ci case QLA82XX_L2INS: 33848c2ecf20Sopenharmony_ci rval = qla8044_minidump_process_l2tag(vha, 33858c2ecf20Sopenharmony_ci entry_hdr, &data_ptr); 33868c2ecf20Sopenharmony_ci if (rval != QLA_SUCCESS) { 33878c2ecf20Sopenharmony_ci qla8044_mark_entry_skipped(vha, entry_hdr, i); 33888c2ecf20Sopenharmony_ci goto md_failed; 33898c2ecf20Sopenharmony_ci } 33908c2ecf20Sopenharmony_ci break; 33918c2ecf20Sopenharmony_ci case QLA8044_L1DTG: 33928c2ecf20Sopenharmony_ci case QLA8044_L1ITG: 33938c2ecf20Sopenharmony_ci case QLA82XX_L1DAT: 33948c2ecf20Sopenharmony_ci case QLA82XX_L1INS: 33958c2ecf20Sopenharmony_ci qla8044_minidump_process_l1cache(vha, 33968c2ecf20Sopenharmony_ci entry_hdr, &data_ptr); 33978c2ecf20Sopenharmony_ci break; 33988c2ecf20Sopenharmony_ci case QLA82XX_RDOCM: 33998c2ecf20Sopenharmony_ci qla8044_minidump_process_rdocm(vha, 34008c2ecf20Sopenharmony_ci entry_hdr, &data_ptr); 34018c2ecf20Sopenharmony_ci break; 34028c2ecf20Sopenharmony_ci case QLA82XX_RDMUX: 34038c2ecf20Sopenharmony_ci qla8044_minidump_process_rdmux(vha, 34048c2ecf20Sopenharmony_ci entry_hdr, &data_ptr); 34058c2ecf20Sopenharmony_ci break; 34068c2ecf20Sopenharmony_ci case QLA82XX_QUEUE: 34078c2ecf20Sopenharmony_ci qla8044_minidump_process_queue(vha, 34088c2ecf20Sopenharmony_ci entry_hdr, &data_ptr); 34098c2ecf20Sopenharmony_ci break; 34108c2ecf20Sopenharmony_ci case QLA8044_POLLRD: 34118c2ecf20Sopenharmony_ci rval = qla8044_minidump_process_pollrd(vha, 34128c2ecf20Sopenharmony_ci entry_hdr, &data_ptr); 34138c2ecf20Sopenharmony_ci if (rval != QLA_SUCCESS) 34148c2ecf20Sopenharmony_ci qla8044_mark_entry_skipped(vha, entry_hdr, i); 34158c2ecf20Sopenharmony_ci break; 34168c2ecf20Sopenharmony_ci case QLA8044_RDMUX2: 34178c2ecf20Sopenharmony_ci qla8044_minidump_process_rdmux2(vha, 34188c2ecf20Sopenharmony_ci entry_hdr, &data_ptr); 34198c2ecf20Sopenharmony_ci break; 34208c2ecf20Sopenharmony_ci case QLA8044_POLLRDMWR: 34218c2ecf20Sopenharmony_ci rval = qla8044_minidump_process_pollrdmwr(vha, 34228c2ecf20Sopenharmony_ci entry_hdr, &data_ptr); 34238c2ecf20Sopenharmony_ci if (rval != QLA_SUCCESS) 34248c2ecf20Sopenharmony_ci qla8044_mark_entry_skipped(vha, entry_hdr, i); 34258c2ecf20Sopenharmony_ci break; 34268c2ecf20Sopenharmony_ci case QLA8044_RDDFE: 34278c2ecf20Sopenharmony_ci rval = qla8044_minidump_process_rddfe(vha, entry_hdr, 34288c2ecf20Sopenharmony_ci &data_ptr); 34298c2ecf20Sopenharmony_ci if (rval != QLA_SUCCESS) 34308c2ecf20Sopenharmony_ci qla8044_mark_entry_skipped(vha, entry_hdr, i); 34318c2ecf20Sopenharmony_ci break; 34328c2ecf20Sopenharmony_ci case QLA8044_RDMDIO: 34338c2ecf20Sopenharmony_ci rval = qla8044_minidump_process_rdmdio(vha, entry_hdr, 34348c2ecf20Sopenharmony_ci &data_ptr); 34358c2ecf20Sopenharmony_ci if (rval != QLA_SUCCESS) 34368c2ecf20Sopenharmony_ci qla8044_mark_entry_skipped(vha, entry_hdr, i); 34378c2ecf20Sopenharmony_ci break; 34388c2ecf20Sopenharmony_ci case QLA8044_POLLWR: 34398c2ecf20Sopenharmony_ci rval = qla8044_minidump_process_pollwr(vha, entry_hdr, 34408c2ecf20Sopenharmony_ci &data_ptr); 34418c2ecf20Sopenharmony_ci if (rval != QLA_SUCCESS) 34428c2ecf20Sopenharmony_ci qla8044_mark_entry_skipped(vha, entry_hdr, i); 34438c2ecf20Sopenharmony_ci break; 34448c2ecf20Sopenharmony_ci case QLA82XX_RDNOP: 34458c2ecf20Sopenharmony_ci default: 34468c2ecf20Sopenharmony_ci qla8044_mark_entry_skipped(vha, entry_hdr, i); 34478c2ecf20Sopenharmony_ci break; 34488c2ecf20Sopenharmony_ci } 34498c2ecf20Sopenharmony_ci 34508c2ecf20Sopenharmony_ci data_collected = (uint8_t *)data_ptr - 34518c2ecf20Sopenharmony_ci (uint8_t *)((uint8_t *)ha->md_dump); 34528c2ecf20Sopenharmony_ciskip_nxt_entry: 34538c2ecf20Sopenharmony_ci /* 34548c2ecf20Sopenharmony_ci * next entry in the template 34558c2ecf20Sopenharmony_ci */ 34568c2ecf20Sopenharmony_ci entry_hdr = (struct qla8044_minidump_entry_hdr *) 34578c2ecf20Sopenharmony_ci (((uint8_t *)entry_hdr) + entry_hdr->entry_size); 34588c2ecf20Sopenharmony_ci } 34598c2ecf20Sopenharmony_ci 34608c2ecf20Sopenharmony_ci if (data_collected != ha->md_dump_size) { 34618c2ecf20Sopenharmony_ci ql_log(ql_log_info, vha, 0xb105, 34628c2ecf20Sopenharmony_ci "Dump data mismatch: Data collected: " 34638c2ecf20Sopenharmony_ci "[0x%x], total_data_size:[0x%x]\n", 34648c2ecf20Sopenharmony_ci data_collected, ha->md_dump_size); 34658c2ecf20Sopenharmony_ci rval = QLA_FUNCTION_FAILED; 34668c2ecf20Sopenharmony_ci goto md_failed; 34678c2ecf20Sopenharmony_ci } 34688c2ecf20Sopenharmony_ci 34698c2ecf20Sopenharmony_ci ql_log(ql_log_info, vha, 0xb110, 34708c2ecf20Sopenharmony_ci "Firmware dump saved to temp buffer (%ld/%p %ld/%p).\n", 34718c2ecf20Sopenharmony_ci vha->host_no, ha->md_tmplt_hdr, vha->host_no, ha->md_dump); 34728c2ecf20Sopenharmony_ci ha->fw_dumped = true; 34738c2ecf20Sopenharmony_ci qla2x00_post_uevent_work(vha, QLA_UEVENT_CODE_FW_DUMP); 34748c2ecf20Sopenharmony_ci 34758c2ecf20Sopenharmony_ci 34768c2ecf20Sopenharmony_ci ql_log(ql_log_info, vha, 0xb106, 34778c2ecf20Sopenharmony_ci "Leaving fn: %s Last entry: 0x%x\n", 34788c2ecf20Sopenharmony_ci __func__, i); 34798c2ecf20Sopenharmony_cimd_failed: 34808c2ecf20Sopenharmony_ci return rval; 34818c2ecf20Sopenharmony_ci} 34828c2ecf20Sopenharmony_ci 34838c2ecf20Sopenharmony_civoid 34848c2ecf20Sopenharmony_ciqla8044_get_minidump(struct scsi_qla_host *vha) 34858c2ecf20Sopenharmony_ci{ 34868c2ecf20Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 34878c2ecf20Sopenharmony_ci 34888c2ecf20Sopenharmony_ci if (!qla8044_collect_md_data(vha)) { 34898c2ecf20Sopenharmony_ci ha->fw_dumped = true; 34908c2ecf20Sopenharmony_ci ha->prev_minidump_failed = 0; 34918c2ecf20Sopenharmony_ci } else { 34928c2ecf20Sopenharmony_ci ql_log(ql_log_fatal, vha, 0xb0db, 34938c2ecf20Sopenharmony_ci "%s: Unable to collect minidump\n", 34948c2ecf20Sopenharmony_ci __func__); 34958c2ecf20Sopenharmony_ci ha->prev_minidump_failed = 1; 34968c2ecf20Sopenharmony_ci } 34978c2ecf20Sopenharmony_ci} 34988c2ecf20Sopenharmony_ci 34998c2ecf20Sopenharmony_cistatic int 35008c2ecf20Sopenharmony_ciqla8044_poll_flash_status_reg(struct scsi_qla_host *vha) 35018c2ecf20Sopenharmony_ci{ 35028c2ecf20Sopenharmony_ci uint32_t flash_status; 35038c2ecf20Sopenharmony_ci int retries = QLA8044_FLASH_READ_RETRY_COUNT; 35048c2ecf20Sopenharmony_ci int ret_val = QLA_SUCCESS; 35058c2ecf20Sopenharmony_ci 35068c2ecf20Sopenharmony_ci while (retries--) { 35078c2ecf20Sopenharmony_ci ret_val = qla8044_rd_reg_indirect(vha, QLA8044_FLASH_STATUS, 35088c2ecf20Sopenharmony_ci &flash_status); 35098c2ecf20Sopenharmony_ci if (ret_val) { 35108c2ecf20Sopenharmony_ci ql_log(ql_log_warn, vha, 0xb13c, 35118c2ecf20Sopenharmony_ci "%s: Failed to read FLASH_STATUS reg.\n", 35128c2ecf20Sopenharmony_ci __func__); 35138c2ecf20Sopenharmony_ci break; 35148c2ecf20Sopenharmony_ci } 35158c2ecf20Sopenharmony_ci if ((flash_status & QLA8044_FLASH_STATUS_READY) == 35168c2ecf20Sopenharmony_ci QLA8044_FLASH_STATUS_READY) 35178c2ecf20Sopenharmony_ci break; 35188c2ecf20Sopenharmony_ci msleep(QLA8044_FLASH_STATUS_REG_POLL_DELAY); 35198c2ecf20Sopenharmony_ci } 35208c2ecf20Sopenharmony_ci 35218c2ecf20Sopenharmony_ci if (!retries) 35228c2ecf20Sopenharmony_ci ret_val = QLA_FUNCTION_FAILED; 35238c2ecf20Sopenharmony_ci 35248c2ecf20Sopenharmony_ci return ret_val; 35258c2ecf20Sopenharmony_ci} 35268c2ecf20Sopenharmony_ci 35278c2ecf20Sopenharmony_cistatic int 35288c2ecf20Sopenharmony_ciqla8044_write_flash_status_reg(struct scsi_qla_host *vha, 35298c2ecf20Sopenharmony_ci uint32_t data) 35308c2ecf20Sopenharmony_ci{ 35318c2ecf20Sopenharmony_ci int ret_val = QLA_SUCCESS; 35328c2ecf20Sopenharmony_ci uint32_t cmd; 35338c2ecf20Sopenharmony_ci 35348c2ecf20Sopenharmony_ci cmd = vha->hw->fdt_wrt_sts_reg_cmd; 35358c2ecf20Sopenharmony_ci 35368c2ecf20Sopenharmony_ci ret_val = qla8044_wr_reg_indirect(vha, QLA8044_FLASH_ADDR, 35378c2ecf20Sopenharmony_ci QLA8044_FLASH_STATUS_WRITE_DEF_SIG | cmd); 35388c2ecf20Sopenharmony_ci if (ret_val) { 35398c2ecf20Sopenharmony_ci ql_log(ql_log_warn, vha, 0xb125, 35408c2ecf20Sopenharmony_ci "%s: Failed to write to FLASH_ADDR.\n", __func__); 35418c2ecf20Sopenharmony_ci goto exit_func; 35428c2ecf20Sopenharmony_ci } 35438c2ecf20Sopenharmony_ci 35448c2ecf20Sopenharmony_ci ret_val = qla8044_wr_reg_indirect(vha, QLA8044_FLASH_WRDATA, data); 35458c2ecf20Sopenharmony_ci if (ret_val) { 35468c2ecf20Sopenharmony_ci ql_log(ql_log_warn, vha, 0xb126, 35478c2ecf20Sopenharmony_ci "%s: Failed to write to FLASH_WRDATA.\n", __func__); 35488c2ecf20Sopenharmony_ci goto exit_func; 35498c2ecf20Sopenharmony_ci } 35508c2ecf20Sopenharmony_ci 35518c2ecf20Sopenharmony_ci ret_val = qla8044_wr_reg_indirect(vha, QLA8044_FLASH_CONTROL, 35528c2ecf20Sopenharmony_ci QLA8044_FLASH_SECOND_ERASE_MS_VAL); 35538c2ecf20Sopenharmony_ci if (ret_val) { 35548c2ecf20Sopenharmony_ci ql_log(ql_log_warn, vha, 0xb127, 35558c2ecf20Sopenharmony_ci "%s: Failed to write to FLASH_CONTROL.\n", __func__); 35568c2ecf20Sopenharmony_ci goto exit_func; 35578c2ecf20Sopenharmony_ci } 35588c2ecf20Sopenharmony_ci 35598c2ecf20Sopenharmony_ci ret_val = qla8044_poll_flash_status_reg(vha); 35608c2ecf20Sopenharmony_ci if (ret_val) 35618c2ecf20Sopenharmony_ci ql_log(ql_log_warn, vha, 0xb128, 35628c2ecf20Sopenharmony_ci "%s: Error polling flash status reg.\n", __func__); 35638c2ecf20Sopenharmony_ci 35648c2ecf20Sopenharmony_ciexit_func: 35658c2ecf20Sopenharmony_ci return ret_val; 35668c2ecf20Sopenharmony_ci} 35678c2ecf20Sopenharmony_ci 35688c2ecf20Sopenharmony_ci/* 35698c2ecf20Sopenharmony_ci * This function assumes that the flash lock is held. 35708c2ecf20Sopenharmony_ci */ 35718c2ecf20Sopenharmony_cistatic int 35728c2ecf20Sopenharmony_ciqla8044_unprotect_flash(scsi_qla_host_t *vha) 35738c2ecf20Sopenharmony_ci{ 35748c2ecf20Sopenharmony_ci int ret_val; 35758c2ecf20Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 35768c2ecf20Sopenharmony_ci 35778c2ecf20Sopenharmony_ci ret_val = qla8044_write_flash_status_reg(vha, ha->fdt_wrt_enable); 35788c2ecf20Sopenharmony_ci if (ret_val) 35798c2ecf20Sopenharmony_ci ql_log(ql_log_warn, vha, 0xb139, 35808c2ecf20Sopenharmony_ci "%s: Write flash status failed.\n", __func__); 35818c2ecf20Sopenharmony_ci 35828c2ecf20Sopenharmony_ci return ret_val; 35838c2ecf20Sopenharmony_ci} 35848c2ecf20Sopenharmony_ci 35858c2ecf20Sopenharmony_ci/* 35868c2ecf20Sopenharmony_ci * This function assumes that the flash lock is held. 35878c2ecf20Sopenharmony_ci */ 35888c2ecf20Sopenharmony_cistatic int 35898c2ecf20Sopenharmony_ciqla8044_protect_flash(scsi_qla_host_t *vha) 35908c2ecf20Sopenharmony_ci{ 35918c2ecf20Sopenharmony_ci int ret_val; 35928c2ecf20Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 35938c2ecf20Sopenharmony_ci 35948c2ecf20Sopenharmony_ci ret_val = qla8044_write_flash_status_reg(vha, ha->fdt_wrt_disable); 35958c2ecf20Sopenharmony_ci if (ret_val) 35968c2ecf20Sopenharmony_ci ql_log(ql_log_warn, vha, 0xb13b, 35978c2ecf20Sopenharmony_ci "%s: Write flash status failed.\n", __func__); 35988c2ecf20Sopenharmony_ci 35998c2ecf20Sopenharmony_ci return ret_val; 36008c2ecf20Sopenharmony_ci} 36018c2ecf20Sopenharmony_ci 36028c2ecf20Sopenharmony_ci 36038c2ecf20Sopenharmony_cistatic int 36048c2ecf20Sopenharmony_ciqla8044_erase_flash_sector(struct scsi_qla_host *vha, 36058c2ecf20Sopenharmony_ci uint32_t sector_start_addr) 36068c2ecf20Sopenharmony_ci{ 36078c2ecf20Sopenharmony_ci uint32_t reversed_addr; 36088c2ecf20Sopenharmony_ci int ret_val = QLA_SUCCESS; 36098c2ecf20Sopenharmony_ci 36108c2ecf20Sopenharmony_ci ret_val = qla8044_poll_flash_status_reg(vha); 36118c2ecf20Sopenharmony_ci if (ret_val) { 36128c2ecf20Sopenharmony_ci ql_log(ql_log_warn, vha, 0xb12e, 36138c2ecf20Sopenharmony_ci "%s: Poll flash status after erase failed..\n", __func__); 36148c2ecf20Sopenharmony_ci } 36158c2ecf20Sopenharmony_ci 36168c2ecf20Sopenharmony_ci reversed_addr = (((sector_start_addr & 0xFF) << 16) | 36178c2ecf20Sopenharmony_ci (sector_start_addr & 0xFF00) | 36188c2ecf20Sopenharmony_ci ((sector_start_addr & 0xFF0000) >> 16)); 36198c2ecf20Sopenharmony_ci 36208c2ecf20Sopenharmony_ci ret_val = qla8044_wr_reg_indirect(vha, 36218c2ecf20Sopenharmony_ci QLA8044_FLASH_WRDATA, reversed_addr); 36228c2ecf20Sopenharmony_ci if (ret_val) { 36238c2ecf20Sopenharmony_ci ql_log(ql_log_warn, vha, 0xb12f, 36248c2ecf20Sopenharmony_ci "%s: Failed to write to FLASH_WRDATA.\n", __func__); 36258c2ecf20Sopenharmony_ci } 36268c2ecf20Sopenharmony_ci ret_val = qla8044_wr_reg_indirect(vha, QLA8044_FLASH_ADDR, 36278c2ecf20Sopenharmony_ci QLA8044_FLASH_ERASE_SIG | vha->hw->fdt_erase_cmd); 36288c2ecf20Sopenharmony_ci if (ret_val) { 36298c2ecf20Sopenharmony_ci ql_log(ql_log_warn, vha, 0xb130, 36308c2ecf20Sopenharmony_ci "%s: Failed to write to FLASH_ADDR.\n", __func__); 36318c2ecf20Sopenharmony_ci } 36328c2ecf20Sopenharmony_ci ret_val = qla8044_wr_reg_indirect(vha, QLA8044_FLASH_CONTROL, 36338c2ecf20Sopenharmony_ci QLA8044_FLASH_LAST_ERASE_MS_VAL); 36348c2ecf20Sopenharmony_ci if (ret_val) { 36358c2ecf20Sopenharmony_ci ql_log(ql_log_warn, vha, 0xb131, 36368c2ecf20Sopenharmony_ci "%s: Failed write to FLASH_CONTROL.\n", __func__); 36378c2ecf20Sopenharmony_ci } 36388c2ecf20Sopenharmony_ci ret_val = qla8044_poll_flash_status_reg(vha); 36398c2ecf20Sopenharmony_ci if (ret_val) { 36408c2ecf20Sopenharmony_ci ql_log(ql_log_warn, vha, 0xb132, 36418c2ecf20Sopenharmony_ci "%s: Poll flash status failed.\n", __func__); 36428c2ecf20Sopenharmony_ci } 36438c2ecf20Sopenharmony_ci 36448c2ecf20Sopenharmony_ci 36458c2ecf20Sopenharmony_ci return ret_val; 36468c2ecf20Sopenharmony_ci} 36478c2ecf20Sopenharmony_ci 36488c2ecf20Sopenharmony_ci/* 36498c2ecf20Sopenharmony_ci * qla8044_flash_write_u32 - Write data to flash 36508c2ecf20Sopenharmony_ci * 36518c2ecf20Sopenharmony_ci * @ha : Pointer to adapter structure 36528c2ecf20Sopenharmony_ci * addr : Flash address to write to 36538c2ecf20Sopenharmony_ci * p_data : Data to be written 36548c2ecf20Sopenharmony_ci * 36558c2ecf20Sopenharmony_ci * Return Value - QLA_SUCCESS/QLA_FUNCTION_FAILED 36568c2ecf20Sopenharmony_ci * 36578c2ecf20Sopenharmony_ci * NOTE: Lock should be held on entry 36588c2ecf20Sopenharmony_ci */ 36598c2ecf20Sopenharmony_cistatic int 36608c2ecf20Sopenharmony_ciqla8044_flash_write_u32(struct scsi_qla_host *vha, uint32_t addr, 36618c2ecf20Sopenharmony_ci uint32_t *p_data) 36628c2ecf20Sopenharmony_ci{ 36638c2ecf20Sopenharmony_ci int ret_val = QLA_SUCCESS; 36648c2ecf20Sopenharmony_ci 36658c2ecf20Sopenharmony_ci ret_val = qla8044_wr_reg_indirect(vha, QLA8044_FLASH_ADDR, 36668c2ecf20Sopenharmony_ci 0x00800000 | (addr >> 2)); 36678c2ecf20Sopenharmony_ci if (ret_val) { 36688c2ecf20Sopenharmony_ci ql_log(ql_log_warn, vha, 0xb134, 36698c2ecf20Sopenharmony_ci "%s: Failed write to FLASH_ADDR.\n", __func__); 36708c2ecf20Sopenharmony_ci goto exit_func; 36718c2ecf20Sopenharmony_ci } 36728c2ecf20Sopenharmony_ci ret_val = qla8044_wr_reg_indirect(vha, QLA8044_FLASH_WRDATA, *p_data); 36738c2ecf20Sopenharmony_ci if (ret_val) { 36748c2ecf20Sopenharmony_ci ql_log(ql_log_warn, vha, 0xb135, 36758c2ecf20Sopenharmony_ci "%s: Failed write to FLASH_WRDATA.\n", __func__); 36768c2ecf20Sopenharmony_ci goto exit_func; 36778c2ecf20Sopenharmony_ci } 36788c2ecf20Sopenharmony_ci ret_val = qla8044_wr_reg_indirect(vha, QLA8044_FLASH_CONTROL, 0x3D); 36798c2ecf20Sopenharmony_ci if (ret_val) { 36808c2ecf20Sopenharmony_ci ql_log(ql_log_warn, vha, 0xb136, 36818c2ecf20Sopenharmony_ci "%s: Failed write to FLASH_CONTROL.\n", __func__); 36828c2ecf20Sopenharmony_ci goto exit_func; 36838c2ecf20Sopenharmony_ci } 36848c2ecf20Sopenharmony_ci ret_val = qla8044_poll_flash_status_reg(vha); 36858c2ecf20Sopenharmony_ci if (ret_val) { 36868c2ecf20Sopenharmony_ci ql_log(ql_log_warn, vha, 0xb137, 36878c2ecf20Sopenharmony_ci "%s: Poll flash status failed.\n", __func__); 36888c2ecf20Sopenharmony_ci } 36898c2ecf20Sopenharmony_ci 36908c2ecf20Sopenharmony_ciexit_func: 36918c2ecf20Sopenharmony_ci return ret_val; 36928c2ecf20Sopenharmony_ci} 36938c2ecf20Sopenharmony_ci 36948c2ecf20Sopenharmony_cistatic int 36958c2ecf20Sopenharmony_ciqla8044_write_flash_buffer_mode(scsi_qla_host_t *vha, uint32_t *dwptr, 36968c2ecf20Sopenharmony_ci uint32_t faddr, uint32_t dwords) 36978c2ecf20Sopenharmony_ci{ 36988c2ecf20Sopenharmony_ci int ret = QLA_FUNCTION_FAILED; 36998c2ecf20Sopenharmony_ci uint32_t spi_val; 37008c2ecf20Sopenharmony_ci 37018c2ecf20Sopenharmony_ci if (dwords < QLA8044_MIN_OPTROM_BURST_DWORDS || 37028c2ecf20Sopenharmony_ci dwords > QLA8044_MAX_OPTROM_BURST_DWORDS) { 37038c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_user, vha, 0xb123, 37048c2ecf20Sopenharmony_ci "Got unsupported dwords = 0x%x.\n", 37058c2ecf20Sopenharmony_ci dwords); 37068c2ecf20Sopenharmony_ci return QLA_FUNCTION_FAILED; 37078c2ecf20Sopenharmony_ci } 37088c2ecf20Sopenharmony_ci 37098c2ecf20Sopenharmony_ci qla8044_rd_reg_indirect(vha, QLA8044_FLASH_SPI_CONTROL, &spi_val); 37108c2ecf20Sopenharmony_ci qla8044_wr_reg_indirect(vha, QLA8044_FLASH_SPI_CONTROL, 37118c2ecf20Sopenharmony_ci spi_val | QLA8044_FLASH_SPI_CTL); 37128c2ecf20Sopenharmony_ci qla8044_wr_reg_indirect(vha, QLA8044_FLASH_ADDR, 37138c2ecf20Sopenharmony_ci QLA8044_FLASH_FIRST_TEMP_VAL); 37148c2ecf20Sopenharmony_ci 37158c2ecf20Sopenharmony_ci /* First DWORD write to FLASH_WRDATA */ 37168c2ecf20Sopenharmony_ci ret = qla8044_wr_reg_indirect(vha, QLA8044_FLASH_WRDATA, 37178c2ecf20Sopenharmony_ci *dwptr++); 37188c2ecf20Sopenharmony_ci qla8044_wr_reg_indirect(vha, QLA8044_FLASH_CONTROL, 37198c2ecf20Sopenharmony_ci QLA8044_FLASH_FIRST_MS_PATTERN); 37208c2ecf20Sopenharmony_ci 37218c2ecf20Sopenharmony_ci ret = qla8044_poll_flash_status_reg(vha); 37228c2ecf20Sopenharmony_ci if (ret) { 37238c2ecf20Sopenharmony_ci ql_log(ql_log_warn, vha, 0xb124, 37248c2ecf20Sopenharmony_ci "%s: Failed.\n", __func__); 37258c2ecf20Sopenharmony_ci goto exit_func; 37268c2ecf20Sopenharmony_ci } 37278c2ecf20Sopenharmony_ci 37288c2ecf20Sopenharmony_ci dwords--; 37298c2ecf20Sopenharmony_ci 37308c2ecf20Sopenharmony_ci qla8044_wr_reg_indirect(vha, QLA8044_FLASH_ADDR, 37318c2ecf20Sopenharmony_ci QLA8044_FLASH_SECOND_TEMP_VAL); 37328c2ecf20Sopenharmony_ci 37338c2ecf20Sopenharmony_ci 37348c2ecf20Sopenharmony_ci /* Second to N-1 DWORDS writes */ 37358c2ecf20Sopenharmony_ci while (dwords != 1) { 37368c2ecf20Sopenharmony_ci qla8044_wr_reg_indirect(vha, QLA8044_FLASH_WRDATA, *dwptr++); 37378c2ecf20Sopenharmony_ci qla8044_wr_reg_indirect(vha, QLA8044_FLASH_CONTROL, 37388c2ecf20Sopenharmony_ci QLA8044_FLASH_SECOND_MS_PATTERN); 37398c2ecf20Sopenharmony_ci ret = qla8044_poll_flash_status_reg(vha); 37408c2ecf20Sopenharmony_ci if (ret) { 37418c2ecf20Sopenharmony_ci ql_log(ql_log_warn, vha, 0xb129, 37428c2ecf20Sopenharmony_ci "%s: Failed.\n", __func__); 37438c2ecf20Sopenharmony_ci goto exit_func; 37448c2ecf20Sopenharmony_ci } 37458c2ecf20Sopenharmony_ci dwords--; 37468c2ecf20Sopenharmony_ci } 37478c2ecf20Sopenharmony_ci 37488c2ecf20Sopenharmony_ci qla8044_wr_reg_indirect(vha, QLA8044_FLASH_ADDR, 37498c2ecf20Sopenharmony_ci QLA8044_FLASH_FIRST_TEMP_VAL | (faddr >> 2)); 37508c2ecf20Sopenharmony_ci 37518c2ecf20Sopenharmony_ci /* Last DWORD write */ 37528c2ecf20Sopenharmony_ci qla8044_wr_reg_indirect(vha, QLA8044_FLASH_WRDATA, *dwptr++); 37538c2ecf20Sopenharmony_ci qla8044_wr_reg_indirect(vha, QLA8044_FLASH_CONTROL, 37548c2ecf20Sopenharmony_ci QLA8044_FLASH_LAST_MS_PATTERN); 37558c2ecf20Sopenharmony_ci ret = qla8044_poll_flash_status_reg(vha); 37568c2ecf20Sopenharmony_ci if (ret) { 37578c2ecf20Sopenharmony_ci ql_log(ql_log_warn, vha, 0xb12a, 37588c2ecf20Sopenharmony_ci "%s: Failed.\n", __func__); 37598c2ecf20Sopenharmony_ci goto exit_func; 37608c2ecf20Sopenharmony_ci } 37618c2ecf20Sopenharmony_ci qla8044_rd_reg_indirect(vha, QLA8044_FLASH_SPI_STATUS, &spi_val); 37628c2ecf20Sopenharmony_ci 37638c2ecf20Sopenharmony_ci if ((spi_val & QLA8044_FLASH_SPI_CTL) == QLA8044_FLASH_SPI_CTL) { 37648c2ecf20Sopenharmony_ci ql_log(ql_log_warn, vha, 0xb12b, 37658c2ecf20Sopenharmony_ci "%s: Failed.\n", __func__); 37668c2ecf20Sopenharmony_ci spi_val = 0; 37678c2ecf20Sopenharmony_ci /* Operation failed, clear error bit. */ 37688c2ecf20Sopenharmony_ci qla8044_rd_reg_indirect(vha, QLA8044_FLASH_SPI_CONTROL, 37698c2ecf20Sopenharmony_ci &spi_val); 37708c2ecf20Sopenharmony_ci qla8044_wr_reg_indirect(vha, QLA8044_FLASH_SPI_CONTROL, 37718c2ecf20Sopenharmony_ci spi_val | QLA8044_FLASH_SPI_CTL); 37728c2ecf20Sopenharmony_ci } 37738c2ecf20Sopenharmony_ciexit_func: 37748c2ecf20Sopenharmony_ci return ret; 37758c2ecf20Sopenharmony_ci} 37768c2ecf20Sopenharmony_ci 37778c2ecf20Sopenharmony_cistatic int 37788c2ecf20Sopenharmony_ciqla8044_write_flash_dword_mode(scsi_qla_host_t *vha, uint32_t *dwptr, 37798c2ecf20Sopenharmony_ci uint32_t faddr, uint32_t dwords) 37808c2ecf20Sopenharmony_ci{ 37818c2ecf20Sopenharmony_ci int ret = QLA_FUNCTION_FAILED; 37828c2ecf20Sopenharmony_ci uint32_t liter; 37838c2ecf20Sopenharmony_ci 37848c2ecf20Sopenharmony_ci for (liter = 0; liter < dwords; liter++, faddr += 4, dwptr++) { 37858c2ecf20Sopenharmony_ci ret = qla8044_flash_write_u32(vha, faddr, dwptr); 37868c2ecf20Sopenharmony_ci if (ret) { 37878c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_p3p, vha, 0xb141, 37888c2ecf20Sopenharmony_ci "%s: flash address=%x data=%x.\n", __func__, 37898c2ecf20Sopenharmony_ci faddr, *dwptr); 37908c2ecf20Sopenharmony_ci break; 37918c2ecf20Sopenharmony_ci } 37928c2ecf20Sopenharmony_ci } 37938c2ecf20Sopenharmony_ci 37948c2ecf20Sopenharmony_ci return ret; 37958c2ecf20Sopenharmony_ci} 37968c2ecf20Sopenharmony_ci 37978c2ecf20Sopenharmony_ciint 37988c2ecf20Sopenharmony_ciqla8044_write_optrom_data(struct scsi_qla_host *vha, void *buf, 37998c2ecf20Sopenharmony_ci uint32_t offset, uint32_t length) 38008c2ecf20Sopenharmony_ci{ 38018c2ecf20Sopenharmony_ci int rval = QLA_FUNCTION_FAILED, i, burst_iter_count; 38028c2ecf20Sopenharmony_ci int dword_count, erase_sec_count; 38038c2ecf20Sopenharmony_ci uint32_t erase_offset; 38048c2ecf20Sopenharmony_ci uint8_t *p_cache, *p_src; 38058c2ecf20Sopenharmony_ci 38068c2ecf20Sopenharmony_ci erase_offset = offset; 38078c2ecf20Sopenharmony_ci 38088c2ecf20Sopenharmony_ci p_cache = kcalloc(length, sizeof(uint8_t), GFP_KERNEL); 38098c2ecf20Sopenharmony_ci if (!p_cache) 38108c2ecf20Sopenharmony_ci return QLA_FUNCTION_FAILED; 38118c2ecf20Sopenharmony_ci 38128c2ecf20Sopenharmony_ci memcpy(p_cache, buf, length); 38138c2ecf20Sopenharmony_ci p_src = p_cache; 38148c2ecf20Sopenharmony_ci dword_count = length / sizeof(uint32_t); 38158c2ecf20Sopenharmony_ci /* Since the offset and legth are sector aligned, it will be always 38168c2ecf20Sopenharmony_ci * multiple of burst_iter_count (64) 38178c2ecf20Sopenharmony_ci */ 38188c2ecf20Sopenharmony_ci burst_iter_count = dword_count / QLA8044_MAX_OPTROM_BURST_DWORDS; 38198c2ecf20Sopenharmony_ci erase_sec_count = length / QLA8044_SECTOR_SIZE; 38208c2ecf20Sopenharmony_ci 38218c2ecf20Sopenharmony_ci /* Suspend HBA. */ 38228c2ecf20Sopenharmony_ci scsi_block_requests(vha->host); 38238c2ecf20Sopenharmony_ci /* Lock and enable write for whole operation. */ 38248c2ecf20Sopenharmony_ci qla8044_flash_lock(vha); 38258c2ecf20Sopenharmony_ci qla8044_unprotect_flash(vha); 38268c2ecf20Sopenharmony_ci 38278c2ecf20Sopenharmony_ci /* Erasing the sectors */ 38288c2ecf20Sopenharmony_ci for (i = 0; i < erase_sec_count; i++) { 38298c2ecf20Sopenharmony_ci rval = qla8044_erase_flash_sector(vha, erase_offset); 38308c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_user, vha, 0xb138, 38318c2ecf20Sopenharmony_ci "Done erase of sector=0x%x.\n", 38328c2ecf20Sopenharmony_ci erase_offset); 38338c2ecf20Sopenharmony_ci if (rval) { 38348c2ecf20Sopenharmony_ci ql_log(ql_log_warn, vha, 0xb121, 38358c2ecf20Sopenharmony_ci "Failed to erase the sector having address: " 38368c2ecf20Sopenharmony_ci "0x%x.\n", erase_offset); 38378c2ecf20Sopenharmony_ci goto out; 38388c2ecf20Sopenharmony_ci } 38398c2ecf20Sopenharmony_ci erase_offset += QLA8044_SECTOR_SIZE; 38408c2ecf20Sopenharmony_ci } 38418c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_user, vha, 0xb13f, 38428c2ecf20Sopenharmony_ci "Got write for addr = 0x%x length=0x%x.\n", 38438c2ecf20Sopenharmony_ci offset, length); 38448c2ecf20Sopenharmony_ci 38458c2ecf20Sopenharmony_ci for (i = 0; i < burst_iter_count; i++) { 38468c2ecf20Sopenharmony_ci 38478c2ecf20Sopenharmony_ci /* Go with write. */ 38488c2ecf20Sopenharmony_ci rval = qla8044_write_flash_buffer_mode(vha, (uint32_t *)p_src, 38498c2ecf20Sopenharmony_ci offset, QLA8044_MAX_OPTROM_BURST_DWORDS); 38508c2ecf20Sopenharmony_ci if (rval) { 38518c2ecf20Sopenharmony_ci /* Buffer Mode failed skip to dword mode */ 38528c2ecf20Sopenharmony_ci ql_log(ql_log_warn, vha, 0xb122, 38538c2ecf20Sopenharmony_ci "Failed to write flash in buffer mode, " 38548c2ecf20Sopenharmony_ci "Reverting to slow-write.\n"); 38558c2ecf20Sopenharmony_ci rval = qla8044_write_flash_dword_mode(vha, 38568c2ecf20Sopenharmony_ci (uint32_t *)p_src, offset, 38578c2ecf20Sopenharmony_ci QLA8044_MAX_OPTROM_BURST_DWORDS); 38588c2ecf20Sopenharmony_ci } 38598c2ecf20Sopenharmony_ci p_src += sizeof(uint32_t) * QLA8044_MAX_OPTROM_BURST_DWORDS; 38608c2ecf20Sopenharmony_ci offset += sizeof(uint32_t) * QLA8044_MAX_OPTROM_BURST_DWORDS; 38618c2ecf20Sopenharmony_ci } 38628c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_user, vha, 0xb133, 38638c2ecf20Sopenharmony_ci "Done writing.\n"); 38648c2ecf20Sopenharmony_ci 38658c2ecf20Sopenharmony_ciout: 38668c2ecf20Sopenharmony_ci qla8044_protect_flash(vha); 38678c2ecf20Sopenharmony_ci qla8044_flash_unlock(vha); 38688c2ecf20Sopenharmony_ci scsi_unblock_requests(vha->host); 38698c2ecf20Sopenharmony_ci kfree(p_cache); 38708c2ecf20Sopenharmony_ci 38718c2ecf20Sopenharmony_ci return rval; 38728c2ecf20Sopenharmony_ci} 38738c2ecf20Sopenharmony_ci 38748c2ecf20Sopenharmony_ci#define LEG_INT_PTR_B31 (1 << 31) 38758c2ecf20Sopenharmony_ci#define LEG_INT_PTR_B30 (1 << 30) 38768c2ecf20Sopenharmony_ci#define PF_BITS_MASK (0xF << 16) 38778c2ecf20Sopenharmony_ci/** 38788c2ecf20Sopenharmony_ci * qla8044_intr_handler() - Process interrupts for the ISP8044 38798c2ecf20Sopenharmony_ci * @irq: interrupt number 38808c2ecf20Sopenharmony_ci * @dev_id: SCSI driver HA context 38818c2ecf20Sopenharmony_ci * 38828c2ecf20Sopenharmony_ci * Called by system whenever the host adapter generates an interrupt. 38838c2ecf20Sopenharmony_ci * 38848c2ecf20Sopenharmony_ci * Returns handled flag. 38858c2ecf20Sopenharmony_ci */ 38868c2ecf20Sopenharmony_ciirqreturn_t 38878c2ecf20Sopenharmony_ciqla8044_intr_handler(int irq, void *dev_id) 38888c2ecf20Sopenharmony_ci{ 38898c2ecf20Sopenharmony_ci scsi_qla_host_t *vha; 38908c2ecf20Sopenharmony_ci struct qla_hw_data *ha; 38918c2ecf20Sopenharmony_ci struct rsp_que *rsp; 38928c2ecf20Sopenharmony_ci struct device_reg_82xx __iomem *reg; 38938c2ecf20Sopenharmony_ci int status = 0; 38948c2ecf20Sopenharmony_ci unsigned long flags; 38958c2ecf20Sopenharmony_ci unsigned long iter; 38968c2ecf20Sopenharmony_ci uint32_t stat; 38978c2ecf20Sopenharmony_ci uint16_t mb[8]; 38988c2ecf20Sopenharmony_ci uint32_t leg_int_ptr = 0, pf_bit; 38998c2ecf20Sopenharmony_ci 39008c2ecf20Sopenharmony_ci rsp = (struct rsp_que *) dev_id; 39018c2ecf20Sopenharmony_ci if (!rsp) { 39028c2ecf20Sopenharmony_ci ql_log(ql_log_info, NULL, 0xb143, 39038c2ecf20Sopenharmony_ci "%s(): NULL response queue pointer\n", __func__); 39048c2ecf20Sopenharmony_ci return IRQ_NONE; 39058c2ecf20Sopenharmony_ci } 39068c2ecf20Sopenharmony_ci ha = rsp->hw; 39078c2ecf20Sopenharmony_ci vha = pci_get_drvdata(ha->pdev); 39088c2ecf20Sopenharmony_ci 39098c2ecf20Sopenharmony_ci if (unlikely(pci_channel_offline(ha->pdev))) 39108c2ecf20Sopenharmony_ci return IRQ_HANDLED; 39118c2ecf20Sopenharmony_ci 39128c2ecf20Sopenharmony_ci leg_int_ptr = qla8044_rd_reg(ha, LEG_INTR_PTR_OFFSET); 39138c2ecf20Sopenharmony_ci 39148c2ecf20Sopenharmony_ci /* Legacy interrupt is valid if bit31 of leg_int_ptr is set */ 39158c2ecf20Sopenharmony_ci if (!(leg_int_ptr & (LEG_INT_PTR_B31))) { 39168c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_p3p, vha, 0xb144, 39178c2ecf20Sopenharmony_ci "%s: Legacy Interrupt Bit 31 not set, " 39188c2ecf20Sopenharmony_ci "spurious interrupt!\n", __func__); 39198c2ecf20Sopenharmony_ci return IRQ_NONE; 39208c2ecf20Sopenharmony_ci } 39218c2ecf20Sopenharmony_ci 39228c2ecf20Sopenharmony_ci pf_bit = ha->portnum << 16; 39238c2ecf20Sopenharmony_ci /* Validate the PCIE function ID set in leg_int_ptr bits [19..16] */ 39248c2ecf20Sopenharmony_ci if ((leg_int_ptr & (PF_BITS_MASK)) != pf_bit) { 39258c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_p3p, vha, 0xb145, 39268c2ecf20Sopenharmony_ci "%s: Incorrect function ID 0x%x in " 39278c2ecf20Sopenharmony_ci "legacy interrupt register, " 39288c2ecf20Sopenharmony_ci "ha->pf_bit = 0x%x\n", __func__, 39298c2ecf20Sopenharmony_ci (leg_int_ptr & (PF_BITS_MASK)), pf_bit); 39308c2ecf20Sopenharmony_ci return IRQ_NONE; 39318c2ecf20Sopenharmony_ci } 39328c2ecf20Sopenharmony_ci 39338c2ecf20Sopenharmony_ci /* To de-assert legacy interrupt, write 0 to Legacy Interrupt Trigger 39348c2ecf20Sopenharmony_ci * Control register and poll till Legacy Interrupt Pointer register 39358c2ecf20Sopenharmony_ci * bit32 is 0. 39368c2ecf20Sopenharmony_ci */ 39378c2ecf20Sopenharmony_ci qla8044_wr_reg(ha, LEG_INTR_TRIG_OFFSET, 0); 39388c2ecf20Sopenharmony_ci do { 39398c2ecf20Sopenharmony_ci leg_int_ptr = qla8044_rd_reg(ha, LEG_INTR_PTR_OFFSET); 39408c2ecf20Sopenharmony_ci if ((leg_int_ptr & (PF_BITS_MASK)) != pf_bit) 39418c2ecf20Sopenharmony_ci break; 39428c2ecf20Sopenharmony_ci } while (leg_int_ptr & (LEG_INT_PTR_B30)); 39438c2ecf20Sopenharmony_ci 39448c2ecf20Sopenharmony_ci reg = &ha->iobase->isp82; 39458c2ecf20Sopenharmony_ci spin_lock_irqsave(&ha->hardware_lock, flags); 39468c2ecf20Sopenharmony_ci for (iter = 1; iter--; ) { 39478c2ecf20Sopenharmony_ci 39488c2ecf20Sopenharmony_ci if (rd_reg_dword(®->host_int)) { 39498c2ecf20Sopenharmony_ci stat = rd_reg_dword(®->host_status); 39508c2ecf20Sopenharmony_ci if ((stat & HSRX_RISC_INT) == 0) 39518c2ecf20Sopenharmony_ci break; 39528c2ecf20Sopenharmony_ci 39538c2ecf20Sopenharmony_ci switch (stat & 0xff) { 39548c2ecf20Sopenharmony_ci case 0x1: 39558c2ecf20Sopenharmony_ci case 0x2: 39568c2ecf20Sopenharmony_ci case 0x10: 39578c2ecf20Sopenharmony_ci case 0x11: 39588c2ecf20Sopenharmony_ci qla82xx_mbx_completion(vha, MSW(stat)); 39598c2ecf20Sopenharmony_ci status |= MBX_INTERRUPT; 39608c2ecf20Sopenharmony_ci break; 39618c2ecf20Sopenharmony_ci case 0x12: 39628c2ecf20Sopenharmony_ci mb[0] = MSW(stat); 39638c2ecf20Sopenharmony_ci mb[1] = rd_reg_word(®->mailbox_out[1]); 39648c2ecf20Sopenharmony_ci mb[2] = rd_reg_word(®->mailbox_out[2]); 39658c2ecf20Sopenharmony_ci mb[3] = rd_reg_word(®->mailbox_out[3]); 39668c2ecf20Sopenharmony_ci qla2x00_async_event(vha, rsp, mb); 39678c2ecf20Sopenharmony_ci break; 39688c2ecf20Sopenharmony_ci case 0x13: 39698c2ecf20Sopenharmony_ci qla24xx_process_response_queue(vha, rsp); 39708c2ecf20Sopenharmony_ci break; 39718c2ecf20Sopenharmony_ci default: 39728c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_p3p, vha, 0xb146, 39738c2ecf20Sopenharmony_ci "Unrecognized interrupt type " 39748c2ecf20Sopenharmony_ci "(%d).\n", stat & 0xff); 39758c2ecf20Sopenharmony_ci break; 39768c2ecf20Sopenharmony_ci } 39778c2ecf20Sopenharmony_ci } 39788c2ecf20Sopenharmony_ci wrt_reg_dword(®->host_int, 0); 39798c2ecf20Sopenharmony_ci } 39808c2ecf20Sopenharmony_ci 39818c2ecf20Sopenharmony_ci qla2x00_handle_mbx_completion(ha, status); 39828c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&ha->hardware_lock, flags); 39838c2ecf20Sopenharmony_ci 39848c2ecf20Sopenharmony_ci return IRQ_HANDLED; 39858c2ecf20Sopenharmony_ci} 39868c2ecf20Sopenharmony_ci 39878c2ecf20Sopenharmony_cistatic int 39888c2ecf20Sopenharmony_ciqla8044_idc_dontreset(struct qla_hw_data *ha) 39898c2ecf20Sopenharmony_ci{ 39908c2ecf20Sopenharmony_ci uint32_t idc_ctrl; 39918c2ecf20Sopenharmony_ci 39928c2ecf20Sopenharmony_ci idc_ctrl = qla8044_rd_reg(ha, QLA8044_IDC_DRV_CTRL); 39938c2ecf20Sopenharmony_ci return idc_ctrl & DONTRESET_BIT0; 39948c2ecf20Sopenharmony_ci} 39958c2ecf20Sopenharmony_ci 39968c2ecf20Sopenharmony_cistatic void 39978c2ecf20Sopenharmony_ciqla8044_clear_rst_ready(scsi_qla_host_t *vha) 39988c2ecf20Sopenharmony_ci{ 39998c2ecf20Sopenharmony_ci uint32_t drv_state; 40008c2ecf20Sopenharmony_ci 40018c2ecf20Sopenharmony_ci drv_state = qla8044_rd_direct(vha, QLA8044_CRB_DRV_STATE_INDEX); 40028c2ecf20Sopenharmony_ci 40038c2ecf20Sopenharmony_ci /* 40048c2ecf20Sopenharmony_ci * For ISP8044, drv_active register has 1 bit per function, 40058c2ecf20Sopenharmony_ci * shift 1 by func_num to set a bit for the function. 40068c2ecf20Sopenharmony_ci * For ISP82xx, drv_active has 4 bits per function 40078c2ecf20Sopenharmony_ci */ 40088c2ecf20Sopenharmony_ci drv_state &= ~(1 << vha->hw->portnum); 40098c2ecf20Sopenharmony_ci 40108c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_p3p, vha, 0xb13d, 40118c2ecf20Sopenharmony_ci "drv_state: 0x%08x\n", drv_state); 40128c2ecf20Sopenharmony_ci qla8044_wr_direct(vha, QLA8044_CRB_DRV_STATE_INDEX, drv_state); 40138c2ecf20Sopenharmony_ci} 40148c2ecf20Sopenharmony_ci 40158c2ecf20Sopenharmony_ciint 40168c2ecf20Sopenharmony_ciqla8044_abort_isp(scsi_qla_host_t *vha) 40178c2ecf20Sopenharmony_ci{ 40188c2ecf20Sopenharmony_ci int rval; 40198c2ecf20Sopenharmony_ci uint32_t dev_state; 40208c2ecf20Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 40218c2ecf20Sopenharmony_ci 40228c2ecf20Sopenharmony_ci qla8044_idc_lock(ha); 40238c2ecf20Sopenharmony_ci dev_state = qla8044_rd_direct(vha, QLA8044_CRB_DEV_STATE_INDEX); 40248c2ecf20Sopenharmony_ci 40258c2ecf20Sopenharmony_ci if (ql2xdontresethba) 40268c2ecf20Sopenharmony_ci qla8044_set_idc_dontreset(vha); 40278c2ecf20Sopenharmony_ci 40288c2ecf20Sopenharmony_ci /* If device_state is NEED_RESET, go ahead with 40298c2ecf20Sopenharmony_ci * Reset,irrespective of ql2xdontresethba. This is to allow a 40308c2ecf20Sopenharmony_ci * non-reset-owner to force a reset. Non-reset-owner sets 40318c2ecf20Sopenharmony_ci * the IDC_CTRL BIT0 to prevent Reset-owner from doing a Reset 40328c2ecf20Sopenharmony_ci * and then forces a Reset by setting device_state to 40338c2ecf20Sopenharmony_ci * NEED_RESET. */ 40348c2ecf20Sopenharmony_ci if (dev_state == QLA8XXX_DEV_READY) { 40358c2ecf20Sopenharmony_ci /* If IDC_CTRL DONTRESETHBA_BIT0 is set don't do reset 40368c2ecf20Sopenharmony_ci * recovery */ 40378c2ecf20Sopenharmony_ci if (qla8044_idc_dontreset(ha) == DONTRESET_BIT0) { 40388c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_p3p, vha, 0xb13e, 40398c2ecf20Sopenharmony_ci "Reset recovery disabled\n"); 40408c2ecf20Sopenharmony_ci rval = QLA_FUNCTION_FAILED; 40418c2ecf20Sopenharmony_ci goto exit_isp_reset; 40428c2ecf20Sopenharmony_ci } 40438c2ecf20Sopenharmony_ci 40448c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_p3p, vha, 0xb140, 40458c2ecf20Sopenharmony_ci "HW State: NEED RESET\n"); 40468c2ecf20Sopenharmony_ci qla8044_wr_direct(vha, QLA8044_CRB_DEV_STATE_INDEX, 40478c2ecf20Sopenharmony_ci QLA8XXX_DEV_NEED_RESET); 40488c2ecf20Sopenharmony_ci } 40498c2ecf20Sopenharmony_ci 40508c2ecf20Sopenharmony_ci /* For ISP8044, Reset owner is NIC, iSCSI or FCOE based on priority 40518c2ecf20Sopenharmony_ci * and which drivers are present. Unlike ISP82XX, the function setting 40528c2ecf20Sopenharmony_ci * NEED_RESET, may not be the Reset owner. */ 40538c2ecf20Sopenharmony_ci qla83xx_reset_ownership(vha); 40548c2ecf20Sopenharmony_ci 40558c2ecf20Sopenharmony_ci qla8044_idc_unlock(ha); 40568c2ecf20Sopenharmony_ci rval = qla8044_device_state_handler(vha); 40578c2ecf20Sopenharmony_ci qla8044_idc_lock(ha); 40588c2ecf20Sopenharmony_ci qla8044_clear_rst_ready(vha); 40598c2ecf20Sopenharmony_ci 40608c2ecf20Sopenharmony_ciexit_isp_reset: 40618c2ecf20Sopenharmony_ci qla8044_idc_unlock(ha); 40628c2ecf20Sopenharmony_ci if (rval == QLA_SUCCESS) { 40638c2ecf20Sopenharmony_ci ha->flags.isp82xx_fw_hung = 0; 40648c2ecf20Sopenharmony_ci ha->flags.nic_core_reset_hdlr_active = 0; 40658c2ecf20Sopenharmony_ci rval = qla82xx_restart_isp(vha); 40668c2ecf20Sopenharmony_ci } 40678c2ecf20Sopenharmony_ci 40688c2ecf20Sopenharmony_ci return rval; 40698c2ecf20Sopenharmony_ci} 40708c2ecf20Sopenharmony_ci 40718c2ecf20Sopenharmony_civoid 40728c2ecf20Sopenharmony_ciqla8044_fw_dump(scsi_qla_host_t *vha) 40738c2ecf20Sopenharmony_ci{ 40748c2ecf20Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 40758c2ecf20Sopenharmony_ci 40768c2ecf20Sopenharmony_ci if (!ha->allow_cna_fw_dump) 40778c2ecf20Sopenharmony_ci return; 40788c2ecf20Sopenharmony_ci 40798c2ecf20Sopenharmony_ci scsi_block_requests(vha->host); 40808c2ecf20Sopenharmony_ci ha->flags.isp82xx_no_md_cap = 1; 40818c2ecf20Sopenharmony_ci qla8044_idc_lock(ha); 40828c2ecf20Sopenharmony_ci qla82xx_set_reset_owner(vha); 40838c2ecf20Sopenharmony_ci qla8044_idc_unlock(ha); 40848c2ecf20Sopenharmony_ci qla2x00_wait_for_chip_reset(vha); 40858c2ecf20Sopenharmony_ci scsi_unblock_requests(vha->host); 40868c2ecf20Sopenharmony_ci} 4087