xref: /openbmc/linux/drivers/scsi/qla4xxx/ql4_83xx.c (revision ed26297d)
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 
qla4_83xx_rd_reg(struct scsi_qla_host * ha,ulong addr)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 
qla4_83xx_wr_reg(struct scsi_qla_host * ha,ulong addr,uint32_t val)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 
qla4_83xx_set_win_base(struct scsi_qla_host * ha,uint32_t addr)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 
qla4_83xx_rd_reg_indirect(struct scsi_qla_host * ha,uint32_t addr,uint32_t * data)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 
qla4_83xx_wr_reg_indirect(struct scsi_qla_host * ha,uint32_t addr,uint32_t data)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 
qla4_83xx_flash_lock(struct scsi_qla_host * ha)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 
qla4_83xx_flash_unlock(struct scsi_qla_host * ha)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 
qla4_83xx_flash_read_u32(struct scsi_qla_host * ha,uint32_t flash_addr,uint8_t * p_data,int u32_word_count)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 
qla4_83xx_lockless_flash_read_u32(struct scsi_qla_host * ha,uint32_t flash_addr,uint8_t * p_data,int u32_word_count)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 
qla4_83xx_rom_lock_recovery(struct scsi_qla_host * ha)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 
qla4_83xx_lock_recovery(struct scsi_qla_host * ha)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 
qla4_83xx_drv_lock(struct scsi_qla_host * ha)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 
qla4_83xx_drv_unlock(struct scsi_qla_host * ha)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 
qla4_83xx_set_idc_dontreset(struct scsi_qla_host * ha)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 
qla4_83xx_clear_idc_dontreset(struct scsi_qla_host * ha)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 
qla4_83xx_idc_dontreset(struct scsi_qla_host * ha)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 
qla4_83xx_can_perform_reset(struct scsi_qla_host * ha)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 ||
475*ed26297dSWan Jiabing 				iscsi_func_low > device_map[i].func_num)
4766e7b4292SVikas Chaudhary 					iscsi_func_low = device_map[i].func_num;
4776e7b4292SVikas Chaudhary 
4786e7b4292SVikas Chaudhary 				iscsi_present++;
4796e7b4292SVikas Chaudhary 			}
4806e7b4292SVikas Chaudhary 		}
4816e7b4292SVikas Chaudhary 
4826e7b4292SVikas Chaudhary 		/* For function_num[8..15] get info from dev_part2 register */
4836e7b4292SVikas Chaudhary 		if (nibble == 7) {
4846e7b4292SVikas Chaudhary 			nibble = 0;
4856e7b4292SVikas Chaudhary 			dev_part = dev_part2;
4866e7b4292SVikas Chaudhary 		}
4876e7b4292SVikas Chaudhary 	}
4886e7b4292SVikas Chaudhary 
4896e7b4292SVikas Chaudhary 	/* NIC, iSCSI and FCOE are the Reset owners based on order, NIC gets
4906e7b4292SVikas Chaudhary 	 * precedence over iSCSI and FCOE and iSCSI over FCOE, based on drivers
4916e7b4292SVikas Chaudhary 	 * present. */
4926e7b4292SVikas Chaudhary 	if (!nic_present && (ha->func_num == iscsi_func_low)) {
4936e7b4292SVikas Chaudhary 		DEBUG2(ql4_printk(KERN_INFO, ha,
4946e7b4292SVikas Chaudhary 				  "%s: can reset - NIC not present and lower iSCSI function is %d\n",
4956e7b4292SVikas Chaudhary 				  __func__, ha->func_num));
4966e7b4292SVikas Chaudhary 		return 1;
4976e7b4292SVikas Chaudhary 	}
4986e7b4292SVikas Chaudhary 
4996e7b4292SVikas Chaudhary 	return 0;
5006e7b4292SVikas Chaudhary }
5016e7b4292SVikas Chaudhary 
5026e7b4292SVikas Chaudhary /**
5036e7b4292SVikas Chaudhary  * qla4_83xx_need_reset_handler - Code to start reset sequence
5046e7b4292SVikas Chaudhary  * @ha: pointer to adapter structure
5056e7b4292SVikas Chaudhary  *
5066e7b4292SVikas Chaudhary  * Note: IDC lock must be held upon entry
5076e7b4292SVikas Chaudhary  **/
qla4_83xx_need_reset_handler(struct scsi_qla_host * ha)5086e7b4292SVikas Chaudhary void qla4_83xx_need_reset_handler(struct scsi_qla_host *ha)
5096e7b4292SVikas Chaudhary {
5106e7b4292SVikas Chaudhary 	uint32_t dev_state, drv_state, drv_active;
5116e7b4292SVikas Chaudhary 	unsigned long reset_timeout, dev_init_timeout;
5126e7b4292SVikas Chaudhary 
5136e7b4292SVikas Chaudhary 	ql4_printk(KERN_INFO, ha, "%s: Performing ISP error recovery\n",
5146e7b4292SVikas Chaudhary 		   __func__);
5156e7b4292SVikas Chaudhary 
5166e7b4292SVikas Chaudhary 	if (!test_bit(AF_8XXX_RST_OWNER, &ha->flags)) {
5176e7b4292SVikas Chaudhary 		DEBUG2(ql4_printk(KERN_INFO, ha, "%s: reset acknowledged\n",
5186e7b4292SVikas Chaudhary 				  __func__));
5196e7b4292SVikas Chaudhary 		qla4_8xxx_set_rst_ready(ha);
5206e7b4292SVikas Chaudhary 
5216e7b4292SVikas Chaudhary 		/* Non-reset owners ACK Reset and wait for device INIT state
5226e7b4292SVikas Chaudhary 		 * as part of Reset Recovery by Reset Owner */
5236e7b4292SVikas Chaudhary 		dev_init_timeout = jiffies + (ha->nx_dev_init_timeout * HZ);
5246e7b4292SVikas Chaudhary 
5256e7b4292SVikas Chaudhary 		do {
5266e7b4292SVikas Chaudhary 			if (time_after_eq(jiffies, dev_init_timeout)) {
5276e7b4292SVikas Chaudhary 				ql4_printk(KERN_INFO, ha, "%s: Non Reset owner dev init timeout\n",
5286e7b4292SVikas Chaudhary 					   __func__);
5296e7b4292SVikas Chaudhary 				break;
5306e7b4292SVikas Chaudhary 			}
5316e7b4292SVikas Chaudhary 
5326e7b4292SVikas Chaudhary 			ha->isp_ops->idc_unlock(ha);
5336e7b4292SVikas Chaudhary 			msleep(1000);
5346e7b4292SVikas Chaudhary 			ha->isp_ops->idc_lock(ha);
5356e7b4292SVikas Chaudhary 
5366e7b4292SVikas Chaudhary 			dev_state = qla4_8xxx_rd_direct(ha,
5376e7b4292SVikas Chaudhary 							QLA8XXX_CRB_DEV_STATE);
5386e7b4292SVikas Chaudhary 		} while (dev_state == QLA8XXX_DEV_NEED_RESET);
5396e7b4292SVikas Chaudhary 	} else {
5406e7b4292SVikas Chaudhary 		qla4_8xxx_set_rst_ready(ha);
5416e7b4292SVikas Chaudhary 		reset_timeout = jiffies + (ha->nx_reset_timeout * HZ);
5426e7b4292SVikas Chaudhary 		drv_state = qla4_8xxx_rd_direct(ha, QLA8XXX_CRB_DRV_STATE);
5436e7b4292SVikas Chaudhary 		drv_active = qla4_8xxx_rd_direct(ha, QLA8XXX_CRB_DRV_ACTIVE);
5446e7b4292SVikas Chaudhary 
5456e7b4292SVikas Chaudhary 		ql4_printk(KERN_INFO, ha, "%s: drv_state = 0x%x, drv_active = 0x%x\n",
5466e7b4292SVikas Chaudhary 			   __func__, drv_state, drv_active);
5476e7b4292SVikas Chaudhary 
5486e7b4292SVikas Chaudhary 		while (drv_state != drv_active) {
5496e7b4292SVikas Chaudhary 			if (time_after_eq(jiffies, reset_timeout)) {
5506e7b4292SVikas Chaudhary 				ql4_printk(KERN_INFO, ha, "%s: %s: RESET TIMEOUT! drv_state: 0x%08x, drv_active: 0x%08x\n",
5516e7b4292SVikas Chaudhary 					   __func__, DRIVER_NAME, drv_state,
5526e7b4292SVikas Chaudhary 					   drv_active);
5536e7b4292SVikas Chaudhary 				break;
5546e7b4292SVikas Chaudhary 			}
5556e7b4292SVikas Chaudhary 
5566e7b4292SVikas Chaudhary 			ha->isp_ops->idc_unlock(ha);
5576e7b4292SVikas Chaudhary 			msleep(1000);
5586e7b4292SVikas Chaudhary 			ha->isp_ops->idc_lock(ha);
5596e7b4292SVikas Chaudhary 
5606e7b4292SVikas Chaudhary 			drv_state = qla4_8xxx_rd_direct(ha,
5616e7b4292SVikas Chaudhary 							QLA8XXX_CRB_DRV_STATE);
5626e7b4292SVikas Chaudhary 			drv_active = qla4_8xxx_rd_direct(ha,
5636e7b4292SVikas Chaudhary 							QLA8XXX_CRB_DRV_ACTIVE);
5646e7b4292SVikas Chaudhary 		}
5656e7b4292SVikas Chaudhary 
5666e7b4292SVikas Chaudhary 		if (drv_state != drv_active) {
5676e7b4292SVikas Chaudhary 			ql4_printk(KERN_INFO, ha, "%s: Reset_owner turning off drv_active of non-acking function 0x%x\n",
5686e7b4292SVikas Chaudhary 				   __func__, (drv_active ^ drv_state));
5696e7b4292SVikas Chaudhary 			drv_active = drv_active & drv_state;
5706e7b4292SVikas Chaudhary 			qla4_8xxx_wr_direct(ha, QLA8XXX_CRB_DRV_ACTIVE,
5716e7b4292SVikas Chaudhary 					    drv_active);
5726e7b4292SVikas Chaudhary 		}
5736e7b4292SVikas Chaudhary 
5746e7b4292SVikas Chaudhary 		clear_bit(AF_8XXX_RST_OWNER, &ha->flags);
5756e7b4292SVikas Chaudhary 		/* Start Reset Recovery */
5766e7b4292SVikas Chaudhary 		qla4_8xxx_device_bootstrap(ha);
5776e7b4292SVikas Chaudhary 	}
5786e7b4292SVikas Chaudhary }
5796e7b4292SVikas Chaudhary 
qla4_83xx_get_idc_param(struct scsi_qla_host * ha)5806e7b4292SVikas Chaudhary void qla4_83xx_get_idc_param(struct scsi_qla_host *ha)
5816e7b4292SVikas Chaudhary {
5826e7b4292SVikas Chaudhary 	uint32_t idc_params, ret_val;
5836e7b4292SVikas Chaudhary 
5846e7b4292SVikas Chaudhary 	ret_val = qla4_83xx_flash_read_u32(ha, QLA83XX_IDC_PARAM_ADDR,
5856e7b4292SVikas Chaudhary 					   (uint8_t *)&idc_params, 1);
5866e7b4292SVikas Chaudhary 	if (ret_val == QLA_SUCCESS) {
5876e7b4292SVikas Chaudhary 		ha->nx_dev_init_timeout = idc_params & 0xFFFF;
5886e7b4292SVikas Chaudhary 		ha->nx_reset_timeout = (idc_params >> 16) & 0xFFFF;
5896e7b4292SVikas Chaudhary 	} else {
5906e7b4292SVikas Chaudhary 		ha->nx_dev_init_timeout = ROM_DEV_INIT_TIMEOUT;
5916e7b4292SVikas Chaudhary 		ha->nx_reset_timeout = ROM_DRV_RESET_ACK_TIMEOUT;
5926e7b4292SVikas Chaudhary 	}
5936e7b4292SVikas Chaudhary 
5946e7b4292SVikas Chaudhary 	DEBUG2(ql4_printk(KERN_DEBUG, ha,
5956e7b4292SVikas Chaudhary 			  "%s: ha->nx_dev_init_timeout = %d, ha->nx_reset_timeout = %d\n",
5966e7b4292SVikas Chaudhary 			  __func__, ha->nx_dev_init_timeout,
5976e7b4292SVikas Chaudhary 			  ha->nx_reset_timeout));
5986e7b4292SVikas Chaudhary }
5996e7b4292SVikas Chaudhary 
6006e7b4292SVikas Chaudhary /*-------------------------Reset Sequence Functions-----------------------*/
6016e7b4292SVikas Chaudhary 
qla4_83xx_dump_reset_seq_hdr(struct scsi_qla_host * ha)6026e7b4292SVikas Chaudhary static void qla4_83xx_dump_reset_seq_hdr(struct scsi_qla_host *ha)
6036e7b4292SVikas Chaudhary {
6046e7b4292SVikas Chaudhary 	uint8_t *phdr;
6056e7b4292SVikas Chaudhary 
6066e7b4292SVikas Chaudhary 	if (!ha->reset_tmplt.buff) {
6076e7b4292SVikas Chaudhary 		ql4_printk(KERN_ERR, ha, "%s: Error: Invalid reset_seq_template\n",
6086e7b4292SVikas Chaudhary 			   __func__);
6096e7b4292SVikas Chaudhary 		return;
6106e7b4292SVikas Chaudhary 	}
6116e7b4292SVikas Chaudhary 
6126e7b4292SVikas Chaudhary 	phdr = ha->reset_tmplt.buff;
6136e7b4292SVikas Chaudhary 
6146e7b4292SVikas Chaudhary 	DEBUG2(ql4_printk(KERN_INFO, ha,
6156e7b4292SVikas 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",
6166e7b4292SVikas Chaudhary 			  *phdr, *(phdr+1), *(phdr+2), *(phdr+3), *(phdr+4),
6176e7b4292SVikas Chaudhary 			  *(phdr+5), *(phdr+6), *(phdr+7), *(phdr + 8),
6186e7b4292SVikas Chaudhary 			  *(phdr+9), *(phdr+10), *(phdr+11), *(phdr+12),
6196e7b4292SVikas Chaudhary 			  *(phdr+13), *(phdr+14), *(phdr+15)));
6206e7b4292SVikas Chaudhary }
6216e7b4292SVikas Chaudhary 
qla4_83xx_copy_bootloader(struct scsi_qla_host * ha)6226e7b4292SVikas Chaudhary static int qla4_83xx_copy_bootloader(struct scsi_qla_host *ha)
6236e7b4292SVikas Chaudhary {
6246e7b4292SVikas Chaudhary 	uint8_t *p_cache;
6256e7b4292SVikas Chaudhary 	uint32_t src, count, size;
6266e7b4292SVikas Chaudhary 	uint64_t dest;
6276e7b4292SVikas Chaudhary 	int ret_val = QLA_SUCCESS;
6286e7b4292SVikas Chaudhary 
6296e7b4292SVikas Chaudhary 	src = QLA83XX_BOOTLOADER_FLASH_ADDR;
6306e7b4292SVikas Chaudhary 	dest = qla4_83xx_rd_reg(ha, QLA83XX_BOOTLOADER_ADDR);
6316e7b4292SVikas Chaudhary 	size = qla4_83xx_rd_reg(ha, QLA83XX_BOOTLOADER_SIZE);
6326e7b4292SVikas Chaudhary 
6336e7b4292SVikas Chaudhary 	/* 128 bit alignment check */
6346e7b4292SVikas Chaudhary 	if (size & 0xF)
6356e7b4292SVikas Chaudhary 		size = (size + 16) & ~0xF;
6366e7b4292SVikas Chaudhary 
6376e7b4292SVikas Chaudhary 	/* 16 byte count */
6386e7b4292SVikas Chaudhary 	count = size/16;
6396e7b4292SVikas Chaudhary 
6406e7b4292SVikas Chaudhary 	p_cache = vmalloc(size);
6416e7b4292SVikas Chaudhary 	if (p_cache == NULL) {
6426e7b4292SVikas Chaudhary 		ql4_printk(KERN_ERR, ha, "%s: Failed to allocate memory for boot loader cache\n",
6436e7b4292SVikas Chaudhary 			   __func__);
6446e7b4292SVikas Chaudhary 		ret_val = QLA_ERROR;
6456e7b4292SVikas Chaudhary 		goto exit_copy_bootloader;
6466e7b4292SVikas Chaudhary 	}
6476e7b4292SVikas Chaudhary 
6486e7b4292SVikas Chaudhary 	ret_val = qla4_83xx_lockless_flash_read_u32(ha, src, p_cache,
6496e7b4292SVikas Chaudhary 						    size / sizeof(uint32_t));
6506e7b4292SVikas Chaudhary 	if (ret_val == QLA_ERROR) {
6516e7b4292SVikas Chaudhary 		ql4_printk(KERN_ERR, ha, "%s: Error reading firmware from flash\n",
6526e7b4292SVikas Chaudhary 			   __func__);
6536e7b4292SVikas Chaudhary 		goto exit_copy_error;
6546e7b4292SVikas Chaudhary 	}
6556e7b4292SVikas Chaudhary 	DEBUG2(ql4_printk(KERN_INFO, ha, "%s: Read firmware from flash\n",
6566e7b4292SVikas Chaudhary 			  __func__));
6576e7b4292SVikas Chaudhary 
6586e7b4292SVikas Chaudhary 	/* 128 bit/16 byte write to MS memory */
6593c3cab17STej Parkash 	ret_val = qla4_8xxx_ms_mem_write_128b(ha, dest, (uint32_t *)p_cache,
6606e7b4292SVikas Chaudhary 					      count);
6616e7b4292SVikas Chaudhary 	if (ret_val == QLA_ERROR) {
6626e7b4292SVikas Chaudhary 		ql4_printk(KERN_ERR, ha, "%s: Error writing firmware to MS\n",
6636e7b4292SVikas Chaudhary 			   __func__);
6646e7b4292SVikas Chaudhary 		goto exit_copy_error;
6656e7b4292SVikas Chaudhary 	}
6666e7b4292SVikas Chaudhary 
6676e7b4292SVikas Chaudhary 	DEBUG2(ql4_printk(KERN_INFO, ha, "%s: Wrote firmware size %d to MS\n",
6686e7b4292SVikas Chaudhary 			  __func__, size));
6696e7b4292SVikas Chaudhary 
6706e7b4292SVikas Chaudhary exit_copy_error:
6716e7b4292SVikas Chaudhary 	vfree(p_cache);
6726e7b4292SVikas Chaudhary 
6736e7b4292SVikas Chaudhary exit_copy_bootloader:
6746e7b4292SVikas Chaudhary 	return ret_val;
6756e7b4292SVikas Chaudhary }
6766e7b4292SVikas Chaudhary 
qla4_83xx_check_cmd_peg_status(struct scsi_qla_host * ha)6776e7b4292SVikas Chaudhary static int qla4_83xx_check_cmd_peg_status(struct scsi_qla_host *ha)
6786e7b4292SVikas Chaudhary {
6796e7b4292SVikas Chaudhary 	uint32_t val, ret_val = QLA_ERROR;
6806e7b4292SVikas Chaudhary 	int retries = CRB_CMDPEG_CHECK_RETRY_COUNT;
6816e7b4292SVikas Chaudhary 
6826e7b4292SVikas Chaudhary 	do {
6836e7b4292SVikas Chaudhary 		val = qla4_83xx_rd_reg(ha, QLA83XX_CMDPEG_STATE);
6846e7b4292SVikas Chaudhary 		if (val == PHAN_INITIALIZE_COMPLETE) {
6856e7b4292SVikas Chaudhary 			DEBUG2(ql4_printk(KERN_INFO, ha,
6866e7b4292SVikas Chaudhary 					  "%s: Command Peg initialization complete. State=0x%x\n",
6876e7b4292SVikas Chaudhary 					  __func__, val));
6886e7b4292SVikas Chaudhary 			ret_val = QLA_SUCCESS;
6896e7b4292SVikas Chaudhary 			break;
6906e7b4292SVikas Chaudhary 		}
6916e7b4292SVikas Chaudhary 		msleep(CRB_CMDPEG_CHECK_DELAY);
6926e7b4292SVikas Chaudhary 	} while (--retries);
6936e7b4292SVikas Chaudhary 
6946e7b4292SVikas Chaudhary 	return ret_val;
6956e7b4292SVikas Chaudhary }
6966e7b4292SVikas Chaudhary 
6976e7b4292SVikas Chaudhary /**
6986e7b4292SVikas Chaudhary  * qla4_83xx_poll_reg - Poll the given CRB addr for duration msecs till
6996e7b4292SVikas Chaudhary  * value read ANDed with test_mask is equal to test_result.
7006e7b4292SVikas Chaudhary  *
7016e7b4292SVikas Chaudhary  * @ha : Pointer to adapter structure
7026e7b4292SVikas Chaudhary  * @addr : CRB register address
7036e7b4292SVikas Chaudhary  * @duration : Poll for total of "duration" msecs
7046e7b4292SVikas Chaudhary  * @test_mask : Mask value read with "test_mask"
7056e7b4292SVikas Chaudhary  * @test_result : Compare (value&test_mask) with test_result.
7066e7b4292SVikas Chaudhary  **/
qla4_83xx_poll_reg(struct scsi_qla_host * ha,uint32_t addr,int duration,uint32_t test_mask,uint32_t test_result)7076e7b4292SVikas Chaudhary static int qla4_83xx_poll_reg(struct scsi_qla_host *ha, uint32_t addr,
7086e7b4292SVikas Chaudhary 			      int duration, uint32_t test_mask,
7096e7b4292SVikas Chaudhary 			      uint32_t test_result)
7106e7b4292SVikas Chaudhary {
7116e7b4292SVikas Chaudhary 	uint32_t value;
7126e7b4292SVikas Chaudhary 	uint8_t retries;
7136e7b4292SVikas Chaudhary 	int ret_val = QLA_SUCCESS;
7146e7b4292SVikas Chaudhary 
7156e7b4292SVikas Chaudhary 	ret_val = qla4_83xx_rd_reg_indirect(ha, addr, &value);
7166e7b4292SVikas Chaudhary 	if (ret_val == QLA_ERROR)
7176e7b4292SVikas Chaudhary 		goto exit_poll_reg;
7186e7b4292SVikas Chaudhary 
7196e7b4292SVikas Chaudhary 	retries = duration / 10;
7206e7b4292SVikas Chaudhary 	do {
7216e7b4292SVikas Chaudhary 		if ((value & test_mask) != test_result) {
7226e7b4292SVikas Chaudhary 			msleep(duration / 10);
7236e7b4292SVikas Chaudhary 			ret_val = qla4_83xx_rd_reg_indirect(ha, addr, &value);
7246e7b4292SVikas Chaudhary 			if (ret_val == QLA_ERROR)
7256e7b4292SVikas Chaudhary 				goto exit_poll_reg;
7266e7b4292SVikas Chaudhary 
7276e7b4292SVikas Chaudhary 			ret_val = QLA_ERROR;
7286e7b4292SVikas Chaudhary 		} else {
7296e7b4292SVikas Chaudhary 			ret_val = QLA_SUCCESS;
7306e7b4292SVikas Chaudhary 			break;
7316e7b4292SVikas Chaudhary 		}
7326e7b4292SVikas Chaudhary 	} while (retries--);
7336e7b4292SVikas Chaudhary 
7346e7b4292SVikas Chaudhary exit_poll_reg:
7356e7b4292SVikas Chaudhary 	if (ret_val == QLA_ERROR) {
7366e7b4292SVikas Chaudhary 		ha->reset_tmplt.seq_error++;
7376e7b4292SVikas Chaudhary 		ql4_printk(KERN_ERR, ha, "%s: Poll Failed:  0x%08x 0x%08x 0x%08x\n",
7386e7b4292SVikas Chaudhary 			   __func__, value, test_mask, test_result);
7396e7b4292SVikas Chaudhary 	}
7406e7b4292SVikas Chaudhary 
7416e7b4292SVikas Chaudhary 	return ret_val;
7426e7b4292SVikas Chaudhary }
7436e7b4292SVikas Chaudhary 
qla4_83xx_reset_seq_checksum_test(struct scsi_qla_host * ha)7446e7b4292SVikas Chaudhary static int qla4_83xx_reset_seq_checksum_test(struct scsi_qla_host *ha)
7456e7b4292SVikas Chaudhary {
7466e7b4292SVikas Chaudhary 	uint32_t sum =  0;
7476e7b4292SVikas Chaudhary 	uint16_t *buff = (uint16_t *)ha->reset_tmplt.buff;
7486e7b4292SVikas Chaudhary 	int u16_count =  ha->reset_tmplt.hdr->size / sizeof(uint16_t);
7496e7b4292SVikas Chaudhary 	int ret_val;
7506e7b4292SVikas Chaudhary 
7516e7b4292SVikas Chaudhary 	while (u16_count-- > 0)
7526e7b4292SVikas Chaudhary 		sum += *buff++;
7536e7b4292SVikas Chaudhary 
7546e7b4292SVikas Chaudhary 	while (sum >> 16)
7556e7b4292SVikas Chaudhary 		sum = (sum & 0xFFFF) +  (sum >> 16);
7566e7b4292SVikas Chaudhary 
7576e7b4292SVikas Chaudhary 	/* checksum of 0 indicates a valid template */
7586e7b4292SVikas Chaudhary 	if (~sum) {
7596e7b4292SVikas Chaudhary 		ret_val = QLA_SUCCESS;
7606e7b4292SVikas Chaudhary 	} else {
7616e7b4292SVikas Chaudhary 		ql4_printk(KERN_ERR, ha, "%s: Reset seq checksum failed\n",
7626e7b4292SVikas Chaudhary 			   __func__);
7636e7b4292SVikas Chaudhary 		ret_val = QLA_ERROR;
7646e7b4292SVikas Chaudhary 	}
7656e7b4292SVikas Chaudhary 
7666e7b4292SVikas Chaudhary 	return ret_val;
7676e7b4292SVikas Chaudhary }
7686e7b4292SVikas Chaudhary 
7696e7b4292SVikas Chaudhary /**
7706e7b4292SVikas Chaudhary  * qla4_83xx_read_reset_template - Read Reset Template from Flash
7716e7b4292SVikas Chaudhary  * @ha: Pointer to adapter structure
7726e7b4292SVikas Chaudhary  **/
qla4_83xx_read_reset_template(struct scsi_qla_host * ha)7736e7b4292SVikas Chaudhary void qla4_83xx_read_reset_template(struct scsi_qla_host *ha)
7746e7b4292SVikas Chaudhary {
7756e7b4292SVikas Chaudhary 	uint8_t *p_buff;
7766e7b4292SVikas Chaudhary 	uint32_t addr, tmplt_hdr_def_size, tmplt_hdr_size;
7776e7b4292SVikas Chaudhary 	uint32_t ret_val;
7786e7b4292SVikas Chaudhary 
7796e7b4292SVikas Chaudhary 	ha->reset_tmplt.seq_error = 0;
7806e7b4292SVikas Chaudhary 	ha->reset_tmplt.buff = vmalloc(QLA83XX_RESTART_TEMPLATE_SIZE);
7816e7b4292SVikas Chaudhary 	if (ha->reset_tmplt.buff == NULL) {
7826e7b4292SVikas Chaudhary 		ql4_printk(KERN_ERR, ha, "%s: Failed to allocate reset template resources\n",
7836e7b4292SVikas Chaudhary 			   __func__);
7846e7b4292SVikas Chaudhary 		goto exit_read_reset_template;
7856e7b4292SVikas Chaudhary 	}
7866e7b4292SVikas Chaudhary 
7876e7b4292SVikas Chaudhary 	p_buff = ha->reset_tmplt.buff;
7886e7b4292SVikas Chaudhary 	addr = QLA83XX_RESET_TEMPLATE_ADDR;
7896e7b4292SVikas Chaudhary 
7906e7b4292SVikas Chaudhary 	tmplt_hdr_def_size = sizeof(struct qla4_83xx_reset_template_hdr) /
7916e7b4292SVikas Chaudhary 				    sizeof(uint32_t);
7926e7b4292SVikas Chaudhary 
7936e7b4292SVikas Chaudhary 	DEBUG2(ql4_printk(KERN_INFO, ha,
7946e7b4292SVikas Chaudhary 			  "%s: Read template hdr size %d from Flash\n",
7956e7b4292SVikas Chaudhary 			  __func__, tmplt_hdr_def_size));
7966e7b4292SVikas Chaudhary 
7976e7b4292SVikas Chaudhary 	/* Copy template header from flash */
7986e7b4292SVikas Chaudhary 	ret_val = qla4_83xx_flash_read_u32(ha, addr, p_buff,
7996e7b4292SVikas Chaudhary 					   tmplt_hdr_def_size);
8006e7b4292SVikas Chaudhary 	if (ret_val != QLA_SUCCESS) {
8016e7b4292SVikas Chaudhary 		ql4_printk(KERN_ERR, ha, "%s: Failed to read reset template\n",
8026e7b4292SVikas Chaudhary 			   __func__);
8036e7b4292SVikas Chaudhary 		goto exit_read_template_error;
8046e7b4292SVikas Chaudhary 	}
8056e7b4292SVikas Chaudhary 
8066e7b4292SVikas Chaudhary 	ha->reset_tmplt.hdr =
8076e7b4292SVikas Chaudhary 		(struct qla4_83xx_reset_template_hdr *)ha->reset_tmplt.buff;
8086e7b4292SVikas Chaudhary 
8096e7b4292SVikas Chaudhary 	/* Validate the template header size and signature */
8106e7b4292SVikas Chaudhary 	tmplt_hdr_size = ha->reset_tmplt.hdr->hdr_size/sizeof(uint32_t);
8116e7b4292SVikas Chaudhary 	if ((tmplt_hdr_size != tmplt_hdr_def_size) ||
8126e7b4292SVikas Chaudhary 	    (ha->reset_tmplt.hdr->signature != RESET_TMPLT_HDR_SIGNATURE)) {
8136e7b4292SVikas Chaudhary 		ql4_printk(KERN_ERR, ha, "%s: Template Header size %d is invalid, tmplt_hdr_def_size %d\n",
8146e7b4292SVikas Chaudhary 			   __func__, tmplt_hdr_size, tmplt_hdr_def_size);
8156e7b4292SVikas Chaudhary 		goto exit_read_template_error;
8166e7b4292SVikas Chaudhary 	}
8176e7b4292SVikas Chaudhary 
8186e7b4292SVikas Chaudhary 	addr = QLA83XX_RESET_TEMPLATE_ADDR + ha->reset_tmplt.hdr->hdr_size;
8196e7b4292SVikas Chaudhary 	p_buff = ha->reset_tmplt.buff + ha->reset_tmplt.hdr->hdr_size;
8206e7b4292SVikas Chaudhary 	tmplt_hdr_def_size = (ha->reset_tmplt.hdr->size -
8216e7b4292SVikas Chaudhary 			      ha->reset_tmplt.hdr->hdr_size) / sizeof(uint32_t);
8226e7b4292SVikas Chaudhary 
8236e7b4292SVikas Chaudhary 	DEBUG2(ql4_printk(KERN_INFO, ha,
8246e7b4292SVikas Chaudhary 			  "%s: Read rest of the template size %d\n",
8256e7b4292SVikas Chaudhary 			  __func__, ha->reset_tmplt.hdr->size));
8266e7b4292SVikas Chaudhary 
8276e7b4292SVikas Chaudhary 	/* Copy rest of the template */
8286e7b4292SVikas Chaudhary 	ret_val = qla4_83xx_flash_read_u32(ha, addr, p_buff,
8296e7b4292SVikas Chaudhary 					   tmplt_hdr_def_size);
8306e7b4292SVikas Chaudhary 	if (ret_val != QLA_SUCCESS) {
8318c519319SMasanari Iida 		ql4_printk(KERN_ERR, ha, "%s: Failed to read reset template\n",
8326e7b4292SVikas Chaudhary 			   __func__);
8336e7b4292SVikas Chaudhary 		goto exit_read_template_error;
8346e7b4292SVikas Chaudhary 	}
8356e7b4292SVikas Chaudhary 
8366e7b4292SVikas Chaudhary 	/* Integrity check */
8376e7b4292SVikas Chaudhary 	if (qla4_83xx_reset_seq_checksum_test(ha)) {
8386e7b4292SVikas Chaudhary 		ql4_printk(KERN_ERR, ha, "%s: Reset Seq checksum failed!\n",
8396e7b4292SVikas Chaudhary 			   __func__);
8406e7b4292SVikas Chaudhary 		goto exit_read_template_error;
8416e7b4292SVikas Chaudhary 	}
8426e7b4292SVikas Chaudhary 	DEBUG2(ql4_printk(KERN_INFO, ha,
8436e7b4292SVikas Chaudhary 			  "%s: Reset Seq checksum passed, Get stop, start and init seq offsets\n",
8446e7b4292SVikas Chaudhary 			  __func__));
8456e7b4292SVikas Chaudhary 
8466e7b4292SVikas Chaudhary 	/* Get STOP, START, INIT sequence offsets */
8476e7b4292SVikas Chaudhary 	ha->reset_tmplt.init_offset = ha->reset_tmplt.buff +
8486e7b4292SVikas Chaudhary 				      ha->reset_tmplt.hdr->init_seq_offset;
8496e7b4292SVikas Chaudhary 	ha->reset_tmplt.start_offset = ha->reset_tmplt.buff +
8506e7b4292SVikas Chaudhary 				       ha->reset_tmplt.hdr->start_seq_offset;
8516e7b4292SVikas Chaudhary 	ha->reset_tmplt.stop_offset = ha->reset_tmplt.buff +
8526e7b4292SVikas Chaudhary 				      ha->reset_tmplt.hdr->hdr_size;
8536e7b4292SVikas Chaudhary 	qla4_83xx_dump_reset_seq_hdr(ha);
8546e7b4292SVikas Chaudhary 
8556e7b4292SVikas Chaudhary 	goto exit_read_reset_template;
8566e7b4292SVikas Chaudhary 
8576e7b4292SVikas Chaudhary exit_read_template_error:
8586e7b4292SVikas Chaudhary 	vfree(ha->reset_tmplt.buff);
8596e7b4292SVikas Chaudhary 
8606e7b4292SVikas Chaudhary exit_read_reset_template:
8616e7b4292SVikas Chaudhary 	return;
8626e7b4292SVikas Chaudhary }
8636e7b4292SVikas Chaudhary 
8646e7b4292SVikas Chaudhary /**
8656e7b4292SVikas Chaudhary  * qla4_83xx_read_write_crb_reg - Read from raddr and write value to waddr.
8666e7b4292SVikas Chaudhary  *
8676e7b4292SVikas Chaudhary  * @ha : Pointer to adapter structure
8686e7b4292SVikas Chaudhary  * @raddr : CRB address to read from
8696e7b4292SVikas Chaudhary  * @waddr : CRB address to write to
8706e7b4292SVikas Chaudhary  **/
qla4_83xx_read_write_crb_reg(struct scsi_qla_host * ha,uint32_t raddr,uint32_t waddr)8716e7b4292SVikas Chaudhary static void qla4_83xx_read_write_crb_reg(struct scsi_qla_host *ha,
8726e7b4292SVikas Chaudhary 					 uint32_t raddr, uint32_t waddr)
8736e7b4292SVikas Chaudhary {
8746e7b4292SVikas Chaudhary 	uint32_t value;
8756e7b4292SVikas Chaudhary 
8766e7b4292SVikas Chaudhary 	qla4_83xx_rd_reg_indirect(ha, raddr, &value);
8776e7b4292SVikas Chaudhary 	qla4_83xx_wr_reg_indirect(ha, waddr, value);
8786e7b4292SVikas Chaudhary }
8796e7b4292SVikas Chaudhary 
8806e7b4292SVikas Chaudhary /**
8816e7b4292SVikas Chaudhary  * qla4_83xx_rmw_crb_reg - Read Modify Write crb register
8826e7b4292SVikas Chaudhary  *
8836e7b4292SVikas Chaudhary  * This function read value from raddr, AND with test_mask,
8846e7b4292SVikas Chaudhary  * Shift Left,Right/OR/XOR with values RMW header and write value to waddr.
8856e7b4292SVikas Chaudhary  *
8866e7b4292SVikas Chaudhary  * @ha : Pointer to adapter structure
8876e7b4292SVikas Chaudhary  * @raddr : CRB address to read from
8886e7b4292SVikas Chaudhary  * @waddr : CRB address to write to
8896e7b4292SVikas Chaudhary  * @p_rmw_hdr : header with shift/or/xor values.
8906e7b4292SVikas Chaudhary  **/
qla4_83xx_rmw_crb_reg(struct scsi_qla_host * ha,uint32_t raddr,uint32_t waddr,struct qla4_83xx_rmw * p_rmw_hdr)8916e7b4292SVikas Chaudhary static void qla4_83xx_rmw_crb_reg(struct scsi_qla_host *ha, uint32_t raddr,
8926e7b4292SVikas Chaudhary 				  uint32_t waddr,
8936e7b4292SVikas Chaudhary 				  struct qla4_83xx_rmw *p_rmw_hdr)
8946e7b4292SVikas Chaudhary {
8956e7b4292SVikas Chaudhary 	uint32_t value;
8966e7b4292SVikas Chaudhary 
8976e7b4292SVikas Chaudhary 	if (p_rmw_hdr->index_a)
8986e7b4292SVikas Chaudhary 		value = ha->reset_tmplt.array[p_rmw_hdr->index_a];
8996e7b4292SVikas Chaudhary 	else
9006e7b4292SVikas Chaudhary 		qla4_83xx_rd_reg_indirect(ha, raddr, &value);
9016e7b4292SVikas Chaudhary 
9026e7b4292SVikas Chaudhary 	value &= p_rmw_hdr->test_mask;
9036e7b4292SVikas Chaudhary 	value <<= p_rmw_hdr->shl;
9046e7b4292SVikas Chaudhary 	value >>= p_rmw_hdr->shr;
9056e7b4292SVikas Chaudhary 	value |= p_rmw_hdr->or_value;
9066e7b4292SVikas Chaudhary 	value ^= p_rmw_hdr->xor_value;
9076e7b4292SVikas Chaudhary 
9086e7b4292SVikas Chaudhary 	qla4_83xx_wr_reg_indirect(ha, waddr, value);
9096e7b4292SVikas Chaudhary 
9106e7b4292SVikas Chaudhary 	return;
9116e7b4292SVikas Chaudhary }
9126e7b4292SVikas Chaudhary 
qla4_83xx_write_list(struct scsi_qla_host * ha,struct qla4_83xx_reset_entry_hdr * p_hdr)9136e7b4292SVikas Chaudhary static void qla4_83xx_write_list(struct scsi_qla_host *ha,
9146e7b4292SVikas Chaudhary 				 struct qla4_83xx_reset_entry_hdr *p_hdr)
9156e7b4292SVikas Chaudhary {
9166e7b4292SVikas Chaudhary 	struct qla4_83xx_entry *p_entry;
9176e7b4292SVikas Chaudhary 	uint32_t i;
9186e7b4292SVikas Chaudhary 
9196e7b4292SVikas Chaudhary 	p_entry = (struct qla4_83xx_entry *)
9206e7b4292SVikas Chaudhary 		  ((char *)p_hdr + sizeof(struct qla4_83xx_reset_entry_hdr));
9216e7b4292SVikas Chaudhary 
9226e7b4292SVikas Chaudhary 	for (i = 0; i < p_hdr->count; i++, p_entry++) {
9236e7b4292SVikas Chaudhary 		qla4_83xx_wr_reg_indirect(ha, p_entry->arg1, p_entry->arg2);
9246e7b4292SVikas Chaudhary 		if (p_hdr->delay)
9256e7b4292SVikas Chaudhary 			udelay((uint32_t)(p_hdr->delay));
9266e7b4292SVikas Chaudhary 	}
9276e7b4292SVikas Chaudhary }
9286e7b4292SVikas Chaudhary 
qla4_83xx_read_write_list(struct scsi_qla_host * ha,struct qla4_83xx_reset_entry_hdr * p_hdr)9296e7b4292SVikas Chaudhary static void qla4_83xx_read_write_list(struct scsi_qla_host *ha,
9306e7b4292SVikas Chaudhary 				      struct qla4_83xx_reset_entry_hdr *p_hdr)
9316e7b4292SVikas Chaudhary {
9326e7b4292SVikas Chaudhary 	struct qla4_83xx_entry *p_entry;
9336e7b4292SVikas Chaudhary 	uint32_t i;
9346e7b4292SVikas Chaudhary 
9356e7b4292SVikas Chaudhary 	p_entry = (struct qla4_83xx_entry *)
9366e7b4292SVikas Chaudhary 		  ((char *)p_hdr + sizeof(struct qla4_83xx_reset_entry_hdr));
9376e7b4292SVikas Chaudhary 
9386e7b4292SVikas Chaudhary 	for (i = 0; i < p_hdr->count; i++, p_entry++) {
9396e7b4292SVikas Chaudhary 		qla4_83xx_read_write_crb_reg(ha, p_entry->arg1, p_entry->arg2);
9406e7b4292SVikas Chaudhary 		if (p_hdr->delay)
9416e7b4292SVikas Chaudhary 			udelay((uint32_t)(p_hdr->delay));
9426e7b4292SVikas Chaudhary 	}
9436e7b4292SVikas Chaudhary }
9446e7b4292SVikas Chaudhary 
qla4_83xx_poll_list(struct scsi_qla_host * ha,struct qla4_83xx_reset_entry_hdr * p_hdr)9456e7b4292SVikas Chaudhary static void qla4_83xx_poll_list(struct scsi_qla_host *ha,
9466e7b4292SVikas Chaudhary 				struct qla4_83xx_reset_entry_hdr *p_hdr)
9476e7b4292SVikas Chaudhary {
9486e7b4292SVikas Chaudhary 	long delay;
9496e7b4292SVikas Chaudhary 	struct qla4_83xx_entry *p_entry;
9506e7b4292SVikas Chaudhary 	struct qla4_83xx_poll *p_poll;
9516e7b4292SVikas Chaudhary 	uint32_t i;
9526e7b4292SVikas Chaudhary 	uint32_t value;
9536e7b4292SVikas Chaudhary 
9546e7b4292SVikas Chaudhary 	p_poll = (struct qla4_83xx_poll *)
9556e7b4292SVikas Chaudhary 		 ((char *)p_hdr + sizeof(struct qla4_83xx_reset_entry_hdr));
9566e7b4292SVikas Chaudhary 
9576e7b4292SVikas Chaudhary 	/* Entries start after 8 byte qla4_83xx_poll, poll header contains
9586e7b4292SVikas Chaudhary 	 * the test_mask, test_value. */
9596e7b4292SVikas Chaudhary 	p_entry = (struct qla4_83xx_entry *)((char *)p_poll +
9606e7b4292SVikas Chaudhary 					     sizeof(struct qla4_83xx_poll));
9616e7b4292SVikas Chaudhary 
9626e7b4292SVikas Chaudhary 	delay = (long)p_hdr->delay;
9636e7b4292SVikas Chaudhary 	if (!delay) {
9646e7b4292SVikas Chaudhary 		for (i = 0; i < p_hdr->count; i++, p_entry++) {
9656e7b4292SVikas Chaudhary 			qla4_83xx_poll_reg(ha, p_entry->arg1, delay,
9666e7b4292SVikas Chaudhary 					   p_poll->test_mask,
9676e7b4292SVikas Chaudhary 					   p_poll->test_value);
9686e7b4292SVikas Chaudhary 		}
9696e7b4292SVikas Chaudhary 	} else {
9706e7b4292SVikas Chaudhary 		for (i = 0; i < p_hdr->count; i++, p_entry++) {
9716e7b4292SVikas Chaudhary 			if (qla4_83xx_poll_reg(ha, p_entry->arg1, delay,
9726e7b4292SVikas Chaudhary 					       p_poll->test_mask,
9736e7b4292SVikas Chaudhary 					       p_poll->test_value)) {
9746e7b4292SVikas Chaudhary 				qla4_83xx_rd_reg_indirect(ha, p_entry->arg1,
9756e7b4292SVikas Chaudhary 							  &value);
9766e7b4292SVikas Chaudhary 				qla4_83xx_rd_reg_indirect(ha, p_entry->arg2,
9776e7b4292SVikas Chaudhary 							  &value);
9786e7b4292SVikas Chaudhary 			}
9796e7b4292SVikas Chaudhary 		}
9806e7b4292SVikas Chaudhary 	}
9816e7b4292SVikas Chaudhary }
9826e7b4292SVikas Chaudhary 
qla4_83xx_poll_write_list(struct scsi_qla_host * ha,struct qla4_83xx_reset_entry_hdr * p_hdr)9836e7b4292SVikas Chaudhary static void qla4_83xx_poll_write_list(struct scsi_qla_host *ha,
9846e7b4292SVikas Chaudhary 				      struct qla4_83xx_reset_entry_hdr *p_hdr)
9856e7b4292SVikas Chaudhary {
9866e7b4292SVikas Chaudhary 	long delay;
9876e7b4292SVikas Chaudhary 	struct qla4_83xx_quad_entry *p_entry;
9886e7b4292SVikas Chaudhary 	struct qla4_83xx_poll *p_poll;
9896e7b4292SVikas Chaudhary 	uint32_t i;
9906e7b4292SVikas Chaudhary 
9916e7b4292SVikas Chaudhary 	p_poll = (struct qla4_83xx_poll *)
9926e7b4292SVikas Chaudhary 		 ((char *)p_hdr + sizeof(struct qla4_83xx_reset_entry_hdr));
9936e7b4292SVikas Chaudhary 	p_entry = (struct qla4_83xx_quad_entry *)
9946e7b4292SVikas Chaudhary 		  ((char *)p_poll + sizeof(struct qla4_83xx_poll));
9956e7b4292SVikas Chaudhary 	delay = (long)p_hdr->delay;
9966e7b4292SVikas Chaudhary 
9976e7b4292SVikas Chaudhary 	for (i = 0; i < p_hdr->count; i++, p_entry++) {
9986e7b4292SVikas Chaudhary 		qla4_83xx_wr_reg_indirect(ha, p_entry->dr_addr,
9996e7b4292SVikas Chaudhary 					  p_entry->dr_value);
10006e7b4292SVikas Chaudhary 		qla4_83xx_wr_reg_indirect(ha, p_entry->ar_addr,
10016e7b4292SVikas Chaudhary 					  p_entry->ar_value);
10026e7b4292SVikas Chaudhary 		if (delay) {
10036e7b4292SVikas Chaudhary 			if (qla4_83xx_poll_reg(ha, p_entry->ar_addr, delay,
10046e7b4292SVikas Chaudhary 					       p_poll->test_mask,
10056e7b4292SVikas Chaudhary 					       p_poll->test_value)) {
10066e7b4292SVikas Chaudhary 				DEBUG2(ql4_printk(KERN_INFO, ha,
10076e7b4292SVikas Chaudhary 						  "%s: Timeout Error: poll list, item_num %d, entry_num %d\n",
10086e7b4292SVikas Chaudhary 						  __func__, i,
10096e7b4292SVikas Chaudhary 						  ha->reset_tmplt.seq_index));
10106e7b4292SVikas Chaudhary 			}
10116e7b4292SVikas Chaudhary 		}
10126e7b4292SVikas Chaudhary 	}
10136e7b4292SVikas Chaudhary }
10146e7b4292SVikas Chaudhary 
qla4_83xx_read_modify_write(struct scsi_qla_host * ha,struct qla4_83xx_reset_entry_hdr * p_hdr)10156e7b4292SVikas Chaudhary static void qla4_83xx_read_modify_write(struct scsi_qla_host *ha,
10166e7b4292SVikas Chaudhary 					struct qla4_83xx_reset_entry_hdr *p_hdr)
10176e7b4292SVikas Chaudhary {
10186e7b4292SVikas Chaudhary 	struct qla4_83xx_entry *p_entry;
10196e7b4292SVikas Chaudhary 	struct qla4_83xx_rmw *p_rmw_hdr;
10206e7b4292SVikas Chaudhary 	uint32_t i;
10216e7b4292SVikas Chaudhary 
10226e7b4292SVikas Chaudhary 	p_rmw_hdr = (struct qla4_83xx_rmw *)
10236e7b4292SVikas Chaudhary 		    ((char *)p_hdr + sizeof(struct qla4_83xx_reset_entry_hdr));
10246e7b4292SVikas Chaudhary 	p_entry = (struct qla4_83xx_entry *)
10256e7b4292SVikas Chaudhary 		  ((char *)p_rmw_hdr + sizeof(struct qla4_83xx_rmw));
10266e7b4292SVikas Chaudhary 
10276e7b4292SVikas Chaudhary 	for (i = 0; i < p_hdr->count; i++, p_entry++) {
10286e7b4292SVikas Chaudhary 		qla4_83xx_rmw_crb_reg(ha, p_entry->arg1, p_entry->arg2,
10296e7b4292SVikas Chaudhary 				      p_rmw_hdr);
10306e7b4292SVikas Chaudhary 		if (p_hdr->delay)
10316e7b4292SVikas Chaudhary 			udelay((uint32_t)(p_hdr->delay));
10326e7b4292SVikas Chaudhary 	}
10336e7b4292SVikas Chaudhary }
10346e7b4292SVikas Chaudhary 
qla4_83xx_pause(struct scsi_qla_host * ha,struct qla4_83xx_reset_entry_hdr * p_hdr)10356e7b4292SVikas Chaudhary static void qla4_83xx_pause(struct scsi_qla_host *ha,
10366e7b4292SVikas Chaudhary 			    struct qla4_83xx_reset_entry_hdr *p_hdr)
10376e7b4292SVikas Chaudhary {
10386e7b4292SVikas Chaudhary 	if (p_hdr->delay)
10396e7b4292SVikas Chaudhary 		mdelay((uint32_t)((long)p_hdr->delay));
10406e7b4292SVikas Chaudhary }
10416e7b4292SVikas Chaudhary 
qla4_83xx_poll_read_list(struct scsi_qla_host * ha,struct qla4_83xx_reset_entry_hdr * p_hdr)10426e7b4292SVikas Chaudhary static void qla4_83xx_poll_read_list(struct scsi_qla_host *ha,
10436e7b4292SVikas Chaudhary 				     struct qla4_83xx_reset_entry_hdr *p_hdr)
10446e7b4292SVikas Chaudhary {
10456e7b4292SVikas Chaudhary 	long delay;
10466e7b4292SVikas Chaudhary 	int index;
10476e7b4292SVikas Chaudhary 	struct qla4_83xx_quad_entry *p_entry;
10486e7b4292SVikas Chaudhary 	struct qla4_83xx_poll *p_poll;
10496e7b4292SVikas Chaudhary 	uint32_t i;
10506e7b4292SVikas Chaudhary 	uint32_t value;
10516e7b4292SVikas Chaudhary 
10526e7b4292SVikas Chaudhary 	p_poll = (struct qla4_83xx_poll *)
10536e7b4292SVikas Chaudhary 		 ((char *)p_hdr + sizeof(struct qla4_83xx_reset_entry_hdr));
10546e7b4292SVikas Chaudhary 	p_entry = (struct qla4_83xx_quad_entry *)
10556e7b4292SVikas Chaudhary 		  ((char *)p_poll + sizeof(struct qla4_83xx_poll));
10566e7b4292SVikas Chaudhary 	delay = (long)p_hdr->delay;
10576e7b4292SVikas Chaudhary 
10586e7b4292SVikas Chaudhary 	for (i = 0; i < p_hdr->count; i++, p_entry++) {
10596e7b4292SVikas Chaudhary 		qla4_83xx_wr_reg_indirect(ha, p_entry->ar_addr,
10606e7b4292SVikas Chaudhary 					  p_entry->ar_value);
10616e7b4292SVikas Chaudhary 		if (delay) {
10626e7b4292SVikas Chaudhary 			if (qla4_83xx_poll_reg(ha, p_entry->ar_addr, delay,
10636e7b4292SVikas Chaudhary 					       p_poll->test_mask,
10646e7b4292SVikas Chaudhary 					       p_poll->test_value)) {
10656e7b4292SVikas Chaudhary 				DEBUG2(ql4_printk(KERN_INFO, ha,
10666e7b4292SVikas Chaudhary 						  "%s: Timeout Error: poll list, Item_num %d, entry_num %d\n",
10676e7b4292SVikas Chaudhary 						  __func__, i,
10686e7b4292SVikas Chaudhary 						  ha->reset_tmplt.seq_index));
10696e7b4292SVikas Chaudhary 			} else {
10706e7b4292SVikas Chaudhary 				index = ha->reset_tmplt.array_index;
10716e7b4292SVikas Chaudhary 				qla4_83xx_rd_reg_indirect(ha, p_entry->dr_addr,
10726e7b4292SVikas Chaudhary 							  &value);
10736e7b4292SVikas Chaudhary 				ha->reset_tmplt.array[index++] = value;
10746e7b4292SVikas Chaudhary 
10756e7b4292SVikas Chaudhary 				if (index == QLA83XX_MAX_RESET_SEQ_ENTRIES)
10766e7b4292SVikas Chaudhary 					ha->reset_tmplt.array_index = 1;
10776e7b4292SVikas Chaudhary 			}
10786e7b4292SVikas Chaudhary 		}
10796e7b4292SVikas Chaudhary 	}
10806e7b4292SVikas Chaudhary }
10816e7b4292SVikas Chaudhary 
qla4_83xx_seq_end(struct scsi_qla_host * ha,struct qla4_83xx_reset_entry_hdr * p_hdr)10826e7b4292SVikas Chaudhary static void qla4_83xx_seq_end(struct scsi_qla_host *ha,
10836e7b4292SVikas Chaudhary 			      struct qla4_83xx_reset_entry_hdr *p_hdr)
10846e7b4292SVikas Chaudhary {
10856e7b4292SVikas Chaudhary 	ha->reset_tmplt.seq_end = 1;
10866e7b4292SVikas Chaudhary }
10876e7b4292SVikas Chaudhary 
qla4_83xx_template_end(struct scsi_qla_host * ha,struct qla4_83xx_reset_entry_hdr * p_hdr)10886e7b4292SVikas Chaudhary static void qla4_83xx_template_end(struct scsi_qla_host *ha,
10896e7b4292SVikas Chaudhary 				   struct qla4_83xx_reset_entry_hdr *p_hdr)
10906e7b4292SVikas Chaudhary {
10916e7b4292SVikas Chaudhary 	ha->reset_tmplt.template_end = 1;
10926e7b4292SVikas Chaudhary 
10936e7b4292SVikas Chaudhary 	if (ha->reset_tmplt.seq_error == 0) {
10946e7b4292SVikas Chaudhary 		DEBUG2(ql4_printk(KERN_INFO, ha,
10956e7b4292SVikas Chaudhary 				  "%s: Reset sequence completed SUCCESSFULLY.\n",
10966e7b4292SVikas Chaudhary 				  __func__));
10976e7b4292SVikas Chaudhary 	} else {
10986e7b4292SVikas Chaudhary 		ql4_printk(KERN_ERR, ha, "%s: Reset sequence completed with some timeout errors.\n",
10996e7b4292SVikas Chaudhary 			   __func__);
11006e7b4292SVikas Chaudhary 	}
11016e7b4292SVikas Chaudhary }
11026e7b4292SVikas Chaudhary 
11036e7b4292SVikas Chaudhary /**
11046e7b4292SVikas Chaudhary  * qla4_83xx_process_reset_template - Process reset template.
11056e7b4292SVikas Chaudhary  *
11066e7b4292SVikas Chaudhary  * Process all entries in reset template till entry with SEQ_END opcode,
11076e7b4292SVikas Chaudhary  * which indicates end of the reset template processing. Each entry has a
11086e7b4292SVikas Chaudhary  * Reset Entry header, entry opcode/command, with size of the entry, number
11096e7b4292SVikas Chaudhary  * of entries in sub-sequence and delay in microsecs or timeout in millisecs.
11106e7b4292SVikas Chaudhary  *
11116e7b4292SVikas Chaudhary  * @ha : Pointer to adapter structure
11126e7b4292SVikas Chaudhary  * @p_buff : Common reset entry header.
11136e7b4292SVikas Chaudhary  **/
qla4_83xx_process_reset_template(struct scsi_qla_host * ha,char * p_buff)11146e7b4292SVikas Chaudhary static void qla4_83xx_process_reset_template(struct scsi_qla_host *ha,
11156e7b4292SVikas Chaudhary 					     char *p_buff)
11166e7b4292SVikas Chaudhary {
11176e7b4292SVikas Chaudhary 	int index, entries;
11186e7b4292SVikas Chaudhary 	struct qla4_83xx_reset_entry_hdr *p_hdr;
11196e7b4292SVikas Chaudhary 	char *p_entry = p_buff;
11206e7b4292SVikas Chaudhary 
11216e7b4292SVikas Chaudhary 	ha->reset_tmplt.seq_end = 0;
11226e7b4292SVikas Chaudhary 	ha->reset_tmplt.template_end = 0;
11236e7b4292SVikas Chaudhary 	entries = ha->reset_tmplt.hdr->entries;
11246e7b4292SVikas Chaudhary 	index = ha->reset_tmplt.seq_index;
11256e7b4292SVikas Chaudhary 
11266e7b4292SVikas Chaudhary 	for (; (!ha->reset_tmplt.seq_end) && (index  < entries); index++) {
11276e7b4292SVikas Chaudhary 
11286e7b4292SVikas Chaudhary 		p_hdr = (struct qla4_83xx_reset_entry_hdr *)p_entry;
11296e7b4292SVikas Chaudhary 		switch (p_hdr->cmd) {
11306e7b4292SVikas Chaudhary 		case OPCODE_NOP:
11316e7b4292SVikas Chaudhary 			break;
11326e7b4292SVikas Chaudhary 		case OPCODE_WRITE_LIST:
11336e7b4292SVikas Chaudhary 			qla4_83xx_write_list(ha, p_hdr);
11346e7b4292SVikas Chaudhary 			break;
11356e7b4292SVikas Chaudhary 		case OPCODE_READ_WRITE_LIST:
11366e7b4292SVikas Chaudhary 			qla4_83xx_read_write_list(ha, p_hdr);
11376e7b4292SVikas Chaudhary 			break;
11386e7b4292SVikas Chaudhary 		case OPCODE_POLL_LIST:
11396e7b4292SVikas Chaudhary 			qla4_83xx_poll_list(ha, p_hdr);
11406e7b4292SVikas Chaudhary 			break;
11416e7b4292SVikas Chaudhary 		case OPCODE_POLL_WRITE_LIST:
11426e7b4292SVikas Chaudhary 			qla4_83xx_poll_write_list(ha, p_hdr);
11436e7b4292SVikas Chaudhary 			break;
11446e7b4292SVikas Chaudhary 		case OPCODE_READ_MODIFY_WRITE:
11456e7b4292SVikas Chaudhary 			qla4_83xx_read_modify_write(ha, p_hdr);
11466e7b4292SVikas Chaudhary 			break;
11476e7b4292SVikas Chaudhary 		case OPCODE_SEQ_PAUSE:
11486e7b4292SVikas Chaudhary 			qla4_83xx_pause(ha, p_hdr);
11496e7b4292SVikas Chaudhary 			break;
11506e7b4292SVikas Chaudhary 		case OPCODE_SEQ_END:
11516e7b4292SVikas Chaudhary 			qla4_83xx_seq_end(ha, p_hdr);
11526e7b4292SVikas Chaudhary 			break;
11536e7b4292SVikas Chaudhary 		case OPCODE_TMPL_END:
11546e7b4292SVikas Chaudhary 			qla4_83xx_template_end(ha, p_hdr);
11556e7b4292SVikas Chaudhary 			break;
11566e7b4292SVikas Chaudhary 		case OPCODE_POLL_READ_LIST:
11576e7b4292SVikas Chaudhary 			qla4_83xx_poll_read_list(ha, p_hdr);
11586e7b4292SVikas Chaudhary 			break;
11596e7b4292SVikas Chaudhary 		default:
11606e7b4292SVikas Chaudhary 			ql4_printk(KERN_ERR, ha, "%s: Unknown command ==> 0x%04x on entry = %d\n",
11616e7b4292SVikas Chaudhary 				   __func__, p_hdr->cmd, index);
11626e7b4292SVikas Chaudhary 			break;
11636e7b4292SVikas Chaudhary 		}
11646e7b4292SVikas Chaudhary 
11656e7b4292SVikas Chaudhary 		/* Set pointer to next entry in the sequence. */
11666e7b4292SVikas Chaudhary 		p_entry += p_hdr->size;
11676e7b4292SVikas Chaudhary 	}
11686e7b4292SVikas Chaudhary 
11696e7b4292SVikas Chaudhary 	ha->reset_tmplt.seq_index = index;
11706e7b4292SVikas Chaudhary }
11716e7b4292SVikas Chaudhary 
qla4_83xx_process_stop_seq(struct scsi_qla_host * ha)11726e7b4292SVikas Chaudhary static void qla4_83xx_process_stop_seq(struct scsi_qla_host *ha)
11736e7b4292SVikas Chaudhary {
11746e7b4292SVikas Chaudhary 	ha->reset_tmplt.seq_index = 0;
11756e7b4292SVikas Chaudhary 	qla4_83xx_process_reset_template(ha, ha->reset_tmplt.stop_offset);
11766e7b4292SVikas Chaudhary 
11776e7b4292SVikas Chaudhary 	if (ha->reset_tmplt.seq_end != 1)
11786e7b4292SVikas Chaudhary 		ql4_printk(KERN_ERR, ha, "%s: Abrupt STOP Sub-Sequence end.\n",
11796e7b4292SVikas Chaudhary 			   __func__);
11806e7b4292SVikas Chaudhary }
11816e7b4292SVikas Chaudhary 
qla4_83xx_process_start_seq(struct scsi_qla_host * ha)11826e7b4292SVikas Chaudhary static void qla4_83xx_process_start_seq(struct scsi_qla_host *ha)
11836e7b4292SVikas Chaudhary {
11846e7b4292SVikas Chaudhary 	qla4_83xx_process_reset_template(ha, ha->reset_tmplt.start_offset);
11856e7b4292SVikas Chaudhary 
11866e7b4292SVikas Chaudhary 	if (ha->reset_tmplt.template_end != 1)
11876e7b4292SVikas Chaudhary 		ql4_printk(KERN_ERR, ha, "%s: Abrupt START Sub-Sequence end.\n",
11886e7b4292SVikas Chaudhary 			   __func__);
11896e7b4292SVikas Chaudhary }
11906e7b4292SVikas Chaudhary 
qla4_83xx_process_init_seq(struct scsi_qla_host * ha)11916e7b4292SVikas Chaudhary static void qla4_83xx_process_init_seq(struct scsi_qla_host *ha)
11926e7b4292SVikas Chaudhary {
11936e7b4292SVikas Chaudhary 	qla4_83xx_process_reset_template(ha, ha->reset_tmplt.init_offset);
11946e7b4292SVikas Chaudhary 
11956e7b4292SVikas Chaudhary 	if (ha->reset_tmplt.seq_end != 1)
11966e7b4292SVikas Chaudhary 		ql4_printk(KERN_ERR, ha, "%s: Abrupt INIT Sub-Sequence end.\n",
11976e7b4292SVikas Chaudhary 			   __func__);
11986e7b4292SVikas Chaudhary }
11996e7b4292SVikas Chaudhary 
qla4_83xx_restart(struct scsi_qla_host * ha)12006e7b4292SVikas Chaudhary static int qla4_83xx_restart(struct scsi_qla_host *ha)
12016e7b4292SVikas Chaudhary {
12026e7b4292SVikas Chaudhary 	int ret_val = QLA_SUCCESS;
120380645dc0SVikas Chaudhary 	uint32_t idc_ctrl;
12046e7b4292SVikas Chaudhary 
12056e7b4292SVikas Chaudhary 	qla4_83xx_process_stop_seq(ha);
12066e7b4292SVikas Chaudhary 
120780645dc0SVikas Chaudhary 	/*
120880645dc0SVikas Chaudhary 	 * Collect minidump.
120980645dc0SVikas Chaudhary 	 * If IDC_CTRL BIT1 is set, clear it on going to INIT state and
121080645dc0SVikas Chaudhary 	 * don't collect minidump
121180645dc0SVikas Chaudhary 	 */
121280645dc0SVikas Chaudhary 	idc_ctrl = qla4_83xx_rd_reg(ha, QLA83XX_IDC_DRV_CTRL);
121380645dc0SVikas Chaudhary 	if (idc_ctrl & GRACEFUL_RESET_BIT1) {
121480645dc0SVikas Chaudhary 		qla4_83xx_wr_reg(ha, QLA83XX_IDC_DRV_CTRL,
121580645dc0SVikas Chaudhary 				 (idc_ctrl & ~GRACEFUL_RESET_BIT1));
121680645dc0SVikas Chaudhary 		ql4_printk(KERN_INFO, ha, "%s: Graceful RESET: Not collecting minidump\n",
121780645dc0SVikas Chaudhary 			   __func__);
121880645dc0SVikas Chaudhary 	} else {
12196e7b4292SVikas Chaudhary 		qla4_8xxx_get_minidump(ha);
122080645dc0SVikas Chaudhary 	}
12216e7b4292SVikas Chaudhary 
12226e7b4292SVikas Chaudhary 	qla4_83xx_process_init_seq(ha);
12236e7b4292SVikas Chaudhary 
12246e7b4292SVikas Chaudhary 	if (qla4_83xx_copy_bootloader(ha)) {
12256e7b4292SVikas Chaudhary 		ql4_printk(KERN_ERR, ha, "%s: Copy bootloader, firmware restart failed!\n",
12266e7b4292SVikas Chaudhary 			   __func__);
12276e7b4292SVikas Chaudhary 		ret_val = QLA_ERROR;
12286e7b4292SVikas Chaudhary 		goto exit_restart;
12296e7b4292SVikas Chaudhary 	}
12306e7b4292SVikas Chaudhary 
12316e7b4292SVikas Chaudhary 	qla4_83xx_wr_reg(ha, QLA83XX_FW_IMAGE_VALID, QLA83XX_BOOT_FROM_FLASH);
12326e7b4292SVikas Chaudhary 	qla4_83xx_process_start_seq(ha);
12336e7b4292SVikas Chaudhary 
12346e7b4292SVikas Chaudhary exit_restart:
12356e7b4292SVikas Chaudhary 	return ret_val;
12366e7b4292SVikas Chaudhary }
12376e7b4292SVikas Chaudhary 
qla4_83xx_start_firmware(struct scsi_qla_host * ha)12386e7b4292SVikas Chaudhary int qla4_83xx_start_firmware(struct scsi_qla_host *ha)
12396e7b4292SVikas Chaudhary {
12406e7b4292SVikas Chaudhary 	int ret_val = QLA_SUCCESS;
12416e7b4292SVikas Chaudhary 
12426e7b4292SVikas Chaudhary 	ret_val = qla4_83xx_restart(ha);
12436e7b4292SVikas Chaudhary 	if (ret_val == QLA_ERROR) {
12446e7b4292SVikas Chaudhary 		ql4_printk(KERN_ERR, ha, "%s: Restart error\n", __func__);
12456e7b4292SVikas Chaudhary 		goto exit_start_fw;
12466e7b4292SVikas Chaudhary 	} else {
12476e7b4292SVikas Chaudhary 		DEBUG2(ql4_printk(KERN_INFO, ha, "%s: Restart done\n",
12486e7b4292SVikas Chaudhary 				  __func__));
12496e7b4292SVikas Chaudhary 	}
12506e7b4292SVikas Chaudhary 
12516e7b4292SVikas Chaudhary 	ret_val = qla4_83xx_check_cmd_peg_status(ha);
12526e7b4292SVikas Chaudhary 	if (ret_val == QLA_ERROR)
12536e7b4292SVikas Chaudhary 		ql4_printk(KERN_ERR, ha, "%s: Peg not initialized\n",
12546e7b4292SVikas Chaudhary 			   __func__);
12556e7b4292SVikas Chaudhary 
12566e7b4292SVikas Chaudhary exit_start_fw:
12576e7b4292SVikas Chaudhary 	return ret_val;
12586e7b4292SVikas Chaudhary }
12596e7b4292SVikas Chaudhary 
12606e7b4292SVikas Chaudhary /*----------------------Interrupt Related functions ---------------------*/
12616e7b4292SVikas Chaudhary 
qla4_83xx_disable_iocb_intrs(struct scsi_qla_host * ha)12625c19b92aSVikas Chaudhary static void qla4_83xx_disable_iocb_intrs(struct scsi_qla_host *ha)
12635c19b92aSVikas Chaudhary {
12645c19b92aSVikas Chaudhary 	if (test_and_clear_bit(AF_83XX_IOCB_INTR_ON, &ha->flags))
12655c19b92aSVikas Chaudhary 		qla4_8xxx_intr_disable(ha);
12665c19b92aSVikas Chaudhary }
12675c19b92aSVikas Chaudhary 
qla4_83xx_disable_mbox_intrs(struct scsi_qla_host * ha)12685c19b92aSVikas Chaudhary static void qla4_83xx_disable_mbox_intrs(struct scsi_qla_host *ha)
12696e7b4292SVikas Chaudhary {
12706e7b4292SVikas Chaudhary 	uint32_t mb_int, ret;
12716e7b4292SVikas Chaudhary 
12725c19b92aSVikas Chaudhary 	if (test_and_clear_bit(AF_83XX_MBOX_INTR_ON, &ha->flags)) {
12736e7b4292SVikas Chaudhary 		ret = readl(&ha->qla4_83xx_reg->mbox_int);
12746e7b4292SVikas Chaudhary 		mb_int = ret & ~INT_ENABLE_FW_MB;
12756e7b4292SVikas Chaudhary 		writel(mb_int, &ha->qla4_83xx_reg->mbox_int);
12766e7b4292SVikas Chaudhary 		writel(1, &ha->qla4_83xx_reg->leg_int_mask);
12776e7b4292SVikas Chaudhary 	}
12785c19b92aSVikas Chaudhary }
12796e7b4292SVikas Chaudhary 
qla4_83xx_disable_intrs(struct scsi_qla_host * ha)12805c19b92aSVikas Chaudhary void qla4_83xx_disable_intrs(struct scsi_qla_host *ha)
12815c19b92aSVikas Chaudhary {
12825c19b92aSVikas Chaudhary 	qla4_83xx_disable_mbox_intrs(ha);
12835c19b92aSVikas Chaudhary 	qla4_83xx_disable_iocb_intrs(ha);
12845c19b92aSVikas Chaudhary }
12855c19b92aSVikas Chaudhary 
qla4_83xx_enable_iocb_intrs(struct scsi_qla_host * ha)12865c19b92aSVikas Chaudhary static void qla4_83xx_enable_iocb_intrs(struct scsi_qla_host *ha)
12875c19b92aSVikas Chaudhary {
12885c19b92aSVikas Chaudhary 	if (!test_bit(AF_83XX_IOCB_INTR_ON, &ha->flags)) {
12895c19b92aSVikas Chaudhary 		qla4_8xxx_intr_enable(ha);
12905c19b92aSVikas Chaudhary 		set_bit(AF_83XX_IOCB_INTR_ON, &ha->flags);
12915c19b92aSVikas Chaudhary 	}
12925c19b92aSVikas Chaudhary }
12935c19b92aSVikas Chaudhary 
qla4_83xx_enable_mbox_intrs(struct scsi_qla_host * ha)12945c19b92aSVikas Chaudhary void qla4_83xx_enable_mbox_intrs(struct scsi_qla_host *ha)
12956e7b4292SVikas Chaudhary {
12966e7b4292SVikas Chaudhary 	uint32_t mb_int;
12976e7b4292SVikas Chaudhary 
12985c19b92aSVikas Chaudhary 	if (!test_bit(AF_83XX_MBOX_INTR_ON, &ha->flags)) {
12996e7b4292SVikas Chaudhary 		mb_int = INT_ENABLE_FW_MB;
13006e7b4292SVikas Chaudhary 		writel(mb_int, &ha->qla4_83xx_reg->mbox_int);
13016e7b4292SVikas Chaudhary 		writel(0, &ha->qla4_83xx_reg->leg_int_mask);
13025c19b92aSVikas Chaudhary 		set_bit(AF_83XX_MBOX_INTR_ON, &ha->flags);
13036e7b4292SVikas Chaudhary 	}
13045c19b92aSVikas Chaudhary }
13055c19b92aSVikas Chaudhary 
13065c19b92aSVikas Chaudhary 
qla4_83xx_enable_intrs(struct scsi_qla_host * ha)13075c19b92aSVikas Chaudhary void qla4_83xx_enable_intrs(struct scsi_qla_host *ha)
13085c19b92aSVikas Chaudhary {
13095c19b92aSVikas Chaudhary 	qla4_83xx_enable_mbox_intrs(ha);
13105c19b92aSVikas Chaudhary 	qla4_83xx_enable_iocb_intrs(ha);
13115c19b92aSVikas Chaudhary }
13125c19b92aSVikas Chaudhary 
13136e7b4292SVikas Chaudhary 
qla4_83xx_queue_mbox_cmd(struct scsi_qla_host * ha,uint32_t * mbx_cmd,int incount)13146e7b4292SVikas Chaudhary void qla4_83xx_queue_mbox_cmd(struct scsi_qla_host *ha, uint32_t *mbx_cmd,
13156e7b4292SVikas Chaudhary 			      int incount)
13166e7b4292SVikas Chaudhary {
13176e7b4292SVikas Chaudhary 	int i;
13186e7b4292SVikas Chaudhary 
13196e7b4292SVikas Chaudhary 	/* Load all mailbox registers, except mailbox 0. */
13206e7b4292SVikas Chaudhary 	for (i = 1; i < incount; i++)
13216e7b4292SVikas Chaudhary 		writel(mbx_cmd[i], &ha->qla4_83xx_reg->mailbox_in[i]);
13226e7b4292SVikas Chaudhary 
13236e7b4292SVikas Chaudhary 	writel(mbx_cmd[0], &ha->qla4_83xx_reg->mailbox_in[0]);
13246e7b4292SVikas Chaudhary 
13256e7b4292SVikas Chaudhary 	/* Set Host Interrupt register to 1, to tell the firmware that
13266e7b4292SVikas Chaudhary 	 * a mailbox command is pending. Firmware after reading the
13276e7b4292SVikas Chaudhary 	 * mailbox command, clears the host interrupt register */
13286e7b4292SVikas Chaudhary 	writel(HINT_MBX_INT_PENDING, &ha->qla4_83xx_reg->host_intr);
13296e7b4292SVikas Chaudhary }
13306e7b4292SVikas Chaudhary 
qla4_83xx_process_mbox_intr(struct scsi_qla_host * ha,int outcount)13316e7b4292SVikas Chaudhary void qla4_83xx_process_mbox_intr(struct scsi_qla_host *ha, int outcount)
13326e7b4292SVikas Chaudhary {
13336e7b4292SVikas Chaudhary 	int intr_status;
13346e7b4292SVikas Chaudhary 
13356e7b4292SVikas Chaudhary 	intr_status = readl(&ha->qla4_83xx_reg->risc_intr);
13366e7b4292SVikas Chaudhary 	if (intr_status) {
13376e7b4292SVikas Chaudhary 		ha->mbox_status_count = outcount;
13386e7b4292SVikas Chaudhary 		ha->isp_ops->interrupt_service_routine(ha, intr_status);
13396e7b4292SVikas Chaudhary 	}
13406e7b4292SVikas Chaudhary }
13416e7b4292SVikas Chaudhary 
13426e7b4292SVikas Chaudhary /**
13436e7b4292SVikas Chaudhary  * qla4_83xx_isp_reset - Resets ISP and aborts all outstanding commands.
13446e7b4292SVikas Chaudhary  * @ha: pointer to host adapter structure.
13456e7b4292SVikas Chaudhary  **/
qla4_83xx_isp_reset(struct scsi_qla_host * ha)13466e7b4292SVikas Chaudhary int qla4_83xx_isp_reset(struct scsi_qla_host *ha)
13476e7b4292SVikas Chaudhary {
13486e7b4292SVikas Chaudhary 	int rval;
13496e7b4292SVikas Chaudhary 	uint32_t dev_state;
13506e7b4292SVikas Chaudhary 
13516e7b4292SVikas Chaudhary 	ha->isp_ops->idc_lock(ha);
13526e7b4292SVikas Chaudhary 	dev_state = qla4_8xxx_rd_direct(ha, QLA8XXX_CRB_DEV_STATE);
13536e7b4292SVikas Chaudhary 
13546e7b4292SVikas Chaudhary 	if (ql4xdontresethba)
13556e7b4292SVikas Chaudhary 		qla4_83xx_set_idc_dontreset(ha);
13566e7b4292SVikas Chaudhary 
13576e7b4292SVikas Chaudhary 	if (dev_state == QLA8XXX_DEV_READY) {
13586e7b4292SVikas Chaudhary 		/* If IDC_CTRL DONTRESETHBA_BIT0 is set dont do reset
13596e7b4292SVikas Chaudhary 		 * recovery */
13606e7b4292SVikas Chaudhary 		if (qla4_83xx_idc_dontreset(ha) == DONTRESET_BIT0) {
13616e7b4292SVikas Chaudhary 			ql4_printk(KERN_ERR, ha, "%s: Reset recovery disabled\n",
13626e7b4292SVikas Chaudhary 				   __func__);
13636e7b4292SVikas Chaudhary 			rval = QLA_ERROR;
13646e7b4292SVikas Chaudhary 			goto exit_isp_reset;
13656e7b4292SVikas Chaudhary 		}
13666e7b4292SVikas Chaudhary 
13676e7b4292SVikas Chaudhary 		DEBUG2(ql4_printk(KERN_INFO, ha, "%s: HW State: NEED RESET\n",
13686e7b4292SVikas Chaudhary 				  __func__));
13696e7b4292SVikas Chaudhary 		qla4_8xxx_wr_direct(ha, QLA8XXX_CRB_DEV_STATE,
13706e7b4292SVikas Chaudhary 				    QLA8XXX_DEV_NEED_RESET);
13716e7b4292SVikas Chaudhary 
13726e7b4292SVikas Chaudhary 	} else {
13736e7b4292SVikas Chaudhary 		/* If device_state is NEED_RESET, go ahead with
13746e7b4292SVikas Chaudhary 		 * Reset,irrespective of ql4xdontresethba. This is to allow a
13756e7b4292SVikas Chaudhary 		 * non-reset-owner to force a reset. Non-reset-owner sets
13766e7b4292SVikas Chaudhary 		 * the IDC_CTRL BIT0 to prevent Reset-owner from doing a Reset
13776e7b4292SVikas Chaudhary 		 * and then forces a Reset by setting device_state to
13786e7b4292SVikas Chaudhary 		 * NEED_RESET. */
13796e7b4292SVikas Chaudhary 		DEBUG2(ql4_printk(KERN_INFO, ha,
13806e7b4292SVikas Chaudhary 				  "%s: HW state already set to NEED_RESET\n",
13816e7b4292SVikas Chaudhary 				  __func__));
13826e7b4292SVikas Chaudhary 	}
13836e7b4292SVikas Chaudhary 
1384b37ca418SVikas Chaudhary 	/* For ISP8324 and ISP8042, Reset owner is NIC, iSCSI or FCOE based on
1385b37ca418SVikas Chaudhary 	 * priority and which drivers are present. Unlike ISP8022, the function
1386b37ca418SVikas Chaudhary 	 * setting NEED_RESET, may not be the Reset owner. */
13876e7b4292SVikas Chaudhary 	if (qla4_83xx_can_perform_reset(ha))
13886e7b4292SVikas Chaudhary 		set_bit(AF_8XXX_RST_OWNER, &ha->flags);
13896e7b4292SVikas Chaudhary 
13906e7b4292SVikas Chaudhary 	ha->isp_ops->idc_unlock(ha);
13916e7b4292SVikas Chaudhary 	rval = qla4_8xxx_device_state_handler(ha);
13926e7b4292SVikas Chaudhary 
13936e7b4292SVikas Chaudhary 	ha->isp_ops->idc_lock(ha);
13946e7b4292SVikas Chaudhary 	qla4_8xxx_clear_rst_ready(ha);
13956e7b4292SVikas Chaudhary exit_isp_reset:
13966e7b4292SVikas Chaudhary 	ha->isp_ops->idc_unlock(ha);
13976e7b4292SVikas Chaudhary 
13986e7b4292SVikas Chaudhary 	if (rval == QLA_SUCCESS)
13996e7b4292SVikas Chaudhary 		clear_bit(AF_FW_RECOVERY, &ha->flags);
14006e7b4292SVikas Chaudhary 
14016e7b4292SVikas Chaudhary 	return rval;
14026e7b4292SVikas Chaudhary }
1403546fef27STej Parkash 
qla4_83xx_dump_pause_control_regs(struct scsi_qla_host * ha)1404546fef27STej Parkash static void qla4_83xx_dump_pause_control_regs(struct scsi_qla_host *ha)
1405546fef27STej Parkash {
1406546fef27STej Parkash 	u32 val = 0, val1 = 0;
14076e3f4f68SLee Jones 	int i;
1408546fef27STej Parkash 
14096e3f4f68SLee Jones 	qla4_83xx_rd_reg_indirect(ha, QLA83XX_SRE_SHIM_CONTROL, &val);
1410546fef27STej Parkash 	DEBUG2(ql4_printk(KERN_INFO, ha, "SRE-Shim Ctrl:0x%x\n", val));
1411546fef27STej Parkash 
1412546fef27STej Parkash 	/* Port 0 Rx Buffer Pause Threshold Registers. */
1413546fef27STej Parkash 	DEBUG2(ql4_printk(KERN_INFO, ha,
1414546fef27STej Parkash 		"Port 0 Rx Buffer Pause Threshold Registers[TC7..TC0]:"));
1415546fef27STej Parkash 	for (i = 0; i < 8; i++) {
14166e3f4f68SLee Jones 		qla4_83xx_rd_reg_indirect(ha,
1417546fef27STej Parkash 				QLA83XX_PORT0_RXB_PAUSE_THRS + (i * 0x4), &val);
1418546fef27STej Parkash 		DEBUG2(pr_info("0x%x ", val));
1419546fef27STej Parkash 	}
1420546fef27STej Parkash 
1421546fef27STej Parkash 	DEBUG2(pr_info("\n"));
1422546fef27STej Parkash 
1423546fef27STej Parkash 	/* Port 1 Rx Buffer Pause Threshold Registers. */
1424546fef27STej Parkash 	DEBUG2(ql4_printk(KERN_INFO, ha,
1425546fef27STej Parkash 		"Port 1 Rx Buffer Pause Threshold Registers[TC7..TC0]:"));
1426546fef27STej Parkash 	for (i = 0; i < 8; i++) {
14276e3f4f68SLee Jones 		qla4_83xx_rd_reg_indirect(ha,
1428546fef27STej Parkash 				QLA83XX_PORT1_RXB_PAUSE_THRS + (i * 0x4), &val);
1429546fef27STej Parkash 		DEBUG2(pr_info("0x%x  ", val));
1430546fef27STej Parkash 	}
1431546fef27STej Parkash 
1432546fef27STej Parkash 	DEBUG2(pr_info("\n"));
1433546fef27STej Parkash 
1434546fef27STej Parkash 	/* Port 0 RxB Traffic Class Max Cell Registers. */
1435546fef27STej Parkash 	DEBUG2(ql4_printk(KERN_INFO, ha,
1436546fef27STej Parkash 		"Port 0 RxB Traffic Class Max Cell Registers[3..0]:"));
1437546fef27STej Parkash 	for (i = 0; i < 4; i++) {
14386e3f4f68SLee Jones 		qla4_83xx_rd_reg_indirect(ha,
1439546fef27STej Parkash 			       QLA83XX_PORT0_RXB_TC_MAX_CELL + (i * 0x4), &val);
1440546fef27STej Parkash 		DEBUG2(pr_info("0x%x  ", val));
1441546fef27STej Parkash 	}
1442546fef27STej Parkash 
1443546fef27STej Parkash 	DEBUG2(pr_info("\n"));
1444546fef27STej Parkash 
1445546fef27STej Parkash 	/* Port 1 RxB Traffic Class Max Cell Registers. */
1446546fef27STej Parkash 	DEBUG2(ql4_printk(KERN_INFO, ha,
1447546fef27STej Parkash 		"Port 1 RxB Traffic Class Max Cell Registers[3..0]:"));
1448546fef27STej Parkash 	for (i = 0; i < 4; i++) {
14496e3f4f68SLee Jones 		qla4_83xx_rd_reg_indirect(ha,
1450546fef27STej Parkash 			       QLA83XX_PORT1_RXB_TC_MAX_CELL + (i * 0x4), &val);
1451546fef27STej Parkash 		DEBUG2(pr_info("0x%x  ", val));
1452546fef27STej Parkash 	}
1453546fef27STej Parkash 
1454546fef27STej Parkash 	DEBUG2(pr_info("\n"));
1455546fef27STej Parkash 
1456546fef27STej Parkash 	/* Port 0 RxB Rx Traffic Class Stats. */
1457546fef27STej Parkash 	DEBUG2(ql4_printk(KERN_INFO, ha,
1458546fef27STej Parkash 			  "Port 0 RxB Rx Traffic Class Stats [TC7..TC0]"));
1459546fef27STej Parkash 	for (i = 7; i >= 0; i--) {
14606e3f4f68SLee Jones 		qla4_83xx_rd_reg_indirect(ha, QLA83XX_PORT0_RXB_TC_STATS, &val);
1461546fef27STej Parkash 		val &= ~(0x7 << 29);    /* Reset bits 29 to 31 */
1462546fef27STej Parkash 		qla4_83xx_wr_reg_indirect(ha, QLA83XX_PORT0_RXB_TC_STATS,
1463546fef27STej Parkash 					  (val | (i << 29)));
14646e3f4f68SLee Jones 		qla4_83xx_rd_reg_indirect(ha, QLA83XX_PORT0_RXB_TC_STATS, &val);
1465546fef27STej Parkash 		DEBUG2(pr_info("0x%x  ", val));
1466546fef27STej Parkash 	}
1467546fef27STej Parkash 
1468546fef27STej Parkash 	DEBUG2(pr_info("\n"));
1469546fef27STej Parkash 
1470546fef27STej Parkash 	/* Port 1 RxB Rx Traffic Class Stats. */
1471546fef27STej Parkash 	DEBUG2(ql4_printk(KERN_INFO, ha,
1472546fef27STej Parkash 			  "Port 1 RxB Rx Traffic Class Stats [TC7..TC0]"));
1473546fef27STej Parkash 	for (i = 7; i >= 0; i--) {
14746e3f4f68SLee Jones 		qla4_83xx_rd_reg_indirect(ha, QLA83XX_PORT1_RXB_TC_STATS, &val);
1475546fef27STej Parkash 		val &= ~(0x7 << 29);    /* Reset bits 29 to 31 */
1476546fef27STej Parkash 		qla4_83xx_wr_reg_indirect(ha, QLA83XX_PORT1_RXB_TC_STATS,
1477546fef27STej Parkash 					  (val | (i << 29)));
14786e3f4f68SLee Jones 		qla4_83xx_rd_reg_indirect(ha, QLA83XX_PORT1_RXB_TC_STATS, &val);
1479546fef27STej Parkash 		DEBUG2(pr_info("0x%x  ", val));
1480546fef27STej Parkash 	}
1481546fef27STej Parkash 
1482546fef27STej Parkash 	DEBUG2(pr_info("\n"));
1483546fef27STej Parkash 
14846e3f4f68SLee Jones 	qla4_83xx_rd_reg_indirect(ha, QLA83XX_PORT2_IFB_PAUSE_THRS, &val);
14856e3f4f68SLee Jones 	qla4_83xx_rd_reg_indirect(ha, QLA83XX_PORT3_IFB_PAUSE_THRS, &val1);
1486546fef27STej Parkash 
1487546fef27STej Parkash 	DEBUG2(ql4_printk(KERN_INFO, ha,
1488546fef27STej Parkash 			  "IFB-Pause Thresholds: Port 2:0x%x, Port 3:0x%x\n",
1489546fef27STej Parkash 			  val, val1));
1490546fef27STej Parkash }
1491546fef27STej Parkash 
__qla4_83xx_disable_pause(struct scsi_qla_host * ha)1492546fef27STej Parkash static void __qla4_83xx_disable_pause(struct scsi_qla_host *ha)
1493546fef27STej Parkash {
1494546fef27STej Parkash 	int i;
1495546fef27STej Parkash 
1496546fef27STej Parkash 	/* set SRE-Shim Control Register */
1497546fef27STej Parkash 	qla4_83xx_wr_reg_indirect(ha, QLA83XX_SRE_SHIM_CONTROL,
1498546fef27STej Parkash 				  QLA83XX_SET_PAUSE_VAL);
1499546fef27STej Parkash 
1500546fef27STej Parkash 	for (i = 0; i < 8; i++) {
1501546fef27STej Parkash 		/* Port 0 Rx Buffer Pause Threshold Registers. */
1502546fef27STej Parkash 		qla4_83xx_wr_reg_indirect(ha,
1503546fef27STej Parkash 				      QLA83XX_PORT0_RXB_PAUSE_THRS + (i * 0x4),
1504546fef27STej Parkash 				      QLA83XX_SET_PAUSE_VAL);
1505546fef27STej Parkash 		/* Port 1 Rx Buffer Pause Threshold Registers. */
1506546fef27STej Parkash 		qla4_83xx_wr_reg_indirect(ha,
1507546fef27STej Parkash 				      QLA83XX_PORT1_RXB_PAUSE_THRS + (i * 0x4),
1508546fef27STej Parkash 				      QLA83XX_SET_PAUSE_VAL);
1509546fef27STej Parkash 	}
1510546fef27STej Parkash 
1511546fef27STej Parkash 	for (i = 0; i < 4; i++) {
1512546fef27STej Parkash 		/* Port 0 RxB Traffic Class Max Cell Registers. */
1513546fef27STej Parkash 		qla4_83xx_wr_reg_indirect(ha,
1514546fef27STej Parkash 				     QLA83XX_PORT0_RXB_TC_MAX_CELL + (i * 0x4),
1515546fef27STej Parkash 				     QLA83XX_SET_TC_MAX_CELL_VAL);
1516546fef27STej Parkash 		/* Port 1 RxB Traffic Class Max Cell Registers. */
1517546fef27STej Parkash 		qla4_83xx_wr_reg_indirect(ha,
1518546fef27STej Parkash 				     QLA83XX_PORT1_RXB_TC_MAX_CELL + (i * 0x4),
1519546fef27STej Parkash 				     QLA83XX_SET_TC_MAX_CELL_VAL);
1520546fef27STej Parkash 	}
1521546fef27STej Parkash 
1522546fef27STej Parkash 	qla4_83xx_wr_reg_indirect(ha, QLA83XX_PORT2_IFB_PAUSE_THRS,
1523546fef27STej Parkash 				  QLA83XX_SET_PAUSE_VAL);
1524546fef27STej Parkash 	qla4_83xx_wr_reg_indirect(ha, QLA83XX_PORT3_IFB_PAUSE_THRS,
1525546fef27STej Parkash 				  QLA83XX_SET_PAUSE_VAL);
1526546fef27STej Parkash 
1527546fef27STej Parkash 	ql4_printk(KERN_INFO, ha, "Disabled pause frames successfully.\n");
1528546fef27STej Parkash }
1529546fef27STej Parkash 
1530c18b78edSManish Dusane /**
1531c18b78edSManish Dusane  * qla4_83xx_eport_init - Initialize EPort.
1532c18b78edSManish Dusane  * @ha: Pointer to host adapter structure.
1533c18b78edSManish Dusane  *
1534c18b78edSManish Dusane  * If EPort hardware is in reset state before disabling pause, there would be
1535c18b78edSManish Dusane  * serious hardware wedging issues. To prevent this perform eport init everytime
1536c18b78edSManish Dusane  * before disabling pause frames.
1537c18b78edSManish Dusane  **/
qla4_83xx_eport_init(struct scsi_qla_host * ha)1538c18b78edSManish Dusane static void qla4_83xx_eport_init(struct scsi_qla_host *ha)
1539c18b78edSManish Dusane {
1540c18b78edSManish Dusane 	/* Clear the 8 registers */
1541c18b78edSManish Dusane 	qla4_83xx_wr_reg_indirect(ha, QLA83XX_RESET_REG, 0x0);
1542c18b78edSManish Dusane 	qla4_83xx_wr_reg_indirect(ha, QLA83XX_RESET_PORT0, 0x0);
1543c18b78edSManish Dusane 	qla4_83xx_wr_reg_indirect(ha, QLA83XX_RESET_PORT1, 0x0);
1544c18b78edSManish Dusane 	qla4_83xx_wr_reg_indirect(ha, QLA83XX_RESET_PORT2, 0x0);
1545c18b78edSManish Dusane 	qla4_83xx_wr_reg_indirect(ha, QLA83XX_RESET_PORT3, 0x0);
1546c18b78edSManish Dusane 	qla4_83xx_wr_reg_indirect(ha, QLA83XX_RESET_SRE_SHIM, 0x0);
1547c18b78edSManish Dusane 	qla4_83xx_wr_reg_indirect(ha, QLA83XX_RESET_EPG_SHIM, 0x0);
1548c18b78edSManish Dusane 	qla4_83xx_wr_reg_indirect(ha, QLA83XX_RESET_ETHER_PCS, 0x0);
1549c18b78edSManish Dusane 
1550c18b78edSManish Dusane 	/* Write any value to Reset Control register */
1551c18b78edSManish Dusane 	qla4_83xx_wr_reg_indirect(ha, QLA83XX_RESET_CONTROL, 0xFF);
1552c18b78edSManish Dusane 
1553c18b78edSManish Dusane 	ql4_printk(KERN_INFO, ha, "EPORT is out of reset.\n");
1554c18b78edSManish Dusane }
1555c18b78edSManish Dusane 
qla4_83xx_disable_pause(struct scsi_qla_host * ha)1556546fef27STej Parkash void qla4_83xx_disable_pause(struct scsi_qla_host *ha)
1557546fef27STej Parkash {
1558546fef27STej Parkash 	ha->isp_ops->idc_lock(ha);
1559c18b78edSManish Dusane 	/* Before disabling pause frames, ensure that eport is not in reset */
1560c18b78edSManish Dusane 	qla4_83xx_eport_init(ha);
1561546fef27STej Parkash 	qla4_83xx_dump_pause_control_regs(ha);
1562546fef27STej Parkash 	__qla4_83xx_disable_pause(ha);
1563546fef27STej Parkash 	ha->isp_ops->idc_unlock(ha);
1564546fef27STej Parkash }
1565a083e8bcSVikas Chaudhary 
1566a083e8bcSVikas Chaudhary /**
1567a083e8bcSVikas Chaudhary  * qla4_83xx_is_detached - Check if we are marked invisible.
1568a083e8bcSVikas Chaudhary  * @ha: Pointer to host adapter structure.
1569a083e8bcSVikas Chaudhary  **/
qla4_83xx_is_detached(struct scsi_qla_host * ha)1570a083e8bcSVikas Chaudhary int qla4_83xx_is_detached(struct scsi_qla_host *ha)
1571a083e8bcSVikas Chaudhary {
1572a083e8bcSVikas Chaudhary 	uint32_t drv_active;
1573a083e8bcSVikas Chaudhary 
1574a083e8bcSVikas Chaudhary 	drv_active = qla4_8xxx_rd_direct(ha, QLA8XXX_CRB_DRV_ACTIVE);
1575a083e8bcSVikas Chaudhary 
1576a083e8bcSVikas Chaudhary 	if (test_bit(AF_INIT_DONE, &ha->flags) &&
1577a083e8bcSVikas Chaudhary 	    !(drv_active & (1 << ha->func_num))) {
1578a083e8bcSVikas Chaudhary 		DEBUG2(ql4_printk(KERN_INFO, ha, "%s: drv_active = 0x%X\n",
1579a083e8bcSVikas Chaudhary 				  __func__, drv_active));
1580a083e8bcSVikas Chaudhary 		return QLA_SUCCESS;
1581a083e8bcSVikas Chaudhary 	}
1582a083e8bcSVikas Chaudhary 
1583a083e8bcSVikas Chaudhary 	return QLA_ERROR;
1584a083e8bcSVikas Chaudhary }
1585