xref: /openbmc/linux/drivers/scsi/qla4xxx/ql4_83xx.c (revision e3976af5)
1e3976af5SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
26e7b4292SVikas Chaudhary /*
36e7b4292SVikas Chaudhary  * QLogic iSCSI HBA Driver
44a4f51e9SVikas Chaudhary  * Copyright (c)   2003-2013 QLogic Corporation
56e7b4292SVikas Chaudhary  */
66e7b4292SVikas Chaudhary 
76e7b4292SVikas Chaudhary #include <linux/ratelimit.h>
86e7b4292SVikas Chaudhary 
96e7b4292SVikas Chaudhary #include "ql4_def.h"
106e7b4292SVikas Chaudhary #include "ql4_version.h"
116e7b4292SVikas Chaudhary #include "ql4_glbl.h"
126e7b4292SVikas Chaudhary #include "ql4_dbg.h"
136e7b4292SVikas Chaudhary #include "ql4_inline.h"
146e7b4292SVikas Chaudhary 
156e7b4292SVikas Chaudhary uint32_t qla4_83xx_rd_reg(struct scsi_qla_host *ha, ulong addr)
166e7b4292SVikas Chaudhary {
176e7b4292SVikas Chaudhary 	return readl((void __iomem *)(ha->nx_pcibase + addr));
186e7b4292SVikas Chaudhary }
196e7b4292SVikas Chaudhary 
206e7b4292SVikas Chaudhary void qla4_83xx_wr_reg(struct scsi_qla_host *ha, ulong addr, uint32_t val)
216e7b4292SVikas Chaudhary {
226e7b4292SVikas Chaudhary 	writel(val, (void __iomem *)(ha->nx_pcibase + addr));
236e7b4292SVikas Chaudhary }
246e7b4292SVikas Chaudhary 
256e7b4292SVikas Chaudhary static int qla4_83xx_set_win_base(struct scsi_qla_host *ha, uint32_t addr)
266e7b4292SVikas Chaudhary {
276e7b4292SVikas Chaudhary 	uint32_t val;
286e7b4292SVikas Chaudhary 	int ret_val = QLA_SUCCESS;
296e7b4292SVikas Chaudhary 
306e7b4292SVikas Chaudhary 	qla4_83xx_wr_reg(ha, QLA83XX_CRB_WIN_FUNC(ha->func_num), addr);
316e7b4292SVikas Chaudhary 	val = qla4_83xx_rd_reg(ha, QLA83XX_CRB_WIN_FUNC(ha->func_num));
326e7b4292SVikas Chaudhary 	if (val != addr) {
336e7b4292SVikas Chaudhary 		ql4_printk(KERN_ERR, ha, "%s: Failed to set register window : addr written 0x%x, read 0x%x!\n",
346e7b4292SVikas Chaudhary 			   __func__, addr, val);
356e7b4292SVikas Chaudhary 		ret_val = QLA_ERROR;
366e7b4292SVikas Chaudhary 	}
376e7b4292SVikas Chaudhary 
386e7b4292SVikas Chaudhary 	return ret_val;
396e7b4292SVikas Chaudhary }
406e7b4292SVikas Chaudhary 
416e7b4292SVikas Chaudhary int qla4_83xx_rd_reg_indirect(struct scsi_qla_host *ha, uint32_t addr,
426e7b4292SVikas Chaudhary 			      uint32_t *data)
436e7b4292SVikas Chaudhary {
446e7b4292SVikas Chaudhary 	int ret_val;
456e7b4292SVikas Chaudhary 
466e7b4292SVikas Chaudhary 	ret_val = qla4_83xx_set_win_base(ha, addr);
476e7b4292SVikas Chaudhary 
48860cd9c0SArnd Bergmann 	if (ret_val == QLA_SUCCESS) {
496e7b4292SVikas Chaudhary 		*data = qla4_83xx_rd_reg(ha, QLA83XX_WILDCARD);
50860cd9c0SArnd Bergmann 	} else {
51860cd9c0SArnd Bergmann 		*data = 0xffffffff;
526e7b4292SVikas Chaudhary 		ql4_printk(KERN_ERR, ha, "%s: failed read of addr 0x%x!\n",
536e7b4292SVikas Chaudhary 			   __func__, addr);
54860cd9c0SArnd Bergmann 	}
556e7b4292SVikas Chaudhary 
566e7b4292SVikas Chaudhary 	return ret_val;
576e7b4292SVikas Chaudhary }
586e7b4292SVikas Chaudhary 
596e7b4292SVikas Chaudhary int qla4_83xx_wr_reg_indirect(struct scsi_qla_host *ha, uint32_t addr,
606e7b4292SVikas Chaudhary 			      uint32_t data)
616e7b4292SVikas Chaudhary {
626e7b4292SVikas Chaudhary 	int ret_val;
636e7b4292SVikas Chaudhary 
646e7b4292SVikas Chaudhary 	ret_val = qla4_83xx_set_win_base(ha, addr);
656e7b4292SVikas Chaudhary 
666e7b4292SVikas Chaudhary 	if (ret_val == QLA_SUCCESS)
676e7b4292SVikas Chaudhary 		qla4_83xx_wr_reg(ha, QLA83XX_WILDCARD, data);
686e7b4292SVikas Chaudhary 	else
696e7b4292SVikas Chaudhary 		ql4_printk(KERN_ERR, ha, "%s: failed wrt to addr 0x%x, data 0x%x\n",
706e7b4292SVikas Chaudhary 			   __func__, addr, data);
716e7b4292SVikas Chaudhary 
726e7b4292SVikas Chaudhary 	return ret_val;
736e7b4292SVikas Chaudhary }
746e7b4292SVikas Chaudhary 
756e7b4292SVikas Chaudhary static int qla4_83xx_flash_lock(struct scsi_qla_host *ha)
766e7b4292SVikas Chaudhary {
776e7b4292SVikas Chaudhary 	int lock_owner;
786e7b4292SVikas Chaudhary 	int timeout = 0;
796e7b4292SVikas Chaudhary 	uint32_t lock_status = 0;
806e7b4292SVikas Chaudhary 	int ret_val = QLA_SUCCESS;
816e7b4292SVikas Chaudhary 
826e7b4292SVikas Chaudhary 	while (lock_status == 0) {
836e7b4292SVikas Chaudhary 		lock_status = qla4_83xx_rd_reg(ha, QLA83XX_FLASH_LOCK);
846e7b4292SVikas Chaudhary 		if (lock_status)
856e7b4292SVikas Chaudhary 			break;
866e7b4292SVikas Chaudhary 
876e7b4292SVikas Chaudhary 		if (++timeout >= QLA83XX_FLASH_LOCK_TIMEOUT / 20) {
886e7b4292SVikas Chaudhary 			lock_owner = qla4_83xx_rd_reg(ha,
896e7b4292SVikas Chaudhary 						      QLA83XX_FLASH_LOCK_ID);
906e7b4292SVikas Chaudhary 			ql4_printk(KERN_ERR, ha, "%s: flash lock by func %d failed, held by func %d\n",
916e7b4292SVikas Chaudhary 				   __func__, ha->func_num, lock_owner);
926e7b4292SVikas Chaudhary 			ret_val = QLA_ERROR;
936e7b4292SVikas Chaudhary 			break;
946e7b4292SVikas Chaudhary 		}
956e7b4292SVikas Chaudhary 		msleep(20);
966e7b4292SVikas Chaudhary 	}
976e7b4292SVikas Chaudhary 
986e7b4292SVikas Chaudhary 	qla4_83xx_wr_reg(ha, QLA83XX_FLASH_LOCK_ID, ha->func_num);
996e7b4292SVikas Chaudhary 	return ret_val;
1006e7b4292SVikas Chaudhary }
1016e7b4292SVikas Chaudhary 
1026e7b4292SVikas Chaudhary static void qla4_83xx_flash_unlock(struct scsi_qla_host *ha)
1036e7b4292SVikas Chaudhary {
1046e7b4292SVikas Chaudhary 	/* Reading FLASH_UNLOCK register unlocks the Flash */
1056e7b4292SVikas Chaudhary 	qla4_83xx_wr_reg(ha, QLA83XX_FLASH_LOCK_ID, 0xFF);
1066e7b4292SVikas Chaudhary 	qla4_83xx_rd_reg(ha, QLA83XX_FLASH_UNLOCK);
1076e7b4292SVikas Chaudhary }
1086e7b4292SVikas Chaudhary 
1096e7b4292SVikas Chaudhary int qla4_83xx_flash_read_u32(struct scsi_qla_host *ha, uint32_t flash_addr,
1106e7b4292SVikas Chaudhary 			     uint8_t *p_data, int u32_word_count)
1116e7b4292SVikas Chaudhary {
1126e7b4292SVikas Chaudhary 	int i;
1136e7b4292SVikas Chaudhary 	uint32_t u32_word;
1146e7b4292SVikas Chaudhary 	uint32_t addr = flash_addr;
1156e7b4292SVikas Chaudhary 	int ret_val = QLA_SUCCESS;
1166e7b4292SVikas Chaudhary 
1176e7b4292SVikas Chaudhary 	ret_val = qla4_83xx_flash_lock(ha);
1186e7b4292SVikas Chaudhary 	if (ret_val == QLA_ERROR)
1196e7b4292SVikas Chaudhary 		goto exit_lock_error;
1206e7b4292SVikas Chaudhary 
1216e7b4292SVikas Chaudhary 	if (addr & 0x03) {
1226e7b4292SVikas Chaudhary 		ql4_printk(KERN_ERR, ha, "%s: Illegal addr = 0x%x\n",
1236e7b4292SVikas Chaudhary 			   __func__, addr);
1246e7b4292SVikas Chaudhary 		ret_val = QLA_ERROR;
1256e7b4292SVikas Chaudhary 		goto exit_flash_read;
1266e7b4292SVikas Chaudhary 	}
1276e7b4292SVikas Chaudhary 
1286e7b4292SVikas Chaudhary 	for (i = 0; i < u32_word_count; i++) {
1296e7b4292SVikas Chaudhary 		ret_val = qla4_83xx_wr_reg_indirect(ha,
1306e7b4292SVikas Chaudhary 						    QLA83XX_FLASH_DIRECT_WINDOW,
1316e7b4292SVikas Chaudhary 						    (addr & 0xFFFF0000));
1326e7b4292SVikas Chaudhary 		if (ret_val == QLA_ERROR) {
1336e7b4292SVikas Chaudhary 			ql4_printk(KERN_ERR, ha, "%s: failed to write addr 0x%x to FLASH_DIRECT_WINDOW\n!",
1346e7b4292SVikas Chaudhary 				   __func__, addr);
1356e7b4292SVikas Chaudhary 			goto exit_flash_read;
1366e7b4292SVikas Chaudhary 		}
1376e7b4292SVikas Chaudhary 
1386e7b4292SVikas Chaudhary 		ret_val = qla4_83xx_rd_reg_indirect(ha,
1396e7b4292SVikas Chaudhary 						QLA83XX_FLASH_DIRECT_DATA(addr),
1406e7b4292SVikas Chaudhary 						&u32_word);
1416e7b4292SVikas Chaudhary 		if (ret_val == QLA_ERROR) {
1426e7b4292SVikas Chaudhary 			ql4_printk(KERN_ERR, ha, "%s: failed to read addr 0x%x!\n",
1436e7b4292SVikas Chaudhary 				   __func__, addr);
1446e7b4292SVikas Chaudhary 			goto exit_flash_read;
1456e7b4292SVikas Chaudhary 		}
1466e7b4292SVikas Chaudhary 
1476e7b4292SVikas Chaudhary 		*(__le32 *)p_data = le32_to_cpu(u32_word);
1486e7b4292SVikas Chaudhary 		p_data = p_data + 4;
1496e7b4292SVikas Chaudhary 		addr = addr + 4;
1506e7b4292SVikas Chaudhary 	}
1516e7b4292SVikas Chaudhary 
1526e7b4292SVikas Chaudhary exit_flash_read:
1536e7b4292SVikas Chaudhary 	qla4_83xx_flash_unlock(ha);
1546e7b4292SVikas Chaudhary 
1556e7b4292SVikas Chaudhary exit_lock_error:
1566e7b4292SVikas Chaudhary 	return ret_val;
1576e7b4292SVikas Chaudhary }
1586e7b4292SVikas Chaudhary 
1596e7b4292SVikas Chaudhary int qla4_83xx_lockless_flash_read_u32(struct scsi_qla_host *ha,
1606e7b4292SVikas Chaudhary 				      uint32_t flash_addr, uint8_t *p_data,
1616e7b4292SVikas Chaudhary 				      int u32_word_count)
1626e7b4292SVikas Chaudhary {
1636e7b4292SVikas Chaudhary 	uint32_t i;
1646e7b4292SVikas Chaudhary 	uint32_t u32_word;
1656e7b4292SVikas Chaudhary 	uint32_t flash_offset;
1666e7b4292SVikas Chaudhary 	uint32_t addr = flash_addr;
1676e7b4292SVikas Chaudhary 	int ret_val = QLA_SUCCESS;
1686e7b4292SVikas Chaudhary 
1696e7b4292SVikas Chaudhary 	flash_offset = addr & (QLA83XX_FLASH_SECTOR_SIZE - 1);
1706e7b4292SVikas Chaudhary 
1716e7b4292SVikas Chaudhary 	if (addr & 0x3) {
1726e7b4292SVikas Chaudhary 		ql4_printk(KERN_ERR, ha, "%s: Illegal addr = 0x%x\n",
1736e7b4292SVikas Chaudhary 			   __func__, addr);
1746e7b4292SVikas Chaudhary 		ret_val = QLA_ERROR;
1756e7b4292SVikas Chaudhary 		goto exit_lockless_read;
1766e7b4292SVikas Chaudhary 	}
1776e7b4292SVikas Chaudhary 
1786e7b4292SVikas Chaudhary 	ret_val = qla4_83xx_wr_reg_indirect(ha, QLA83XX_FLASH_DIRECT_WINDOW,
1796e7b4292SVikas Chaudhary 					    addr);
1806e7b4292SVikas Chaudhary 	if (ret_val == QLA_ERROR) {
1816e7b4292SVikas Chaudhary 		ql4_printk(KERN_ERR, ha, "%s: failed to write addr 0x%x to FLASH_DIRECT_WINDOW!\n",
1826e7b4292SVikas Chaudhary 			   __func__, addr);
1836e7b4292SVikas Chaudhary 		goto exit_lockless_read;
1846e7b4292SVikas Chaudhary 	}
1856e7b4292SVikas Chaudhary 
1866e7b4292SVikas Chaudhary 	/* Check if data is spread across multiple sectors  */
1876e7b4292SVikas Chaudhary 	if ((flash_offset + (u32_word_count * sizeof(uint32_t))) >
1886e7b4292SVikas Chaudhary 	    (QLA83XX_FLASH_SECTOR_SIZE - 1)) {
1896e7b4292SVikas Chaudhary 
1906e7b4292SVikas Chaudhary 		/* Multi sector read */
1916e7b4292SVikas Chaudhary 		for (i = 0; i < u32_word_count; i++) {
1926e7b4292SVikas Chaudhary 			ret_val = qla4_83xx_rd_reg_indirect(ha,
1936e7b4292SVikas Chaudhary 						QLA83XX_FLASH_DIRECT_DATA(addr),
1946e7b4292SVikas Chaudhary 						&u32_word);
1956e7b4292SVikas Chaudhary 			if (ret_val == QLA_ERROR) {
1966e7b4292SVikas Chaudhary 				ql4_printk(KERN_ERR, ha, "%s: failed to read addr 0x%x!\n",
1976e7b4292SVikas Chaudhary 					   __func__, addr);
1986e7b4292SVikas Chaudhary 				goto exit_lockless_read;
1996e7b4292SVikas Chaudhary 			}
2006e7b4292SVikas Chaudhary 
2016e7b4292SVikas Chaudhary 			*(__le32 *)p_data  = le32_to_cpu(u32_word);
2026e7b4292SVikas Chaudhary 			p_data = p_data + 4;
2036e7b4292SVikas Chaudhary 			addr = addr + 4;
2046e7b4292SVikas Chaudhary 			flash_offset = flash_offset + 4;
2056e7b4292SVikas Chaudhary 
2066e7b4292SVikas Chaudhary 			if (flash_offset > (QLA83XX_FLASH_SECTOR_SIZE - 1)) {
2076e7b4292SVikas Chaudhary 				/* This write is needed once for each sector */
2086e7b4292SVikas Chaudhary 				ret_val = qla4_83xx_wr_reg_indirect(ha,
2096e7b4292SVikas Chaudhary 						   QLA83XX_FLASH_DIRECT_WINDOW,
2106e7b4292SVikas Chaudhary 						   addr);
2116e7b4292SVikas Chaudhary 				if (ret_val == QLA_ERROR) {
2126e7b4292SVikas Chaudhary 					ql4_printk(KERN_ERR, ha, "%s: failed to write addr 0x%x to FLASH_DIRECT_WINDOW!\n",
2136e7b4292SVikas Chaudhary 						   __func__, addr);
2146e7b4292SVikas Chaudhary 					goto exit_lockless_read;
2156e7b4292SVikas Chaudhary 				}
2166e7b4292SVikas Chaudhary 				flash_offset = 0;
2176e7b4292SVikas Chaudhary 			}
2186e7b4292SVikas Chaudhary 		}
2196e7b4292SVikas Chaudhary 	} else {
2206e7b4292SVikas Chaudhary 		/* Single sector read */
2216e7b4292SVikas Chaudhary 		for (i = 0; i < u32_word_count; i++) {
2226e7b4292SVikas Chaudhary 			ret_val = qla4_83xx_rd_reg_indirect(ha,
2236e7b4292SVikas Chaudhary 						QLA83XX_FLASH_DIRECT_DATA(addr),
2246e7b4292SVikas Chaudhary 						&u32_word);
2256e7b4292SVikas Chaudhary 			if (ret_val == QLA_ERROR) {
2266e7b4292SVikas Chaudhary 				ql4_printk(KERN_ERR, ha, "%s: failed to read addr 0x%x!\n",
2276e7b4292SVikas Chaudhary 					   __func__, addr);
2286e7b4292SVikas Chaudhary 				goto exit_lockless_read;
2296e7b4292SVikas Chaudhary 			}
2306e7b4292SVikas Chaudhary 
2316e7b4292SVikas Chaudhary 			*(__le32 *)p_data = le32_to_cpu(u32_word);
2326e7b4292SVikas Chaudhary 			p_data = p_data + 4;
2336e7b4292SVikas Chaudhary 			addr = addr + 4;
2346e7b4292SVikas Chaudhary 		}
2356e7b4292SVikas Chaudhary 	}
2366e7b4292SVikas Chaudhary 
2376e7b4292SVikas Chaudhary exit_lockless_read:
2386e7b4292SVikas Chaudhary 	return ret_val;
2396e7b4292SVikas Chaudhary }
2406e7b4292SVikas Chaudhary 
2416e7b4292SVikas Chaudhary void qla4_83xx_rom_lock_recovery(struct scsi_qla_host *ha)
2426e7b4292SVikas Chaudhary {
2436e7b4292SVikas Chaudhary 	if (qla4_83xx_flash_lock(ha))
2446e7b4292SVikas Chaudhary 		ql4_printk(KERN_INFO, ha, "%s: Resetting rom lock\n", __func__);
2456e7b4292SVikas Chaudhary 
2466e7b4292SVikas Chaudhary 	/*
2476e7b4292SVikas Chaudhary 	 * We got the lock, or someone else is holding the lock
2486e7b4292SVikas Chaudhary 	 * since we are restting, forcefully unlock
2496e7b4292SVikas Chaudhary 	 */
2506e7b4292SVikas Chaudhary 	qla4_83xx_flash_unlock(ha);
2516e7b4292SVikas Chaudhary }
2526e7b4292SVikas Chaudhary 
2536e7b4292SVikas Chaudhary #define INTENT_TO_RECOVER	0x01
2546e7b4292SVikas Chaudhary #define PROCEED_TO_RECOVER	0x02
2556e7b4292SVikas Chaudhary 
2566e7b4292SVikas Chaudhary static int qla4_83xx_lock_recovery(struct scsi_qla_host *ha)
2576e7b4292SVikas Chaudhary {
2586e7b4292SVikas Chaudhary 
2596e7b4292SVikas Chaudhary 	uint32_t lock = 0, lockid;
2606e7b4292SVikas Chaudhary 	int ret_val = QLA_ERROR;
2616e7b4292SVikas Chaudhary 
2626e7b4292SVikas Chaudhary 	lockid = ha->isp_ops->rd_reg_direct(ha, QLA83XX_DRV_LOCKRECOVERY);
2636e7b4292SVikas Chaudhary 
2646e7b4292SVikas Chaudhary 	/* Check for other Recovery in progress, go wait */
2656e7b4292SVikas Chaudhary 	if ((lockid & 0x3) != 0)
2666e7b4292SVikas Chaudhary 		goto exit_lock_recovery;
2676e7b4292SVikas Chaudhary 
2686e7b4292SVikas Chaudhary 	/* Intent to Recover */
2696e7b4292SVikas Chaudhary 	ha->isp_ops->wr_reg_direct(ha, QLA83XX_DRV_LOCKRECOVERY,
2706e7b4292SVikas Chaudhary 				   (ha->func_num << 2) | INTENT_TO_RECOVER);
2716e7b4292SVikas Chaudhary 
2726e7b4292SVikas Chaudhary 	msleep(200);
2736e7b4292SVikas Chaudhary 
2746e7b4292SVikas Chaudhary 	/* Check Intent to Recover is advertised */
2756e7b4292SVikas Chaudhary 	lockid = ha->isp_ops->rd_reg_direct(ha, QLA83XX_DRV_LOCKRECOVERY);
2766e7b4292SVikas Chaudhary 	if ((lockid & 0x3C) != (ha->func_num << 2))
2776e7b4292SVikas Chaudhary 		goto exit_lock_recovery;
2786e7b4292SVikas Chaudhary 
2796e7b4292SVikas Chaudhary 	ql4_printk(KERN_INFO, ha, "%s: IDC Lock recovery initiated for func %d\n",
2806e7b4292SVikas Chaudhary 		   __func__, ha->func_num);
2816e7b4292SVikas Chaudhary 
2826e7b4292SVikas Chaudhary 	/* Proceed to Recover */
2836e7b4292SVikas Chaudhary 	ha->isp_ops->wr_reg_direct(ha, QLA83XX_DRV_LOCKRECOVERY,
2846e7b4292SVikas Chaudhary 				   (ha->func_num << 2) | PROCEED_TO_RECOVER);
2856e7b4292SVikas Chaudhary 
2866e7b4292SVikas Chaudhary 	/* Force Unlock */
2876e7b4292SVikas Chaudhary 	ha->isp_ops->wr_reg_direct(ha, QLA83XX_DRV_LOCK_ID, 0xFF);
2886e7b4292SVikas Chaudhary 	ha->isp_ops->rd_reg_direct(ha, QLA83XX_DRV_UNLOCK);
2896e7b4292SVikas Chaudhary 
2906e7b4292SVikas Chaudhary 	/* Clear bits 0-5 in IDC_RECOVERY register*/
2916e7b4292SVikas Chaudhary 	ha->isp_ops->wr_reg_direct(ha, QLA83XX_DRV_LOCKRECOVERY, 0);
2926e7b4292SVikas Chaudhary 
2936e7b4292SVikas Chaudhary 	/* Get lock */
2946e7b4292SVikas Chaudhary 	lock = ha->isp_ops->rd_reg_direct(ha, QLA83XX_DRV_LOCK);
2956e7b4292SVikas Chaudhary 	if (lock) {
2966e7b4292SVikas Chaudhary 		lockid = ha->isp_ops->rd_reg_direct(ha, QLA83XX_DRV_LOCK_ID);
2976e7b4292SVikas Chaudhary 		lockid = ((lockid + (1 << 8)) & ~0xFF) | ha->func_num;
2986e7b4292SVikas Chaudhary 		ha->isp_ops->wr_reg_direct(ha, QLA83XX_DRV_LOCK_ID, lockid);
2996e7b4292SVikas Chaudhary 		ret_val = QLA_SUCCESS;
3006e7b4292SVikas Chaudhary 	}
3016e7b4292SVikas Chaudhary 
3026e7b4292SVikas Chaudhary exit_lock_recovery:
3036e7b4292SVikas Chaudhary 	return ret_val;
3046e7b4292SVikas Chaudhary }
3056e7b4292SVikas Chaudhary 
3066e7b4292SVikas Chaudhary #define	QLA83XX_DRV_LOCK_MSLEEP		200
3076e7b4292SVikas Chaudhary 
3086e7b4292SVikas Chaudhary int qla4_83xx_drv_lock(struct scsi_qla_host *ha)
3096e7b4292SVikas Chaudhary {
3106e7b4292SVikas Chaudhary 	int timeout = 0;
3116e7b4292SVikas Chaudhary 	uint32_t status = 0;
3126e7b4292SVikas Chaudhary 	int ret_val = QLA_SUCCESS;
3136e7b4292SVikas Chaudhary 	uint32_t first_owner = 0;
3146e7b4292SVikas Chaudhary 	uint32_t tmo_owner = 0;
3156e7b4292SVikas Chaudhary 	uint32_t lock_id;
3166e7b4292SVikas Chaudhary 	uint32_t func_num;
3176e7b4292SVikas Chaudhary 	uint32_t lock_cnt;
3186e7b4292SVikas Chaudhary 
3196e7b4292SVikas Chaudhary 	while (status == 0) {
3206e7b4292SVikas Chaudhary 		status = qla4_83xx_rd_reg(ha, QLA83XX_DRV_LOCK);
3216e7b4292SVikas Chaudhary 		if (status) {
3226e7b4292SVikas Chaudhary 			/* Increment Counter (8-31) and update func_num (0-7) on
3236e7b4292SVikas Chaudhary 			 * getting a successful lock  */
3246e7b4292SVikas Chaudhary 			lock_id = qla4_83xx_rd_reg(ha, QLA83XX_DRV_LOCK_ID);
3256e7b4292SVikas Chaudhary 			lock_id = ((lock_id + (1 << 8)) & ~0xFF) | ha->func_num;
3266e7b4292SVikas Chaudhary 			qla4_83xx_wr_reg(ha, QLA83XX_DRV_LOCK_ID, lock_id);
3276e7b4292SVikas Chaudhary 			break;
3286e7b4292SVikas Chaudhary 		}
3296e7b4292SVikas Chaudhary 
3306e7b4292SVikas Chaudhary 		if (timeout == 0)
3316e7b4292SVikas Chaudhary 			/* Save counter + ID of function holding the lock for
3326e7b4292SVikas Chaudhary 			 * first failure */
3336e7b4292SVikas Chaudhary 			first_owner = ha->isp_ops->rd_reg_direct(ha,
3346e7b4292SVikas Chaudhary 							  QLA83XX_DRV_LOCK_ID);
3356e7b4292SVikas Chaudhary 
3366e7b4292SVikas Chaudhary 		if (++timeout >=
3376e7b4292SVikas Chaudhary 		    (QLA83XX_DRV_LOCK_TIMEOUT / QLA83XX_DRV_LOCK_MSLEEP)) {
3386e7b4292SVikas Chaudhary 			tmo_owner = qla4_83xx_rd_reg(ha, QLA83XX_DRV_LOCK_ID);
3396e7b4292SVikas Chaudhary 			func_num = tmo_owner & 0xFF;
3406e7b4292SVikas Chaudhary 			lock_cnt = tmo_owner >> 8;
3416e7b4292SVikas Chaudhary 			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",
3426e7b4292SVikas Chaudhary 				   __func__, ha->func_num, func_num, lock_cnt,
3436e7b4292SVikas Chaudhary 				   (first_owner & 0xFF));
3446e7b4292SVikas Chaudhary 
3456e7b4292SVikas Chaudhary 			if (first_owner != tmo_owner) {
3466e7b4292SVikas Chaudhary 				/* Some other driver got lock, OR same driver
3476e7b4292SVikas Chaudhary 				 * got lock again (counter value changed), when
3486e7b4292SVikas Chaudhary 				 * we were waiting for lock.
3496e7b4292SVikas Chaudhary 				 * Retry for another 2 sec */
3506e7b4292SVikas Chaudhary 				ql4_printk(KERN_INFO, ha, "%s: IDC lock failed for func %d\n",
3516e7b4292SVikas Chaudhary 					   __func__, ha->func_num);
3526e7b4292SVikas Chaudhary 				timeout = 0;
3536e7b4292SVikas Chaudhary 			} else {
3546e7b4292SVikas Chaudhary 				/* Same driver holding lock > 2sec.
3556e7b4292SVikas Chaudhary 				 * Force Recovery */
3566e7b4292SVikas Chaudhary 				ret_val = qla4_83xx_lock_recovery(ha);
3576e7b4292SVikas Chaudhary 				if (ret_val == QLA_SUCCESS) {
3586e7b4292SVikas Chaudhary 					/* Recovered and got lock */
3596e7b4292SVikas Chaudhary 					ql4_printk(KERN_INFO, ha, "%s: IDC lock Recovery by %d successful\n",
3606e7b4292SVikas Chaudhary 						   __func__, ha->func_num);
3616e7b4292SVikas Chaudhary 					break;
3626e7b4292SVikas Chaudhary 				}
3636e7b4292SVikas Chaudhary 				/* Recovery Failed, some other function
3646e7b4292SVikas Chaudhary 				 * has the lock, wait for 2secs and retry */
3658faaaeadSMasanari Iida 				ql4_printk(KERN_INFO, ha, "%s: IDC lock Recovery by %d failed, Retrying timeout\n",
3666e7b4292SVikas Chaudhary 					   __func__, ha->func_num);
3676e7b4292SVikas Chaudhary 				timeout = 0;
3686e7b4292SVikas Chaudhary 			}
3696e7b4292SVikas Chaudhary 		}
3706e7b4292SVikas Chaudhary 		msleep(QLA83XX_DRV_LOCK_MSLEEP);
3716e7b4292SVikas Chaudhary 	}
3726e7b4292SVikas Chaudhary 
3736e7b4292SVikas Chaudhary 	return ret_val;
3746e7b4292SVikas Chaudhary }
3756e7b4292SVikas Chaudhary 
3766e7b4292SVikas Chaudhary void qla4_83xx_drv_unlock(struct scsi_qla_host *ha)
3776e7b4292SVikas Chaudhary {
3786e7b4292SVikas Chaudhary 	int id;
3796e7b4292SVikas Chaudhary 
3806e7b4292SVikas Chaudhary 	id = qla4_83xx_rd_reg(ha, QLA83XX_DRV_LOCK_ID);
3816e7b4292SVikas Chaudhary 
3826e7b4292SVikas Chaudhary 	if ((id & 0xFF) != ha->func_num) {
3836e7b4292SVikas Chaudhary 		ql4_printk(KERN_ERR, ha, "%s: IDC Unlock by %d failed, lock owner is %d\n",
3846e7b4292SVikas Chaudhary 			   __func__, ha->func_num, (id & 0xFF));
3856e7b4292SVikas Chaudhary 		return;
3866e7b4292SVikas Chaudhary 	}
3876e7b4292SVikas Chaudhary 
3886e7b4292SVikas Chaudhary 	/* Keep lock counter value, update the ha->func_num to 0xFF */
3896e7b4292SVikas Chaudhary 	qla4_83xx_wr_reg(ha, QLA83XX_DRV_LOCK_ID, (id | 0xFF));
3906e7b4292SVikas Chaudhary 	qla4_83xx_rd_reg(ha, QLA83XX_DRV_UNLOCK);
3916e7b4292SVikas Chaudhary }
3926e7b4292SVikas Chaudhary 
3936e7b4292SVikas Chaudhary void qla4_83xx_set_idc_dontreset(struct scsi_qla_host *ha)
3946e7b4292SVikas Chaudhary {
3956e7b4292SVikas Chaudhary 	uint32_t idc_ctrl;
3966e7b4292SVikas Chaudhary 
3976e7b4292SVikas Chaudhary 	idc_ctrl = qla4_83xx_rd_reg(ha, QLA83XX_IDC_DRV_CTRL);
3986e7b4292SVikas Chaudhary 	idc_ctrl |= DONTRESET_BIT0;
3996e7b4292SVikas Chaudhary 	qla4_83xx_wr_reg(ha, QLA83XX_IDC_DRV_CTRL, idc_ctrl);
4006e7b4292SVikas Chaudhary 	DEBUG2(ql4_printk(KERN_INFO, ha, "%s: idc_ctrl = %d\n", __func__,
4016e7b4292SVikas Chaudhary 			  idc_ctrl));
4026e7b4292SVikas Chaudhary }
4036e7b4292SVikas Chaudhary 
4046e7b4292SVikas Chaudhary void qla4_83xx_clear_idc_dontreset(struct scsi_qla_host *ha)
4056e7b4292SVikas Chaudhary {
4066e7b4292SVikas Chaudhary 	uint32_t idc_ctrl;
4076e7b4292SVikas Chaudhary 
4086e7b4292SVikas Chaudhary 	idc_ctrl = qla4_83xx_rd_reg(ha, QLA83XX_IDC_DRV_CTRL);
4096e7b4292SVikas Chaudhary 	idc_ctrl &= ~DONTRESET_BIT0;
4106e7b4292SVikas Chaudhary 	qla4_83xx_wr_reg(ha, QLA83XX_IDC_DRV_CTRL, idc_ctrl);
4116e7b4292SVikas Chaudhary 	DEBUG2(ql4_printk(KERN_INFO, ha, "%s: idc_ctrl = %d\n", __func__,
4126e7b4292SVikas Chaudhary 			  idc_ctrl));
4136e7b4292SVikas Chaudhary }
4146e7b4292SVikas Chaudhary 
4156e7b4292SVikas Chaudhary int qla4_83xx_idc_dontreset(struct scsi_qla_host *ha)
4166e7b4292SVikas Chaudhary {
4176e7b4292SVikas Chaudhary 	uint32_t idc_ctrl;
4186e7b4292SVikas Chaudhary 
4196e7b4292SVikas Chaudhary 	idc_ctrl = qla4_83xx_rd_reg(ha, QLA83XX_IDC_DRV_CTRL);
4206e7b4292SVikas Chaudhary 	return idc_ctrl & DONTRESET_BIT0;
4216e7b4292SVikas Chaudhary }
4226e7b4292SVikas Chaudhary 
4236e7b4292SVikas Chaudhary /*-------------------------IDC State Machine ---------------------*/
4246e7b4292SVikas Chaudhary 
4256e7b4292SVikas Chaudhary enum {
4266e7b4292SVikas Chaudhary 	UNKNOWN_CLASS = 0,
4276e7b4292SVikas Chaudhary 	NIC_CLASS,
4286e7b4292SVikas Chaudhary 	FCOE_CLASS,
4296e7b4292SVikas Chaudhary 	ISCSI_CLASS
4306e7b4292SVikas Chaudhary };
4316e7b4292SVikas Chaudhary 
4326e7b4292SVikas Chaudhary struct device_info {
4336e7b4292SVikas Chaudhary 	int func_num;
4346e7b4292SVikas Chaudhary 	int device_type;
4356e7b4292SVikas Chaudhary 	int port_num;
4366e7b4292SVikas Chaudhary };
4376e7b4292SVikas Chaudhary 
4389661975fSVikas Chaudhary int qla4_83xx_can_perform_reset(struct scsi_qla_host *ha)
4396e7b4292SVikas Chaudhary {
4406e7b4292SVikas Chaudhary 	uint32_t drv_active;
4416e7b4292SVikas Chaudhary 	uint32_t dev_part, dev_part1, dev_part2;
4426e7b4292SVikas Chaudhary 	int i;
4436e7b4292SVikas Chaudhary 	struct device_info device_map[16];
4446e7b4292SVikas Chaudhary 	int func_nibble;
4456e7b4292SVikas Chaudhary 	int nibble;
4466e7b4292SVikas Chaudhary 	int nic_present = 0;
4476e7b4292SVikas Chaudhary 	int iscsi_present = 0;
4486e7b4292SVikas Chaudhary 	int iscsi_func_low = 0;
4496e7b4292SVikas Chaudhary 
4506e7b4292SVikas Chaudhary 	/* Use the dev_partition register to determine the PCI function number
4516e7b4292SVikas Chaudhary 	 * and then check drv_active register to see which driver is loaded */
4526e7b4292SVikas Chaudhary 	dev_part1 = qla4_83xx_rd_reg(ha,
4536e7b4292SVikas Chaudhary 				     ha->reg_tbl[QLA8XXX_CRB_DEV_PART_INFO]);
4546e7b4292SVikas Chaudhary 	dev_part2 = qla4_83xx_rd_reg(ha, QLA83XX_CRB_DEV_PART_INFO2);
4556e7b4292SVikas Chaudhary 	drv_active = qla4_83xx_rd_reg(ha, ha->reg_tbl[QLA8XXX_CRB_DRV_ACTIVE]);
4566e7b4292SVikas Chaudhary 
4576e7b4292SVikas Chaudhary 	/* Each function has 4 bits in dev_partition Info register,
4586e7b4292SVikas Chaudhary 	 * Lower 2 bits - device type, Upper 2 bits - physical port number */
4596e7b4292SVikas Chaudhary 	dev_part = dev_part1;
4606e7b4292SVikas Chaudhary 	for (i = nibble = 0; i <= 15; i++, nibble++) {
4616e7b4292SVikas Chaudhary 		func_nibble = dev_part & (0xF << (nibble * 4));
4626e7b4292SVikas Chaudhary 		func_nibble >>= (nibble * 4);
4636e7b4292SVikas Chaudhary 		device_map[i].func_num = i;
4646e7b4292SVikas Chaudhary 		device_map[i].device_type = func_nibble & 0x3;
4656e7b4292SVikas Chaudhary 		device_map[i].port_num = func_nibble & 0xC;
4666e7b4292SVikas Chaudhary 
4676e7b4292SVikas Chaudhary 		if (device_map[i].device_type == NIC_CLASS) {
4686e7b4292SVikas Chaudhary 			if (drv_active & (1 << device_map[i].func_num)) {
4696e7b4292SVikas Chaudhary 				nic_present++;
4706e7b4292SVikas Chaudhary 				break;
4716e7b4292SVikas Chaudhary 			}
4726e7b4292SVikas Chaudhary 		} else if (device_map[i].device_type == ISCSI_CLASS) {
4736e7b4292SVikas Chaudhary 			if (drv_active & (1 << device_map[i].func_num)) {
4746e7b4292SVikas Chaudhary 				if (!iscsi_present ||
4756e7b4292SVikas Chaudhary 				    (iscsi_present &&
4766e7b4292SVikas Chaudhary 				     (iscsi_func_low > device_map[i].func_num)))
4776e7b4292SVikas Chaudhary 					iscsi_func_low = device_map[i].func_num;
4786e7b4292SVikas Chaudhary 
4796e7b4292SVikas Chaudhary 				iscsi_present++;
4806e7b4292SVikas Chaudhary 			}
4816e7b4292SVikas Chaudhary 		}
4826e7b4292SVikas Chaudhary 
4836e7b4292SVikas Chaudhary 		/* For function_num[8..15] get info from dev_part2 register */
4846e7b4292SVikas Chaudhary 		if (nibble == 7) {
4856e7b4292SVikas Chaudhary 			nibble = 0;
4866e7b4292SVikas Chaudhary 			dev_part = dev_part2;
4876e7b4292SVikas Chaudhary 		}
4886e7b4292SVikas Chaudhary 	}
4896e7b4292SVikas Chaudhary 
4906e7b4292SVikas Chaudhary 	/* NIC, iSCSI and FCOE are the Reset owners based on order, NIC gets
4916e7b4292SVikas Chaudhary 	 * precedence over iSCSI and FCOE and iSCSI over FCOE, based on drivers
4926e7b4292SVikas Chaudhary 	 * present. */
4936e7b4292SVikas Chaudhary 	if (!nic_present && (ha->func_num == iscsi_func_low)) {
4946e7b4292SVikas Chaudhary 		DEBUG2(ql4_printk(KERN_INFO, ha,
4956e7b4292SVikas Chaudhary 				  "%s: can reset - NIC not present and lower iSCSI function is %d\n",
4966e7b4292SVikas Chaudhary 				  __func__, ha->func_num));
4976e7b4292SVikas Chaudhary 		return 1;
4986e7b4292SVikas Chaudhary 	}
4996e7b4292SVikas Chaudhary 
5006e7b4292SVikas Chaudhary 	return 0;
5016e7b4292SVikas Chaudhary }
5026e7b4292SVikas Chaudhary 
5036e7b4292SVikas Chaudhary /**
5046e7b4292SVikas Chaudhary  * qla4_83xx_need_reset_handler - Code to start reset sequence
5056e7b4292SVikas Chaudhary  * @ha: pointer to adapter structure
5066e7b4292SVikas Chaudhary  *
5076e7b4292SVikas Chaudhary  * Note: IDC lock must be held upon entry
5086e7b4292SVikas Chaudhary  **/
5096e7b4292SVikas Chaudhary void qla4_83xx_need_reset_handler(struct scsi_qla_host *ha)
5106e7b4292SVikas Chaudhary {
5116e7b4292SVikas Chaudhary 	uint32_t dev_state, drv_state, drv_active;
5126e7b4292SVikas Chaudhary 	unsigned long reset_timeout, dev_init_timeout;
5136e7b4292SVikas Chaudhary 
5146e7b4292SVikas Chaudhary 	ql4_printk(KERN_INFO, ha, "%s: Performing ISP error recovery\n",
5156e7b4292SVikas Chaudhary 		   __func__);
5166e7b4292SVikas Chaudhary 
5176e7b4292SVikas Chaudhary 	if (!test_bit(AF_8XXX_RST_OWNER, &ha->flags)) {
5186e7b4292SVikas Chaudhary 		DEBUG2(ql4_printk(KERN_INFO, ha, "%s: reset acknowledged\n",
5196e7b4292SVikas Chaudhary 				  __func__));
5206e7b4292SVikas Chaudhary 		qla4_8xxx_set_rst_ready(ha);
5216e7b4292SVikas Chaudhary 
5226e7b4292SVikas Chaudhary 		/* Non-reset owners ACK Reset and wait for device INIT state
5236e7b4292SVikas Chaudhary 		 * as part of Reset Recovery by Reset Owner */
5246e7b4292SVikas Chaudhary 		dev_init_timeout = jiffies + (ha->nx_dev_init_timeout * HZ);
5256e7b4292SVikas Chaudhary 
5266e7b4292SVikas Chaudhary 		do {
5276e7b4292SVikas Chaudhary 			if (time_after_eq(jiffies, dev_init_timeout)) {
5286e7b4292SVikas Chaudhary 				ql4_printk(KERN_INFO, ha, "%s: Non Reset owner dev init timeout\n",
5296e7b4292SVikas Chaudhary 					   __func__);
5306e7b4292SVikas Chaudhary 				break;
5316e7b4292SVikas Chaudhary 			}
5326e7b4292SVikas Chaudhary 
5336e7b4292SVikas Chaudhary 			ha->isp_ops->idc_unlock(ha);
5346e7b4292SVikas Chaudhary 			msleep(1000);
5356e7b4292SVikas Chaudhary 			ha->isp_ops->idc_lock(ha);
5366e7b4292SVikas Chaudhary 
5376e7b4292SVikas Chaudhary 			dev_state = qla4_8xxx_rd_direct(ha,
5386e7b4292SVikas Chaudhary 							QLA8XXX_CRB_DEV_STATE);
5396e7b4292SVikas Chaudhary 		} while (dev_state == QLA8XXX_DEV_NEED_RESET);
5406e7b4292SVikas Chaudhary 	} else {
5416e7b4292SVikas Chaudhary 		qla4_8xxx_set_rst_ready(ha);
5426e7b4292SVikas Chaudhary 		reset_timeout = jiffies + (ha->nx_reset_timeout * HZ);
5436e7b4292SVikas Chaudhary 		drv_state = qla4_8xxx_rd_direct(ha, QLA8XXX_CRB_DRV_STATE);
5446e7b4292SVikas Chaudhary 		drv_active = qla4_8xxx_rd_direct(ha, QLA8XXX_CRB_DRV_ACTIVE);
5456e7b4292SVikas Chaudhary 
5466e7b4292SVikas Chaudhary 		ql4_printk(KERN_INFO, ha, "%s: drv_state = 0x%x, drv_active = 0x%x\n",
5476e7b4292SVikas Chaudhary 			   __func__, drv_state, drv_active);
5486e7b4292SVikas Chaudhary 
5496e7b4292SVikas Chaudhary 		while (drv_state != drv_active) {
5506e7b4292SVikas Chaudhary 			if (time_after_eq(jiffies, reset_timeout)) {
5516e7b4292SVikas Chaudhary 				ql4_printk(KERN_INFO, ha, "%s: %s: RESET TIMEOUT! drv_state: 0x%08x, drv_active: 0x%08x\n",
5526e7b4292SVikas Chaudhary 					   __func__, DRIVER_NAME, drv_state,
5536e7b4292SVikas Chaudhary 					   drv_active);
5546e7b4292SVikas Chaudhary 				break;
5556e7b4292SVikas Chaudhary 			}
5566e7b4292SVikas Chaudhary 
5576e7b4292SVikas Chaudhary 			ha->isp_ops->idc_unlock(ha);
5586e7b4292SVikas Chaudhary 			msleep(1000);
5596e7b4292SVikas Chaudhary 			ha->isp_ops->idc_lock(ha);
5606e7b4292SVikas Chaudhary 
5616e7b4292SVikas Chaudhary 			drv_state = qla4_8xxx_rd_direct(ha,
5626e7b4292SVikas Chaudhary 							QLA8XXX_CRB_DRV_STATE);
5636e7b4292SVikas Chaudhary 			drv_active = qla4_8xxx_rd_direct(ha,
5646e7b4292SVikas Chaudhary 							QLA8XXX_CRB_DRV_ACTIVE);
5656e7b4292SVikas Chaudhary 		}
5666e7b4292SVikas Chaudhary 
5676e7b4292SVikas Chaudhary 		if (drv_state != drv_active) {
5686e7b4292SVikas Chaudhary 			ql4_printk(KERN_INFO, ha, "%s: Reset_owner turning off drv_active of non-acking function 0x%x\n",
5696e7b4292SVikas Chaudhary 				   __func__, (drv_active ^ drv_state));
5706e7b4292SVikas Chaudhary 			drv_active = drv_active & drv_state;
5716e7b4292SVikas Chaudhary 			qla4_8xxx_wr_direct(ha, QLA8XXX_CRB_DRV_ACTIVE,
5726e7b4292SVikas Chaudhary 					    drv_active);
5736e7b4292SVikas Chaudhary 		}
5746e7b4292SVikas Chaudhary 
5756e7b4292SVikas Chaudhary 		clear_bit(AF_8XXX_RST_OWNER, &ha->flags);
5766e7b4292SVikas Chaudhary 		/* Start Reset Recovery */
5776e7b4292SVikas Chaudhary 		qla4_8xxx_device_bootstrap(ha);
5786e7b4292SVikas Chaudhary 	}
5796e7b4292SVikas Chaudhary }
5806e7b4292SVikas Chaudhary 
5816e7b4292SVikas Chaudhary void qla4_83xx_get_idc_param(struct scsi_qla_host *ha)
5826e7b4292SVikas Chaudhary {
5836e7b4292SVikas Chaudhary 	uint32_t idc_params, ret_val;
5846e7b4292SVikas Chaudhary 
5856e7b4292SVikas Chaudhary 	ret_val = qla4_83xx_flash_read_u32(ha, QLA83XX_IDC_PARAM_ADDR,
5866e7b4292SVikas Chaudhary 					   (uint8_t *)&idc_params, 1);
5876e7b4292SVikas Chaudhary 	if (ret_val == QLA_SUCCESS) {
5886e7b4292SVikas Chaudhary 		ha->nx_dev_init_timeout = idc_params & 0xFFFF;
5896e7b4292SVikas Chaudhary 		ha->nx_reset_timeout = (idc_params >> 16) & 0xFFFF;
5906e7b4292SVikas Chaudhary 	} else {
5916e7b4292SVikas Chaudhary 		ha->nx_dev_init_timeout = ROM_DEV_INIT_TIMEOUT;
5926e7b4292SVikas Chaudhary 		ha->nx_reset_timeout = ROM_DRV_RESET_ACK_TIMEOUT;
5936e7b4292SVikas Chaudhary 	}
5946e7b4292SVikas Chaudhary 
5956e7b4292SVikas Chaudhary 	DEBUG2(ql4_printk(KERN_DEBUG, ha,
5966e7b4292SVikas Chaudhary 			  "%s: ha->nx_dev_init_timeout = %d, ha->nx_reset_timeout = %d\n",
5976e7b4292SVikas Chaudhary 			  __func__, ha->nx_dev_init_timeout,
5986e7b4292SVikas Chaudhary 			  ha->nx_reset_timeout));
5996e7b4292SVikas Chaudhary }
6006e7b4292SVikas Chaudhary 
6016e7b4292SVikas Chaudhary /*-------------------------Reset Sequence Functions-----------------------*/
6026e7b4292SVikas Chaudhary 
6036e7b4292SVikas Chaudhary static void qla4_83xx_dump_reset_seq_hdr(struct scsi_qla_host *ha)
6046e7b4292SVikas Chaudhary {
6056e7b4292SVikas Chaudhary 	uint8_t *phdr;
6066e7b4292SVikas Chaudhary 
6076e7b4292SVikas Chaudhary 	if (!ha->reset_tmplt.buff) {
6086e7b4292SVikas Chaudhary 		ql4_printk(KERN_ERR, ha, "%s: Error: Invalid reset_seq_template\n",
6096e7b4292SVikas Chaudhary 			   __func__);
6106e7b4292SVikas Chaudhary 		return;
6116e7b4292SVikas Chaudhary 	}
6126e7b4292SVikas Chaudhary 
6136e7b4292SVikas Chaudhary 	phdr = ha->reset_tmplt.buff;
6146e7b4292SVikas Chaudhary 
6156e7b4292SVikas Chaudhary 	DEBUG2(ql4_printk(KERN_INFO, ha,
6166e7b4292SVikas Chaudhary 			  "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",
6176e7b4292SVikas Chaudhary 			  *phdr, *(phdr+1), *(phdr+2), *(phdr+3), *(phdr+4),
6186e7b4292SVikas Chaudhary 			  *(phdr+5), *(phdr+6), *(phdr+7), *(phdr + 8),
6196e7b4292SVikas Chaudhary 			  *(phdr+9), *(phdr+10), *(phdr+11), *(phdr+12),
6206e7b4292SVikas Chaudhary 			  *(phdr+13), *(phdr+14), *(phdr+15)));
6216e7b4292SVikas Chaudhary }
6226e7b4292SVikas Chaudhary 
6236e7b4292SVikas Chaudhary static int qla4_83xx_copy_bootloader(struct scsi_qla_host *ha)
6246e7b4292SVikas Chaudhary {
6256e7b4292SVikas Chaudhary 	uint8_t *p_cache;
6266e7b4292SVikas Chaudhary 	uint32_t src, count, size;
6276e7b4292SVikas Chaudhary 	uint64_t dest;
6286e7b4292SVikas Chaudhary 	int ret_val = QLA_SUCCESS;
6296e7b4292SVikas Chaudhary 
6306e7b4292SVikas Chaudhary 	src = QLA83XX_BOOTLOADER_FLASH_ADDR;
6316e7b4292SVikas Chaudhary 	dest = qla4_83xx_rd_reg(ha, QLA83XX_BOOTLOADER_ADDR);
6326e7b4292SVikas Chaudhary 	size = qla4_83xx_rd_reg(ha, QLA83XX_BOOTLOADER_SIZE);
6336e7b4292SVikas Chaudhary 
6346e7b4292SVikas Chaudhary 	/* 128 bit alignment check */
6356e7b4292SVikas Chaudhary 	if (size & 0xF)
6366e7b4292SVikas Chaudhary 		size = (size + 16) & ~0xF;
6376e7b4292SVikas Chaudhary 
6386e7b4292SVikas Chaudhary 	/* 16 byte count */
6396e7b4292SVikas Chaudhary 	count = size/16;
6406e7b4292SVikas Chaudhary 
6416e7b4292SVikas Chaudhary 	p_cache = vmalloc(size);
6426e7b4292SVikas Chaudhary 	if (p_cache == NULL) {
6436e7b4292SVikas Chaudhary 		ql4_printk(KERN_ERR, ha, "%s: Failed to allocate memory for boot loader cache\n",
6446e7b4292SVikas Chaudhary 			   __func__);
6456e7b4292SVikas Chaudhary 		ret_val = QLA_ERROR;
6466e7b4292SVikas Chaudhary 		goto exit_copy_bootloader;
6476e7b4292SVikas Chaudhary 	}
6486e7b4292SVikas Chaudhary 
6496e7b4292SVikas Chaudhary 	ret_val = qla4_83xx_lockless_flash_read_u32(ha, src, p_cache,
6506e7b4292SVikas Chaudhary 						    size / sizeof(uint32_t));
6516e7b4292SVikas Chaudhary 	if (ret_val == QLA_ERROR) {
6526e7b4292SVikas Chaudhary 		ql4_printk(KERN_ERR, ha, "%s: Error reading firmware from flash\n",
6536e7b4292SVikas Chaudhary 			   __func__);
6546e7b4292SVikas Chaudhary 		goto exit_copy_error;
6556e7b4292SVikas Chaudhary 	}
6566e7b4292SVikas Chaudhary 	DEBUG2(ql4_printk(KERN_INFO, ha, "%s: Read firmware from flash\n",
6576e7b4292SVikas Chaudhary 			  __func__));
6586e7b4292SVikas Chaudhary 
6596e7b4292SVikas Chaudhary 	/* 128 bit/16 byte write to MS memory */
6603c3cab17STej Parkash 	ret_val = qla4_8xxx_ms_mem_write_128b(ha, dest, (uint32_t *)p_cache,
6616e7b4292SVikas Chaudhary 					      count);
6626e7b4292SVikas Chaudhary 	if (ret_val == QLA_ERROR) {
6636e7b4292SVikas Chaudhary 		ql4_printk(KERN_ERR, ha, "%s: Error writing firmware to MS\n",
6646e7b4292SVikas Chaudhary 			   __func__);
6656e7b4292SVikas Chaudhary 		goto exit_copy_error;
6666e7b4292SVikas Chaudhary 	}
6676e7b4292SVikas Chaudhary 
6686e7b4292SVikas Chaudhary 	DEBUG2(ql4_printk(KERN_INFO, ha, "%s: Wrote firmware size %d to MS\n",
6696e7b4292SVikas Chaudhary 			  __func__, size));
6706e7b4292SVikas Chaudhary 
6716e7b4292SVikas Chaudhary exit_copy_error:
6726e7b4292SVikas Chaudhary 	vfree(p_cache);
6736e7b4292SVikas Chaudhary 
6746e7b4292SVikas Chaudhary exit_copy_bootloader:
6756e7b4292SVikas Chaudhary 	return ret_val;
6766e7b4292SVikas Chaudhary }
6776e7b4292SVikas Chaudhary 
6786e7b4292SVikas Chaudhary static int qla4_83xx_check_cmd_peg_status(struct scsi_qla_host *ha)
6796e7b4292SVikas Chaudhary {
6806e7b4292SVikas Chaudhary 	uint32_t val, ret_val = QLA_ERROR;
6816e7b4292SVikas Chaudhary 	int retries = CRB_CMDPEG_CHECK_RETRY_COUNT;
6826e7b4292SVikas Chaudhary 
6836e7b4292SVikas Chaudhary 	do {
6846e7b4292SVikas Chaudhary 		val = qla4_83xx_rd_reg(ha, QLA83XX_CMDPEG_STATE);
6856e7b4292SVikas Chaudhary 		if (val == PHAN_INITIALIZE_COMPLETE) {
6866e7b4292SVikas Chaudhary 			DEBUG2(ql4_printk(KERN_INFO, ha,
6876e7b4292SVikas Chaudhary 					  "%s: Command Peg initialization complete. State=0x%x\n",
6886e7b4292SVikas Chaudhary 					  __func__, val));
6896e7b4292SVikas Chaudhary 			ret_val = QLA_SUCCESS;
6906e7b4292SVikas Chaudhary 			break;
6916e7b4292SVikas Chaudhary 		}
6926e7b4292SVikas Chaudhary 		msleep(CRB_CMDPEG_CHECK_DELAY);
6936e7b4292SVikas Chaudhary 	} while (--retries);
6946e7b4292SVikas Chaudhary 
6956e7b4292SVikas Chaudhary 	return ret_val;
6966e7b4292SVikas Chaudhary }
6976e7b4292SVikas Chaudhary 
6986e7b4292SVikas Chaudhary /**
6996e7b4292SVikas Chaudhary  * qla4_83xx_poll_reg - Poll the given CRB addr for duration msecs till
7006e7b4292SVikas Chaudhary  * value read ANDed with test_mask is equal to test_result.
7016e7b4292SVikas Chaudhary  *
7026e7b4292SVikas Chaudhary  * @ha : Pointer to adapter structure
7036e7b4292SVikas Chaudhary  * @addr : CRB register address
7046e7b4292SVikas Chaudhary  * @duration : Poll for total of "duration" msecs
7056e7b4292SVikas Chaudhary  * @test_mask : Mask value read with "test_mask"
7066e7b4292SVikas Chaudhary  * @test_result : Compare (value&test_mask) with test_result.
7076e7b4292SVikas Chaudhary  **/
7086e7b4292SVikas Chaudhary static int qla4_83xx_poll_reg(struct scsi_qla_host *ha, uint32_t addr,
7096e7b4292SVikas Chaudhary 			      int duration, uint32_t test_mask,
7106e7b4292SVikas Chaudhary 			      uint32_t test_result)
7116e7b4292SVikas Chaudhary {
7126e7b4292SVikas Chaudhary 	uint32_t value;
7136e7b4292SVikas Chaudhary 	uint8_t retries;
7146e7b4292SVikas Chaudhary 	int ret_val = QLA_SUCCESS;
7156e7b4292SVikas Chaudhary 
7166e7b4292SVikas Chaudhary 	ret_val = qla4_83xx_rd_reg_indirect(ha, addr, &value);
7176e7b4292SVikas Chaudhary 	if (ret_val == QLA_ERROR)
7186e7b4292SVikas Chaudhary 		goto exit_poll_reg;
7196e7b4292SVikas Chaudhary 
7206e7b4292SVikas Chaudhary 	retries = duration / 10;
7216e7b4292SVikas Chaudhary 	do {
7226e7b4292SVikas Chaudhary 		if ((value & test_mask) != test_result) {
7236e7b4292SVikas Chaudhary 			msleep(duration / 10);
7246e7b4292SVikas Chaudhary 			ret_val = qla4_83xx_rd_reg_indirect(ha, addr, &value);
7256e7b4292SVikas Chaudhary 			if (ret_val == QLA_ERROR)
7266e7b4292SVikas Chaudhary 				goto exit_poll_reg;
7276e7b4292SVikas Chaudhary 
7286e7b4292SVikas Chaudhary 			ret_val = QLA_ERROR;
7296e7b4292SVikas Chaudhary 		} else {
7306e7b4292SVikas Chaudhary 			ret_val = QLA_SUCCESS;
7316e7b4292SVikas Chaudhary 			break;
7326e7b4292SVikas Chaudhary 		}
7336e7b4292SVikas Chaudhary 	} while (retries--);
7346e7b4292SVikas Chaudhary 
7356e7b4292SVikas Chaudhary exit_poll_reg:
7366e7b4292SVikas Chaudhary 	if (ret_val == QLA_ERROR) {
7376e7b4292SVikas Chaudhary 		ha->reset_tmplt.seq_error++;
7386e7b4292SVikas Chaudhary 		ql4_printk(KERN_ERR, ha, "%s: Poll Failed:  0x%08x 0x%08x 0x%08x\n",
7396e7b4292SVikas Chaudhary 			   __func__, value, test_mask, test_result);
7406e7b4292SVikas Chaudhary 	}
7416e7b4292SVikas Chaudhary 
7426e7b4292SVikas Chaudhary 	return ret_val;
7436e7b4292SVikas Chaudhary }
7446e7b4292SVikas Chaudhary 
7456e7b4292SVikas Chaudhary static int qla4_83xx_reset_seq_checksum_test(struct scsi_qla_host *ha)
7466e7b4292SVikas Chaudhary {
7476e7b4292SVikas Chaudhary 	uint32_t sum =  0;
7486e7b4292SVikas Chaudhary 	uint16_t *buff = (uint16_t *)ha->reset_tmplt.buff;
7496e7b4292SVikas Chaudhary 	int u16_count =  ha->reset_tmplt.hdr->size / sizeof(uint16_t);
7506e7b4292SVikas Chaudhary 	int ret_val;
7516e7b4292SVikas Chaudhary 
7526e7b4292SVikas Chaudhary 	while (u16_count-- > 0)
7536e7b4292SVikas Chaudhary 		sum += *buff++;
7546e7b4292SVikas Chaudhary 
7556e7b4292SVikas Chaudhary 	while (sum >> 16)
7566e7b4292SVikas Chaudhary 		sum = (sum & 0xFFFF) +  (sum >> 16);
7576e7b4292SVikas Chaudhary 
7586e7b4292SVikas Chaudhary 	/* checksum of 0 indicates a valid template */
7596e7b4292SVikas Chaudhary 	if (~sum) {
7606e7b4292SVikas Chaudhary 		ret_val = QLA_SUCCESS;
7616e7b4292SVikas Chaudhary 	} else {
7626e7b4292SVikas Chaudhary 		ql4_printk(KERN_ERR, ha, "%s: Reset seq checksum failed\n",
7636e7b4292SVikas Chaudhary 			   __func__);
7646e7b4292SVikas Chaudhary 		ret_val = QLA_ERROR;
7656e7b4292SVikas Chaudhary 	}
7666e7b4292SVikas Chaudhary 
7676e7b4292SVikas Chaudhary 	return ret_val;
7686e7b4292SVikas Chaudhary }
7696e7b4292SVikas Chaudhary 
7706e7b4292SVikas Chaudhary /**
7716e7b4292SVikas Chaudhary  * qla4_83xx_read_reset_template - Read Reset Template from Flash
7726e7b4292SVikas Chaudhary  * @ha: Pointer to adapter structure
7736e7b4292SVikas Chaudhary  **/
7746e7b4292SVikas Chaudhary void qla4_83xx_read_reset_template(struct scsi_qla_host *ha)
7756e7b4292SVikas Chaudhary {
7766e7b4292SVikas Chaudhary 	uint8_t *p_buff;
7776e7b4292SVikas Chaudhary 	uint32_t addr, tmplt_hdr_def_size, tmplt_hdr_size;
7786e7b4292SVikas Chaudhary 	uint32_t ret_val;
7796e7b4292SVikas Chaudhary 
7806e7b4292SVikas Chaudhary 	ha->reset_tmplt.seq_error = 0;
7816e7b4292SVikas Chaudhary 	ha->reset_tmplt.buff = vmalloc(QLA83XX_RESTART_TEMPLATE_SIZE);
7826e7b4292SVikas Chaudhary 	if (ha->reset_tmplt.buff == NULL) {
7836e7b4292SVikas Chaudhary 		ql4_printk(KERN_ERR, ha, "%s: Failed to allocate reset template resources\n",
7846e7b4292SVikas Chaudhary 			   __func__);
7856e7b4292SVikas Chaudhary 		goto exit_read_reset_template;
7866e7b4292SVikas Chaudhary 	}
7876e7b4292SVikas Chaudhary 
7886e7b4292SVikas Chaudhary 	p_buff = ha->reset_tmplt.buff;
7896e7b4292SVikas Chaudhary 	addr = QLA83XX_RESET_TEMPLATE_ADDR;
7906e7b4292SVikas Chaudhary 
7916e7b4292SVikas Chaudhary 	tmplt_hdr_def_size = sizeof(struct qla4_83xx_reset_template_hdr) /
7926e7b4292SVikas Chaudhary 				    sizeof(uint32_t);
7936e7b4292SVikas Chaudhary 
7946e7b4292SVikas Chaudhary 	DEBUG2(ql4_printk(KERN_INFO, ha,
7956e7b4292SVikas Chaudhary 			  "%s: Read template hdr size %d from Flash\n",
7966e7b4292SVikas Chaudhary 			  __func__, tmplt_hdr_def_size));
7976e7b4292SVikas Chaudhary 
7986e7b4292SVikas Chaudhary 	/* Copy template header from flash */
7996e7b4292SVikas Chaudhary 	ret_val = qla4_83xx_flash_read_u32(ha, addr, p_buff,
8006e7b4292SVikas Chaudhary 					   tmplt_hdr_def_size);
8016e7b4292SVikas Chaudhary 	if (ret_val != QLA_SUCCESS) {
8026e7b4292SVikas Chaudhary 		ql4_printk(KERN_ERR, ha, "%s: Failed to read reset template\n",
8036e7b4292SVikas Chaudhary 			   __func__);
8046e7b4292SVikas Chaudhary 		goto exit_read_template_error;
8056e7b4292SVikas Chaudhary 	}
8066e7b4292SVikas Chaudhary 
8076e7b4292SVikas Chaudhary 	ha->reset_tmplt.hdr =
8086e7b4292SVikas Chaudhary 		(struct qla4_83xx_reset_template_hdr *)ha->reset_tmplt.buff;
8096e7b4292SVikas Chaudhary 
8106e7b4292SVikas Chaudhary 	/* Validate the template header size and signature */
8116e7b4292SVikas Chaudhary 	tmplt_hdr_size = ha->reset_tmplt.hdr->hdr_size/sizeof(uint32_t);
8126e7b4292SVikas Chaudhary 	if ((tmplt_hdr_size != tmplt_hdr_def_size) ||
8136e7b4292SVikas Chaudhary 	    (ha->reset_tmplt.hdr->signature != RESET_TMPLT_HDR_SIGNATURE)) {
8146e7b4292SVikas Chaudhary 		ql4_printk(KERN_ERR, ha, "%s: Template Header size %d is invalid, tmplt_hdr_def_size %d\n",
8156e7b4292SVikas Chaudhary 			   __func__, tmplt_hdr_size, tmplt_hdr_def_size);
8166e7b4292SVikas Chaudhary 		goto exit_read_template_error;
8176e7b4292SVikas Chaudhary 	}
8186e7b4292SVikas Chaudhary 
8196e7b4292SVikas Chaudhary 	addr = QLA83XX_RESET_TEMPLATE_ADDR + ha->reset_tmplt.hdr->hdr_size;
8206e7b4292SVikas Chaudhary 	p_buff = ha->reset_tmplt.buff + ha->reset_tmplt.hdr->hdr_size;
8216e7b4292SVikas Chaudhary 	tmplt_hdr_def_size = (ha->reset_tmplt.hdr->size -
8226e7b4292SVikas Chaudhary 			      ha->reset_tmplt.hdr->hdr_size) / sizeof(uint32_t);
8236e7b4292SVikas Chaudhary 
8246e7b4292SVikas Chaudhary 	DEBUG2(ql4_printk(KERN_INFO, ha,
8256e7b4292SVikas Chaudhary 			  "%s: Read rest of the template size %d\n",
8266e7b4292SVikas Chaudhary 			  __func__, ha->reset_tmplt.hdr->size));
8276e7b4292SVikas Chaudhary 
8286e7b4292SVikas Chaudhary 	/* Copy rest of the template */
8296e7b4292SVikas Chaudhary 	ret_val = qla4_83xx_flash_read_u32(ha, addr, p_buff,
8306e7b4292SVikas Chaudhary 					   tmplt_hdr_def_size);
8316e7b4292SVikas Chaudhary 	if (ret_val != QLA_SUCCESS) {
8328c519319SMasanari Iida 		ql4_printk(KERN_ERR, ha, "%s: Failed to read reset template\n",
8336e7b4292SVikas Chaudhary 			   __func__);
8346e7b4292SVikas Chaudhary 		goto exit_read_template_error;
8356e7b4292SVikas Chaudhary 	}
8366e7b4292SVikas Chaudhary 
8376e7b4292SVikas Chaudhary 	/* Integrity check */
8386e7b4292SVikas Chaudhary 	if (qla4_83xx_reset_seq_checksum_test(ha)) {
8396e7b4292SVikas Chaudhary 		ql4_printk(KERN_ERR, ha, "%s: Reset Seq checksum failed!\n",
8406e7b4292SVikas Chaudhary 			   __func__);
8416e7b4292SVikas Chaudhary 		goto exit_read_template_error;
8426e7b4292SVikas Chaudhary 	}
8436e7b4292SVikas Chaudhary 	DEBUG2(ql4_printk(KERN_INFO, ha,
8446e7b4292SVikas Chaudhary 			  "%s: Reset Seq checksum passed, Get stop, start and init seq offsets\n",
8456e7b4292SVikas Chaudhary 			  __func__));
8466e7b4292SVikas Chaudhary 
8476e7b4292SVikas Chaudhary 	/* Get STOP, START, INIT sequence offsets */
8486e7b4292SVikas Chaudhary 	ha->reset_tmplt.init_offset = ha->reset_tmplt.buff +
8496e7b4292SVikas Chaudhary 				      ha->reset_tmplt.hdr->init_seq_offset;
8506e7b4292SVikas Chaudhary 	ha->reset_tmplt.start_offset = ha->reset_tmplt.buff +
8516e7b4292SVikas Chaudhary 				       ha->reset_tmplt.hdr->start_seq_offset;
8526e7b4292SVikas Chaudhary 	ha->reset_tmplt.stop_offset = ha->reset_tmplt.buff +
8536e7b4292SVikas Chaudhary 				      ha->reset_tmplt.hdr->hdr_size;
8546e7b4292SVikas Chaudhary 	qla4_83xx_dump_reset_seq_hdr(ha);
8556e7b4292SVikas Chaudhary 
8566e7b4292SVikas Chaudhary 	goto exit_read_reset_template;
8576e7b4292SVikas Chaudhary 
8586e7b4292SVikas Chaudhary exit_read_template_error:
8596e7b4292SVikas Chaudhary 	vfree(ha->reset_tmplt.buff);
8606e7b4292SVikas Chaudhary 
8616e7b4292SVikas Chaudhary exit_read_reset_template:
8626e7b4292SVikas Chaudhary 	return;
8636e7b4292SVikas Chaudhary }
8646e7b4292SVikas Chaudhary 
8656e7b4292SVikas Chaudhary /**
8666e7b4292SVikas Chaudhary  * qla4_83xx_read_write_crb_reg - Read from raddr and write value to waddr.
8676e7b4292SVikas Chaudhary  *
8686e7b4292SVikas Chaudhary  * @ha : Pointer to adapter structure
8696e7b4292SVikas Chaudhary  * @raddr : CRB address to read from
8706e7b4292SVikas Chaudhary  * @waddr : CRB address to write to
8716e7b4292SVikas Chaudhary  **/
8726e7b4292SVikas Chaudhary static void qla4_83xx_read_write_crb_reg(struct scsi_qla_host *ha,
8736e7b4292SVikas Chaudhary 					 uint32_t raddr, uint32_t waddr)
8746e7b4292SVikas Chaudhary {
8756e7b4292SVikas Chaudhary 	uint32_t value;
8766e7b4292SVikas Chaudhary 
8776e7b4292SVikas Chaudhary 	qla4_83xx_rd_reg_indirect(ha, raddr, &value);
8786e7b4292SVikas Chaudhary 	qla4_83xx_wr_reg_indirect(ha, waddr, value);
8796e7b4292SVikas Chaudhary }
8806e7b4292SVikas Chaudhary 
8816e7b4292SVikas Chaudhary /**
8826e7b4292SVikas Chaudhary  * qla4_83xx_rmw_crb_reg - Read Modify Write crb register
8836e7b4292SVikas Chaudhary  *
8846e7b4292SVikas Chaudhary  * This function read value from raddr, AND with test_mask,
8856e7b4292SVikas Chaudhary  * Shift Left,Right/OR/XOR with values RMW header and write value to waddr.
8866e7b4292SVikas Chaudhary  *
8876e7b4292SVikas Chaudhary  * @ha : Pointer to adapter structure
8886e7b4292SVikas Chaudhary  * @raddr : CRB address to read from
8896e7b4292SVikas Chaudhary  * @waddr : CRB address to write to
8906e7b4292SVikas Chaudhary  * @p_rmw_hdr : header with shift/or/xor values.
8916e7b4292SVikas Chaudhary  **/
8926e7b4292SVikas Chaudhary static void qla4_83xx_rmw_crb_reg(struct scsi_qla_host *ha, uint32_t raddr,
8936e7b4292SVikas Chaudhary 				  uint32_t waddr,
8946e7b4292SVikas Chaudhary 				  struct qla4_83xx_rmw *p_rmw_hdr)
8956e7b4292SVikas Chaudhary {
8966e7b4292SVikas Chaudhary 	uint32_t value;
8976e7b4292SVikas Chaudhary 
8986e7b4292SVikas Chaudhary 	if (p_rmw_hdr->index_a)
8996e7b4292SVikas Chaudhary 		value = ha->reset_tmplt.array[p_rmw_hdr->index_a];
9006e7b4292SVikas Chaudhary 	else
9016e7b4292SVikas Chaudhary 		qla4_83xx_rd_reg_indirect(ha, raddr, &value);
9026e7b4292SVikas Chaudhary 
9036e7b4292SVikas Chaudhary 	value &= p_rmw_hdr->test_mask;
9046e7b4292SVikas Chaudhary 	value <<= p_rmw_hdr->shl;
9056e7b4292SVikas Chaudhary 	value >>= p_rmw_hdr->shr;
9066e7b4292SVikas Chaudhary 	value |= p_rmw_hdr->or_value;
9076e7b4292SVikas Chaudhary 	value ^= p_rmw_hdr->xor_value;
9086e7b4292SVikas Chaudhary 
9096e7b4292SVikas Chaudhary 	qla4_83xx_wr_reg_indirect(ha, waddr, value);
9106e7b4292SVikas Chaudhary 
9116e7b4292SVikas Chaudhary 	return;
9126e7b4292SVikas Chaudhary }
9136e7b4292SVikas Chaudhary 
9146e7b4292SVikas Chaudhary static void qla4_83xx_write_list(struct scsi_qla_host *ha,
9156e7b4292SVikas Chaudhary 				 struct qla4_83xx_reset_entry_hdr *p_hdr)
9166e7b4292SVikas Chaudhary {
9176e7b4292SVikas Chaudhary 	struct qla4_83xx_entry *p_entry;
9186e7b4292SVikas Chaudhary 	uint32_t i;
9196e7b4292SVikas Chaudhary 
9206e7b4292SVikas Chaudhary 	p_entry = (struct qla4_83xx_entry *)
9216e7b4292SVikas Chaudhary 		  ((char *)p_hdr + sizeof(struct qla4_83xx_reset_entry_hdr));
9226e7b4292SVikas Chaudhary 
9236e7b4292SVikas Chaudhary 	for (i = 0; i < p_hdr->count; i++, p_entry++) {
9246e7b4292SVikas Chaudhary 		qla4_83xx_wr_reg_indirect(ha, p_entry->arg1, p_entry->arg2);
9256e7b4292SVikas Chaudhary 		if (p_hdr->delay)
9266e7b4292SVikas Chaudhary 			udelay((uint32_t)(p_hdr->delay));
9276e7b4292SVikas Chaudhary 	}
9286e7b4292SVikas Chaudhary }
9296e7b4292SVikas Chaudhary 
9306e7b4292SVikas Chaudhary static void qla4_83xx_read_write_list(struct scsi_qla_host *ha,
9316e7b4292SVikas Chaudhary 				      struct qla4_83xx_reset_entry_hdr *p_hdr)
9326e7b4292SVikas Chaudhary {
9336e7b4292SVikas Chaudhary 	struct qla4_83xx_entry *p_entry;
9346e7b4292SVikas Chaudhary 	uint32_t i;
9356e7b4292SVikas Chaudhary 
9366e7b4292SVikas Chaudhary 	p_entry = (struct qla4_83xx_entry *)
9376e7b4292SVikas Chaudhary 		  ((char *)p_hdr + sizeof(struct qla4_83xx_reset_entry_hdr));
9386e7b4292SVikas Chaudhary 
9396e7b4292SVikas Chaudhary 	for (i = 0; i < p_hdr->count; i++, p_entry++) {
9406e7b4292SVikas Chaudhary 		qla4_83xx_read_write_crb_reg(ha, p_entry->arg1, p_entry->arg2);
9416e7b4292SVikas Chaudhary 		if (p_hdr->delay)
9426e7b4292SVikas Chaudhary 			udelay((uint32_t)(p_hdr->delay));
9436e7b4292SVikas Chaudhary 	}
9446e7b4292SVikas Chaudhary }
9456e7b4292SVikas Chaudhary 
9466e7b4292SVikas Chaudhary static void qla4_83xx_poll_list(struct scsi_qla_host *ha,
9476e7b4292SVikas Chaudhary 				struct qla4_83xx_reset_entry_hdr *p_hdr)
9486e7b4292SVikas Chaudhary {
9496e7b4292SVikas Chaudhary 	long delay;
9506e7b4292SVikas Chaudhary 	struct qla4_83xx_entry *p_entry;
9516e7b4292SVikas Chaudhary 	struct qla4_83xx_poll *p_poll;
9526e7b4292SVikas Chaudhary 	uint32_t i;
9536e7b4292SVikas Chaudhary 	uint32_t value;
9546e7b4292SVikas Chaudhary 
9556e7b4292SVikas Chaudhary 	p_poll = (struct qla4_83xx_poll *)
9566e7b4292SVikas Chaudhary 		 ((char *)p_hdr + sizeof(struct qla4_83xx_reset_entry_hdr));
9576e7b4292SVikas Chaudhary 
9586e7b4292SVikas Chaudhary 	/* Entries start after 8 byte qla4_83xx_poll, poll header contains
9596e7b4292SVikas Chaudhary 	 * the test_mask, test_value. */
9606e7b4292SVikas Chaudhary 	p_entry = (struct qla4_83xx_entry *)((char *)p_poll +
9616e7b4292SVikas Chaudhary 					     sizeof(struct qla4_83xx_poll));
9626e7b4292SVikas Chaudhary 
9636e7b4292SVikas Chaudhary 	delay = (long)p_hdr->delay;
9646e7b4292SVikas Chaudhary 	if (!delay) {
9656e7b4292SVikas Chaudhary 		for (i = 0; i < p_hdr->count; i++, p_entry++) {
9666e7b4292SVikas Chaudhary 			qla4_83xx_poll_reg(ha, p_entry->arg1, delay,
9676e7b4292SVikas Chaudhary 					   p_poll->test_mask,
9686e7b4292SVikas Chaudhary 					   p_poll->test_value);
9696e7b4292SVikas Chaudhary 		}
9706e7b4292SVikas Chaudhary 	} else {
9716e7b4292SVikas Chaudhary 		for (i = 0; i < p_hdr->count; i++, p_entry++) {
9726e7b4292SVikas Chaudhary 			if (qla4_83xx_poll_reg(ha, p_entry->arg1, delay,
9736e7b4292SVikas Chaudhary 					       p_poll->test_mask,
9746e7b4292SVikas Chaudhary 					       p_poll->test_value)) {
9756e7b4292SVikas Chaudhary 				qla4_83xx_rd_reg_indirect(ha, p_entry->arg1,
9766e7b4292SVikas Chaudhary 							  &value);
9776e7b4292SVikas Chaudhary 				qla4_83xx_rd_reg_indirect(ha, p_entry->arg2,
9786e7b4292SVikas Chaudhary 							  &value);
9796e7b4292SVikas Chaudhary 			}
9806e7b4292SVikas Chaudhary 		}
9816e7b4292SVikas Chaudhary 	}
9826e7b4292SVikas Chaudhary }
9836e7b4292SVikas Chaudhary 
9846e7b4292SVikas Chaudhary static void qla4_83xx_poll_write_list(struct scsi_qla_host *ha,
9856e7b4292SVikas Chaudhary 				      struct qla4_83xx_reset_entry_hdr *p_hdr)
9866e7b4292SVikas Chaudhary {
9876e7b4292SVikas Chaudhary 	long delay;
9886e7b4292SVikas Chaudhary 	struct qla4_83xx_quad_entry *p_entry;
9896e7b4292SVikas Chaudhary 	struct qla4_83xx_poll *p_poll;
9906e7b4292SVikas Chaudhary 	uint32_t i;
9916e7b4292SVikas Chaudhary 
9926e7b4292SVikas Chaudhary 	p_poll = (struct qla4_83xx_poll *)
9936e7b4292SVikas Chaudhary 		 ((char *)p_hdr + sizeof(struct qla4_83xx_reset_entry_hdr));
9946e7b4292SVikas Chaudhary 	p_entry = (struct qla4_83xx_quad_entry *)
9956e7b4292SVikas Chaudhary 		  ((char *)p_poll + sizeof(struct qla4_83xx_poll));
9966e7b4292SVikas Chaudhary 	delay = (long)p_hdr->delay;
9976e7b4292SVikas Chaudhary 
9986e7b4292SVikas Chaudhary 	for (i = 0; i < p_hdr->count; i++, p_entry++) {
9996e7b4292SVikas Chaudhary 		qla4_83xx_wr_reg_indirect(ha, p_entry->dr_addr,
10006e7b4292SVikas Chaudhary 					  p_entry->dr_value);
10016e7b4292SVikas Chaudhary 		qla4_83xx_wr_reg_indirect(ha, p_entry->ar_addr,
10026e7b4292SVikas Chaudhary 					  p_entry->ar_value);
10036e7b4292SVikas Chaudhary 		if (delay) {
10046e7b4292SVikas Chaudhary 			if (qla4_83xx_poll_reg(ha, p_entry->ar_addr, delay,
10056e7b4292SVikas Chaudhary 					       p_poll->test_mask,
10066e7b4292SVikas Chaudhary 					       p_poll->test_value)) {
10076e7b4292SVikas Chaudhary 				DEBUG2(ql4_printk(KERN_INFO, ha,
10086e7b4292SVikas Chaudhary 						  "%s: Timeout Error: poll list, item_num %d, entry_num %d\n",
10096e7b4292SVikas Chaudhary 						  __func__, i,
10106e7b4292SVikas Chaudhary 						  ha->reset_tmplt.seq_index));
10116e7b4292SVikas Chaudhary 			}
10126e7b4292SVikas Chaudhary 		}
10136e7b4292SVikas Chaudhary 	}
10146e7b4292SVikas Chaudhary }
10156e7b4292SVikas Chaudhary 
10166e7b4292SVikas Chaudhary static void qla4_83xx_read_modify_write(struct scsi_qla_host *ha,
10176e7b4292SVikas Chaudhary 					struct qla4_83xx_reset_entry_hdr *p_hdr)
10186e7b4292SVikas Chaudhary {
10196e7b4292SVikas Chaudhary 	struct qla4_83xx_entry *p_entry;
10206e7b4292SVikas Chaudhary 	struct qla4_83xx_rmw *p_rmw_hdr;
10216e7b4292SVikas Chaudhary 	uint32_t i;
10226e7b4292SVikas Chaudhary 
10236e7b4292SVikas Chaudhary 	p_rmw_hdr = (struct qla4_83xx_rmw *)
10246e7b4292SVikas Chaudhary 		    ((char *)p_hdr + sizeof(struct qla4_83xx_reset_entry_hdr));
10256e7b4292SVikas Chaudhary 	p_entry = (struct qla4_83xx_entry *)
10266e7b4292SVikas Chaudhary 		  ((char *)p_rmw_hdr + sizeof(struct qla4_83xx_rmw));
10276e7b4292SVikas Chaudhary 
10286e7b4292SVikas Chaudhary 	for (i = 0; i < p_hdr->count; i++, p_entry++) {
10296e7b4292SVikas Chaudhary 		qla4_83xx_rmw_crb_reg(ha, p_entry->arg1, p_entry->arg2,
10306e7b4292SVikas Chaudhary 				      p_rmw_hdr);
10316e7b4292SVikas Chaudhary 		if (p_hdr->delay)
10326e7b4292SVikas Chaudhary 			udelay((uint32_t)(p_hdr->delay));
10336e7b4292SVikas Chaudhary 	}
10346e7b4292SVikas Chaudhary }
10356e7b4292SVikas Chaudhary 
10366e7b4292SVikas Chaudhary static void qla4_83xx_pause(struct scsi_qla_host *ha,
10376e7b4292SVikas Chaudhary 			    struct qla4_83xx_reset_entry_hdr *p_hdr)
10386e7b4292SVikas Chaudhary {
10396e7b4292SVikas Chaudhary 	if (p_hdr->delay)
10406e7b4292SVikas Chaudhary 		mdelay((uint32_t)((long)p_hdr->delay));
10416e7b4292SVikas Chaudhary }
10426e7b4292SVikas Chaudhary 
10436e7b4292SVikas Chaudhary static void qla4_83xx_poll_read_list(struct scsi_qla_host *ha,
10446e7b4292SVikas Chaudhary 				     struct qla4_83xx_reset_entry_hdr *p_hdr)
10456e7b4292SVikas Chaudhary {
10466e7b4292SVikas Chaudhary 	long delay;
10476e7b4292SVikas Chaudhary 	int index;
10486e7b4292SVikas Chaudhary 	struct qla4_83xx_quad_entry *p_entry;
10496e7b4292SVikas Chaudhary 	struct qla4_83xx_poll *p_poll;
10506e7b4292SVikas Chaudhary 	uint32_t i;
10516e7b4292SVikas Chaudhary 	uint32_t value;
10526e7b4292SVikas Chaudhary 
10536e7b4292SVikas Chaudhary 	p_poll = (struct qla4_83xx_poll *)
10546e7b4292SVikas Chaudhary 		 ((char *)p_hdr + sizeof(struct qla4_83xx_reset_entry_hdr));
10556e7b4292SVikas Chaudhary 	p_entry = (struct qla4_83xx_quad_entry *)
10566e7b4292SVikas Chaudhary 		  ((char *)p_poll + sizeof(struct qla4_83xx_poll));
10576e7b4292SVikas Chaudhary 	delay = (long)p_hdr->delay;
10586e7b4292SVikas Chaudhary 
10596e7b4292SVikas Chaudhary 	for (i = 0; i < p_hdr->count; i++, p_entry++) {
10606e7b4292SVikas Chaudhary 		qla4_83xx_wr_reg_indirect(ha, p_entry->ar_addr,
10616e7b4292SVikas Chaudhary 					  p_entry->ar_value);
10626e7b4292SVikas Chaudhary 		if (delay) {
10636e7b4292SVikas Chaudhary 			if (qla4_83xx_poll_reg(ha, p_entry->ar_addr, delay,
10646e7b4292SVikas Chaudhary 					       p_poll->test_mask,
10656e7b4292SVikas Chaudhary 					       p_poll->test_value)) {
10666e7b4292SVikas Chaudhary 				DEBUG2(ql4_printk(KERN_INFO, ha,
10676e7b4292SVikas Chaudhary 						  "%s: Timeout Error: poll list, Item_num %d, entry_num %d\n",
10686e7b4292SVikas Chaudhary 						  __func__, i,
10696e7b4292SVikas Chaudhary 						  ha->reset_tmplt.seq_index));
10706e7b4292SVikas Chaudhary 			} else {
10716e7b4292SVikas Chaudhary 				index = ha->reset_tmplt.array_index;
10726e7b4292SVikas Chaudhary 				qla4_83xx_rd_reg_indirect(ha, p_entry->dr_addr,
10736e7b4292SVikas Chaudhary 							  &value);
10746e7b4292SVikas Chaudhary 				ha->reset_tmplt.array[index++] = value;
10756e7b4292SVikas Chaudhary 
10766e7b4292SVikas Chaudhary 				if (index == QLA83XX_MAX_RESET_SEQ_ENTRIES)
10776e7b4292SVikas Chaudhary 					ha->reset_tmplt.array_index = 1;
10786e7b4292SVikas Chaudhary 			}
10796e7b4292SVikas Chaudhary 		}
10806e7b4292SVikas Chaudhary 	}
10816e7b4292SVikas Chaudhary }
10826e7b4292SVikas Chaudhary 
10836e7b4292SVikas Chaudhary static void qla4_83xx_seq_end(struct scsi_qla_host *ha,
10846e7b4292SVikas Chaudhary 			      struct qla4_83xx_reset_entry_hdr *p_hdr)
10856e7b4292SVikas Chaudhary {
10866e7b4292SVikas Chaudhary 	ha->reset_tmplt.seq_end = 1;
10876e7b4292SVikas Chaudhary }
10886e7b4292SVikas Chaudhary 
10896e7b4292SVikas Chaudhary static void qla4_83xx_template_end(struct scsi_qla_host *ha,
10906e7b4292SVikas Chaudhary 				   struct qla4_83xx_reset_entry_hdr *p_hdr)
10916e7b4292SVikas Chaudhary {
10926e7b4292SVikas Chaudhary 	ha->reset_tmplt.template_end = 1;
10936e7b4292SVikas Chaudhary 
10946e7b4292SVikas Chaudhary 	if (ha->reset_tmplt.seq_error == 0) {
10956e7b4292SVikas Chaudhary 		DEBUG2(ql4_printk(KERN_INFO, ha,
10966e7b4292SVikas Chaudhary 				  "%s: Reset sequence completed SUCCESSFULLY.\n",
10976e7b4292SVikas Chaudhary 				  __func__));
10986e7b4292SVikas Chaudhary 	} else {
10996e7b4292SVikas Chaudhary 		ql4_printk(KERN_ERR, ha, "%s: Reset sequence completed with some timeout errors.\n",
11006e7b4292SVikas Chaudhary 			   __func__);
11016e7b4292SVikas Chaudhary 	}
11026e7b4292SVikas Chaudhary }
11036e7b4292SVikas Chaudhary 
11046e7b4292SVikas Chaudhary /**
11056e7b4292SVikas Chaudhary  * qla4_83xx_process_reset_template - Process reset template.
11066e7b4292SVikas Chaudhary  *
11076e7b4292SVikas Chaudhary  * Process all entries in reset template till entry with SEQ_END opcode,
11086e7b4292SVikas Chaudhary  * which indicates end of the reset template processing. Each entry has a
11096e7b4292SVikas Chaudhary  * Reset Entry header, entry opcode/command, with size of the entry, number
11106e7b4292SVikas Chaudhary  * of entries in sub-sequence and delay in microsecs or timeout in millisecs.
11116e7b4292SVikas Chaudhary  *
11126e7b4292SVikas Chaudhary  * @ha : Pointer to adapter structure
11136e7b4292SVikas Chaudhary  * @p_buff : Common reset entry header.
11146e7b4292SVikas Chaudhary  **/
11156e7b4292SVikas Chaudhary static void qla4_83xx_process_reset_template(struct scsi_qla_host *ha,
11166e7b4292SVikas Chaudhary 					     char *p_buff)
11176e7b4292SVikas Chaudhary {
11186e7b4292SVikas Chaudhary 	int index, entries;
11196e7b4292SVikas Chaudhary 	struct qla4_83xx_reset_entry_hdr *p_hdr;
11206e7b4292SVikas Chaudhary 	char *p_entry = p_buff;
11216e7b4292SVikas Chaudhary 
11226e7b4292SVikas Chaudhary 	ha->reset_tmplt.seq_end = 0;
11236e7b4292SVikas Chaudhary 	ha->reset_tmplt.template_end = 0;
11246e7b4292SVikas Chaudhary 	entries = ha->reset_tmplt.hdr->entries;
11256e7b4292SVikas Chaudhary 	index = ha->reset_tmplt.seq_index;
11266e7b4292SVikas Chaudhary 
11276e7b4292SVikas Chaudhary 	for (; (!ha->reset_tmplt.seq_end) && (index  < entries); index++) {
11286e7b4292SVikas Chaudhary 
11296e7b4292SVikas Chaudhary 		p_hdr = (struct qla4_83xx_reset_entry_hdr *)p_entry;
11306e7b4292SVikas Chaudhary 		switch (p_hdr->cmd) {
11316e7b4292SVikas Chaudhary 		case OPCODE_NOP:
11326e7b4292SVikas Chaudhary 			break;
11336e7b4292SVikas Chaudhary 		case OPCODE_WRITE_LIST:
11346e7b4292SVikas Chaudhary 			qla4_83xx_write_list(ha, p_hdr);
11356e7b4292SVikas Chaudhary 			break;
11366e7b4292SVikas Chaudhary 		case OPCODE_READ_WRITE_LIST:
11376e7b4292SVikas Chaudhary 			qla4_83xx_read_write_list(ha, p_hdr);
11386e7b4292SVikas Chaudhary 			break;
11396e7b4292SVikas Chaudhary 		case OPCODE_POLL_LIST:
11406e7b4292SVikas Chaudhary 			qla4_83xx_poll_list(ha, p_hdr);
11416e7b4292SVikas Chaudhary 			break;
11426e7b4292SVikas Chaudhary 		case OPCODE_POLL_WRITE_LIST:
11436e7b4292SVikas Chaudhary 			qla4_83xx_poll_write_list(ha, p_hdr);
11446e7b4292SVikas Chaudhary 			break;
11456e7b4292SVikas Chaudhary 		case OPCODE_READ_MODIFY_WRITE:
11466e7b4292SVikas Chaudhary 			qla4_83xx_read_modify_write(ha, p_hdr);
11476e7b4292SVikas Chaudhary 			break;
11486e7b4292SVikas Chaudhary 		case OPCODE_SEQ_PAUSE:
11496e7b4292SVikas Chaudhary 			qla4_83xx_pause(ha, p_hdr);
11506e7b4292SVikas Chaudhary 			break;
11516e7b4292SVikas Chaudhary 		case OPCODE_SEQ_END:
11526e7b4292SVikas Chaudhary 			qla4_83xx_seq_end(ha, p_hdr);
11536e7b4292SVikas Chaudhary 			break;
11546e7b4292SVikas Chaudhary 		case OPCODE_TMPL_END:
11556e7b4292SVikas Chaudhary 			qla4_83xx_template_end(ha, p_hdr);
11566e7b4292SVikas Chaudhary 			break;
11576e7b4292SVikas Chaudhary 		case OPCODE_POLL_READ_LIST:
11586e7b4292SVikas Chaudhary 			qla4_83xx_poll_read_list(ha, p_hdr);
11596e7b4292SVikas Chaudhary 			break;
11606e7b4292SVikas Chaudhary 		default:
11616e7b4292SVikas Chaudhary 			ql4_printk(KERN_ERR, ha, "%s: Unknown command ==> 0x%04x on entry = %d\n",
11626e7b4292SVikas Chaudhary 				   __func__, p_hdr->cmd, index);
11636e7b4292SVikas Chaudhary 			break;
11646e7b4292SVikas Chaudhary 		}
11656e7b4292SVikas Chaudhary 
11666e7b4292SVikas Chaudhary 		/* Set pointer to next entry in the sequence. */
11676e7b4292SVikas Chaudhary 		p_entry += p_hdr->size;
11686e7b4292SVikas Chaudhary 	}
11696e7b4292SVikas Chaudhary 
11706e7b4292SVikas Chaudhary 	ha->reset_tmplt.seq_index = index;
11716e7b4292SVikas Chaudhary }
11726e7b4292SVikas Chaudhary 
11736e7b4292SVikas Chaudhary static void qla4_83xx_process_stop_seq(struct scsi_qla_host *ha)
11746e7b4292SVikas Chaudhary {
11756e7b4292SVikas Chaudhary 	ha->reset_tmplt.seq_index = 0;
11766e7b4292SVikas Chaudhary 	qla4_83xx_process_reset_template(ha, ha->reset_tmplt.stop_offset);
11776e7b4292SVikas Chaudhary 
11786e7b4292SVikas Chaudhary 	if (ha->reset_tmplt.seq_end != 1)
11796e7b4292SVikas Chaudhary 		ql4_printk(KERN_ERR, ha, "%s: Abrupt STOP Sub-Sequence end.\n",
11806e7b4292SVikas Chaudhary 			   __func__);
11816e7b4292SVikas Chaudhary }
11826e7b4292SVikas Chaudhary 
11836e7b4292SVikas Chaudhary static void qla4_83xx_process_start_seq(struct scsi_qla_host *ha)
11846e7b4292SVikas Chaudhary {
11856e7b4292SVikas Chaudhary 	qla4_83xx_process_reset_template(ha, ha->reset_tmplt.start_offset);
11866e7b4292SVikas Chaudhary 
11876e7b4292SVikas Chaudhary 	if (ha->reset_tmplt.template_end != 1)
11886e7b4292SVikas Chaudhary 		ql4_printk(KERN_ERR, ha, "%s: Abrupt START Sub-Sequence end.\n",
11896e7b4292SVikas Chaudhary 			   __func__);
11906e7b4292SVikas Chaudhary }
11916e7b4292SVikas Chaudhary 
11926e7b4292SVikas Chaudhary static void qla4_83xx_process_init_seq(struct scsi_qla_host *ha)
11936e7b4292SVikas Chaudhary {
11946e7b4292SVikas Chaudhary 	qla4_83xx_process_reset_template(ha, ha->reset_tmplt.init_offset);
11956e7b4292SVikas Chaudhary 
11966e7b4292SVikas Chaudhary 	if (ha->reset_tmplt.seq_end != 1)
11976e7b4292SVikas Chaudhary 		ql4_printk(KERN_ERR, ha, "%s: Abrupt INIT Sub-Sequence end.\n",
11986e7b4292SVikas Chaudhary 			   __func__);
11996e7b4292SVikas Chaudhary }
12006e7b4292SVikas Chaudhary 
12016e7b4292SVikas Chaudhary static int qla4_83xx_restart(struct scsi_qla_host *ha)
12026e7b4292SVikas Chaudhary {
12036e7b4292SVikas Chaudhary 	int ret_val = QLA_SUCCESS;
120480645dc0SVikas Chaudhary 	uint32_t idc_ctrl;
12056e7b4292SVikas Chaudhary 
12066e7b4292SVikas Chaudhary 	qla4_83xx_process_stop_seq(ha);
12076e7b4292SVikas Chaudhary 
120880645dc0SVikas Chaudhary 	/*
120980645dc0SVikas Chaudhary 	 * Collect minidump.
121080645dc0SVikas Chaudhary 	 * If IDC_CTRL BIT1 is set, clear it on going to INIT state and
121180645dc0SVikas Chaudhary 	 * don't collect minidump
121280645dc0SVikas Chaudhary 	 */
121380645dc0SVikas Chaudhary 	idc_ctrl = qla4_83xx_rd_reg(ha, QLA83XX_IDC_DRV_CTRL);
121480645dc0SVikas Chaudhary 	if (idc_ctrl & GRACEFUL_RESET_BIT1) {
121580645dc0SVikas Chaudhary 		qla4_83xx_wr_reg(ha, QLA83XX_IDC_DRV_CTRL,
121680645dc0SVikas Chaudhary 				 (idc_ctrl & ~GRACEFUL_RESET_BIT1));
121780645dc0SVikas Chaudhary 		ql4_printk(KERN_INFO, ha, "%s: Graceful RESET: Not collecting minidump\n",
121880645dc0SVikas Chaudhary 			   __func__);
121980645dc0SVikas Chaudhary 	} else {
12206e7b4292SVikas Chaudhary 		qla4_8xxx_get_minidump(ha);
122180645dc0SVikas Chaudhary 	}
12226e7b4292SVikas Chaudhary 
12236e7b4292SVikas Chaudhary 	qla4_83xx_process_init_seq(ha);
12246e7b4292SVikas Chaudhary 
12256e7b4292SVikas Chaudhary 	if (qla4_83xx_copy_bootloader(ha)) {
12266e7b4292SVikas Chaudhary 		ql4_printk(KERN_ERR, ha, "%s: Copy bootloader, firmware restart failed!\n",
12276e7b4292SVikas Chaudhary 			   __func__);
12286e7b4292SVikas Chaudhary 		ret_val = QLA_ERROR;
12296e7b4292SVikas Chaudhary 		goto exit_restart;
12306e7b4292SVikas Chaudhary 	}
12316e7b4292SVikas Chaudhary 
12326e7b4292SVikas Chaudhary 	qla4_83xx_wr_reg(ha, QLA83XX_FW_IMAGE_VALID, QLA83XX_BOOT_FROM_FLASH);
12336e7b4292SVikas Chaudhary 	qla4_83xx_process_start_seq(ha);
12346e7b4292SVikas Chaudhary 
12356e7b4292SVikas Chaudhary exit_restart:
12366e7b4292SVikas Chaudhary 	return ret_val;
12376e7b4292SVikas Chaudhary }
12386e7b4292SVikas Chaudhary 
12396e7b4292SVikas Chaudhary int qla4_83xx_start_firmware(struct scsi_qla_host *ha)
12406e7b4292SVikas Chaudhary {
12416e7b4292SVikas Chaudhary 	int ret_val = QLA_SUCCESS;
12426e7b4292SVikas Chaudhary 
12436e7b4292SVikas Chaudhary 	ret_val = qla4_83xx_restart(ha);
12446e7b4292SVikas Chaudhary 	if (ret_val == QLA_ERROR) {
12456e7b4292SVikas Chaudhary 		ql4_printk(KERN_ERR, ha, "%s: Restart error\n", __func__);
12466e7b4292SVikas Chaudhary 		goto exit_start_fw;
12476e7b4292SVikas Chaudhary 	} else {
12486e7b4292SVikas Chaudhary 		DEBUG2(ql4_printk(KERN_INFO, ha, "%s: Restart done\n",
12496e7b4292SVikas Chaudhary 				  __func__));
12506e7b4292SVikas Chaudhary 	}
12516e7b4292SVikas Chaudhary 
12526e7b4292SVikas Chaudhary 	ret_val = qla4_83xx_check_cmd_peg_status(ha);
12536e7b4292SVikas Chaudhary 	if (ret_val == QLA_ERROR)
12546e7b4292SVikas Chaudhary 		ql4_printk(KERN_ERR, ha, "%s: Peg not initialized\n",
12556e7b4292SVikas Chaudhary 			   __func__);
12566e7b4292SVikas Chaudhary 
12576e7b4292SVikas Chaudhary exit_start_fw:
12586e7b4292SVikas Chaudhary 	return ret_val;
12596e7b4292SVikas Chaudhary }
12606e7b4292SVikas Chaudhary 
12616e7b4292SVikas Chaudhary /*----------------------Interrupt Related functions ---------------------*/
12626e7b4292SVikas Chaudhary 
12635c19b92aSVikas Chaudhary static void qla4_83xx_disable_iocb_intrs(struct scsi_qla_host *ha)
12645c19b92aSVikas Chaudhary {
12655c19b92aSVikas Chaudhary 	if (test_and_clear_bit(AF_83XX_IOCB_INTR_ON, &ha->flags))
12665c19b92aSVikas Chaudhary 		qla4_8xxx_intr_disable(ha);
12675c19b92aSVikas Chaudhary }
12685c19b92aSVikas Chaudhary 
12695c19b92aSVikas Chaudhary static void qla4_83xx_disable_mbox_intrs(struct scsi_qla_host *ha)
12706e7b4292SVikas Chaudhary {
12716e7b4292SVikas Chaudhary 	uint32_t mb_int, ret;
12726e7b4292SVikas Chaudhary 
12735c19b92aSVikas Chaudhary 	if (test_and_clear_bit(AF_83XX_MBOX_INTR_ON, &ha->flags)) {
12746e7b4292SVikas Chaudhary 		ret = readl(&ha->qla4_83xx_reg->mbox_int);
12756e7b4292SVikas Chaudhary 		mb_int = ret & ~INT_ENABLE_FW_MB;
12766e7b4292SVikas Chaudhary 		writel(mb_int, &ha->qla4_83xx_reg->mbox_int);
12776e7b4292SVikas Chaudhary 		writel(1, &ha->qla4_83xx_reg->leg_int_mask);
12786e7b4292SVikas Chaudhary 	}
12795c19b92aSVikas Chaudhary }
12806e7b4292SVikas Chaudhary 
12815c19b92aSVikas Chaudhary void qla4_83xx_disable_intrs(struct scsi_qla_host *ha)
12825c19b92aSVikas Chaudhary {
12835c19b92aSVikas Chaudhary 	qla4_83xx_disable_mbox_intrs(ha);
12845c19b92aSVikas Chaudhary 	qla4_83xx_disable_iocb_intrs(ha);
12855c19b92aSVikas Chaudhary }
12865c19b92aSVikas Chaudhary 
12875c19b92aSVikas Chaudhary static void qla4_83xx_enable_iocb_intrs(struct scsi_qla_host *ha)
12885c19b92aSVikas Chaudhary {
12895c19b92aSVikas Chaudhary 	if (!test_bit(AF_83XX_IOCB_INTR_ON, &ha->flags)) {
12905c19b92aSVikas Chaudhary 		qla4_8xxx_intr_enable(ha);
12915c19b92aSVikas Chaudhary 		set_bit(AF_83XX_IOCB_INTR_ON, &ha->flags);
12925c19b92aSVikas Chaudhary 	}
12935c19b92aSVikas Chaudhary }
12945c19b92aSVikas Chaudhary 
12955c19b92aSVikas Chaudhary void qla4_83xx_enable_mbox_intrs(struct scsi_qla_host *ha)
12966e7b4292SVikas Chaudhary {
12976e7b4292SVikas Chaudhary 	uint32_t mb_int;
12986e7b4292SVikas Chaudhary 
12995c19b92aSVikas Chaudhary 	if (!test_bit(AF_83XX_MBOX_INTR_ON, &ha->flags)) {
13006e7b4292SVikas Chaudhary 		mb_int = INT_ENABLE_FW_MB;
13016e7b4292SVikas Chaudhary 		writel(mb_int, &ha->qla4_83xx_reg->mbox_int);
13026e7b4292SVikas Chaudhary 		writel(0, &ha->qla4_83xx_reg->leg_int_mask);
13035c19b92aSVikas Chaudhary 		set_bit(AF_83XX_MBOX_INTR_ON, &ha->flags);
13046e7b4292SVikas Chaudhary 	}
13055c19b92aSVikas Chaudhary }
13065c19b92aSVikas Chaudhary 
13075c19b92aSVikas Chaudhary 
13085c19b92aSVikas Chaudhary void qla4_83xx_enable_intrs(struct scsi_qla_host *ha)
13095c19b92aSVikas Chaudhary {
13105c19b92aSVikas Chaudhary 	qla4_83xx_enable_mbox_intrs(ha);
13115c19b92aSVikas Chaudhary 	qla4_83xx_enable_iocb_intrs(ha);
13125c19b92aSVikas Chaudhary }
13135c19b92aSVikas Chaudhary 
13146e7b4292SVikas Chaudhary 
13156e7b4292SVikas Chaudhary void qla4_83xx_queue_mbox_cmd(struct scsi_qla_host *ha, uint32_t *mbx_cmd,
13166e7b4292SVikas Chaudhary 			      int incount)
13176e7b4292SVikas Chaudhary {
13186e7b4292SVikas Chaudhary 	int i;
13196e7b4292SVikas Chaudhary 
13206e7b4292SVikas Chaudhary 	/* Load all mailbox registers, except mailbox 0. */
13216e7b4292SVikas Chaudhary 	for (i = 1; i < incount; i++)
13226e7b4292SVikas Chaudhary 		writel(mbx_cmd[i], &ha->qla4_83xx_reg->mailbox_in[i]);
13236e7b4292SVikas Chaudhary 
13246e7b4292SVikas Chaudhary 	writel(mbx_cmd[0], &ha->qla4_83xx_reg->mailbox_in[0]);
13256e7b4292SVikas Chaudhary 
13266e7b4292SVikas Chaudhary 	/* Set Host Interrupt register to 1, to tell the firmware that
13276e7b4292SVikas Chaudhary 	 * a mailbox command is pending. Firmware after reading the
13286e7b4292SVikas Chaudhary 	 * mailbox command, clears the host interrupt register */
13296e7b4292SVikas Chaudhary 	writel(HINT_MBX_INT_PENDING, &ha->qla4_83xx_reg->host_intr);
13306e7b4292SVikas Chaudhary }
13316e7b4292SVikas Chaudhary 
13326e7b4292SVikas Chaudhary void qla4_83xx_process_mbox_intr(struct scsi_qla_host *ha, int outcount)
13336e7b4292SVikas Chaudhary {
13346e7b4292SVikas Chaudhary 	int intr_status;
13356e7b4292SVikas Chaudhary 
13366e7b4292SVikas Chaudhary 	intr_status = readl(&ha->qla4_83xx_reg->risc_intr);
13376e7b4292SVikas Chaudhary 	if (intr_status) {
13386e7b4292SVikas Chaudhary 		ha->mbox_status_count = outcount;
13396e7b4292SVikas Chaudhary 		ha->isp_ops->interrupt_service_routine(ha, intr_status);
13406e7b4292SVikas Chaudhary 	}
13416e7b4292SVikas Chaudhary }
13426e7b4292SVikas Chaudhary 
13436e7b4292SVikas Chaudhary /**
13446e7b4292SVikas Chaudhary  * qla4_83xx_isp_reset - Resets ISP and aborts all outstanding commands.
13456e7b4292SVikas Chaudhary  * @ha: pointer to host adapter structure.
13466e7b4292SVikas Chaudhary  **/
13476e7b4292SVikas Chaudhary int qla4_83xx_isp_reset(struct scsi_qla_host *ha)
13486e7b4292SVikas Chaudhary {
13496e7b4292SVikas Chaudhary 	int rval;
13506e7b4292SVikas Chaudhary 	uint32_t dev_state;
13516e7b4292SVikas Chaudhary 
13526e7b4292SVikas Chaudhary 	ha->isp_ops->idc_lock(ha);
13536e7b4292SVikas Chaudhary 	dev_state = qla4_8xxx_rd_direct(ha, QLA8XXX_CRB_DEV_STATE);
13546e7b4292SVikas Chaudhary 
13556e7b4292SVikas Chaudhary 	if (ql4xdontresethba)
13566e7b4292SVikas Chaudhary 		qla4_83xx_set_idc_dontreset(ha);
13576e7b4292SVikas Chaudhary 
13586e7b4292SVikas Chaudhary 	if (dev_state == QLA8XXX_DEV_READY) {
13596e7b4292SVikas Chaudhary 		/* If IDC_CTRL DONTRESETHBA_BIT0 is set dont do reset
13606e7b4292SVikas Chaudhary 		 * recovery */
13616e7b4292SVikas Chaudhary 		if (qla4_83xx_idc_dontreset(ha) == DONTRESET_BIT0) {
13626e7b4292SVikas Chaudhary 			ql4_printk(KERN_ERR, ha, "%s: Reset recovery disabled\n",
13636e7b4292SVikas Chaudhary 				   __func__);
13646e7b4292SVikas Chaudhary 			rval = QLA_ERROR;
13656e7b4292SVikas Chaudhary 			goto exit_isp_reset;
13666e7b4292SVikas Chaudhary 		}
13676e7b4292SVikas Chaudhary 
13686e7b4292SVikas Chaudhary 		DEBUG2(ql4_printk(KERN_INFO, ha, "%s: HW State: NEED RESET\n",
13696e7b4292SVikas Chaudhary 				  __func__));
13706e7b4292SVikas Chaudhary 		qla4_8xxx_wr_direct(ha, QLA8XXX_CRB_DEV_STATE,
13716e7b4292SVikas Chaudhary 				    QLA8XXX_DEV_NEED_RESET);
13726e7b4292SVikas Chaudhary 
13736e7b4292SVikas Chaudhary 	} else {
13746e7b4292SVikas Chaudhary 		/* If device_state is NEED_RESET, go ahead with
13756e7b4292SVikas Chaudhary 		 * Reset,irrespective of ql4xdontresethba. This is to allow a
13766e7b4292SVikas Chaudhary 		 * non-reset-owner to force a reset. Non-reset-owner sets
13776e7b4292SVikas Chaudhary 		 * the IDC_CTRL BIT0 to prevent Reset-owner from doing a Reset
13786e7b4292SVikas Chaudhary 		 * and then forces a Reset by setting device_state to
13796e7b4292SVikas Chaudhary 		 * NEED_RESET. */
13806e7b4292SVikas Chaudhary 		DEBUG2(ql4_printk(KERN_INFO, ha,
13816e7b4292SVikas Chaudhary 				  "%s: HW state already set to NEED_RESET\n",
13826e7b4292SVikas Chaudhary 				  __func__));
13836e7b4292SVikas Chaudhary 	}
13846e7b4292SVikas Chaudhary 
1385b37ca418SVikas Chaudhary 	/* For ISP8324 and ISP8042, Reset owner is NIC, iSCSI or FCOE based on
1386b37ca418SVikas Chaudhary 	 * priority and which drivers are present. Unlike ISP8022, the function
1387b37ca418SVikas Chaudhary 	 * setting NEED_RESET, may not be the Reset owner. */
13886e7b4292SVikas Chaudhary 	if (qla4_83xx_can_perform_reset(ha))
13896e7b4292SVikas Chaudhary 		set_bit(AF_8XXX_RST_OWNER, &ha->flags);
13906e7b4292SVikas Chaudhary 
13916e7b4292SVikas Chaudhary 	ha->isp_ops->idc_unlock(ha);
13926e7b4292SVikas Chaudhary 	rval = qla4_8xxx_device_state_handler(ha);
13936e7b4292SVikas Chaudhary 
13946e7b4292SVikas Chaudhary 	ha->isp_ops->idc_lock(ha);
13956e7b4292SVikas Chaudhary 	qla4_8xxx_clear_rst_ready(ha);
13966e7b4292SVikas Chaudhary exit_isp_reset:
13976e7b4292SVikas Chaudhary 	ha->isp_ops->idc_unlock(ha);
13986e7b4292SVikas Chaudhary 
13996e7b4292SVikas Chaudhary 	if (rval == QLA_SUCCESS)
14006e7b4292SVikas Chaudhary 		clear_bit(AF_FW_RECOVERY, &ha->flags);
14016e7b4292SVikas Chaudhary 
14026e7b4292SVikas Chaudhary 	return rval;
14036e7b4292SVikas Chaudhary }
1404546fef27STej Parkash 
1405546fef27STej Parkash static void qla4_83xx_dump_pause_control_regs(struct scsi_qla_host *ha)
1406546fef27STej Parkash {
1407546fef27STej Parkash 	u32 val = 0, val1 = 0;
14086e3f4f68SLee Jones 	int i;
1409546fef27STej Parkash 
14106e3f4f68SLee Jones 	qla4_83xx_rd_reg_indirect(ha, QLA83XX_SRE_SHIM_CONTROL, &val);
1411546fef27STej Parkash 	DEBUG2(ql4_printk(KERN_INFO, ha, "SRE-Shim Ctrl:0x%x\n", val));
1412546fef27STej Parkash 
1413546fef27STej Parkash 	/* Port 0 Rx Buffer Pause Threshold Registers. */
1414546fef27STej Parkash 	DEBUG2(ql4_printk(KERN_INFO, ha,
1415546fef27STej Parkash 		"Port 0 Rx Buffer Pause Threshold Registers[TC7..TC0]:"));
1416546fef27STej Parkash 	for (i = 0; i < 8; i++) {
14176e3f4f68SLee Jones 		qla4_83xx_rd_reg_indirect(ha,
1418546fef27STej Parkash 				QLA83XX_PORT0_RXB_PAUSE_THRS + (i * 0x4), &val);
1419546fef27STej Parkash 		DEBUG2(pr_info("0x%x ", val));
1420546fef27STej Parkash 	}
1421546fef27STej Parkash 
1422546fef27STej Parkash 	DEBUG2(pr_info("\n"));
1423546fef27STej Parkash 
1424546fef27STej Parkash 	/* Port 1 Rx Buffer Pause Threshold Registers. */
1425546fef27STej Parkash 	DEBUG2(ql4_printk(KERN_INFO, ha,
1426546fef27STej Parkash 		"Port 1 Rx Buffer Pause Threshold Registers[TC7..TC0]:"));
1427546fef27STej Parkash 	for (i = 0; i < 8; i++) {
14286e3f4f68SLee Jones 		qla4_83xx_rd_reg_indirect(ha,
1429546fef27STej Parkash 				QLA83XX_PORT1_RXB_PAUSE_THRS + (i * 0x4), &val);
1430546fef27STej Parkash 		DEBUG2(pr_info("0x%x  ", val));
1431546fef27STej Parkash 	}
1432546fef27STej Parkash 
1433546fef27STej Parkash 	DEBUG2(pr_info("\n"));
1434546fef27STej Parkash 
1435546fef27STej Parkash 	/* Port 0 RxB Traffic Class Max Cell Registers. */
1436546fef27STej Parkash 	DEBUG2(ql4_printk(KERN_INFO, ha,
1437546fef27STej Parkash 		"Port 0 RxB Traffic Class Max Cell Registers[3..0]:"));
1438546fef27STej Parkash 	for (i = 0; i < 4; i++) {
14396e3f4f68SLee Jones 		qla4_83xx_rd_reg_indirect(ha,
1440546fef27STej Parkash 			       QLA83XX_PORT0_RXB_TC_MAX_CELL + (i * 0x4), &val);
1441546fef27STej Parkash 		DEBUG2(pr_info("0x%x  ", val));
1442546fef27STej Parkash 	}
1443546fef27STej Parkash 
1444546fef27STej Parkash 	DEBUG2(pr_info("\n"));
1445546fef27STej Parkash 
1446546fef27STej Parkash 	/* Port 1 RxB Traffic Class Max Cell Registers. */
1447546fef27STej Parkash 	DEBUG2(ql4_printk(KERN_INFO, ha,
1448546fef27STej Parkash 		"Port 1 RxB Traffic Class Max Cell Registers[3..0]:"));
1449546fef27STej Parkash 	for (i = 0; i < 4; i++) {
14506e3f4f68SLee Jones 		qla4_83xx_rd_reg_indirect(ha,
1451546fef27STej Parkash 			       QLA83XX_PORT1_RXB_TC_MAX_CELL + (i * 0x4), &val);
1452546fef27STej Parkash 		DEBUG2(pr_info("0x%x  ", val));
1453546fef27STej Parkash 	}
1454546fef27STej Parkash 
1455546fef27STej Parkash 	DEBUG2(pr_info("\n"));
1456546fef27STej Parkash 
1457546fef27STej Parkash 	/* Port 0 RxB Rx Traffic Class Stats. */
1458546fef27STej Parkash 	DEBUG2(ql4_printk(KERN_INFO, ha,
1459546fef27STej Parkash 			  "Port 0 RxB Rx Traffic Class Stats [TC7..TC0]"));
1460546fef27STej Parkash 	for (i = 7; i >= 0; i--) {
14616e3f4f68SLee Jones 		qla4_83xx_rd_reg_indirect(ha, QLA83XX_PORT0_RXB_TC_STATS, &val);
1462546fef27STej Parkash 		val &= ~(0x7 << 29);    /* Reset bits 29 to 31 */
1463546fef27STej Parkash 		qla4_83xx_wr_reg_indirect(ha, QLA83XX_PORT0_RXB_TC_STATS,
1464546fef27STej Parkash 					  (val | (i << 29)));
14656e3f4f68SLee Jones 		qla4_83xx_rd_reg_indirect(ha, QLA83XX_PORT0_RXB_TC_STATS, &val);
1466546fef27STej Parkash 		DEBUG2(pr_info("0x%x  ", val));
1467546fef27STej Parkash 	}
1468546fef27STej Parkash 
1469546fef27STej Parkash 	DEBUG2(pr_info("\n"));
1470546fef27STej Parkash 
1471546fef27STej Parkash 	/* Port 1 RxB Rx Traffic Class Stats. */
1472546fef27STej Parkash 	DEBUG2(ql4_printk(KERN_INFO, ha,
1473546fef27STej Parkash 			  "Port 1 RxB Rx Traffic Class Stats [TC7..TC0]"));
1474546fef27STej Parkash 	for (i = 7; i >= 0; i--) {
14756e3f4f68SLee Jones 		qla4_83xx_rd_reg_indirect(ha, QLA83XX_PORT1_RXB_TC_STATS, &val);
1476546fef27STej Parkash 		val &= ~(0x7 << 29);    /* Reset bits 29 to 31 */
1477546fef27STej Parkash 		qla4_83xx_wr_reg_indirect(ha, QLA83XX_PORT1_RXB_TC_STATS,
1478546fef27STej Parkash 					  (val | (i << 29)));
14796e3f4f68SLee Jones 		qla4_83xx_rd_reg_indirect(ha, QLA83XX_PORT1_RXB_TC_STATS, &val);
1480546fef27STej Parkash 		DEBUG2(pr_info("0x%x  ", val));
1481546fef27STej Parkash 	}
1482546fef27STej Parkash 
1483546fef27STej Parkash 	DEBUG2(pr_info("\n"));
1484546fef27STej Parkash 
14856e3f4f68SLee Jones 	qla4_83xx_rd_reg_indirect(ha, QLA83XX_PORT2_IFB_PAUSE_THRS, &val);
14866e3f4f68SLee Jones 	qla4_83xx_rd_reg_indirect(ha, QLA83XX_PORT3_IFB_PAUSE_THRS, &val1);
1487546fef27STej Parkash 
1488546fef27STej Parkash 	DEBUG2(ql4_printk(KERN_INFO, ha,
1489546fef27STej Parkash 			  "IFB-Pause Thresholds: Port 2:0x%x, Port 3:0x%x\n",
1490546fef27STej Parkash 			  val, val1));
1491546fef27STej Parkash }
1492546fef27STej Parkash 
1493546fef27STej Parkash static void __qla4_83xx_disable_pause(struct scsi_qla_host *ha)
1494546fef27STej Parkash {
1495546fef27STej Parkash 	int i;
1496546fef27STej Parkash 
1497546fef27STej Parkash 	/* set SRE-Shim Control Register */
1498546fef27STej Parkash 	qla4_83xx_wr_reg_indirect(ha, QLA83XX_SRE_SHIM_CONTROL,
1499546fef27STej Parkash 				  QLA83XX_SET_PAUSE_VAL);
1500546fef27STej Parkash 
1501546fef27STej Parkash 	for (i = 0; i < 8; i++) {
1502546fef27STej Parkash 		/* Port 0 Rx Buffer Pause Threshold Registers. */
1503546fef27STej Parkash 		qla4_83xx_wr_reg_indirect(ha,
1504546fef27STej Parkash 				      QLA83XX_PORT0_RXB_PAUSE_THRS + (i * 0x4),
1505546fef27STej Parkash 				      QLA83XX_SET_PAUSE_VAL);
1506546fef27STej Parkash 		/* Port 1 Rx Buffer Pause Threshold Registers. */
1507546fef27STej Parkash 		qla4_83xx_wr_reg_indirect(ha,
1508546fef27STej Parkash 				      QLA83XX_PORT1_RXB_PAUSE_THRS + (i * 0x4),
1509546fef27STej Parkash 				      QLA83XX_SET_PAUSE_VAL);
1510546fef27STej Parkash 	}
1511546fef27STej Parkash 
1512546fef27STej Parkash 	for (i = 0; i < 4; i++) {
1513546fef27STej Parkash 		/* Port 0 RxB Traffic Class Max Cell Registers. */
1514546fef27STej Parkash 		qla4_83xx_wr_reg_indirect(ha,
1515546fef27STej Parkash 				     QLA83XX_PORT0_RXB_TC_MAX_CELL + (i * 0x4),
1516546fef27STej Parkash 				     QLA83XX_SET_TC_MAX_CELL_VAL);
1517546fef27STej Parkash 		/* Port 1 RxB Traffic Class Max Cell Registers. */
1518546fef27STej Parkash 		qla4_83xx_wr_reg_indirect(ha,
1519546fef27STej Parkash 				     QLA83XX_PORT1_RXB_TC_MAX_CELL + (i * 0x4),
1520546fef27STej Parkash 				     QLA83XX_SET_TC_MAX_CELL_VAL);
1521546fef27STej Parkash 	}
1522546fef27STej Parkash 
1523546fef27STej Parkash 	qla4_83xx_wr_reg_indirect(ha, QLA83XX_PORT2_IFB_PAUSE_THRS,
1524546fef27STej Parkash 				  QLA83XX_SET_PAUSE_VAL);
1525546fef27STej Parkash 	qla4_83xx_wr_reg_indirect(ha, QLA83XX_PORT3_IFB_PAUSE_THRS,
1526546fef27STej Parkash 				  QLA83XX_SET_PAUSE_VAL);
1527546fef27STej Parkash 
1528546fef27STej Parkash 	ql4_printk(KERN_INFO, ha, "Disabled pause frames successfully.\n");
1529546fef27STej Parkash }
1530546fef27STej Parkash 
1531c18b78edSManish Dusane /**
1532c18b78edSManish Dusane  * qla4_83xx_eport_init - Initialize EPort.
1533c18b78edSManish Dusane  * @ha: Pointer to host adapter structure.
1534c18b78edSManish Dusane  *
1535c18b78edSManish Dusane  * If EPort hardware is in reset state before disabling pause, there would be
1536c18b78edSManish Dusane  * serious hardware wedging issues. To prevent this perform eport init everytime
1537c18b78edSManish Dusane  * before disabling pause frames.
1538c18b78edSManish Dusane  **/
1539c18b78edSManish Dusane static void qla4_83xx_eport_init(struct scsi_qla_host *ha)
1540c18b78edSManish Dusane {
1541c18b78edSManish Dusane 	/* Clear the 8 registers */
1542c18b78edSManish Dusane 	qla4_83xx_wr_reg_indirect(ha, QLA83XX_RESET_REG, 0x0);
1543c18b78edSManish Dusane 	qla4_83xx_wr_reg_indirect(ha, QLA83XX_RESET_PORT0, 0x0);
1544c18b78edSManish Dusane 	qla4_83xx_wr_reg_indirect(ha, QLA83XX_RESET_PORT1, 0x0);
1545c18b78edSManish Dusane 	qla4_83xx_wr_reg_indirect(ha, QLA83XX_RESET_PORT2, 0x0);
1546c18b78edSManish Dusane 	qla4_83xx_wr_reg_indirect(ha, QLA83XX_RESET_PORT3, 0x0);
1547c18b78edSManish Dusane 	qla4_83xx_wr_reg_indirect(ha, QLA83XX_RESET_SRE_SHIM, 0x0);
1548c18b78edSManish Dusane 	qla4_83xx_wr_reg_indirect(ha, QLA83XX_RESET_EPG_SHIM, 0x0);
1549c18b78edSManish Dusane 	qla4_83xx_wr_reg_indirect(ha, QLA83XX_RESET_ETHER_PCS, 0x0);
1550c18b78edSManish Dusane 
1551c18b78edSManish Dusane 	/* Write any value to Reset Control register */
1552c18b78edSManish Dusane 	qla4_83xx_wr_reg_indirect(ha, QLA83XX_RESET_CONTROL, 0xFF);
1553c18b78edSManish Dusane 
1554c18b78edSManish Dusane 	ql4_printk(KERN_INFO, ha, "EPORT is out of reset.\n");
1555c18b78edSManish Dusane }
1556c18b78edSManish Dusane 
1557546fef27STej Parkash void qla4_83xx_disable_pause(struct scsi_qla_host *ha)
1558546fef27STej Parkash {
1559546fef27STej Parkash 	ha->isp_ops->idc_lock(ha);
1560c18b78edSManish Dusane 	/* Before disabling pause frames, ensure that eport is not in reset */
1561c18b78edSManish Dusane 	qla4_83xx_eport_init(ha);
1562546fef27STej Parkash 	qla4_83xx_dump_pause_control_regs(ha);
1563546fef27STej Parkash 	__qla4_83xx_disable_pause(ha);
1564546fef27STej Parkash 	ha->isp_ops->idc_unlock(ha);
1565546fef27STej Parkash }
1566a083e8bcSVikas Chaudhary 
1567a083e8bcSVikas Chaudhary /**
1568a083e8bcSVikas Chaudhary  * qla4_83xx_is_detached - Check if we are marked invisible.
1569a083e8bcSVikas Chaudhary  * @ha: Pointer to host adapter structure.
1570a083e8bcSVikas Chaudhary  **/
1571a083e8bcSVikas Chaudhary int qla4_83xx_is_detached(struct scsi_qla_host *ha)
1572a083e8bcSVikas Chaudhary {
1573a083e8bcSVikas Chaudhary 	uint32_t drv_active;
1574a083e8bcSVikas Chaudhary 
1575a083e8bcSVikas Chaudhary 	drv_active = qla4_8xxx_rd_direct(ha, QLA8XXX_CRB_DRV_ACTIVE);
1576a083e8bcSVikas Chaudhary 
1577a083e8bcSVikas Chaudhary 	if (test_bit(AF_INIT_DONE, &ha->flags) &&
1578a083e8bcSVikas Chaudhary 	    !(drv_active & (1 << ha->func_num))) {
1579a083e8bcSVikas Chaudhary 		DEBUG2(ql4_printk(KERN_INFO, ha, "%s: drv_active = 0x%X\n",
1580a083e8bcSVikas Chaudhary 				  __func__, drv_active));
1581a083e8bcSVikas Chaudhary 		return QLA_SUCCESS;
1582a083e8bcSVikas Chaudhary 	}
1583a083e8bcSVikas Chaudhary 
1584a083e8bcSVikas Chaudhary 	return QLA_ERROR;
1585a083e8bcSVikas Chaudhary }
1586