18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * QLogic iSCSI HBA Driver 48c2ecf20Sopenharmony_ci * Copyright (c) 2003-2013 QLogic Corporation 58c2ecf20Sopenharmony_ci */ 68c2ecf20Sopenharmony_ci 78c2ecf20Sopenharmony_ci#include <linux/ratelimit.h> 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ci#include "ql4_def.h" 108c2ecf20Sopenharmony_ci#include "ql4_version.h" 118c2ecf20Sopenharmony_ci#include "ql4_glbl.h" 128c2ecf20Sopenharmony_ci#include "ql4_dbg.h" 138c2ecf20Sopenharmony_ci#include "ql4_inline.h" 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_ciuint32_t qla4_83xx_rd_reg(struct scsi_qla_host *ha, ulong addr) 168c2ecf20Sopenharmony_ci{ 178c2ecf20Sopenharmony_ci return readl((void __iomem *)(ha->nx_pcibase + addr)); 188c2ecf20Sopenharmony_ci} 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_civoid qla4_83xx_wr_reg(struct scsi_qla_host *ha, ulong addr, uint32_t val) 218c2ecf20Sopenharmony_ci{ 228c2ecf20Sopenharmony_ci writel(val, (void __iomem *)(ha->nx_pcibase + addr)); 238c2ecf20Sopenharmony_ci} 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_cistatic int qla4_83xx_set_win_base(struct scsi_qla_host *ha, uint32_t addr) 268c2ecf20Sopenharmony_ci{ 278c2ecf20Sopenharmony_ci uint32_t val; 288c2ecf20Sopenharmony_ci int ret_val = QLA_SUCCESS; 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_ci qla4_83xx_wr_reg(ha, QLA83XX_CRB_WIN_FUNC(ha->func_num), addr); 318c2ecf20Sopenharmony_ci val = qla4_83xx_rd_reg(ha, QLA83XX_CRB_WIN_FUNC(ha->func_num)); 328c2ecf20Sopenharmony_ci if (val != addr) { 338c2ecf20Sopenharmony_ci ql4_printk(KERN_ERR, ha, "%s: Failed to set register window : addr written 0x%x, read 0x%x!\n", 348c2ecf20Sopenharmony_ci __func__, addr, val); 358c2ecf20Sopenharmony_ci ret_val = QLA_ERROR; 368c2ecf20Sopenharmony_ci } 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci return ret_val; 398c2ecf20Sopenharmony_ci} 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ciint qla4_83xx_rd_reg_indirect(struct scsi_qla_host *ha, uint32_t addr, 428c2ecf20Sopenharmony_ci uint32_t *data) 438c2ecf20Sopenharmony_ci{ 448c2ecf20Sopenharmony_ci int ret_val; 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_ci ret_val = qla4_83xx_set_win_base(ha, addr); 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci if (ret_val == QLA_SUCCESS) { 498c2ecf20Sopenharmony_ci *data = qla4_83xx_rd_reg(ha, QLA83XX_WILDCARD); 508c2ecf20Sopenharmony_ci } else { 518c2ecf20Sopenharmony_ci *data = 0xffffffff; 528c2ecf20Sopenharmony_ci ql4_printk(KERN_ERR, ha, "%s: failed read of addr 0x%x!\n", 538c2ecf20Sopenharmony_ci __func__, addr); 548c2ecf20Sopenharmony_ci } 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ci return ret_val; 578c2ecf20Sopenharmony_ci} 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_ciint qla4_83xx_wr_reg_indirect(struct scsi_qla_host *ha, uint32_t addr, 608c2ecf20Sopenharmony_ci uint32_t data) 618c2ecf20Sopenharmony_ci{ 628c2ecf20Sopenharmony_ci int ret_val; 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci ret_val = qla4_83xx_set_win_base(ha, addr); 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_ci if (ret_val == QLA_SUCCESS) 678c2ecf20Sopenharmony_ci qla4_83xx_wr_reg(ha, QLA83XX_WILDCARD, data); 688c2ecf20Sopenharmony_ci else 698c2ecf20Sopenharmony_ci ql4_printk(KERN_ERR, ha, "%s: failed wrt to addr 0x%x, data 0x%x\n", 708c2ecf20Sopenharmony_ci __func__, addr, data); 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci return ret_val; 738c2ecf20Sopenharmony_ci} 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_cistatic int qla4_83xx_flash_lock(struct scsi_qla_host *ha) 768c2ecf20Sopenharmony_ci{ 778c2ecf20Sopenharmony_ci int lock_owner; 788c2ecf20Sopenharmony_ci int timeout = 0; 798c2ecf20Sopenharmony_ci uint32_t lock_status = 0; 808c2ecf20Sopenharmony_ci int ret_val = QLA_SUCCESS; 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ci while (lock_status == 0) { 838c2ecf20Sopenharmony_ci lock_status = qla4_83xx_rd_reg(ha, QLA83XX_FLASH_LOCK); 848c2ecf20Sopenharmony_ci if (lock_status) 858c2ecf20Sopenharmony_ci break; 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci if (++timeout >= QLA83XX_FLASH_LOCK_TIMEOUT / 20) { 888c2ecf20Sopenharmony_ci lock_owner = qla4_83xx_rd_reg(ha, 898c2ecf20Sopenharmony_ci QLA83XX_FLASH_LOCK_ID); 908c2ecf20Sopenharmony_ci ql4_printk(KERN_ERR, ha, "%s: flash lock by func %d failed, held by func %d\n", 918c2ecf20Sopenharmony_ci __func__, ha->func_num, lock_owner); 928c2ecf20Sopenharmony_ci ret_val = QLA_ERROR; 938c2ecf20Sopenharmony_ci break; 948c2ecf20Sopenharmony_ci } 958c2ecf20Sopenharmony_ci msleep(20); 968c2ecf20Sopenharmony_ci } 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ci qla4_83xx_wr_reg(ha, QLA83XX_FLASH_LOCK_ID, ha->func_num); 998c2ecf20Sopenharmony_ci return ret_val; 1008c2ecf20Sopenharmony_ci} 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_cistatic void qla4_83xx_flash_unlock(struct scsi_qla_host *ha) 1038c2ecf20Sopenharmony_ci{ 1048c2ecf20Sopenharmony_ci /* Reading FLASH_UNLOCK register unlocks the Flash */ 1058c2ecf20Sopenharmony_ci qla4_83xx_wr_reg(ha, QLA83XX_FLASH_LOCK_ID, 0xFF); 1068c2ecf20Sopenharmony_ci qla4_83xx_rd_reg(ha, QLA83XX_FLASH_UNLOCK); 1078c2ecf20Sopenharmony_ci} 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ciint qla4_83xx_flash_read_u32(struct scsi_qla_host *ha, uint32_t flash_addr, 1108c2ecf20Sopenharmony_ci uint8_t *p_data, int u32_word_count) 1118c2ecf20Sopenharmony_ci{ 1128c2ecf20Sopenharmony_ci int i; 1138c2ecf20Sopenharmony_ci uint32_t u32_word; 1148c2ecf20Sopenharmony_ci uint32_t addr = flash_addr; 1158c2ecf20Sopenharmony_ci int ret_val = QLA_SUCCESS; 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_ci ret_val = qla4_83xx_flash_lock(ha); 1188c2ecf20Sopenharmony_ci if (ret_val == QLA_ERROR) 1198c2ecf20Sopenharmony_ci goto exit_lock_error; 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_ci if (addr & 0x03) { 1228c2ecf20Sopenharmony_ci ql4_printk(KERN_ERR, ha, "%s: Illegal addr = 0x%x\n", 1238c2ecf20Sopenharmony_ci __func__, addr); 1248c2ecf20Sopenharmony_ci ret_val = QLA_ERROR; 1258c2ecf20Sopenharmony_ci goto exit_flash_read; 1268c2ecf20Sopenharmony_ci } 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_ci for (i = 0; i < u32_word_count; i++) { 1298c2ecf20Sopenharmony_ci ret_val = qla4_83xx_wr_reg_indirect(ha, 1308c2ecf20Sopenharmony_ci QLA83XX_FLASH_DIRECT_WINDOW, 1318c2ecf20Sopenharmony_ci (addr & 0xFFFF0000)); 1328c2ecf20Sopenharmony_ci if (ret_val == QLA_ERROR) { 1338c2ecf20Sopenharmony_ci ql4_printk(KERN_ERR, ha, "%s: failed to write addr 0x%x to FLASH_DIRECT_WINDOW\n!", 1348c2ecf20Sopenharmony_ci __func__, addr); 1358c2ecf20Sopenharmony_ci goto exit_flash_read; 1368c2ecf20Sopenharmony_ci } 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_ci ret_val = qla4_83xx_rd_reg_indirect(ha, 1398c2ecf20Sopenharmony_ci QLA83XX_FLASH_DIRECT_DATA(addr), 1408c2ecf20Sopenharmony_ci &u32_word); 1418c2ecf20Sopenharmony_ci if (ret_val == QLA_ERROR) { 1428c2ecf20Sopenharmony_ci ql4_printk(KERN_ERR, ha, "%s: failed to read addr 0x%x!\n", 1438c2ecf20Sopenharmony_ci __func__, addr); 1448c2ecf20Sopenharmony_ci goto exit_flash_read; 1458c2ecf20Sopenharmony_ci } 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_ci *(__le32 *)p_data = le32_to_cpu(u32_word); 1488c2ecf20Sopenharmony_ci p_data = p_data + 4; 1498c2ecf20Sopenharmony_ci addr = addr + 4; 1508c2ecf20Sopenharmony_ci } 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ciexit_flash_read: 1538c2ecf20Sopenharmony_ci qla4_83xx_flash_unlock(ha); 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ciexit_lock_error: 1568c2ecf20Sopenharmony_ci return ret_val; 1578c2ecf20Sopenharmony_ci} 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_ciint qla4_83xx_lockless_flash_read_u32(struct scsi_qla_host *ha, 1608c2ecf20Sopenharmony_ci uint32_t flash_addr, uint8_t *p_data, 1618c2ecf20Sopenharmony_ci int u32_word_count) 1628c2ecf20Sopenharmony_ci{ 1638c2ecf20Sopenharmony_ci uint32_t i; 1648c2ecf20Sopenharmony_ci uint32_t u32_word; 1658c2ecf20Sopenharmony_ci uint32_t flash_offset; 1668c2ecf20Sopenharmony_ci uint32_t addr = flash_addr; 1678c2ecf20Sopenharmony_ci int ret_val = QLA_SUCCESS; 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_ci flash_offset = addr & (QLA83XX_FLASH_SECTOR_SIZE - 1); 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_ci if (addr & 0x3) { 1728c2ecf20Sopenharmony_ci ql4_printk(KERN_ERR, ha, "%s: Illegal addr = 0x%x\n", 1738c2ecf20Sopenharmony_ci __func__, addr); 1748c2ecf20Sopenharmony_ci ret_val = QLA_ERROR; 1758c2ecf20Sopenharmony_ci goto exit_lockless_read; 1768c2ecf20Sopenharmony_ci } 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_ci ret_val = qla4_83xx_wr_reg_indirect(ha, QLA83XX_FLASH_DIRECT_WINDOW, 1798c2ecf20Sopenharmony_ci addr); 1808c2ecf20Sopenharmony_ci if (ret_val == QLA_ERROR) { 1818c2ecf20Sopenharmony_ci ql4_printk(KERN_ERR, ha, "%s: failed to write addr 0x%x to FLASH_DIRECT_WINDOW!\n", 1828c2ecf20Sopenharmony_ci __func__, addr); 1838c2ecf20Sopenharmony_ci goto exit_lockless_read; 1848c2ecf20Sopenharmony_ci } 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_ci /* Check if data is spread across multiple sectors */ 1878c2ecf20Sopenharmony_ci if ((flash_offset + (u32_word_count * sizeof(uint32_t))) > 1888c2ecf20Sopenharmony_ci (QLA83XX_FLASH_SECTOR_SIZE - 1)) { 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_ci /* Multi sector read */ 1918c2ecf20Sopenharmony_ci for (i = 0; i < u32_word_count; i++) { 1928c2ecf20Sopenharmony_ci ret_val = qla4_83xx_rd_reg_indirect(ha, 1938c2ecf20Sopenharmony_ci QLA83XX_FLASH_DIRECT_DATA(addr), 1948c2ecf20Sopenharmony_ci &u32_word); 1958c2ecf20Sopenharmony_ci if (ret_val == QLA_ERROR) { 1968c2ecf20Sopenharmony_ci ql4_printk(KERN_ERR, ha, "%s: failed to read addr 0x%x!\n", 1978c2ecf20Sopenharmony_ci __func__, addr); 1988c2ecf20Sopenharmony_ci goto exit_lockless_read; 1998c2ecf20Sopenharmony_ci } 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_ci *(__le32 *)p_data = le32_to_cpu(u32_word); 2028c2ecf20Sopenharmony_ci p_data = p_data + 4; 2038c2ecf20Sopenharmony_ci addr = addr + 4; 2048c2ecf20Sopenharmony_ci flash_offset = flash_offset + 4; 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_ci if (flash_offset > (QLA83XX_FLASH_SECTOR_SIZE - 1)) { 2078c2ecf20Sopenharmony_ci /* This write is needed once for each sector */ 2088c2ecf20Sopenharmony_ci ret_val = qla4_83xx_wr_reg_indirect(ha, 2098c2ecf20Sopenharmony_ci QLA83XX_FLASH_DIRECT_WINDOW, 2108c2ecf20Sopenharmony_ci addr); 2118c2ecf20Sopenharmony_ci if (ret_val == QLA_ERROR) { 2128c2ecf20Sopenharmony_ci ql4_printk(KERN_ERR, ha, "%s: failed to write addr 0x%x to FLASH_DIRECT_WINDOW!\n", 2138c2ecf20Sopenharmony_ci __func__, addr); 2148c2ecf20Sopenharmony_ci goto exit_lockless_read; 2158c2ecf20Sopenharmony_ci } 2168c2ecf20Sopenharmony_ci flash_offset = 0; 2178c2ecf20Sopenharmony_ci } 2188c2ecf20Sopenharmony_ci } 2198c2ecf20Sopenharmony_ci } else { 2208c2ecf20Sopenharmony_ci /* Single sector read */ 2218c2ecf20Sopenharmony_ci for (i = 0; i < u32_word_count; i++) { 2228c2ecf20Sopenharmony_ci ret_val = qla4_83xx_rd_reg_indirect(ha, 2238c2ecf20Sopenharmony_ci QLA83XX_FLASH_DIRECT_DATA(addr), 2248c2ecf20Sopenharmony_ci &u32_word); 2258c2ecf20Sopenharmony_ci if (ret_val == QLA_ERROR) { 2268c2ecf20Sopenharmony_ci ql4_printk(KERN_ERR, ha, "%s: failed to read addr 0x%x!\n", 2278c2ecf20Sopenharmony_ci __func__, addr); 2288c2ecf20Sopenharmony_ci goto exit_lockless_read; 2298c2ecf20Sopenharmony_ci } 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_ci *(__le32 *)p_data = le32_to_cpu(u32_word); 2328c2ecf20Sopenharmony_ci p_data = p_data + 4; 2338c2ecf20Sopenharmony_ci addr = addr + 4; 2348c2ecf20Sopenharmony_ci } 2358c2ecf20Sopenharmony_ci } 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_ciexit_lockless_read: 2388c2ecf20Sopenharmony_ci return ret_val; 2398c2ecf20Sopenharmony_ci} 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_civoid qla4_83xx_rom_lock_recovery(struct scsi_qla_host *ha) 2428c2ecf20Sopenharmony_ci{ 2438c2ecf20Sopenharmony_ci if (qla4_83xx_flash_lock(ha)) 2448c2ecf20Sopenharmony_ci ql4_printk(KERN_INFO, ha, "%s: Resetting rom lock\n", __func__); 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_ci /* 2478c2ecf20Sopenharmony_ci * We got the lock, or someone else is holding the lock 2488c2ecf20Sopenharmony_ci * since we are restting, forcefully unlock 2498c2ecf20Sopenharmony_ci */ 2508c2ecf20Sopenharmony_ci qla4_83xx_flash_unlock(ha); 2518c2ecf20Sopenharmony_ci} 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_ci#define INTENT_TO_RECOVER 0x01 2548c2ecf20Sopenharmony_ci#define PROCEED_TO_RECOVER 0x02 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_cistatic int qla4_83xx_lock_recovery(struct scsi_qla_host *ha) 2578c2ecf20Sopenharmony_ci{ 2588c2ecf20Sopenharmony_ci 2598c2ecf20Sopenharmony_ci uint32_t lock = 0, lockid; 2608c2ecf20Sopenharmony_ci int ret_val = QLA_ERROR; 2618c2ecf20Sopenharmony_ci 2628c2ecf20Sopenharmony_ci lockid = ha->isp_ops->rd_reg_direct(ha, QLA83XX_DRV_LOCKRECOVERY); 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_ci /* Check for other Recovery in progress, go wait */ 2658c2ecf20Sopenharmony_ci if ((lockid & 0x3) != 0) 2668c2ecf20Sopenharmony_ci goto exit_lock_recovery; 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_ci /* Intent to Recover */ 2698c2ecf20Sopenharmony_ci ha->isp_ops->wr_reg_direct(ha, QLA83XX_DRV_LOCKRECOVERY, 2708c2ecf20Sopenharmony_ci (ha->func_num << 2) | INTENT_TO_RECOVER); 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_ci msleep(200); 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_ci /* Check Intent to Recover is advertised */ 2758c2ecf20Sopenharmony_ci lockid = ha->isp_ops->rd_reg_direct(ha, QLA83XX_DRV_LOCKRECOVERY); 2768c2ecf20Sopenharmony_ci if ((lockid & 0x3C) != (ha->func_num << 2)) 2778c2ecf20Sopenharmony_ci goto exit_lock_recovery; 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_ci ql4_printk(KERN_INFO, ha, "%s: IDC Lock recovery initiated for func %d\n", 2808c2ecf20Sopenharmony_ci __func__, ha->func_num); 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_ci /* Proceed to Recover */ 2838c2ecf20Sopenharmony_ci ha->isp_ops->wr_reg_direct(ha, QLA83XX_DRV_LOCKRECOVERY, 2848c2ecf20Sopenharmony_ci (ha->func_num << 2) | PROCEED_TO_RECOVER); 2858c2ecf20Sopenharmony_ci 2868c2ecf20Sopenharmony_ci /* Force Unlock */ 2878c2ecf20Sopenharmony_ci ha->isp_ops->wr_reg_direct(ha, QLA83XX_DRV_LOCK_ID, 0xFF); 2888c2ecf20Sopenharmony_ci ha->isp_ops->rd_reg_direct(ha, QLA83XX_DRV_UNLOCK); 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_ci /* Clear bits 0-5 in IDC_RECOVERY register*/ 2918c2ecf20Sopenharmony_ci ha->isp_ops->wr_reg_direct(ha, QLA83XX_DRV_LOCKRECOVERY, 0); 2928c2ecf20Sopenharmony_ci 2938c2ecf20Sopenharmony_ci /* Get lock */ 2948c2ecf20Sopenharmony_ci lock = ha->isp_ops->rd_reg_direct(ha, QLA83XX_DRV_LOCK); 2958c2ecf20Sopenharmony_ci if (lock) { 2968c2ecf20Sopenharmony_ci lockid = ha->isp_ops->rd_reg_direct(ha, QLA83XX_DRV_LOCK_ID); 2978c2ecf20Sopenharmony_ci lockid = ((lockid + (1 << 8)) & ~0xFF) | ha->func_num; 2988c2ecf20Sopenharmony_ci ha->isp_ops->wr_reg_direct(ha, QLA83XX_DRV_LOCK_ID, lockid); 2998c2ecf20Sopenharmony_ci ret_val = QLA_SUCCESS; 3008c2ecf20Sopenharmony_ci } 3018c2ecf20Sopenharmony_ci 3028c2ecf20Sopenharmony_ciexit_lock_recovery: 3038c2ecf20Sopenharmony_ci return ret_val; 3048c2ecf20Sopenharmony_ci} 3058c2ecf20Sopenharmony_ci 3068c2ecf20Sopenharmony_ci#define QLA83XX_DRV_LOCK_MSLEEP 200 3078c2ecf20Sopenharmony_ci 3088c2ecf20Sopenharmony_ciint qla4_83xx_drv_lock(struct scsi_qla_host *ha) 3098c2ecf20Sopenharmony_ci{ 3108c2ecf20Sopenharmony_ci int timeout = 0; 3118c2ecf20Sopenharmony_ci uint32_t status = 0; 3128c2ecf20Sopenharmony_ci int ret_val = QLA_SUCCESS; 3138c2ecf20Sopenharmony_ci uint32_t first_owner = 0; 3148c2ecf20Sopenharmony_ci uint32_t tmo_owner = 0; 3158c2ecf20Sopenharmony_ci uint32_t lock_id; 3168c2ecf20Sopenharmony_ci uint32_t func_num; 3178c2ecf20Sopenharmony_ci uint32_t lock_cnt; 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_ci while (status == 0) { 3208c2ecf20Sopenharmony_ci status = qla4_83xx_rd_reg(ha, QLA83XX_DRV_LOCK); 3218c2ecf20Sopenharmony_ci if (status) { 3228c2ecf20Sopenharmony_ci /* Increment Counter (8-31) and update func_num (0-7) on 3238c2ecf20Sopenharmony_ci * getting a successful lock */ 3248c2ecf20Sopenharmony_ci lock_id = qla4_83xx_rd_reg(ha, QLA83XX_DRV_LOCK_ID); 3258c2ecf20Sopenharmony_ci lock_id = ((lock_id + (1 << 8)) & ~0xFF) | ha->func_num; 3268c2ecf20Sopenharmony_ci qla4_83xx_wr_reg(ha, QLA83XX_DRV_LOCK_ID, lock_id); 3278c2ecf20Sopenharmony_ci break; 3288c2ecf20Sopenharmony_ci } 3298c2ecf20Sopenharmony_ci 3308c2ecf20Sopenharmony_ci if (timeout == 0) 3318c2ecf20Sopenharmony_ci /* Save counter + ID of function holding the lock for 3328c2ecf20Sopenharmony_ci * first failure */ 3338c2ecf20Sopenharmony_ci first_owner = ha->isp_ops->rd_reg_direct(ha, 3348c2ecf20Sopenharmony_ci QLA83XX_DRV_LOCK_ID); 3358c2ecf20Sopenharmony_ci 3368c2ecf20Sopenharmony_ci if (++timeout >= 3378c2ecf20Sopenharmony_ci (QLA83XX_DRV_LOCK_TIMEOUT / QLA83XX_DRV_LOCK_MSLEEP)) { 3388c2ecf20Sopenharmony_ci tmo_owner = qla4_83xx_rd_reg(ha, QLA83XX_DRV_LOCK_ID); 3398c2ecf20Sopenharmony_ci func_num = tmo_owner & 0xFF; 3408c2ecf20Sopenharmony_ci lock_cnt = tmo_owner >> 8; 3418c2ecf20Sopenharmony_ci ql4_printk(KERN_INFO, ha, "%s: Lock by func %d failed after 2s, lock held by func %d, lock count %d, first_owner %d\n", 3428c2ecf20Sopenharmony_ci __func__, ha->func_num, func_num, lock_cnt, 3438c2ecf20Sopenharmony_ci (first_owner & 0xFF)); 3448c2ecf20Sopenharmony_ci 3458c2ecf20Sopenharmony_ci if (first_owner != tmo_owner) { 3468c2ecf20Sopenharmony_ci /* Some other driver got lock, OR same driver 3478c2ecf20Sopenharmony_ci * got lock again (counter value changed), when 3488c2ecf20Sopenharmony_ci * we were waiting for lock. 3498c2ecf20Sopenharmony_ci * Retry for another 2 sec */ 3508c2ecf20Sopenharmony_ci ql4_printk(KERN_INFO, ha, "%s: IDC lock failed for func %d\n", 3518c2ecf20Sopenharmony_ci __func__, ha->func_num); 3528c2ecf20Sopenharmony_ci timeout = 0; 3538c2ecf20Sopenharmony_ci } else { 3548c2ecf20Sopenharmony_ci /* Same driver holding lock > 2sec. 3558c2ecf20Sopenharmony_ci * Force Recovery */ 3568c2ecf20Sopenharmony_ci ret_val = qla4_83xx_lock_recovery(ha); 3578c2ecf20Sopenharmony_ci if (ret_val == QLA_SUCCESS) { 3588c2ecf20Sopenharmony_ci /* Recovered and got lock */ 3598c2ecf20Sopenharmony_ci ql4_printk(KERN_INFO, ha, "%s: IDC lock Recovery by %d successful\n", 3608c2ecf20Sopenharmony_ci __func__, ha->func_num); 3618c2ecf20Sopenharmony_ci break; 3628c2ecf20Sopenharmony_ci } 3638c2ecf20Sopenharmony_ci /* Recovery Failed, some other function 3648c2ecf20Sopenharmony_ci * has the lock, wait for 2secs and retry */ 3658c2ecf20Sopenharmony_ci ql4_printk(KERN_INFO, ha, "%s: IDC lock Recovery by %d failed, Retrying timeout\n", 3668c2ecf20Sopenharmony_ci __func__, ha->func_num); 3678c2ecf20Sopenharmony_ci timeout = 0; 3688c2ecf20Sopenharmony_ci } 3698c2ecf20Sopenharmony_ci } 3708c2ecf20Sopenharmony_ci msleep(QLA83XX_DRV_LOCK_MSLEEP); 3718c2ecf20Sopenharmony_ci } 3728c2ecf20Sopenharmony_ci 3738c2ecf20Sopenharmony_ci return ret_val; 3748c2ecf20Sopenharmony_ci} 3758c2ecf20Sopenharmony_ci 3768c2ecf20Sopenharmony_civoid qla4_83xx_drv_unlock(struct scsi_qla_host *ha) 3778c2ecf20Sopenharmony_ci{ 3788c2ecf20Sopenharmony_ci int id; 3798c2ecf20Sopenharmony_ci 3808c2ecf20Sopenharmony_ci id = qla4_83xx_rd_reg(ha, QLA83XX_DRV_LOCK_ID); 3818c2ecf20Sopenharmony_ci 3828c2ecf20Sopenharmony_ci if ((id & 0xFF) != ha->func_num) { 3838c2ecf20Sopenharmony_ci ql4_printk(KERN_ERR, ha, "%s: IDC Unlock by %d failed, lock owner is %d\n", 3848c2ecf20Sopenharmony_ci __func__, ha->func_num, (id & 0xFF)); 3858c2ecf20Sopenharmony_ci return; 3868c2ecf20Sopenharmony_ci } 3878c2ecf20Sopenharmony_ci 3888c2ecf20Sopenharmony_ci /* Keep lock counter value, update the ha->func_num to 0xFF */ 3898c2ecf20Sopenharmony_ci qla4_83xx_wr_reg(ha, QLA83XX_DRV_LOCK_ID, (id | 0xFF)); 3908c2ecf20Sopenharmony_ci qla4_83xx_rd_reg(ha, QLA83XX_DRV_UNLOCK); 3918c2ecf20Sopenharmony_ci} 3928c2ecf20Sopenharmony_ci 3938c2ecf20Sopenharmony_civoid qla4_83xx_set_idc_dontreset(struct scsi_qla_host *ha) 3948c2ecf20Sopenharmony_ci{ 3958c2ecf20Sopenharmony_ci uint32_t idc_ctrl; 3968c2ecf20Sopenharmony_ci 3978c2ecf20Sopenharmony_ci idc_ctrl = qla4_83xx_rd_reg(ha, QLA83XX_IDC_DRV_CTRL); 3988c2ecf20Sopenharmony_ci idc_ctrl |= DONTRESET_BIT0; 3998c2ecf20Sopenharmony_ci qla4_83xx_wr_reg(ha, QLA83XX_IDC_DRV_CTRL, idc_ctrl); 4008c2ecf20Sopenharmony_ci DEBUG2(ql4_printk(KERN_INFO, ha, "%s: idc_ctrl = %d\n", __func__, 4018c2ecf20Sopenharmony_ci idc_ctrl)); 4028c2ecf20Sopenharmony_ci} 4038c2ecf20Sopenharmony_ci 4048c2ecf20Sopenharmony_civoid qla4_83xx_clear_idc_dontreset(struct scsi_qla_host *ha) 4058c2ecf20Sopenharmony_ci{ 4068c2ecf20Sopenharmony_ci uint32_t idc_ctrl; 4078c2ecf20Sopenharmony_ci 4088c2ecf20Sopenharmony_ci idc_ctrl = qla4_83xx_rd_reg(ha, QLA83XX_IDC_DRV_CTRL); 4098c2ecf20Sopenharmony_ci idc_ctrl &= ~DONTRESET_BIT0; 4108c2ecf20Sopenharmony_ci qla4_83xx_wr_reg(ha, QLA83XX_IDC_DRV_CTRL, idc_ctrl); 4118c2ecf20Sopenharmony_ci DEBUG2(ql4_printk(KERN_INFO, ha, "%s: idc_ctrl = %d\n", __func__, 4128c2ecf20Sopenharmony_ci idc_ctrl)); 4138c2ecf20Sopenharmony_ci} 4148c2ecf20Sopenharmony_ci 4158c2ecf20Sopenharmony_ciint qla4_83xx_idc_dontreset(struct scsi_qla_host *ha) 4168c2ecf20Sopenharmony_ci{ 4178c2ecf20Sopenharmony_ci uint32_t idc_ctrl; 4188c2ecf20Sopenharmony_ci 4198c2ecf20Sopenharmony_ci idc_ctrl = qla4_83xx_rd_reg(ha, QLA83XX_IDC_DRV_CTRL); 4208c2ecf20Sopenharmony_ci return idc_ctrl & DONTRESET_BIT0; 4218c2ecf20Sopenharmony_ci} 4228c2ecf20Sopenharmony_ci 4238c2ecf20Sopenharmony_ci/*-------------------------IDC State Machine ---------------------*/ 4248c2ecf20Sopenharmony_ci 4258c2ecf20Sopenharmony_cienum { 4268c2ecf20Sopenharmony_ci UNKNOWN_CLASS = 0, 4278c2ecf20Sopenharmony_ci NIC_CLASS, 4288c2ecf20Sopenharmony_ci FCOE_CLASS, 4298c2ecf20Sopenharmony_ci ISCSI_CLASS 4308c2ecf20Sopenharmony_ci}; 4318c2ecf20Sopenharmony_ci 4328c2ecf20Sopenharmony_cistruct device_info { 4338c2ecf20Sopenharmony_ci int func_num; 4348c2ecf20Sopenharmony_ci int device_type; 4358c2ecf20Sopenharmony_ci int port_num; 4368c2ecf20Sopenharmony_ci}; 4378c2ecf20Sopenharmony_ci 4388c2ecf20Sopenharmony_ciint qla4_83xx_can_perform_reset(struct scsi_qla_host *ha) 4398c2ecf20Sopenharmony_ci{ 4408c2ecf20Sopenharmony_ci uint32_t drv_active; 4418c2ecf20Sopenharmony_ci uint32_t dev_part, dev_part1, dev_part2; 4428c2ecf20Sopenharmony_ci int i; 4438c2ecf20Sopenharmony_ci struct device_info device_map[16]; 4448c2ecf20Sopenharmony_ci int func_nibble; 4458c2ecf20Sopenharmony_ci int nibble; 4468c2ecf20Sopenharmony_ci int nic_present = 0; 4478c2ecf20Sopenharmony_ci int iscsi_present = 0; 4488c2ecf20Sopenharmony_ci int iscsi_func_low = 0; 4498c2ecf20Sopenharmony_ci 4508c2ecf20Sopenharmony_ci /* Use the dev_partition register to determine the PCI function number 4518c2ecf20Sopenharmony_ci * and then check drv_active register to see which driver is loaded */ 4528c2ecf20Sopenharmony_ci dev_part1 = qla4_83xx_rd_reg(ha, 4538c2ecf20Sopenharmony_ci ha->reg_tbl[QLA8XXX_CRB_DEV_PART_INFO]); 4548c2ecf20Sopenharmony_ci dev_part2 = qla4_83xx_rd_reg(ha, QLA83XX_CRB_DEV_PART_INFO2); 4558c2ecf20Sopenharmony_ci drv_active = qla4_83xx_rd_reg(ha, ha->reg_tbl[QLA8XXX_CRB_DRV_ACTIVE]); 4568c2ecf20Sopenharmony_ci 4578c2ecf20Sopenharmony_ci /* Each function has 4 bits in dev_partition Info register, 4588c2ecf20Sopenharmony_ci * Lower 2 bits - device type, Upper 2 bits - physical port number */ 4598c2ecf20Sopenharmony_ci dev_part = dev_part1; 4608c2ecf20Sopenharmony_ci for (i = nibble = 0; i <= 15; i++, nibble++) { 4618c2ecf20Sopenharmony_ci func_nibble = dev_part & (0xF << (nibble * 4)); 4628c2ecf20Sopenharmony_ci func_nibble >>= (nibble * 4); 4638c2ecf20Sopenharmony_ci device_map[i].func_num = i; 4648c2ecf20Sopenharmony_ci device_map[i].device_type = func_nibble & 0x3; 4658c2ecf20Sopenharmony_ci device_map[i].port_num = func_nibble & 0xC; 4668c2ecf20Sopenharmony_ci 4678c2ecf20Sopenharmony_ci if (device_map[i].device_type == NIC_CLASS) { 4688c2ecf20Sopenharmony_ci if (drv_active & (1 << device_map[i].func_num)) { 4698c2ecf20Sopenharmony_ci nic_present++; 4708c2ecf20Sopenharmony_ci break; 4718c2ecf20Sopenharmony_ci } 4728c2ecf20Sopenharmony_ci } else if (device_map[i].device_type == ISCSI_CLASS) { 4738c2ecf20Sopenharmony_ci if (drv_active & (1 << device_map[i].func_num)) { 4748c2ecf20Sopenharmony_ci if (!iscsi_present || 4758c2ecf20Sopenharmony_ci (iscsi_present && 4768c2ecf20Sopenharmony_ci (iscsi_func_low > device_map[i].func_num))) 4778c2ecf20Sopenharmony_ci iscsi_func_low = device_map[i].func_num; 4788c2ecf20Sopenharmony_ci 4798c2ecf20Sopenharmony_ci iscsi_present++; 4808c2ecf20Sopenharmony_ci } 4818c2ecf20Sopenharmony_ci } 4828c2ecf20Sopenharmony_ci 4838c2ecf20Sopenharmony_ci /* For function_num[8..15] get info from dev_part2 register */ 4848c2ecf20Sopenharmony_ci if (nibble == 7) { 4858c2ecf20Sopenharmony_ci nibble = 0; 4868c2ecf20Sopenharmony_ci dev_part = dev_part2; 4878c2ecf20Sopenharmony_ci } 4888c2ecf20Sopenharmony_ci } 4898c2ecf20Sopenharmony_ci 4908c2ecf20Sopenharmony_ci /* NIC, iSCSI and FCOE are the Reset owners based on order, NIC gets 4918c2ecf20Sopenharmony_ci * precedence over iSCSI and FCOE and iSCSI over FCOE, based on drivers 4928c2ecf20Sopenharmony_ci * present. */ 4938c2ecf20Sopenharmony_ci if (!nic_present && (ha->func_num == iscsi_func_low)) { 4948c2ecf20Sopenharmony_ci DEBUG2(ql4_printk(KERN_INFO, ha, 4958c2ecf20Sopenharmony_ci "%s: can reset - NIC not present and lower iSCSI function is %d\n", 4968c2ecf20Sopenharmony_ci __func__, ha->func_num)); 4978c2ecf20Sopenharmony_ci return 1; 4988c2ecf20Sopenharmony_ci } 4998c2ecf20Sopenharmony_ci 5008c2ecf20Sopenharmony_ci return 0; 5018c2ecf20Sopenharmony_ci} 5028c2ecf20Sopenharmony_ci 5038c2ecf20Sopenharmony_ci/** 5048c2ecf20Sopenharmony_ci * qla4_83xx_need_reset_handler - Code to start reset sequence 5058c2ecf20Sopenharmony_ci * @ha: pointer to adapter structure 5068c2ecf20Sopenharmony_ci * 5078c2ecf20Sopenharmony_ci * Note: IDC lock must be held upon entry 5088c2ecf20Sopenharmony_ci **/ 5098c2ecf20Sopenharmony_civoid qla4_83xx_need_reset_handler(struct scsi_qla_host *ha) 5108c2ecf20Sopenharmony_ci{ 5118c2ecf20Sopenharmony_ci uint32_t dev_state, drv_state, drv_active; 5128c2ecf20Sopenharmony_ci unsigned long reset_timeout, dev_init_timeout; 5138c2ecf20Sopenharmony_ci 5148c2ecf20Sopenharmony_ci ql4_printk(KERN_INFO, ha, "%s: Performing ISP error recovery\n", 5158c2ecf20Sopenharmony_ci __func__); 5168c2ecf20Sopenharmony_ci 5178c2ecf20Sopenharmony_ci if (!test_bit(AF_8XXX_RST_OWNER, &ha->flags)) { 5188c2ecf20Sopenharmony_ci DEBUG2(ql4_printk(KERN_INFO, ha, "%s: reset acknowledged\n", 5198c2ecf20Sopenharmony_ci __func__)); 5208c2ecf20Sopenharmony_ci qla4_8xxx_set_rst_ready(ha); 5218c2ecf20Sopenharmony_ci 5228c2ecf20Sopenharmony_ci /* Non-reset owners ACK Reset and wait for device INIT state 5238c2ecf20Sopenharmony_ci * as part of Reset Recovery by Reset Owner */ 5248c2ecf20Sopenharmony_ci dev_init_timeout = jiffies + (ha->nx_dev_init_timeout * HZ); 5258c2ecf20Sopenharmony_ci 5268c2ecf20Sopenharmony_ci do { 5278c2ecf20Sopenharmony_ci if (time_after_eq(jiffies, dev_init_timeout)) { 5288c2ecf20Sopenharmony_ci ql4_printk(KERN_INFO, ha, "%s: Non Reset owner dev init timeout\n", 5298c2ecf20Sopenharmony_ci __func__); 5308c2ecf20Sopenharmony_ci break; 5318c2ecf20Sopenharmony_ci } 5328c2ecf20Sopenharmony_ci 5338c2ecf20Sopenharmony_ci ha->isp_ops->idc_unlock(ha); 5348c2ecf20Sopenharmony_ci msleep(1000); 5358c2ecf20Sopenharmony_ci ha->isp_ops->idc_lock(ha); 5368c2ecf20Sopenharmony_ci 5378c2ecf20Sopenharmony_ci dev_state = qla4_8xxx_rd_direct(ha, 5388c2ecf20Sopenharmony_ci QLA8XXX_CRB_DEV_STATE); 5398c2ecf20Sopenharmony_ci } while (dev_state == QLA8XXX_DEV_NEED_RESET); 5408c2ecf20Sopenharmony_ci } else { 5418c2ecf20Sopenharmony_ci qla4_8xxx_set_rst_ready(ha); 5428c2ecf20Sopenharmony_ci reset_timeout = jiffies + (ha->nx_reset_timeout * HZ); 5438c2ecf20Sopenharmony_ci drv_state = qla4_8xxx_rd_direct(ha, QLA8XXX_CRB_DRV_STATE); 5448c2ecf20Sopenharmony_ci drv_active = qla4_8xxx_rd_direct(ha, QLA8XXX_CRB_DRV_ACTIVE); 5458c2ecf20Sopenharmony_ci 5468c2ecf20Sopenharmony_ci ql4_printk(KERN_INFO, ha, "%s: drv_state = 0x%x, drv_active = 0x%x\n", 5478c2ecf20Sopenharmony_ci __func__, drv_state, drv_active); 5488c2ecf20Sopenharmony_ci 5498c2ecf20Sopenharmony_ci while (drv_state != drv_active) { 5508c2ecf20Sopenharmony_ci if (time_after_eq(jiffies, reset_timeout)) { 5518c2ecf20Sopenharmony_ci ql4_printk(KERN_INFO, ha, "%s: %s: RESET TIMEOUT! drv_state: 0x%08x, drv_active: 0x%08x\n", 5528c2ecf20Sopenharmony_ci __func__, DRIVER_NAME, drv_state, 5538c2ecf20Sopenharmony_ci drv_active); 5548c2ecf20Sopenharmony_ci break; 5558c2ecf20Sopenharmony_ci } 5568c2ecf20Sopenharmony_ci 5578c2ecf20Sopenharmony_ci ha->isp_ops->idc_unlock(ha); 5588c2ecf20Sopenharmony_ci msleep(1000); 5598c2ecf20Sopenharmony_ci ha->isp_ops->idc_lock(ha); 5608c2ecf20Sopenharmony_ci 5618c2ecf20Sopenharmony_ci drv_state = qla4_8xxx_rd_direct(ha, 5628c2ecf20Sopenharmony_ci QLA8XXX_CRB_DRV_STATE); 5638c2ecf20Sopenharmony_ci drv_active = qla4_8xxx_rd_direct(ha, 5648c2ecf20Sopenharmony_ci QLA8XXX_CRB_DRV_ACTIVE); 5658c2ecf20Sopenharmony_ci } 5668c2ecf20Sopenharmony_ci 5678c2ecf20Sopenharmony_ci if (drv_state != drv_active) { 5688c2ecf20Sopenharmony_ci ql4_printk(KERN_INFO, ha, "%s: Reset_owner turning off drv_active of non-acking function 0x%x\n", 5698c2ecf20Sopenharmony_ci __func__, (drv_active ^ drv_state)); 5708c2ecf20Sopenharmony_ci drv_active = drv_active & drv_state; 5718c2ecf20Sopenharmony_ci qla4_8xxx_wr_direct(ha, QLA8XXX_CRB_DRV_ACTIVE, 5728c2ecf20Sopenharmony_ci drv_active); 5738c2ecf20Sopenharmony_ci } 5748c2ecf20Sopenharmony_ci 5758c2ecf20Sopenharmony_ci clear_bit(AF_8XXX_RST_OWNER, &ha->flags); 5768c2ecf20Sopenharmony_ci /* Start Reset Recovery */ 5778c2ecf20Sopenharmony_ci qla4_8xxx_device_bootstrap(ha); 5788c2ecf20Sopenharmony_ci } 5798c2ecf20Sopenharmony_ci} 5808c2ecf20Sopenharmony_ci 5818c2ecf20Sopenharmony_civoid qla4_83xx_get_idc_param(struct scsi_qla_host *ha) 5828c2ecf20Sopenharmony_ci{ 5838c2ecf20Sopenharmony_ci uint32_t idc_params, ret_val; 5848c2ecf20Sopenharmony_ci 5858c2ecf20Sopenharmony_ci ret_val = qla4_83xx_flash_read_u32(ha, QLA83XX_IDC_PARAM_ADDR, 5868c2ecf20Sopenharmony_ci (uint8_t *)&idc_params, 1); 5878c2ecf20Sopenharmony_ci if (ret_val == QLA_SUCCESS) { 5888c2ecf20Sopenharmony_ci ha->nx_dev_init_timeout = idc_params & 0xFFFF; 5898c2ecf20Sopenharmony_ci ha->nx_reset_timeout = (idc_params >> 16) & 0xFFFF; 5908c2ecf20Sopenharmony_ci } else { 5918c2ecf20Sopenharmony_ci ha->nx_dev_init_timeout = ROM_DEV_INIT_TIMEOUT; 5928c2ecf20Sopenharmony_ci ha->nx_reset_timeout = ROM_DRV_RESET_ACK_TIMEOUT; 5938c2ecf20Sopenharmony_ci } 5948c2ecf20Sopenharmony_ci 5958c2ecf20Sopenharmony_ci DEBUG2(ql4_printk(KERN_DEBUG, ha, 5968c2ecf20Sopenharmony_ci "%s: ha->nx_dev_init_timeout = %d, ha->nx_reset_timeout = %d\n", 5978c2ecf20Sopenharmony_ci __func__, ha->nx_dev_init_timeout, 5988c2ecf20Sopenharmony_ci ha->nx_reset_timeout)); 5998c2ecf20Sopenharmony_ci} 6008c2ecf20Sopenharmony_ci 6018c2ecf20Sopenharmony_ci/*-------------------------Reset Sequence Functions-----------------------*/ 6028c2ecf20Sopenharmony_ci 6038c2ecf20Sopenharmony_cistatic void qla4_83xx_dump_reset_seq_hdr(struct scsi_qla_host *ha) 6048c2ecf20Sopenharmony_ci{ 6058c2ecf20Sopenharmony_ci uint8_t *phdr; 6068c2ecf20Sopenharmony_ci 6078c2ecf20Sopenharmony_ci if (!ha->reset_tmplt.buff) { 6088c2ecf20Sopenharmony_ci ql4_printk(KERN_ERR, ha, "%s: Error: Invalid reset_seq_template\n", 6098c2ecf20Sopenharmony_ci __func__); 6108c2ecf20Sopenharmony_ci return; 6118c2ecf20Sopenharmony_ci } 6128c2ecf20Sopenharmony_ci 6138c2ecf20Sopenharmony_ci phdr = ha->reset_tmplt.buff; 6148c2ecf20Sopenharmony_ci 6158c2ecf20Sopenharmony_ci DEBUG2(ql4_printk(KERN_INFO, ha, 6168c2ecf20Sopenharmony_ci "Reset Template: 0x%X 0x%X 0x%X 0x%X 0x%X 0x%X 0x%X 0x%X 0x%X 0x%X 0x%X 0x%X 0x%X 0x%X 0x%X 0x%X\n", 6178c2ecf20Sopenharmony_ci *phdr, *(phdr+1), *(phdr+2), *(phdr+3), *(phdr+4), 6188c2ecf20Sopenharmony_ci *(phdr+5), *(phdr+6), *(phdr+7), *(phdr + 8), 6198c2ecf20Sopenharmony_ci *(phdr+9), *(phdr+10), *(phdr+11), *(phdr+12), 6208c2ecf20Sopenharmony_ci *(phdr+13), *(phdr+14), *(phdr+15))); 6218c2ecf20Sopenharmony_ci} 6228c2ecf20Sopenharmony_ci 6238c2ecf20Sopenharmony_cistatic int qla4_83xx_copy_bootloader(struct scsi_qla_host *ha) 6248c2ecf20Sopenharmony_ci{ 6258c2ecf20Sopenharmony_ci uint8_t *p_cache; 6268c2ecf20Sopenharmony_ci uint32_t src, count, size; 6278c2ecf20Sopenharmony_ci uint64_t dest; 6288c2ecf20Sopenharmony_ci int ret_val = QLA_SUCCESS; 6298c2ecf20Sopenharmony_ci 6308c2ecf20Sopenharmony_ci src = QLA83XX_BOOTLOADER_FLASH_ADDR; 6318c2ecf20Sopenharmony_ci dest = qla4_83xx_rd_reg(ha, QLA83XX_BOOTLOADER_ADDR); 6328c2ecf20Sopenharmony_ci size = qla4_83xx_rd_reg(ha, QLA83XX_BOOTLOADER_SIZE); 6338c2ecf20Sopenharmony_ci 6348c2ecf20Sopenharmony_ci /* 128 bit alignment check */ 6358c2ecf20Sopenharmony_ci if (size & 0xF) 6368c2ecf20Sopenharmony_ci size = (size + 16) & ~0xF; 6378c2ecf20Sopenharmony_ci 6388c2ecf20Sopenharmony_ci /* 16 byte count */ 6398c2ecf20Sopenharmony_ci count = size/16; 6408c2ecf20Sopenharmony_ci 6418c2ecf20Sopenharmony_ci p_cache = vmalloc(size); 6428c2ecf20Sopenharmony_ci if (p_cache == NULL) { 6438c2ecf20Sopenharmony_ci ql4_printk(KERN_ERR, ha, "%s: Failed to allocate memory for boot loader cache\n", 6448c2ecf20Sopenharmony_ci __func__); 6458c2ecf20Sopenharmony_ci ret_val = QLA_ERROR; 6468c2ecf20Sopenharmony_ci goto exit_copy_bootloader; 6478c2ecf20Sopenharmony_ci } 6488c2ecf20Sopenharmony_ci 6498c2ecf20Sopenharmony_ci ret_val = qla4_83xx_lockless_flash_read_u32(ha, src, p_cache, 6508c2ecf20Sopenharmony_ci size / sizeof(uint32_t)); 6518c2ecf20Sopenharmony_ci if (ret_val == QLA_ERROR) { 6528c2ecf20Sopenharmony_ci ql4_printk(KERN_ERR, ha, "%s: Error reading firmware from flash\n", 6538c2ecf20Sopenharmony_ci __func__); 6548c2ecf20Sopenharmony_ci goto exit_copy_error; 6558c2ecf20Sopenharmony_ci } 6568c2ecf20Sopenharmony_ci DEBUG2(ql4_printk(KERN_INFO, ha, "%s: Read firmware from flash\n", 6578c2ecf20Sopenharmony_ci __func__)); 6588c2ecf20Sopenharmony_ci 6598c2ecf20Sopenharmony_ci /* 128 bit/16 byte write to MS memory */ 6608c2ecf20Sopenharmony_ci ret_val = qla4_8xxx_ms_mem_write_128b(ha, dest, (uint32_t *)p_cache, 6618c2ecf20Sopenharmony_ci count); 6628c2ecf20Sopenharmony_ci if (ret_val == QLA_ERROR) { 6638c2ecf20Sopenharmony_ci ql4_printk(KERN_ERR, ha, "%s: Error writing firmware to MS\n", 6648c2ecf20Sopenharmony_ci __func__); 6658c2ecf20Sopenharmony_ci goto exit_copy_error; 6668c2ecf20Sopenharmony_ci } 6678c2ecf20Sopenharmony_ci 6688c2ecf20Sopenharmony_ci DEBUG2(ql4_printk(KERN_INFO, ha, "%s: Wrote firmware size %d to MS\n", 6698c2ecf20Sopenharmony_ci __func__, size)); 6708c2ecf20Sopenharmony_ci 6718c2ecf20Sopenharmony_ciexit_copy_error: 6728c2ecf20Sopenharmony_ci vfree(p_cache); 6738c2ecf20Sopenharmony_ci 6748c2ecf20Sopenharmony_ciexit_copy_bootloader: 6758c2ecf20Sopenharmony_ci return ret_val; 6768c2ecf20Sopenharmony_ci} 6778c2ecf20Sopenharmony_ci 6788c2ecf20Sopenharmony_cistatic int qla4_83xx_check_cmd_peg_status(struct scsi_qla_host *ha) 6798c2ecf20Sopenharmony_ci{ 6808c2ecf20Sopenharmony_ci uint32_t val, ret_val = QLA_ERROR; 6818c2ecf20Sopenharmony_ci int retries = CRB_CMDPEG_CHECK_RETRY_COUNT; 6828c2ecf20Sopenharmony_ci 6838c2ecf20Sopenharmony_ci do { 6848c2ecf20Sopenharmony_ci val = qla4_83xx_rd_reg(ha, QLA83XX_CMDPEG_STATE); 6858c2ecf20Sopenharmony_ci if (val == PHAN_INITIALIZE_COMPLETE) { 6868c2ecf20Sopenharmony_ci DEBUG2(ql4_printk(KERN_INFO, ha, 6878c2ecf20Sopenharmony_ci "%s: Command Peg initialization complete. State=0x%x\n", 6888c2ecf20Sopenharmony_ci __func__, val)); 6898c2ecf20Sopenharmony_ci ret_val = QLA_SUCCESS; 6908c2ecf20Sopenharmony_ci break; 6918c2ecf20Sopenharmony_ci } 6928c2ecf20Sopenharmony_ci msleep(CRB_CMDPEG_CHECK_DELAY); 6938c2ecf20Sopenharmony_ci } while (--retries); 6948c2ecf20Sopenharmony_ci 6958c2ecf20Sopenharmony_ci return ret_val; 6968c2ecf20Sopenharmony_ci} 6978c2ecf20Sopenharmony_ci 6988c2ecf20Sopenharmony_ci/** 6998c2ecf20Sopenharmony_ci * qla4_83xx_poll_reg - Poll the given CRB addr for duration msecs till 7008c2ecf20Sopenharmony_ci * value read ANDed with test_mask is equal to test_result. 7018c2ecf20Sopenharmony_ci * 7028c2ecf20Sopenharmony_ci * @ha : Pointer to adapter structure 7038c2ecf20Sopenharmony_ci * @addr : CRB register address 7048c2ecf20Sopenharmony_ci * @duration : Poll for total of "duration" msecs 7058c2ecf20Sopenharmony_ci * @test_mask : Mask value read with "test_mask" 7068c2ecf20Sopenharmony_ci * @test_result : Compare (value&test_mask) with test_result. 7078c2ecf20Sopenharmony_ci **/ 7088c2ecf20Sopenharmony_cistatic int qla4_83xx_poll_reg(struct scsi_qla_host *ha, uint32_t addr, 7098c2ecf20Sopenharmony_ci int duration, uint32_t test_mask, 7108c2ecf20Sopenharmony_ci uint32_t test_result) 7118c2ecf20Sopenharmony_ci{ 7128c2ecf20Sopenharmony_ci uint32_t value; 7138c2ecf20Sopenharmony_ci uint8_t retries; 7148c2ecf20Sopenharmony_ci int ret_val = QLA_SUCCESS; 7158c2ecf20Sopenharmony_ci 7168c2ecf20Sopenharmony_ci ret_val = qla4_83xx_rd_reg_indirect(ha, addr, &value); 7178c2ecf20Sopenharmony_ci if (ret_val == QLA_ERROR) 7188c2ecf20Sopenharmony_ci goto exit_poll_reg; 7198c2ecf20Sopenharmony_ci 7208c2ecf20Sopenharmony_ci retries = duration / 10; 7218c2ecf20Sopenharmony_ci do { 7228c2ecf20Sopenharmony_ci if ((value & test_mask) != test_result) { 7238c2ecf20Sopenharmony_ci msleep(duration / 10); 7248c2ecf20Sopenharmony_ci ret_val = qla4_83xx_rd_reg_indirect(ha, addr, &value); 7258c2ecf20Sopenharmony_ci if (ret_val == QLA_ERROR) 7268c2ecf20Sopenharmony_ci goto exit_poll_reg; 7278c2ecf20Sopenharmony_ci 7288c2ecf20Sopenharmony_ci ret_val = QLA_ERROR; 7298c2ecf20Sopenharmony_ci } else { 7308c2ecf20Sopenharmony_ci ret_val = QLA_SUCCESS; 7318c2ecf20Sopenharmony_ci break; 7328c2ecf20Sopenharmony_ci } 7338c2ecf20Sopenharmony_ci } while (retries--); 7348c2ecf20Sopenharmony_ci 7358c2ecf20Sopenharmony_ciexit_poll_reg: 7368c2ecf20Sopenharmony_ci if (ret_val == QLA_ERROR) { 7378c2ecf20Sopenharmony_ci ha->reset_tmplt.seq_error++; 7388c2ecf20Sopenharmony_ci ql4_printk(KERN_ERR, ha, "%s: Poll Failed: 0x%08x 0x%08x 0x%08x\n", 7398c2ecf20Sopenharmony_ci __func__, value, test_mask, test_result); 7408c2ecf20Sopenharmony_ci } 7418c2ecf20Sopenharmony_ci 7428c2ecf20Sopenharmony_ci return ret_val; 7438c2ecf20Sopenharmony_ci} 7448c2ecf20Sopenharmony_ci 7458c2ecf20Sopenharmony_cistatic int qla4_83xx_reset_seq_checksum_test(struct scsi_qla_host *ha) 7468c2ecf20Sopenharmony_ci{ 7478c2ecf20Sopenharmony_ci uint32_t sum = 0; 7488c2ecf20Sopenharmony_ci uint16_t *buff = (uint16_t *)ha->reset_tmplt.buff; 7498c2ecf20Sopenharmony_ci int u16_count = ha->reset_tmplt.hdr->size / sizeof(uint16_t); 7508c2ecf20Sopenharmony_ci int ret_val; 7518c2ecf20Sopenharmony_ci 7528c2ecf20Sopenharmony_ci while (u16_count-- > 0) 7538c2ecf20Sopenharmony_ci sum += *buff++; 7548c2ecf20Sopenharmony_ci 7558c2ecf20Sopenharmony_ci while (sum >> 16) 7568c2ecf20Sopenharmony_ci sum = (sum & 0xFFFF) + (sum >> 16); 7578c2ecf20Sopenharmony_ci 7588c2ecf20Sopenharmony_ci /* checksum of 0 indicates a valid template */ 7598c2ecf20Sopenharmony_ci if (~sum) { 7608c2ecf20Sopenharmony_ci ret_val = QLA_SUCCESS; 7618c2ecf20Sopenharmony_ci } else { 7628c2ecf20Sopenharmony_ci ql4_printk(KERN_ERR, ha, "%s: Reset seq checksum failed\n", 7638c2ecf20Sopenharmony_ci __func__); 7648c2ecf20Sopenharmony_ci ret_val = QLA_ERROR; 7658c2ecf20Sopenharmony_ci } 7668c2ecf20Sopenharmony_ci 7678c2ecf20Sopenharmony_ci return ret_val; 7688c2ecf20Sopenharmony_ci} 7698c2ecf20Sopenharmony_ci 7708c2ecf20Sopenharmony_ci/** 7718c2ecf20Sopenharmony_ci * qla4_83xx_read_reset_template - Read Reset Template from Flash 7728c2ecf20Sopenharmony_ci * @ha: Pointer to adapter structure 7738c2ecf20Sopenharmony_ci **/ 7748c2ecf20Sopenharmony_civoid qla4_83xx_read_reset_template(struct scsi_qla_host *ha) 7758c2ecf20Sopenharmony_ci{ 7768c2ecf20Sopenharmony_ci uint8_t *p_buff; 7778c2ecf20Sopenharmony_ci uint32_t addr, tmplt_hdr_def_size, tmplt_hdr_size; 7788c2ecf20Sopenharmony_ci uint32_t ret_val; 7798c2ecf20Sopenharmony_ci 7808c2ecf20Sopenharmony_ci ha->reset_tmplt.seq_error = 0; 7818c2ecf20Sopenharmony_ci ha->reset_tmplt.buff = vmalloc(QLA83XX_RESTART_TEMPLATE_SIZE); 7828c2ecf20Sopenharmony_ci if (ha->reset_tmplt.buff == NULL) { 7838c2ecf20Sopenharmony_ci ql4_printk(KERN_ERR, ha, "%s: Failed to allocate reset template resources\n", 7848c2ecf20Sopenharmony_ci __func__); 7858c2ecf20Sopenharmony_ci goto exit_read_reset_template; 7868c2ecf20Sopenharmony_ci } 7878c2ecf20Sopenharmony_ci 7888c2ecf20Sopenharmony_ci p_buff = ha->reset_tmplt.buff; 7898c2ecf20Sopenharmony_ci addr = QLA83XX_RESET_TEMPLATE_ADDR; 7908c2ecf20Sopenharmony_ci 7918c2ecf20Sopenharmony_ci tmplt_hdr_def_size = sizeof(struct qla4_83xx_reset_template_hdr) / 7928c2ecf20Sopenharmony_ci sizeof(uint32_t); 7938c2ecf20Sopenharmony_ci 7948c2ecf20Sopenharmony_ci DEBUG2(ql4_printk(KERN_INFO, ha, 7958c2ecf20Sopenharmony_ci "%s: Read template hdr size %d from Flash\n", 7968c2ecf20Sopenharmony_ci __func__, tmplt_hdr_def_size)); 7978c2ecf20Sopenharmony_ci 7988c2ecf20Sopenharmony_ci /* Copy template header from flash */ 7998c2ecf20Sopenharmony_ci ret_val = qla4_83xx_flash_read_u32(ha, addr, p_buff, 8008c2ecf20Sopenharmony_ci tmplt_hdr_def_size); 8018c2ecf20Sopenharmony_ci if (ret_val != QLA_SUCCESS) { 8028c2ecf20Sopenharmony_ci ql4_printk(KERN_ERR, ha, "%s: Failed to read reset template\n", 8038c2ecf20Sopenharmony_ci __func__); 8048c2ecf20Sopenharmony_ci goto exit_read_template_error; 8058c2ecf20Sopenharmony_ci } 8068c2ecf20Sopenharmony_ci 8078c2ecf20Sopenharmony_ci ha->reset_tmplt.hdr = 8088c2ecf20Sopenharmony_ci (struct qla4_83xx_reset_template_hdr *)ha->reset_tmplt.buff; 8098c2ecf20Sopenharmony_ci 8108c2ecf20Sopenharmony_ci /* Validate the template header size and signature */ 8118c2ecf20Sopenharmony_ci tmplt_hdr_size = ha->reset_tmplt.hdr->hdr_size/sizeof(uint32_t); 8128c2ecf20Sopenharmony_ci if ((tmplt_hdr_size != tmplt_hdr_def_size) || 8138c2ecf20Sopenharmony_ci (ha->reset_tmplt.hdr->signature != RESET_TMPLT_HDR_SIGNATURE)) { 8148c2ecf20Sopenharmony_ci ql4_printk(KERN_ERR, ha, "%s: Template Header size %d is invalid, tmplt_hdr_def_size %d\n", 8158c2ecf20Sopenharmony_ci __func__, tmplt_hdr_size, tmplt_hdr_def_size); 8168c2ecf20Sopenharmony_ci goto exit_read_template_error; 8178c2ecf20Sopenharmony_ci } 8188c2ecf20Sopenharmony_ci 8198c2ecf20Sopenharmony_ci addr = QLA83XX_RESET_TEMPLATE_ADDR + ha->reset_tmplt.hdr->hdr_size; 8208c2ecf20Sopenharmony_ci p_buff = ha->reset_tmplt.buff + ha->reset_tmplt.hdr->hdr_size; 8218c2ecf20Sopenharmony_ci tmplt_hdr_def_size = (ha->reset_tmplt.hdr->size - 8228c2ecf20Sopenharmony_ci ha->reset_tmplt.hdr->hdr_size) / sizeof(uint32_t); 8238c2ecf20Sopenharmony_ci 8248c2ecf20Sopenharmony_ci DEBUG2(ql4_printk(KERN_INFO, ha, 8258c2ecf20Sopenharmony_ci "%s: Read rest of the template size %d\n", 8268c2ecf20Sopenharmony_ci __func__, ha->reset_tmplt.hdr->size)); 8278c2ecf20Sopenharmony_ci 8288c2ecf20Sopenharmony_ci /* Copy rest of the template */ 8298c2ecf20Sopenharmony_ci ret_val = qla4_83xx_flash_read_u32(ha, addr, p_buff, 8308c2ecf20Sopenharmony_ci tmplt_hdr_def_size); 8318c2ecf20Sopenharmony_ci if (ret_val != QLA_SUCCESS) { 8328c2ecf20Sopenharmony_ci ql4_printk(KERN_ERR, ha, "%s: Failed to read reset template\n", 8338c2ecf20Sopenharmony_ci __func__); 8348c2ecf20Sopenharmony_ci goto exit_read_template_error; 8358c2ecf20Sopenharmony_ci } 8368c2ecf20Sopenharmony_ci 8378c2ecf20Sopenharmony_ci /* Integrity check */ 8388c2ecf20Sopenharmony_ci if (qla4_83xx_reset_seq_checksum_test(ha)) { 8398c2ecf20Sopenharmony_ci ql4_printk(KERN_ERR, ha, "%s: Reset Seq checksum failed!\n", 8408c2ecf20Sopenharmony_ci __func__); 8418c2ecf20Sopenharmony_ci goto exit_read_template_error; 8428c2ecf20Sopenharmony_ci } 8438c2ecf20Sopenharmony_ci DEBUG2(ql4_printk(KERN_INFO, ha, 8448c2ecf20Sopenharmony_ci "%s: Reset Seq checksum passed, Get stop, start and init seq offsets\n", 8458c2ecf20Sopenharmony_ci __func__)); 8468c2ecf20Sopenharmony_ci 8478c2ecf20Sopenharmony_ci /* Get STOP, START, INIT sequence offsets */ 8488c2ecf20Sopenharmony_ci ha->reset_tmplt.init_offset = ha->reset_tmplt.buff + 8498c2ecf20Sopenharmony_ci ha->reset_tmplt.hdr->init_seq_offset; 8508c2ecf20Sopenharmony_ci ha->reset_tmplt.start_offset = ha->reset_tmplt.buff + 8518c2ecf20Sopenharmony_ci ha->reset_tmplt.hdr->start_seq_offset; 8528c2ecf20Sopenharmony_ci ha->reset_tmplt.stop_offset = ha->reset_tmplt.buff + 8538c2ecf20Sopenharmony_ci ha->reset_tmplt.hdr->hdr_size; 8548c2ecf20Sopenharmony_ci qla4_83xx_dump_reset_seq_hdr(ha); 8558c2ecf20Sopenharmony_ci 8568c2ecf20Sopenharmony_ci goto exit_read_reset_template; 8578c2ecf20Sopenharmony_ci 8588c2ecf20Sopenharmony_ciexit_read_template_error: 8598c2ecf20Sopenharmony_ci vfree(ha->reset_tmplt.buff); 8608c2ecf20Sopenharmony_ci 8618c2ecf20Sopenharmony_ciexit_read_reset_template: 8628c2ecf20Sopenharmony_ci return; 8638c2ecf20Sopenharmony_ci} 8648c2ecf20Sopenharmony_ci 8658c2ecf20Sopenharmony_ci/** 8668c2ecf20Sopenharmony_ci * qla4_83xx_read_write_crb_reg - Read from raddr and write value to waddr. 8678c2ecf20Sopenharmony_ci * 8688c2ecf20Sopenharmony_ci * @ha : Pointer to adapter structure 8698c2ecf20Sopenharmony_ci * @raddr : CRB address to read from 8708c2ecf20Sopenharmony_ci * @waddr : CRB address to write to 8718c2ecf20Sopenharmony_ci **/ 8728c2ecf20Sopenharmony_cistatic void qla4_83xx_read_write_crb_reg(struct scsi_qla_host *ha, 8738c2ecf20Sopenharmony_ci uint32_t raddr, uint32_t waddr) 8748c2ecf20Sopenharmony_ci{ 8758c2ecf20Sopenharmony_ci uint32_t value; 8768c2ecf20Sopenharmony_ci 8778c2ecf20Sopenharmony_ci qla4_83xx_rd_reg_indirect(ha, raddr, &value); 8788c2ecf20Sopenharmony_ci qla4_83xx_wr_reg_indirect(ha, waddr, value); 8798c2ecf20Sopenharmony_ci} 8808c2ecf20Sopenharmony_ci 8818c2ecf20Sopenharmony_ci/** 8828c2ecf20Sopenharmony_ci * qla4_83xx_rmw_crb_reg - Read Modify Write crb register 8838c2ecf20Sopenharmony_ci * 8848c2ecf20Sopenharmony_ci * This function read value from raddr, AND with test_mask, 8858c2ecf20Sopenharmony_ci * Shift Left,Right/OR/XOR with values RMW header and write value to waddr. 8868c2ecf20Sopenharmony_ci * 8878c2ecf20Sopenharmony_ci * @ha : Pointer to adapter structure 8888c2ecf20Sopenharmony_ci * @raddr : CRB address to read from 8898c2ecf20Sopenharmony_ci * @waddr : CRB address to write to 8908c2ecf20Sopenharmony_ci * @p_rmw_hdr : header with shift/or/xor values. 8918c2ecf20Sopenharmony_ci **/ 8928c2ecf20Sopenharmony_cistatic void qla4_83xx_rmw_crb_reg(struct scsi_qla_host *ha, uint32_t raddr, 8938c2ecf20Sopenharmony_ci uint32_t waddr, 8948c2ecf20Sopenharmony_ci struct qla4_83xx_rmw *p_rmw_hdr) 8958c2ecf20Sopenharmony_ci{ 8968c2ecf20Sopenharmony_ci uint32_t value; 8978c2ecf20Sopenharmony_ci 8988c2ecf20Sopenharmony_ci if (p_rmw_hdr->index_a) 8998c2ecf20Sopenharmony_ci value = ha->reset_tmplt.array[p_rmw_hdr->index_a]; 9008c2ecf20Sopenharmony_ci else 9018c2ecf20Sopenharmony_ci qla4_83xx_rd_reg_indirect(ha, raddr, &value); 9028c2ecf20Sopenharmony_ci 9038c2ecf20Sopenharmony_ci value &= p_rmw_hdr->test_mask; 9048c2ecf20Sopenharmony_ci value <<= p_rmw_hdr->shl; 9058c2ecf20Sopenharmony_ci value >>= p_rmw_hdr->shr; 9068c2ecf20Sopenharmony_ci value |= p_rmw_hdr->or_value; 9078c2ecf20Sopenharmony_ci value ^= p_rmw_hdr->xor_value; 9088c2ecf20Sopenharmony_ci 9098c2ecf20Sopenharmony_ci qla4_83xx_wr_reg_indirect(ha, waddr, value); 9108c2ecf20Sopenharmony_ci 9118c2ecf20Sopenharmony_ci return; 9128c2ecf20Sopenharmony_ci} 9138c2ecf20Sopenharmony_ci 9148c2ecf20Sopenharmony_cistatic void qla4_83xx_write_list(struct scsi_qla_host *ha, 9158c2ecf20Sopenharmony_ci struct qla4_83xx_reset_entry_hdr *p_hdr) 9168c2ecf20Sopenharmony_ci{ 9178c2ecf20Sopenharmony_ci struct qla4_83xx_entry *p_entry; 9188c2ecf20Sopenharmony_ci uint32_t i; 9198c2ecf20Sopenharmony_ci 9208c2ecf20Sopenharmony_ci p_entry = (struct qla4_83xx_entry *) 9218c2ecf20Sopenharmony_ci ((char *)p_hdr + sizeof(struct qla4_83xx_reset_entry_hdr)); 9228c2ecf20Sopenharmony_ci 9238c2ecf20Sopenharmony_ci for (i = 0; i < p_hdr->count; i++, p_entry++) { 9248c2ecf20Sopenharmony_ci qla4_83xx_wr_reg_indirect(ha, p_entry->arg1, p_entry->arg2); 9258c2ecf20Sopenharmony_ci if (p_hdr->delay) 9268c2ecf20Sopenharmony_ci udelay((uint32_t)(p_hdr->delay)); 9278c2ecf20Sopenharmony_ci } 9288c2ecf20Sopenharmony_ci} 9298c2ecf20Sopenharmony_ci 9308c2ecf20Sopenharmony_cistatic void qla4_83xx_read_write_list(struct scsi_qla_host *ha, 9318c2ecf20Sopenharmony_ci struct qla4_83xx_reset_entry_hdr *p_hdr) 9328c2ecf20Sopenharmony_ci{ 9338c2ecf20Sopenharmony_ci struct qla4_83xx_entry *p_entry; 9348c2ecf20Sopenharmony_ci uint32_t i; 9358c2ecf20Sopenharmony_ci 9368c2ecf20Sopenharmony_ci p_entry = (struct qla4_83xx_entry *) 9378c2ecf20Sopenharmony_ci ((char *)p_hdr + sizeof(struct qla4_83xx_reset_entry_hdr)); 9388c2ecf20Sopenharmony_ci 9398c2ecf20Sopenharmony_ci for (i = 0; i < p_hdr->count; i++, p_entry++) { 9408c2ecf20Sopenharmony_ci qla4_83xx_read_write_crb_reg(ha, p_entry->arg1, p_entry->arg2); 9418c2ecf20Sopenharmony_ci if (p_hdr->delay) 9428c2ecf20Sopenharmony_ci udelay((uint32_t)(p_hdr->delay)); 9438c2ecf20Sopenharmony_ci } 9448c2ecf20Sopenharmony_ci} 9458c2ecf20Sopenharmony_ci 9468c2ecf20Sopenharmony_cistatic void qla4_83xx_poll_list(struct scsi_qla_host *ha, 9478c2ecf20Sopenharmony_ci struct qla4_83xx_reset_entry_hdr *p_hdr) 9488c2ecf20Sopenharmony_ci{ 9498c2ecf20Sopenharmony_ci long delay; 9508c2ecf20Sopenharmony_ci struct qla4_83xx_entry *p_entry; 9518c2ecf20Sopenharmony_ci struct qla4_83xx_poll *p_poll; 9528c2ecf20Sopenharmony_ci uint32_t i; 9538c2ecf20Sopenharmony_ci uint32_t value; 9548c2ecf20Sopenharmony_ci 9558c2ecf20Sopenharmony_ci p_poll = (struct qla4_83xx_poll *) 9568c2ecf20Sopenharmony_ci ((char *)p_hdr + sizeof(struct qla4_83xx_reset_entry_hdr)); 9578c2ecf20Sopenharmony_ci 9588c2ecf20Sopenharmony_ci /* Entries start after 8 byte qla4_83xx_poll, poll header contains 9598c2ecf20Sopenharmony_ci * the test_mask, test_value. */ 9608c2ecf20Sopenharmony_ci p_entry = (struct qla4_83xx_entry *)((char *)p_poll + 9618c2ecf20Sopenharmony_ci sizeof(struct qla4_83xx_poll)); 9628c2ecf20Sopenharmony_ci 9638c2ecf20Sopenharmony_ci delay = (long)p_hdr->delay; 9648c2ecf20Sopenharmony_ci if (!delay) { 9658c2ecf20Sopenharmony_ci for (i = 0; i < p_hdr->count; i++, p_entry++) { 9668c2ecf20Sopenharmony_ci qla4_83xx_poll_reg(ha, p_entry->arg1, delay, 9678c2ecf20Sopenharmony_ci p_poll->test_mask, 9688c2ecf20Sopenharmony_ci p_poll->test_value); 9698c2ecf20Sopenharmony_ci } 9708c2ecf20Sopenharmony_ci } else { 9718c2ecf20Sopenharmony_ci for (i = 0; i < p_hdr->count; i++, p_entry++) { 9728c2ecf20Sopenharmony_ci if (qla4_83xx_poll_reg(ha, p_entry->arg1, delay, 9738c2ecf20Sopenharmony_ci p_poll->test_mask, 9748c2ecf20Sopenharmony_ci p_poll->test_value)) { 9758c2ecf20Sopenharmony_ci qla4_83xx_rd_reg_indirect(ha, p_entry->arg1, 9768c2ecf20Sopenharmony_ci &value); 9778c2ecf20Sopenharmony_ci qla4_83xx_rd_reg_indirect(ha, p_entry->arg2, 9788c2ecf20Sopenharmony_ci &value); 9798c2ecf20Sopenharmony_ci } 9808c2ecf20Sopenharmony_ci } 9818c2ecf20Sopenharmony_ci } 9828c2ecf20Sopenharmony_ci} 9838c2ecf20Sopenharmony_ci 9848c2ecf20Sopenharmony_cistatic void qla4_83xx_poll_write_list(struct scsi_qla_host *ha, 9858c2ecf20Sopenharmony_ci struct qla4_83xx_reset_entry_hdr *p_hdr) 9868c2ecf20Sopenharmony_ci{ 9878c2ecf20Sopenharmony_ci long delay; 9888c2ecf20Sopenharmony_ci struct qla4_83xx_quad_entry *p_entry; 9898c2ecf20Sopenharmony_ci struct qla4_83xx_poll *p_poll; 9908c2ecf20Sopenharmony_ci uint32_t i; 9918c2ecf20Sopenharmony_ci 9928c2ecf20Sopenharmony_ci p_poll = (struct qla4_83xx_poll *) 9938c2ecf20Sopenharmony_ci ((char *)p_hdr + sizeof(struct qla4_83xx_reset_entry_hdr)); 9948c2ecf20Sopenharmony_ci p_entry = (struct qla4_83xx_quad_entry *) 9958c2ecf20Sopenharmony_ci ((char *)p_poll + sizeof(struct qla4_83xx_poll)); 9968c2ecf20Sopenharmony_ci delay = (long)p_hdr->delay; 9978c2ecf20Sopenharmony_ci 9988c2ecf20Sopenharmony_ci for (i = 0; i < p_hdr->count; i++, p_entry++) { 9998c2ecf20Sopenharmony_ci qla4_83xx_wr_reg_indirect(ha, p_entry->dr_addr, 10008c2ecf20Sopenharmony_ci p_entry->dr_value); 10018c2ecf20Sopenharmony_ci qla4_83xx_wr_reg_indirect(ha, p_entry->ar_addr, 10028c2ecf20Sopenharmony_ci p_entry->ar_value); 10038c2ecf20Sopenharmony_ci if (delay) { 10048c2ecf20Sopenharmony_ci if (qla4_83xx_poll_reg(ha, p_entry->ar_addr, delay, 10058c2ecf20Sopenharmony_ci p_poll->test_mask, 10068c2ecf20Sopenharmony_ci p_poll->test_value)) { 10078c2ecf20Sopenharmony_ci DEBUG2(ql4_printk(KERN_INFO, ha, 10088c2ecf20Sopenharmony_ci "%s: Timeout Error: poll list, item_num %d, entry_num %d\n", 10098c2ecf20Sopenharmony_ci __func__, i, 10108c2ecf20Sopenharmony_ci ha->reset_tmplt.seq_index)); 10118c2ecf20Sopenharmony_ci } 10128c2ecf20Sopenharmony_ci } 10138c2ecf20Sopenharmony_ci } 10148c2ecf20Sopenharmony_ci} 10158c2ecf20Sopenharmony_ci 10168c2ecf20Sopenharmony_cistatic void qla4_83xx_read_modify_write(struct scsi_qla_host *ha, 10178c2ecf20Sopenharmony_ci struct qla4_83xx_reset_entry_hdr *p_hdr) 10188c2ecf20Sopenharmony_ci{ 10198c2ecf20Sopenharmony_ci struct qla4_83xx_entry *p_entry; 10208c2ecf20Sopenharmony_ci struct qla4_83xx_rmw *p_rmw_hdr; 10218c2ecf20Sopenharmony_ci uint32_t i; 10228c2ecf20Sopenharmony_ci 10238c2ecf20Sopenharmony_ci p_rmw_hdr = (struct qla4_83xx_rmw *) 10248c2ecf20Sopenharmony_ci ((char *)p_hdr + sizeof(struct qla4_83xx_reset_entry_hdr)); 10258c2ecf20Sopenharmony_ci p_entry = (struct qla4_83xx_entry *) 10268c2ecf20Sopenharmony_ci ((char *)p_rmw_hdr + sizeof(struct qla4_83xx_rmw)); 10278c2ecf20Sopenharmony_ci 10288c2ecf20Sopenharmony_ci for (i = 0; i < p_hdr->count; i++, p_entry++) { 10298c2ecf20Sopenharmony_ci qla4_83xx_rmw_crb_reg(ha, p_entry->arg1, p_entry->arg2, 10308c2ecf20Sopenharmony_ci p_rmw_hdr); 10318c2ecf20Sopenharmony_ci if (p_hdr->delay) 10328c2ecf20Sopenharmony_ci udelay((uint32_t)(p_hdr->delay)); 10338c2ecf20Sopenharmony_ci } 10348c2ecf20Sopenharmony_ci} 10358c2ecf20Sopenharmony_ci 10368c2ecf20Sopenharmony_cistatic void qla4_83xx_pause(struct scsi_qla_host *ha, 10378c2ecf20Sopenharmony_ci struct qla4_83xx_reset_entry_hdr *p_hdr) 10388c2ecf20Sopenharmony_ci{ 10398c2ecf20Sopenharmony_ci if (p_hdr->delay) 10408c2ecf20Sopenharmony_ci mdelay((uint32_t)((long)p_hdr->delay)); 10418c2ecf20Sopenharmony_ci} 10428c2ecf20Sopenharmony_ci 10438c2ecf20Sopenharmony_cistatic void qla4_83xx_poll_read_list(struct scsi_qla_host *ha, 10448c2ecf20Sopenharmony_ci struct qla4_83xx_reset_entry_hdr *p_hdr) 10458c2ecf20Sopenharmony_ci{ 10468c2ecf20Sopenharmony_ci long delay; 10478c2ecf20Sopenharmony_ci int index; 10488c2ecf20Sopenharmony_ci struct qla4_83xx_quad_entry *p_entry; 10498c2ecf20Sopenharmony_ci struct qla4_83xx_poll *p_poll; 10508c2ecf20Sopenharmony_ci uint32_t i; 10518c2ecf20Sopenharmony_ci uint32_t value; 10528c2ecf20Sopenharmony_ci 10538c2ecf20Sopenharmony_ci p_poll = (struct qla4_83xx_poll *) 10548c2ecf20Sopenharmony_ci ((char *)p_hdr + sizeof(struct qla4_83xx_reset_entry_hdr)); 10558c2ecf20Sopenharmony_ci p_entry = (struct qla4_83xx_quad_entry *) 10568c2ecf20Sopenharmony_ci ((char *)p_poll + sizeof(struct qla4_83xx_poll)); 10578c2ecf20Sopenharmony_ci delay = (long)p_hdr->delay; 10588c2ecf20Sopenharmony_ci 10598c2ecf20Sopenharmony_ci for (i = 0; i < p_hdr->count; i++, p_entry++) { 10608c2ecf20Sopenharmony_ci qla4_83xx_wr_reg_indirect(ha, p_entry->ar_addr, 10618c2ecf20Sopenharmony_ci p_entry->ar_value); 10628c2ecf20Sopenharmony_ci if (delay) { 10638c2ecf20Sopenharmony_ci if (qla4_83xx_poll_reg(ha, p_entry->ar_addr, delay, 10648c2ecf20Sopenharmony_ci p_poll->test_mask, 10658c2ecf20Sopenharmony_ci p_poll->test_value)) { 10668c2ecf20Sopenharmony_ci DEBUG2(ql4_printk(KERN_INFO, ha, 10678c2ecf20Sopenharmony_ci "%s: Timeout Error: poll list, Item_num %d, entry_num %d\n", 10688c2ecf20Sopenharmony_ci __func__, i, 10698c2ecf20Sopenharmony_ci ha->reset_tmplt.seq_index)); 10708c2ecf20Sopenharmony_ci } else { 10718c2ecf20Sopenharmony_ci index = ha->reset_tmplt.array_index; 10728c2ecf20Sopenharmony_ci qla4_83xx_rd_reg_indirect(ha, p_entry->dr_addr, 10738c2ecf20Sopenharmony_ci &value); 10748c2ecf20Sopenharmony_ci ha->reset_tmplt.array[index++] = value; 10758c2ecf20Sopenharmony_ci 10768c2ecf20Sopenharmony_ci if (index == QLA83XX_MAX_RESET_SEQ_ENTRIES) 10778c2ecf20Sopenharmony_ci ha->reset_tmplt.array_index = 1; 10788c2ecf20Sopenharmony_ci } 10798c2ecf20Sopenharmony_ci } 10808c2ecf20Sopenharmony_ci } 10818c2ecf20Sopenharmony_ci} 10828c2ecf20Sopenharmony_ci 10838c2ecf20Sopenharmony_cistatic void qla4_83xx_seq_end(struct scsi_qla_host *ha, 10848c2ecf20Sopenharmony_ci struct qla4_83xx_reset_entry_hdr *p_hdr) 10858c2ecf20Sopenharmony_ci{ 10868c2ecf20Sopenharmony_ci ha->reset_tmplt.seq_end = 1; 10878c2ecf20Sopenharmony_ci} 10888c2ecf20Sopenharmony_ci 10898c2ecf20Sopenharmony_cistatic void qla4_83xx_template_end(struct scsi_qla_host *ha, 10908c2ecf20Sopenharmony_ci struct qla4_83xx_reset_entry_hdr *p_hdr) 10918c2ecf20Sopenharmony_ci{ 10928c2ecf20Sopenharmony_ci ha->reset_tmplt.template_end = 1; 10938c2ecf20Sopenharmony_ci 10948c2ecf20Sopenharmony_ci if (ha->reset_tmplt.seq_error == 0) { 10958c2ecf20Sopenharmony_ci DEBUG2(ql4_printk(KERN_INFO, ha, 10968c2ecf20Sopenharmony_ci "%s: Reset sequence completed SUCCESSFULLY.\n", 10978c2ecf20Sopenharmony_ci __func__)); 10988c2ecf20Sopenharmony_ci } else { 10998c2ecf20Sopenharmony_ci ql4_printk(KERN_ERR, ha, "%s: Reset sequence completed with some timeout errors.\n", 11008c2ecf20Sopenharmony_ci __func__); 11018c2ecf20Sopenharmony_ci } 11028c2ecf20Sopenharmony_ci} 11038c2ecf20Sopenharmony_ci 11048c2ecf20Sopenharmony_ci/** 11058c2ecf20Sopenharmony_ci * qla4_83xx_process_reset_template - Process reset template. 11068c2ecf20Sopenharmony_ci * 11078c2ecf20Sopenharmony_ci * Process all entries in reset template till entry with SEQ_END opcode, 11088c2ecf20Sopenharmony_ci * which indicates end of the reset template processing. Each entry has a 11098c2ecf20Sopenharmony_ci * Reset Entry header, entry opcode/command, with size of the entry, number 11108c2ecf20Sopenharmony_ci * of entries in sub-sequence and delay in microsecs or timeout in millisecs. 11118c2ecf20Sopenharmony_ci * 11128c2ecf20Sopenharmony_ci * @ha : Pointer to adapter structure 11138c2ecf20Sopenharmony_ci * @p_buff : Common reset entry header. 11148c2ecf20Sopenharmony_ci **/ 11158c2ecf20Sopenharmony_cistatic void qla4_83xx_process_reset_template(struct scsi_qla_host *ha, 11168c2ecf20Sopenharmony_ci char *p_buff) 11178c2ecf20Sopenharmony_ci{ 11188c2ecf20Sopenharmony_ci int index, entries; 11198c2ecf20Sopenharmony_ci struct qla4_83xx_reset_entry_hdr *p_hdr; 11208c2ecf20Sopenharmony_ci char *p_entry = p_buff; 11218c2ecf20Sopenharmony_ci 11228c2ecf20Sopenharmony_ci ha->reset_tmplt.seq_end = 0; 11238c2ecf20Sopenharmony_ci ha->reset_tmplt.template_end = 0; 11248c2ecf20Sopenharmony_ci entries = ha->reset_tmplt.hdr->entries; 11258c2ecf20Sopenharmony_ci index = ha->reset_tmplt.seq_index; 11268c2ecf20Sopenharmony_ci 11278c2ecf20Sopenharmony_ci for (; (!ha->reset_tmplt.seq_end) && (index < entries); index++) { 11288c2ecf20Sopenharmony_ci 11298c2ecf20Sopenharmony_ci p_hdr = (struct qla4_83xx_reset_entry_hdr *)p_entry; 11308c2ecf20Sopenharmony_ci switch (p_hdr->cmd) { 11318c2ecf20Sopenharmony_ci case OPCODE_NOP: 11328c2ecf20Sopenharmony_ci break; 11338c2ecf20Sopenharmony_ci case OPCODE_WRITE_LIST: 11348c2ecf20Sopenharmony_ci qla4_83xx_write_list(ha, p_hdr); 11358c2ecf20Sopenharmony_ci break; 11368c2ecf20Sopenharmony_ci case OPCODE_READ_WRITE_LIST: 11378c2ecf20Sopenharmony_ci qla4_83xx_read_write_list(ha, p_hdr); 11388c2ecf20Sopenharmony_ci break; 11398c2ecf20Sopenharmony_ci case OPCODE_POLL_LIST: 11408c2ecf20Sopenharmony_ci qla4_83xx_poll_list(ha, p_hdr); 11418c2ecf20Sopenharmony_ci break; 11428c2ecf20Sopenharmony_ci case OPCODE_POLL_WRITE_LIST: 11438c2ecf20Sopenharmony_ci qla4_83xx_poll_write_list(ha, p_hdr); 11448c2ecf20Sopenharmony_ci break; 11458c2ecf20Sopenharmony_ci case OPCODE_READ_MODIFY_WRITE: 11468c2ecf20Sopenharmony_ci qla4_83xx_read_modify_write(ha, p_hdr); 11478c2ecf20Sopenharmony_ci break; 11488c2ecf20Sopenharmony_ci case OPCODE_SEQ_PAUSE: 11498c2ecf20Sopenharmony_ci qla4_83xx_pause(ha, p_hdr); 11508c2ecf20Sopenharmony_ci break; 11518c2ecf20Sopenharmony_ci case OPCODE_SEQ_END: 11528c2ecf20Sopenharmony_ci qla4_83xx_seq_end(ha, p_hdr); 11538c2ecf20Sopenharmony_ci break; 11548c2ecf20Sopenharmony_ci case OPCODE_TMPL_END: 11558c2ecf20Sopenharmony_ci qla4_83xx_template_end(ha, p_hdr); 11568c2ecf20Sopenharmony_ci break; 11578c2ecf20Sopenharmony_ci case OPCODE_POLL_READ_LIST: 11588c2ecf20Sopenharmony_ci qla4_83xx_poll_read_list(ha, p_hdr); 11598c2ecf20Sopenharmony_ci break; 11608c2ecf20Sopenharmony_ci default: 11618c2ecf20Sopenharmony_ci ql4_printk(KERN_ERR, ha, "%s: Unknown command ==> 0x%04x on entry = %d\n", 11628c2ecf20Sopenharmony_ci __func__, p_hdr->cmd, index); 11638c2ecf20Sopenharmony_ci break; 11648c2ecf20Sopenharmony_ci } 11658c2ecf20Sopenharmony_ci 11668c2ecf20Sopenharmony_ci /* Set pointer to next entry in the sequence. */ 11678c2ecf20Sopenharmony_ci p_entry += p_hdr->size; 11688c2ecf20Sopenharmony_ci } 11698c2ecf20Sopenharmony_ci 11708c2ecf20Sopenharmony_ci ha->reset_tmplt.seq_index = index; 11718c2ecf20Sopenharmony_ci} 11728c2ecf20Sopenharmony_ci 11738c2ecf20Sopenharmony_cistatic void qla4_83xx_process_stop_seq(struct scsi_qla_host *ha) 11748c2ecf20Sopenharmony_ci{ 11758c2ecf20Sopenharmony_ci ha->reset_tmplt.seq_index = 0; 11768c2ecf20Sopenharmony_ci qla4_83xx_process_reset_template(ha, ha->reset_tmplt.stop_offset); 11778c2ecf20Sopenharmony_ci 11788c2ecf20Sopenharmony_ci if (ha->reset_tmplt.seq_end != 1) 11798c2ecf20Sopenharmony_ci ql4_printk(KERN_ERR, ha, "%s: Abrupt STOP Sub-Sequence end.\n", 11808c2ecf20Sopenharmony_ci __func__); 11818c2ecf20Sopenharmony_ci} 11828c2ecf20Sopenharmony_ci 11838c2ecf20Sopenharmony_cistatic void qla4_83xx_process_start_seq(struct scsi_qla_host *ha) 11848c2ecf20Sopenharmony_ci{ 11858c2ecf20Sopenharmony_ci qla4_83xx_process_reset_template(ha, ha->reset_tmplt.start_offset); 11868c2ecf20Sopenharmony_ci 11878c2ecf20Sopenharmony_ci if (ha->reset_tmplt.template_end != 1) 11888c2ecf20Sopenharmony_ci ql4_printk(KERN_ERR, ha, "%s: Abrupt START Sub-Sequence end.\n", 11898c2ecf20Sopenharmony_ci __func__); 11908c2ecf20Sopenharmony_ci} 11918c2ecf20Sopenharmony_ci 11928c2ecf20Sopenharmony_cistatic void qla4_83xx_process_init_seq(struct scsi_qla_host *ha) 11938c2ecf20Sopenharmony_ci{ 11948c2ecf20Sopenharmony_ci qla4_83xx_process_reset_template(ha, ha->reset_tmplt.init_offset); 11958c2ecf20Sopenharmony_ci 11968c2ecf20Sopenharmony_ci if (ha->reset_tmplt.seq_end != 1) 11978c2ecf20Sopenharmony_ci ql4_printk(KERN_ERR, ha, "%s: Abrupt INIT Sub-Sequence end.\n", 11988c2ecf20Sopenharmony_ci __func__); 11998c2ecf20Sopenharmony_ci} 12008c2ecf20Sopenharmony_ci 12018c2ecf20Sopenharmony_cistatic int qla4_83xx_restart(struct scsi_qla_host *ha) 12028c2ecf20Sopenharmony_ci{ 12038c2ecf20Sopenharmony_ci int ret_val = QLA_SUCCESS; 12048c2ecf20Sopenharmony_ci uint32_t idc_ctrl; 12058c2ecf20Sopenharmony_ci 12068c2ecf20Sopenharmony_ci qla4_83xx_process_stop_seq(ha); 12078c2ecf20Sopenharmony_ci 12088c2ecf20Sopenharmony_ci /* 12098c2ecf20Sopenharmony_ci * Collect minidump. 12108c2ecf20Sopenharmony_ci * If IDC_CTRL BIT1 is set, clear it on going to INIT state and 12118c2ecf20Sopenharmony_ci * don't collect minidump 12128c2ecf20Sopenharmony_ci */ 12138c2ecf20Sopenharmony_ci idc_ctrl = qla4_83xx_rd_reg(ha, QLA83XX_IDC_DRV_CTRL); 12148c2ecf20Sopenharmony_ci if (idc_ctrl & GRACEFUL_RESET_BIT1) { 12158c2ecf20Sopenharmony_ci qla4_83xx_wr_reg(ha, QLA83XX_IDC_DRV_CTRL, 12168c2ecf20Sopenharmony_ci (idc_ctrl & ~GRACEFUL_RESET_BIT1)); 12178c2ecf20Sopenharmony_ci ql4_printk(KERN_INFO, ha, "%s: Graceful RESET: Not collecting minidump\n", 12188c2ecf20Sopenharmony_ci __func__); 12198c2ecf20Sopenharmony_ci } else { 12208c2ecf20Sopenharmony_ci qla4_8xxx_get_minidump(ha); 12218c2ecf20Sopenharmony_ci } 12228c2ecf20Sopenharmony_ci 12238c2ecf20Sopenharmony_ci qla4_83xx_process_init_seq(ha); 12248c2ecf20Sopenharmony_ci 12258c2ecf20Sopenharmony_ci if (qla4_83xx_copy_bootloader(ha)) { 12268c2ecf20Sopenharmony_ci ql4_printk(KERN_ERR, ha, "%s: Copy bootloader, firmware restart failed!\n", 12278c2ecf20Sopenharmony_ci __func__); 12288c2ecf20Sopenharmony_ci ret_val = QLA_ERROR; 12298c2ecf20Sopenharmony_ci goto exit_restart; 12308c2ecf20Sopenharmony_ci } 12318c2ecf20Sopenharmony_ci 12328c2ecf20Sopenharmony_ci qla4_83xx_wr_reg(ha, QLA83XX_FW_IMAGE_VALID, QLA83XX_BOOT_FROM_FLASH); 12338c2ecf20Sopenharmony_ci qla4_83xx_process_start_seq(ha); 12348c2ecf20Sopenharmony_ci 12358c2ecf20Sopenharmony_ciexit_restart: 12368c2ecf20Sopenharmony_ci return ret_val; 12378c2ecf20Sopenharmony_ci} 12388c2ecf20Sopenharmony_ci 12398c2ecf20Sopenharmony_ciint qla4_83xx_start_firmware(struct scsi_qla_host *ha) 12408c2ecf20Sopenharmony_ci{ 12418c2ecf20Sopenharmony_ci int ret_val = QLA_SUCCESS; 12428c2ecf20Sopenharmony_ci 12438c2ecf20Sopenharmony_ci ret_val = qla4_83xx_restart(ha); 12448c2ecf20Sopenharmony_ci if (ret_val == QLA_ERROR) { 12458c2ecf20Sopenharmony_ci ql4_printk(KERN_ERR, ha, "%s: Restart error\n", __func__); 12468c2ecf20Sopenharmony_ci goto exit_start_fw; 12478c2ecf20Sopenharmony_ci } else { 12488c2ecf20Sopenharmony_ci DEBUG2(ql4_printk(KERN_INFO, ha, "%s: Restart done\n", 12498c2ecf20Sopenharmony_ci __func__)); 12508c2ecf20Sopenharmony_ci } 12518c2ecf20Sopenharmony_ci 12528c2ecf20Sopenharmony_ci ret_val = qla4_83xx_check_cmd_peg_status(ha); 12538c2ecf20Sopenharmony_ci if (ret_val == QLA_ERROR) 12548c2ecf20Sopenharmony_ci ql4_printk(KERN_ERR, ha, "%s: Peg not initialized\n", 12558c2ecf20Sopenharmony_ci __func__); 12568c2ecf20Sopenharmony_ci 12578c2ecf20Sopenharmony_ciexit_start_fw: 12588c2ecf20Sopenharmony_ci return ret_val; 12598c2ecf20Sopenharmony_ci} 12608c2ecf20Sopenharmony_ci 12618c2ecf20Sopenharmony_ci/*----------------------Interrupt Related functions ---------------------*/ 12628c2ecf20Sopenharmony_ci 12638c2ecf20Sopenharmony_cistatic void qla4_83xx_disable_iocb_intrs(struct scsi_qla_host *ha) 12648c2ecf20Sopenharmony_ci{ 12658c2ecf20Sopenharmony_ci if (test_and_clear_bit(AF_83XX_IOCB_INTR_ON, &ha->flags)) 12668c2ecf20Sopenharmony_ci qla4_8xxx_intr_disable(ha); 12678c2ecf20Sopenharmony_ci} 12688c2ecf20Sopenharmony_ci 12698c2ecf20Sopenharmony_cistatic void qla4_83xx_disable_mbox_intrs(struct scsi_qla_host *ha) 12708c2ecf20Sopenharmony_ci{ 12718c2ecf20Sopenharmony_ci uint32_t mb_int, ret; 12728c2ecf20Sopenharmony_ci 12738c2ecf20Sopenharmony_ci if (test_and_clear_bit(AF_83XX_MBOX_INTR_ON, &ha->flags)) { 12748c2ecf20Sopenharmony_ci ret = readl(&ha->qla4_83xx_reg->mbox_int); 12758c2ecf20Sopenharmony_ci mb_int = ret & ~INT_ENABLE_FW_MB; 12768c2ecf20Sopenharmony_ci writel(mb_int, &ha->qla4_83xx_reg->mbox_int); 12778c2ecf20Sopenharmony_ci writel(1, &ha->qla4_83xx_reg->leg_int_mask); 12788c2ecf20Sopenharmony_ci } 12798c2ecf20Sopenharmony_ci} 12808c2ecf20Sopenharmony_ci 12818c2ecf20Sopenharmony_civoid qla4_83xx_disable_intrs(struct scsi_qla_host *ha) 12828c2ecf20Sopenharmony_ci{ 12838c2ecf20Sopenharmony_ci qla4_83xx_disable_mbox_intrs(ha); 12848c2ecf20Sopenharmony_ci qla4_83xx_disable_iocb_intrs(ha); 12858c2ecf20Sopenharmony_ci} 12868c2ecf20Sopenharmony_ci 12878c2ecf20Sopenharmony_cistatic void qla4_83xx_enable_iocb_intrs(struct scsi_qla_host *ha) 12888c2ecf20Sopenharmony_ci{ 12898c2ecf20Sopenharmony_ci if (!test_bit(AF_83XX_IOCB_INTR_ON, &ha->flags)) { 12908c2ecf20Sopenharmony_ci qla4_8xxx_intr_enable(ha); 12918c2ecf20Sopenharmony_ci set_bit(AF_83XX_IOCB_INTR_ON, &ha->flags); 12928c2ecf20Sopenharmony_ci } 12938c2ecf20Sopenharmony_ci} 12948c2ecf20Sopenharmony_ci 12958c2ecf20Sopenharmony_civoid qla4_83xx_enable_mbox_intrs(struct scsi_qla_host *ha) 12968c2ecf20Sopenharmony_ci{ 12978c2ecf20Sopenharmony_ci uint32_t mb_int; 12988c2ecf20Sopenharmony_ci 12998c2ecf20Sopenharmony_ci if (!test_bit(AF_83XX_MBOX_INTR_ON, &ha->flags)) { 13008c2ecf20Sopenharmony_ci mb_int = INT_ENABLE_FW_MB; 13018c2ecf20Sopenharmony_ci writel(mb_int, &ha->qla4_83xx_reg->mbox_int); 13028c2ecf20Sopenharmony_ci writel(0, &ha->qla4_83xx_reg->leg_int_mask); 13038c2ecf20Sopenharmony_ci set_bit(AF_83XX_MBOX_INTR_ON, &ha->flags); 13048c2ecf20Sopenharmony_ci } 13058c2ecf20Sopenharmony_ci} 13068c2ecf20Sopenharmony_ci 13078c2ecf20Sopenharmony_ci 13088c2ecf20Sopenharmony_civoid qla4_83xx_enable_intrs(struct scsi_qla_host *ha) 13098c2ecf20Sopenharmony_ci{ 13108c2ecf20Sopenharmony_ci qla4_83xx_enable_mbox_intrs(ha); 13118c2ecf20Sopenharmony_ci qla4_83xx_enable_iocb_intrs(ha); 13128c2ecf20Sopenharmony_ci} 13138c2ecf20Sopenharmony_ci 13148c2ecf20Sopenharmony_ci 13158c2ecf20Sopenharmony_civoid qla4_83xx_queue_mbox_cmd(struct scsi_qla_host *ha, uint32_t *mbx_cmd, 13168c2ecf20Sopenharmony_ci int incount) 13178c2ecf20Sopenharmony_ci{ 13188c2ecf20Sopenharmony_ci int i; 13198c2ecf20Sopenharmony_ci 13208c2ecf20Sopenharmony_ci /* Load all mailbox registers, except mailbox 0. */ 13218c2ecf20Sopenharmony_ci for (i = 1; i < incount; i++) 13228c2ecf20Sopenharmony_ci writel(mbx_cmd[i], &ha->qla4_83xx_reg->mailbox_in[i]); 13238c2ecf20Sopenharmony_ci 13248c2ecf20Sopenharmony_ci writel(mbx_cmd[0], &ha->qla4_83xx_reg->mailbox_in[0]); 13258c2ecf20Sopenharmony_ci 13268c2ecf20Sopenharmony_ci /* Set Host Interrupt register to 1, to tell the firmware that 13278c2ecf20Sopenharmony_ci * a mailbox command is pending. Firmware after reading the 13288c2ecf20Sopenharmony_ci * mailbox command, clears the host interrupt register */ 13298c2ecf20Sopenharmony_ci writel(HINT_MBX_INT_PENDING, &ha->qla4_83xx_reg->host_intr); 13308c2ecf20Sopenharmony_ci} 13318c2ecf20Sopenharmony_ci 13328c2ecf20Sopenharmony_civoid qla4_83xx_process_mbox_intr(struct scsi_qla_host *ha, int outcount) 13338c2ecf20Sopenharmony_ci{ 13348c2ecf20Sopenharmony_ci int intr_status; 13358c2ecf20Sopenharmony_ci 13368c2ecf20Sopenharmony_ci intr_status = readl(&ha->qla4_83xx_reg->risc_intr); 13378c2ecf20Sopenharmony_ci if (intr_status) { 13388c2ecf20Sopenharmony_ci ha->mbox_status_count = outcount; 13398c2ecf20Sopenharmony_ci ha->isp_ops->interrupt_service_routine(ha, intr_status); 13408c2ecf20Sopenharmony_ci } 13418c2ecf20Sopenharmony_ci} 13428c2ecf20Sopenharmony_ci 13438c2ecf20Sopenharmony_ci/** 13448c2ecf20Sopenharmony_ci * qla4_83xx_isp_reset - Resets ISP and aborts all outstanding commands. 13458c2ecf20Sopenharmony_ci * @ha: pointer to host adapter structure. 13468c2ecf20Sopenharmony_ci **/ 13478c2ecf20Sopenharmony_ciint qla4_83xx_isp_reset(struct scsi_qla_host *ha) 13488c2ecf20Sopenharmony_ci{ 13498c2ecf20Sopenharmony_ci int rval; 13508c2ecf20Sopenharmony_ci uint32_t dev_state; 13518c2ecf20Sopenharmony_ci 13528c2ecf20Sopenharmony_ci ha->isp_ops->idc_lock(ha); 13538c2ecf20Sopenharmony_ci dev_state = qla4_8xxx_rd_direct(ha, QLA8XXX_CRB_DEV_STATE); 13548c2ecf20Sopenharmony_ci 13558c2ecf20Sopenharmony_ci if (ql4xdontresethba) 13568c2ecf20Sopenharmony_ci qla4_83xx_set_idc_dontreset(ha); 13578c2ecf20Sopenharmony_ci 13588c2ecf20Sopenharmony_ci if (dev_state == QLA8XXX_DEV_READY) { 13598c2ecf20Sopenharmony_ci /* If IDC_CTRL DONTRESETHBA_BIT0 is set dont do reset 13608c2ecf20Sopenharmony_ci * recovery */ 13618c2ecf20Sopenharmony_ci if (qla4_83xx_idc_dontreset(ha) == DONTRESET_BIT0) { 13628c2ecf20Sopenharmony_ci ql4_printk(KERN_ERR, ha, "%s: Reset recovery disabled\n", 13638c2ecf20Sopenharmony_ci __func__); 13648c2ecf20Sopenharmony_ci rval = QLA_ERROR; 13658c2ecf20Sopenharmony_ci goto exit_isp_reset; 13668c2ecf20Sopenharmony_ci } 13678c2ecf20Sopenharmony_ci 13688c2ecf20Sopenharmony_ci DEBUG2(ql4_printk(KERN_INFO, ha, "%s: HW State: NEED RESET\n", 13698c2ecf20Sopenharmony_ci __func__)); 13708c2ecf20Sopenharmony_ci qla4_8xxx_wr_direct(ha, QLA8XXX_CRB_DEV_STATE, 13718c2ecf20Sopenharmony_ci QLA8XXX_DEV_NEED_RESET); 13728c2ecf20Sopenharmony_ci 13738c2ecf20Sopenharmony_ci } else { 13748c2ecf20Sopenharmony_ci /* If device_state is NEED_RESET, go ahead with 13758c2ecf20Sopenharmony_ci * Reset,irrespective of ql4xdontresethba. This is to allow a 13768c2ecf20Sopenharmony_ci * non-reset-owner to force a reset. Non-reset-owner sets 13778c2ecf20Sopenharmony_ci * the IDC_CTRL BIT0 to prevent Reset-owner from doing a Reset 13788c2ecf20Sopenharmony_ci * and then forces a Reset by setting device_state to 13798c2ecf20Sopenharmony_ci * NEED_RESET. */ 13808c2ecf20Sopenharmony_ci DEBUG2(ql4_printk(KERN_INFO, ha, 13818c2ecf20Sopenharmony_ci "%s: HW state already set to NEED_RESET\n", 13828c2ecf20Sopenharmony_ci __func__)); 13838c2ecf20Sopenharmony_ci } 13848c2ecf20Sopenharmony_ci 13858c2ecf20Sopenharmony_ci /* For ISP8324 and ISP8042, Reset owner is NIC, iSCSI or FCOE based on 13868c2ecf20Sopenharmony_ci * priority and which drivers are present. Unlike ISP8022, the function 13878c2ecf20Sopenharmony_ci * setting NEED_RESET, may not be the Reset owner. */ 13888c2ecf20Sopenharmony_ci if (qla4_83xx_can_perform_reset(ha)) 13898c2ecf20Sopenharmony_ci set_bit(AF_8XXX_RST_OWNER, &ha->flags); 13908c2ecf20Sopenharmony_ci 13918c2ecf20Sopenharmony_ci ha->isp_ops->idc_unlock(ha); 13928c2ecf20Sopenharmony_ci rval = qla4_8xxx_device_state_handler(ha); 13938c2ecf20Sopenharmony_ci 13948c2ecf20Sopenharmony_ci ha->isp_ops->idc_lock(ha); 13958c2ecf20Sopenharmony_ci qla4_8xxx_clear_rst_ready(ha); 13968c2ecf20Sopenharmony_ciexit_isp_reset: 13978c2ecf20Sopenharmony_ci ha->isp_ops->idc_unlock(ha); 13988c2ecf20Sopenharmony_ci 13998c2ecf20Sopenharmony_ci if (rval == QLA_SUCCESS) 14008c2ecf20Sopenharmony_ci clear_bit(AF_FW_RECOVERY, &ha->flags); 14018c2ecf20Sopenharmony_ci 14028c2ecf20Sopenharmony_ci return rval; 14038c2ecf20Sopenharmony_ci} 14048c2ecf20Sopenharmony_ci 14058c2ecf20Sopenharmony_cistatic void qla4_83xx_dump_pause_control_regs(struct scsi_qla_host *ha) 14068c2ecf20Sopenharmony_ci{ 14078c2ecf20Sopenharmony_ci u32 val = 0, val1 = 0; 14088c2ecf20Sopenharmony_ci int i; 14098c2ecf20Sopenharmony_ci 14108c2ecf20Sopenharmony_ci qla4_83xx_rd_reg_indirect(ha, QLA83XX_SRE_SHIM_CONTROL, &val); 14118c2ecf20Sopenharmony_ci DEBUG2(ql4_printk(KERN_INFO, ha, "SRE-Shim Ctrl:0x%x\n", val)); 14128c2ecf20Sopenharmony_ci 14138c2ecf20Sopenharmony_ci /* Port 0 Rx Buffer Pause Threshold Registers. */ 14148c2ecf20Sopenharmony_ci DEBUG2(ql4_printk(KERN_INFO, ha, 14158c2ecf20Sopenharmony_ci "Port 0 Rx Buffer Pause Threshold Registers[TC7..TC0]:")); 14168c2ecf20Sopenharmony_ci for (i = 0; i < 8; i++) { 14178c2ecf20Sopenharmony_ci qla4_83xx_rd_reg_indirect(ha, 14188c2ecf20Sopenharmony_ci QLA83XX_PORT0_RXB_PAUSE_THRS + (i * 0x4), &val); 14198c2ecf20Sopenharmony_ci DEBUG2(pr_info("0x%x ", val)); 14208c2ecf20Sopenharmony_ci } 14218c2ecf20Sopenharmony_ci 14228c2ecf20Sopenharmony_ci DEBUG2(pr_info("\n")); 14238c2ecf20Sopenharmony_ci 14248c2ecf20Sopenharmony_ci /* Port 1 Rx Buffer Pause Threshold Registers. */ 14258c2ecf20Sopenharmony_ci DEBUG2(ql4_printk(KERN_INFO, ha, 14268c2ecf20Sopenharmony_ci "Port 1 Rx Buffer Pause Threshold Registers[TC7..TC0]:")); 14278c2ecf20Sopenharmony_ci for (i = 0; i < 8; i++) { 14288c2ecf20Sopenharmony_ci qla4_83xx_rd_reg_indirect(ha, 14298c2ecf20Sopenharmony_ci QLA83XX_PORT1_RXB_PAUSE_THRS + (i * 0x4), &val); 14308c2ecf20Sopenharmony_ci DEBUG2(pr_info("0x%x ", val)); 14318c2ecf20Sopenharmony_ci } 14328c2ecf20Sopenharmony_ci 14338c2ecf20Sopenharmony_ci DEBUG2(pr_info("\n")); 14348c2ecf20Sopenharmony_ci 14358c2ecf20Sopenharmony_ci /* Port 0 RxB Traffic Class Max Cell Registers. */ 14368c2ecf20Sopenharmony_ci DEBUG2(ql4_printk(KERN_INFO, ha, 14378c2ecf20Sopenharmony_ci "Port 0 RxB Traffic Class Max Cell Registers[3..0]:")); 14388c2ecf20Sopenharmony_ci for (i = 0; i < 4; i++) { 14398c2ecf20Sopenharmony_ci qla4_83xx_rd_reg_indirect(ha, 14408c2ecf20Sopenharmony_ci QLA83XX_PORT0_RXB_TC_MAX_CELL + (i * 0x4), &val); 14418c2ecf20Sopenharmony_ci DEBUG2(pr_info("0x%x ", val)); 14428c2ecf20Sopenharmony_ci } 14438c2ecf20Sopenharmony_ci 14448c2ecf20Sopenharmony_ci DEBUG2(pr_info("\n")); 14458c2ecf20Sopenharmony_ci 14468c2ecf20Sopenharmony_ci /* Port 1 RxB Traffic Class Max Cell Registers. */ 14478c2ecf20Sopenharmony_ci DEBUG2(ql4_printk(KERN_INFO, ha, 14488c2ecf20Sopenharmony_ci "Port 1 RxB Traffic Class Max Cell Registers[3..0]:")); 14498c2ecf20Sopenharmony_ci for (i = 0; i < 4; i++) { 14508c2ecf20Sopenharmony_ci qla4_83xx_rd_reg_indirect(ha, 14518c2ecf20Sopenharmony_ci QLA83XX_PORT1_RXB_TC_MAX_CELL + (i * 0x4), &val); 14528c2ecf20Sopenharmony_ci DEBUG2(pr_info("0x%x ", val)); 14538c2ecf20Sopenharmony_ci } 14548c2ecf20Sopenharmony_ci 14558c2ecf20Sopenharmony_ci DEBUG2(pr_info("\n")); 14568c2ecf20Sopenharmony_ci 14578c2ecf20Sopenharmony_ci /* Port 0 RxB Rx Traffic Class Stats. */ 14588c2ecf20Sopenharmony_ci DEBUG2(ql4_printk(KERN_INFO, ha, 14598c2ecf20Sopenharmony_ci "Port 0 RxB Rx Traffic Class Stats [TC7..TC0]")); 14608c2ecf20Sopenharmony_ci for (i = 7; i >= 0; i--) { 14618c2ecf20Sopenharmony_ci qla4_83xx_rd_reg_indirect(ha, QLA83XX_PORT0_RXB_TC_STATS, &val); 14628c2ecf20Sopenharmony_ci val &= ~(0x7 << 29); /* Reset bits 29 to 31 */ 14638c2ecf20Sopenharmony_ci qla4_83xx_wr_reg_indirect(ha, QLA83XX_PORT0_RXB_TC_STATS, 14648c2ecf20Sopenharmony_ci (val | (i << 29))); 14658c2ecf20Sopenharmony_ci qla4_83xx_rd_reg_indirect(ha, QLA83XX_PORT0_RXB_TC_STATS, &val); 14668c2ecf20Sopenharmony_ci DEBUG2(pr_info("0x%x ", val)); 14678c2ecf20Sopenharmony_ci } 14688c2ecf20Sopenharmony_ci 14698c2ecf20Sopenharmony_ci DEBUG2(pr_info("\n")); 14708c2ecf20Sopenharmony_ci 14718c2ecf20Sopenharmony_ci /* Port 1 RxB Rx Traffic Class Stats. */ 14728c2ecf20Sopenharmony_ci DEBUG2(ql4_printk(KERN_INFO, ha, 14738c2ecf20Sopenharmony_ci "Port 1 RxB Rx Traffic Class Stats [TC7..TC0]")); 14748c2ecf20Sopenharmony_ci for (i = 7; i >= 0; i--) { 14758c2ecf20Sopenharmony_ci qla4_83xx_rd_reg_indirect(ha, QLA83XX_PORT1_RXB_TC_STATS, &val); 14768c2ecf20Sopenharmony_ci val &= ~(0x7 << 29); /* Reset bits 29 to 31 */ 14778c2ecf20Sopenharmony_ci qla4_83xx_wr_reg_indirect(ha, QLA83XX_PORT1_RXB_TC_STATS, 14788c2ecf20Sopenharmony_ci (val | (i << 29))); 14798c2ecf20Sopenharmony_ci qla4_83xx_rd_reg_indirect(ha, QLA83XX_PORT1_RXB_TC_STATS, &val); 14808c2ecf20Sopenharmony_ci DEBUG2(pr_info("0x%x ", val)); 14818c2ecf20Sopenharmony_ci } 14828c2ecf20Sopenharmony_ci 14838c2ecf20Sopenharmony_ci DEBUG2(pr_info("\n")); 14848c2ecf20Sopenharmony_ci 14858c2ecf20Sopenharmony_ci qla4_83xx_rd_reg_indirect(ha, QLA83XX_PORT2_IFB_PAUSE_THRS, &val); 14868c2ecf20Sopenharmony_ci qla4_83xx_rd_reg_indirect(ha, QLA83XX_PORT3_IFB_PAUSE_THRS, &val1); 14878c2ecf20Sopenharmony_ci 14888c2ecf20Sopenharmony_ci DEBUG2(ql4_printk(KERN_INFO, ha, 14898c2ecf20Sopenharmony_ci "IFB-Pause Thresholds: Port 2:0x%x, Port 3:0x%x\n", 14908c2ecf20Sopenharmony_ci val, val1)); 14918c2ecf20Sopenharmony_ci} 14928c2ecf20Sopenharmony_ci 14938c2ecf20Sopenharmony_cistatic void __qla4_83xx_disable_pause(struct scsi_qla_host *ha) 14948c2ecf20Sopenharmony_ci{ 14958c2ecf20Sopenharmony_ci int i; 14968c2ecf20Sopenharmony_ci 14978c2ecf20Sopenharmony_ci /* set SRE-Shim Control Register */ 14988c2ecf20Sopenharmony_ci qla4_83xx_wr_reg_indirect(ha, QLA83XX_SRE_SHIM_CONTROL, 14998c2ecf20Sopenharmony_ci QLA83XX_SET_PAUSE_VAL); 15008c2ecf20Sopenharmony_ci 15018c2ecf20Sopenharmony_ci for (i = 0; i < 8; i++) { 15028c2ecf20Sopenharmony_ci /* Port 0 Rx Buffer Pause Threshold Registers. */ 15038c2ecf20Sopenharmony_ci qla4_83xx_wr_reg_indirect(ha, 15048c2ecf20Sopenharmony_ci QLA83XX_PORT0_RXB_PAUSE_THRS + (i * 0x4), 15058c2ecf20Sopenharmony_ci QLA83XX_SET_PAUSE_VAL); 15068c2ecf20Sopenharmony_ci /* Port 1 Rx Buffer Pause Threshold Registers. */ 15078c2ecf20Sopenharmony_ci qla4_83xx_wr_reg_indirect(ha, 15088c2ecf20Sopenharmony_ci QLA83XX_PORT1_RXB_PAUSE_THRS + (i * 0x4), 15098c2ecf20Sopenharmony_ci QLA83XX_SET_PAUSE_VAL); 15108c2ecf20Sopenharmony_ci } 15118c2ecf20Sopenharmony_ci 15128c2ecf20Sopenharmony_ci for (i = 0; i < 4; i++) { 15138c2ecf20Sopenharmony_ci /* Port 0 RxB Traffic Class Max Cell Registers. */ 15148c2ecf20Sopenharmony_ci qla4_83xx_wr_reg_indirect(ha, 15158c2ecf20Sopenharmony_ci QLA83XX_PORT0_RXB_TC_MAX_CELL + (i * 0x4), 15168c2ecf20Sopenharmony_ci QLA83XX_SET_TC_MAX_CELL_VAL); 15178c2ecf20Sopenharmony_ci /* Port 1 RxB Traffic Class Max Cell Registers. */ 15188c2ecf20Sopenharmony_ci qla4_83xx_wr_reg_indirect(ha, 15198c2ecf20Sopenharmony_ci QLA83XX_PORT1_RXB_TC_MAX_CELL + (i * 0x4), 15208c2ecf20Sopenharmony_ci QLA83XX_SET_TC_MAX_CELL_VAL); 15218c2ecf20Sopenharmony_ci } 15228c2ecf20Sopenharmony_ci 15238c2ecf20Sopenharmony_ci qla4_83xx_wr_reg_indirect(ha, QLA83XX_PORT2_IFB_PAUSE_THRS, 15248c2ecf20Sopenharmony_ci QLA83XX_SET_PAUSE_VAL); 15258c2ecf20Sopenharmony_ci qla4_83xx_wr_reg_indirect(ha, QLA83XX_PORT3_IFB_PAUSE_THRS, 15268c2ecf20Sopenharmony_ci QLA83XX_SET_PAUSE_VAL); 15278c2ecf20Sopenharmony_ci 15288c2ecf20Sopenharmony_ci ql4_printk(KERN_INFO, ha, "Disabled pause frames successfully.\n"); 15298c2ecf20Sopenharmony_ci} 15308c2ecf20Sopenharmony_ci 15318c2ecf20Sopenharmony_ci/** 15328c2ecf20Sopenharmony_ci * qla4_83xx_eport_init - Initialize EPort. 15338c2ecf20Sopenharmony_ci * @ha: Pointer to host adapter structure. 15348c2ecf20Sopenharmony_ci * 15358c2ecf20Sopenharmony_ci * If EPort hardware is in reset state before disabling pause, there would be 15368c2ecf20Sopenharmony_ci * serious hardware wedging issues. To prevent this perform eport init everytime 15378c2ecf20Sopenharmony_ci * before disabling pause frames. 15388c2ecf20Sopenharmony_ci **/ 15398c2ecf20Sopenharmony_cistatic void qla4_83xx_eport_init(struct scsi_qla_host *ha) 15408c2ecf20Sopenharmony_ci{ 15418c2ecf20Sopenharmony_ci /* Clear the 8 registers */ 15428c2ecf20Sopenharmony_ci qla4_83xx_wr_reg_indirect(ha, QLA83XX_RESET_REG, 0x0); 15438c2ecf20Sopenharmony_ci qla4_83xx_wr_reg_indirect(ha, QLA83XX_RESET_PORT0, 0x0); 15448c2ecf20Sopenharmony_ci qla4_83xx_wr_reg_indirect(ha, QLA83XX_RESET_PORT1, 0x0); 15458c2ecf20Sopenharmony_ci qla4_83xx_wr_reg_indirect(ha, QLA83XX_RESET_PORT2, 0x0); 15468c2ecf20Sopenharmony_ci qla4_83xx_wr_reg_indirect(ha, QLA83XX_RESET_PORT3, 0x0); 15478c2ecf20Sopenharmony_ci qla4_83xx_wr_reg_indirect(ha, QLA83XX_RESET_SRE_SHIM, 0x0); 15488c2ecf20Sopenharmony_ci qla4_83xx_wr_reg_indirect(ha, QLA83XX_RESET_EPG_SHIM, 0x0); 15498c2ecf20Sopenharmony_ci qla4_83xx_wr_reg_indirect(ha, QLA83XX_RESET_ETHER_PCS, 0x0); 15508c2ecf20Sopenharmony_ci 15518c2ecf20Sopenharmony_ci /* Write any value to Reset Control register */ 15528c2ecf20Sopenharmony_ci qla4_83xx_wr_reg_indirect(ha, QLA83XX_RESET_CONTROL, 0xFF); 15538c2ecf20Sopenharmony_ci 15548c2ecf20Sopenharmony_ci ql4_printk(KERN_INFO, ha, "EPORT is out of reset.\n"); 15558c2ecf20Sopenharmony_ci} 15568c2ecf20Sopenharmony_ci 15578c2ecf20Sopenharmony_civoid qla4_83xx_disable_pause(struct scsi_qla_host *ha) 15588c2ecf20Sopenharmony_ci{ 15598c2ecf20Sopenharmony_ci ha->isp_ops->idc_lock(ha); 15608c2ecf20Sopenharmony_ci /* Before disabling pause frames, ensure that eport is not in reset */ 15618c2ecf20Sopenharmony_ci qla4_83xx_eport_init(ha); 15628c2ecf20Sopenharmony_ci qla4_83xx_dump_pause_control_regs(ha); 15638c2ecf20Sopenharmony_ci __qla4_83xx_disable_pause(ha); 15648c2ecf20Sopenharmony_ci ha->isp_ops->idc_unlock(ha); 15658c2ecf20Sopenharmony_ci} 15668c2ecf20Sopenharmony_ci 15678c2ecf20Sopenharmony_ci/** 15688c2ecf20Sopenharmony_ci * qla4_83xx_is_detached - Check if we are marked invisible. 15698c2ecf20Sopenharmony_ci * @ha: Pointer to host adapter structure. 15708c2ecf20Sopenharmony_ci **/ 15718c2ecf20Sopenharmony_ciint qla4_83xx_is_detached(struct scsi_qla_host *ha) 15728c2ecf20Sopenharmony_ci{ 15738c2ecf20Sopenharmony_ci uint32_t drv_active; 15748c2ecf20Sopenharmony_ci 15758c2ecf20Sopenharmony_ci drv_active = qla4_8xxx_rd_direct(ha, QLA8XXX_CRB_DRV_ACTIVE); 15768c2ecf20Sopenharmony_ci 15778c2ecf20Sopenharmony_ci if (test_bit(AF_INIT_DONE, &ha->flags) && 15788c2ecf20Sopenharmony_ci !(drv_active & (1 << ha->func_num))) { 15798c2ecf20Sopenharmony_ci DEBUG2(ql4_printk(KERN_INFO, ha, "%s: drv_active = 0x%X\n", 15808c2ecf20Sopenharmony_ci __func__, drv_active)); 15818c2ecf20Sopenharmony_ci return QLA_SUCCESS; 15828c2ecf20Sopenharmony_ci } 15838c2ecf20Sopenharmony_ci 15848c2ecf20Sopenharmony_ci return QLA_ERROR; 15858c2ecf20Sopenharmony_ci} 1586