xref: /openbmc/linux/drivers/scsi/qla4xxx/ql4_83xx.c (revision c18b78ed)
16e7b4292SVikas Chaudhary /*
26e7b4292SVikas Chaudhary  * QLogic iSCSI HBA Driver
36e7b4292SVikas Chaudhary  * Copyright (c)   2003-2012 QLogic Corporation
46e7b4292SVikas Chaudhary  *
56e7b4292SVikas Chaudhary  * See LICENSE.qla4xxx for copyright and licensing details.
66e7b4292SVikas Chaudhary  */
76e7b4292SVikas Chaudhary 
86e7b4292SVikas Chaudhary #include <linux/ratelimit.h>
96e7b4292SVikas Chaudhary 
106e7b4292SVikas Chaudhary #include "ql4_def.h"
116e7b4292SVikas Chaudhary #include "ql4_version.h"
126e7b4292SVikas Chaudhary #include "ql4_glbl.h"
136e7b4292SVikas Chaudhary #include "ql4_dbg.h"
146e7b4292SVikas Chaudhary #include "ql4_inline.h"
156e7b4292SVikas Chaudhary 
166e7b4292SVikas Chaudhary uint32_t qla4_83xx_rd_reg(struct scsi_qla_host *ha, ulong addr)
176e7b4292SVikas Chaudhary {
186e7b4292SVikas Chaudhary 	return readl((void __iomem *)(ha->nx_pcibase + addr));
196e7b4292SVikas Chaudhary }
206e7b4292SVikas Chaudhary 
216e7b4292SVikas Chaudhary void qla4_83xx_wr_reg(struct scsi_qla_host *ha, ulong addr, uint32_t val)
226e7b4292SVikas Chaudhary {
236e7b4292SVikas Chaudhary 	writel(val, (void __iomem *)(ha->nx_pcibase + addr));
246e7b4292SVikas Chaudhary }
256e7b4292SVikas Chaudhary 
266e7b4292SVikas Chaudhary static int qla4_83xx_set_win_base(struct scsi_qla_host *ha, uint32_t addr)
276e7b4292SVikas Chaudhary {
286e7b4292SVikas Chaudhary 	uint32_t val;
296e7b4292SVikas Chaudhary 	int ret_val = QLA_SUCCESS;
306e7b4292SVikas Chaudhary 
316e7b4292SVikas Chaudhary 	qla4_83xx_wr_reg(ha, QLA83XX_CRB_WIN_FUNC(ha->func_num), addr);
326e7b4292SVikas Chaudhary 	val = qla4_83xx_rd_reg(ha, QLA83XX_CRB_WIN_FUNC(ha->func_num));
336e7b4292SVikas Chaudhary 	if (val != addr) {
346e7b4292SVikas Chaudhary 		ql4_printk(KERN_ERR, ha, "%s: Failed to set register window : addr written 0x%x, read 0x%x!\n",
356e7b4292SVikas Chaudhary 			   __func__, addr, val);
366e7b4292SVikas Chaudhary 		ret_val = QLA_ERROR;
376e7b4292SVikas Chaudhary 	}
386e7b4292SVikas Chaudhary 
396e7b4292SVikas Chaudhary 	return ret_val;
406e7b4292SVikas Chaudhary }
416e7b4292SVikas Chaudhary 
426e7b4292SVikas Chaudhary int qla4_83xx_rd_reg_indirect(struct scsi_qla_host *ha, uint32_t addr,
436e7b4292SVikas Chaudhary 			      uint32_t *data)
446e7b4292SVikas Chaudhary {
456e7b4292SVikas Chaudhary 	int ret_val;
466e7b4292SVikas Chaudhary 
476e7b4292SVikas Chaudhary 	ret_val = qla4_83xx_set_win_base(ha, addr);
486e7b4292SVikas Chaudhary 
496e7b4292SVikas Chaudhary 	if (ret_val == QLA_SUCCESS)
506e7b4292SVikas Chaudhary 		*data = qla4_83xx_rd_reg(ha, QLA83XX_WILDCARD);
516e7b4292SVikas Chaudhary 	else
526e7b4292SVikas Chaudhary 		ql4_printk(KERN_ERR, ha, "%s: failed read of addr 0x%x!\n",
536e7b4292SVikas Chaudhary 			   __func__, addr);
546e7b4292SVikas Chaudhary 
556e7b4292SVikas Chaudhary 	return ret_val;
566e7b4292SVikas Chaudhary }
576e7b4292SVikas Chaudhary 
586e7b4292SVikas Chaudhary int qla4_83xx_wr_reg_indirect(struct scsi_qla_host *ha, uint32_t addr,
596e7b4292SVikas Chaudhary 			      uint32_t data)
606e7b4292SVikas Chaudhary {
616e7b4292SVikas Chaudhary 	int ret_val;
626e7b4292SVikas Chaudhary 
636e7b4292SVikas Chaudhary 	ret_val = qla4_83xx_set_win_base(ha, addr);
646e7b4292SVikas Chaudhary 
656e7b4292SVikas Chaudhary 	if (ret_val == QLA_SUCCESS)
666e7b4292SVikas Chaudhary 		qla4_83xx_wr_reg(ha, QLA83XX_WILDCARD, data);
676e7b4292SVikas Chaudhary 	else
686e7b4292SVikas Chaudhary 		ql4_printk(KERN_ERR, ha, "%s: failed wrt to addr 0x%x, data 0x%x\n",
696e7b4292SVikas Chaudhary 			   __func__, addr, data);
706e7b4292SVikas Chaudhary 
716e7b4292SVikas Chaudhary 	return ret_val;
726e7b4292SVikas Chaudhary }
736e7b4292SVikas Chaudhary 
746e7b4292SVikas Chaudhary static int qla4_83xx_flash_lock(struct scsi_qla_host *ha)
756e7b4292SVikas Chaudhary {
766e7b4292SVikas Chaudhary 	int lock_owner;
776e7b4292SVikas Chaudhary 	int timeout = 0;
786e7b4292SVikas Chaudhary 	uint32_t lock_status = 0;
796e7b4292SVikas Chaudhary 	int ret_val = QLA_SUCCESS;
806e7b4292SVikas Chaudhary 
816e7b4292SVikas Chaudhary 	while (lock_status == 0) {
826e7b4292SVikas Chaudhary 		lock_status = qla4_83xx_rd_reg(ha, QLA83XX_FLASH_LOCK);
836e7b4292SVikas Chaudhary 		if (lock_status)
846e7b4292SVikas Chaudhary 			break;
856e7b4292SVikas Chaudhary 
866e7b4292SVikas Chaudhary 		if (++timeout >= QLA83XX_FLASH_LOCK_TIMEOUT / 20) {
876e7b4292SVikas Chaudhary 			lock_owner = qla4_83xx_rd_reg(ha,
886e7b4292SVikas Chaudhary 						      QLA83XX_FLASH_LOCK_ID);
896e7b4292SVikas Chaudhary 			ql4_printk(KERN_ERR, ha, "%s: flash lock by func %d failed, held by func %d\n",
906e7b4292SVikas Chaudhary 				   __func__, ha->func_num, lock_owner);
916e7b4292SVikas Chaudhary 			ret_val = QLA_ERROR;
926e7b4292SVikas Chaudhary 			break;
936e7b4292SVikas Chaudhary 		}
946e7b4292SVikas Chaudhary 		msleep(20);
956e7b4292SVikas Chaudhary 	}
966e7b4292SVikas Chaudhary 
976e7b4292SVikas Chaudhary 	qla4_83xx_wr_reg(ha, QLA83XX_FLASH_LOCK_ID, ha->func_num);
986e7b4292SVikas Chaudhary 	return ret_val;
996e7b4292SVikas Chaudhary }
1006e7b4292SVikas Chaudhary 
1016e7b4292SVikas Chaudhary static void qla4_83xx_flash_unlock(struct scsi_qla_host *ha)
1026e7b4292SVikas Chaudhary {
1036e7b4292SVikas Chaudhary 	/* Reading FLASH_UNLOCK register unlocks the Flash */
1046e7b4292SVikas Chaudhary 	qla4_83xx_wr_reg(ha, QLA83XX_FLASH_LOCK_ID, 0xFF);
1056e7b4292SVikas Chaudhary 	qla4_83xx_rd_reg(ha, QLA83XX_FLASH_UNLOCK);
1066e7b4292SVikas Chaudhary }
1076e7b4292SVikas Chaudhary 
1086e7b4292SVikas Chaudhary int qla4_83xx_flash_read_u32(struct scsi_qla_host *ha, uint32_t flash_addr,
1096e7b4292SVikas Chaudhary 			     uint8_t *p_data, int u32_word_count)
1106e7b4292SVikas Chaudhary {
1116e7b4292SVikas Chaudhary 	int i;
1126e7b4292SVikas Chaudhary 	uint32_t u32_word;
1136e7b4292SVikas Chaudhary 	uint32_t addr = flash_addr;
1146e7b4292SVikas Chaudhary 	int ret_val = QLA_SUCCESS;
1156e7b4292SVikas Chaudhary 
1166e7b4292SVikas Chaudhary 	ret_val = qla4_83xx_flash_lock(ha);
1176e7b4292SVikas Chaudhary 	if (ret_val == QLA_ERROR)
1186e7b4292SVikas Chaudhary 		goto exit_lock_error;
1196e7b4292SVikas Chaudhary 
1206e7b4292SVikas Chaudhary 	if (addr & 0x03) {
1216e7b4292SVikas Chaudhary 		ql4_printk(KERN_ERR, ha, "%s: Illegal addr = 0x%x\n",
1226e7b4292SVikas Chaudhary 			   __func__, addr);
1236e7b4292SVikas Chaudhary 		ret_val = QLA_ERROR;
1246e7b4292SVikas Chaudhary 		goto exit_flash_read;
1256e7b4292SVikas Chaudhary 	}
1266e7b4292SVikas Chaudhary 
1276e7b4292SVikas Chaudhary 	for (i = 0; i < u32_word_count; i++) {
1286e7b4292SVikas Chaudhary 		ret_val = qla4_83xx_wr_reg_indirect(ha,
1296e7b4292SVikas Chaudhary 						    QLA83XX_FLASH_DIRECT_WINDOW,
1306e7b4292SVikas Chaudhary 						    (addr & 0xFFFF0000));
1316e7b4292SVikas Chaudhary 		if (ret_val == QLA_ERROR) {
1326e7b4292SVikas Chaudhary 			ql4_printk(KERN_ERR, ha, "%s: failed to write addr 0x%x to FLASH_DIRECT_WINDOW\n!",
1336e7b4292SVikas Chaudhary 				   __func__, addr);
1346e7b4292SVikas Chaudhary 			goto exit_flash_read;
1356e7b4292SVikas Chaudhary 		}
1366e7b4292SVikas Chaudhary 
1376e7b4292SVikas Chaudhary 		ret_val = qla4_83xx_rd_reg_indirect(ha,
1386e7b4292SVikas Chaudhary 						QLA83XX_FLASH_DIRECT_DATA(addr),
1396e7b4292SVikas Chaudhary 						&u32_word);
1406e7b4292SVikas Chaudhary 		if (ret_val == QLA_ERROR) {
1416e7b4292SVikas Chaudhary 			ql4_printk(KERN_ERR, ha, "%s: failed to read addr 0x%x!\n",
1426e7b4292SVikas Chaudhary 				   __func__, addr);
1436e7b4292SVikas Chaudhary 			goto exit_flash_read;
1446e7b4292SVikas Chaudhary 		}
1456e7b4292SVikas Chaudhary 
1466e7b4292SVikas Chaudhary 		*(__le32 *)p_data = le32_to_cpu(u32_word);
1476e7b4292SVikas Chaudhary 		p_data = p_data + 4;
1486e7b4292SVikas Chaudhary 		addr = addr + 4;
1496e7b4292SVikas Chaudhary 	}
1506e7b4292SVikas Chaudhary 
1516e7b4292SVikas Chaudhary exit_flash_read:
1526e7b4292SVikas Chaudhary 	qla4_83xx_flash_unlock(ha);
1536e7b4292SVikas Chaudhary 
1546e7b4292SVikas Chaudhary exit_lock_error:
1556e7b4292SVikas Chaudhary 	return ret_val;
1566e7b4292SVikas Chaudhary }
1576e7b4292SVikas Chaudhary 
1586e7b4292SVikas Chaudhary int qla4_83xx_lockless_flash_read_u32(struct scsi_qla_host *ha,
1596e7b4292SVikas Chaudhary 				      uint32_t flash_addr, uint8_t *p_data,
1606e7b4292SVikas Chaudhary 				      int u32_word_count)
1616e7b4292SVikas Chaudhary {
1626e7b4292SVikas Chaudhary 	uint32_t i;
1636e7b4292SVikas Chaudhary 	uint32_t u32_word;
1646e7b4292SVikas Chaudhary 	uint32_t flash_offset;
1656e7b4292SVikas Chaudhary 	uint32_t addr = flash_addr;
1666e7b4292SVikas Chaudhary 	int ret_val = QLA_SUCCESS;
1676e7b4292SVikas Chaudhary 
1686e7b4292SVikas Chaudhary 	flash_offset = addr & (QLA83XX_FLASH_SECTOR_SIZE - 1);
1696e7b4292SVikas Chaudhary 
1706e7b4292SVikas Chaudhary 	if (addr & 0x3) {
1716e7b4292SVikas Chaudhary 		ql4_printk(KERN_ERR, ha, "%s: Illegal addr = 0x%x\n",
1726e7b4292SVikas Chaudhary 			   __func__, addr);
1736e7b4292SVikas Chaudhary 		ret_val = QLA_ERROR;
1746e7b4292SVikas Chaudhary 		goto exit_lockless_read;
1756e7b4292SVikas Chaudhary 	}
1766e7b4292SVikas Chaudhary 
1776e7b4292SVikas Chaudhary 	ret_val = qla4_83xx_wr_reg_indirect(ha, QLA83XX_FLASH_DIRECT_WINDOW,
1786e7b4292SVikas Chaudhary 					    addr);
1796e7b4292SVikas Chaudhary 	if (ret_val == QLA_ERROR) {
1806e7b4292SVikas Chaudhary 		ql4_printk(KERN_ERR, ha, "%s: failed to write addr 0x%x to FLASH_DIRECT_WINDOW!\n",
1816e7b4292SVikas Chaudhary 			   __func__, addr);
1826e7b4292SVikas Chaudhary 		goto exit_lockless_read;
1836e7b4292SVikas Chaudhary 	}
1846e7b4292SVikas Chaudhary 
1856e7b4292SVikas Chaudhary 	/* Check if data is spread across multiple sectors  */
1866e7b4292SVikas Chaudhary 	if ((flash_offset + (u32_word_count * sizeof(uint32_t))) >
1876e7b4292SVikas Chaudhary 	    (QLA83XX_FLASH_SECTOR_SIZE - 1)) {
1886e7b4292SVikas Chaudhary 
1896e7b4292SVikas Chaudhary 		/* Multi sector read */
1906e7b4292SVikas Chaudhary 		for (i = 0; i < u32_word_count; i++) {
1916e7b4292SVikas Chaudhary 			ret_val = qla4_83xx_rd_reg_indirect(ha,
1926e7b4292SVikas Chaudhary 						QLA83XX_FLASH_DIRECT_DATA(addr),
1936e7b4292SVikas Chaudhary 						&u32_word);
1946e7b4292SVikas Chaudhary 			if (ret_val == QLA_ERROR) {
1956e7b4292SVikas Chaudhary 				ql4_printk(KERN_ERR, ha, "%s: failed to read addr 0x%x!\n",
1966e7b4292SVikas Chaudhary 					   __func__, addr);
1976e7b4292SVikas Chaudhary 				goto exit_lockless_read;
1986e7b4292SVikas Chaudhary 			}
1996e7b4292SVikas Chaudhary 
2006e7b4292SVikas Chaudhary 			*(__le32 *)p_data  = le32_to_cpu(u32_word);
2016e7b4292SVikas Chaudhary 			p_data = p_data + 4;
2026e7b4292SVikas Chaudhary 			addr = addr + 4;
2036e7b4292SVikas Chaudhary 			flash_offset = flash_offset + 4;
2046e7b4292SVikas Chaudhary 
2056e7b4292SVikas Chaudhary 			if (flash_offset > (QLA83XX_FLASH_SECTOR_SIZE - 1)) {
2066e7b4292SVikas Chaudhary 				/* This write is needed once for each sector */
2076e7b4292SVikas Chaudhary 				ret_val = qla4_83xx_wr_reg_indirect(ha,
2086e7b4292SVikas Chaudhary 						   QLA83XX_FLASH_DIRECT_WINDOW,
2096e7b4292SVikas Chaudhary 						   addr);
2106e7b4292SVikas Chaudhary 				if (ret_val == QLA_ERROR) {
2116e7b4292SVikas Chaudhary 					ql4_printk(KERN_ERR, ha, "%s: failed to write addr 0x%x to FLASH_DIRECT_WINDOW!\n",
2126e7b4292SVikas Chaudhary 						   __func__, addr);
2136e7b4292SVikas Chaudhary 					goto exit_lockless_read;
2146e7b4292SVikas Chaudhary 				}
2156e7b4292SVikas Chaudhary 				flash_offset = 0;
2166e7b4292SVikas Chaudhary 			}
2176e7b4292SVikas Chaudhary 		}
2186e7b4292SVikas Chaudhary 	} else {
2196e7b4292SVikas Chaudhary 		/* Single sector read */
2206e7b4292SVikas Chaudhary 		for (i = 0; i < u32_word_count; i++) {
2216e7b4292SVikas Chaudhary 			ret_val = qla4_83xx_rd_reg_indirect(ha,
2226e7b4292SVikas Chaudhary 						QLA83XX_FLASH_DIRECT_DATA(addr),
2236e7b4292SVikas Chaudhary 						&u32_word);
2246e7b4292SVikas Chaudhary 			if (ret_val == QLA_ERROR) {
2256e7b4292SVikas Chaudhary 				ql4_printk(KERN_ERR, ha, "%s: failed to read addr 0x%x!\n",
2266e7b4292SVikas Chaudhary 					   __func__, addr);
2276e7b4292SVikas Chaudhary 				goto exit_lockless_read;
2286e7b4292SVikas Chaudhary 			}
2296e7b4292SVikas Chaudhary 
2306e7b4292SVikas Chaudhary 			*(__le32 *)p_data = le32_to_cpu(u32_word);
2316e7b4292SVikas Chaudhary 			p_data = p_data + 4;
2326e7b4292SVikas Chaudhary 			addr = addr + 4;
2336e7b4292SVikas Chaudhary 		}
2346e7b4292SVikas Chaudhary 	}
2356e7b4292SVikas Chaudhary 
2366e7b4292SVikas Chaudhary exit_lockless_read:
2376e7b4292SVikas Chaudhary 	return ret_val;
2386e7b4292SVikas Chaudhary }
2396e7b4292SVikas Chaudhary 
2406e7b4292SVikas Chaudhary void qla4_83xx_rom_lock_recovery(struct scsi_qla_host *ha)
2416e7b4292SVikas Chaudhary {
2426e7b4292SVikas Chaudhary 	if (qla4_83xx_flash_lock(ha))
2436e7b4292SVikas Chaudhary 		ql4_printk(KERN_INFO, ha, "%s: Resetting rom lock\n", __func__);
2446e7b4292SVikas Chaudhary 
2456e7b4292SVikas Chaudhary 	/*
2466e7b4292SVikas Chaudhary 	 * We got the lock, or someone else is holding the lock
2476e7b4292SVikas Chaudhary 	 * since we are restting, forcefully unlock
2486e7b4292SVikas Chaudhary 	 */
2496e7b4292SVikas Chaudhary 	qla4_83xx_flash_unlock(ha);
2506e7b4292SVikas Chaudhary }
2516e7b4292SVikas Chaudhary 
2526e7b4292SVikas Chaudhary /**
2536e7b4292SVikas Chaudhary  * qla4_83xx_ms_mem_write_128b - Writes data to MS/off-chip memory
2546e7b4292SVikas Chaudhary  * @ha: Pointer to adapter structure
2556e7b4292SVikas Chaudhary  * @addr: Flash address to write to
2566e7b4292SVikas Chaudhary  * @data: Data to be written
2576e7b4292SVikas Chaudhary  * @count: word_count to be written
2586e7b4292SVikas Chaudhary  *
2596e7b4292SVikas Chaudhary  * Return: On success return QLA_SUCCESS
2606e7b4292SVikas Chaudhary  *	   On error return QLA_ERROR
2616e7b4292SVikas Chaudhary  **/
2626e7b4292SVikas Chaudhary static int qla4_83xx_ms_mem_write_128b(struct scsi_qla_host *ha, uint64_t addr,
2636e7b4292SVikas Chaudhary 				       uint32_t *data, uint32_t count)
2646e7b4292SVikas Chaudhary {
2656e7b4292SVikas Chaudhary 	int i, j;
2666e7b4292SVikas Chaudhary 	uint32_t agt_ctrl;
2676e7b4292SVikas Chaudhary 	unsigned long flags;
2686e7b4292SVikas Chaudhary 	int ret_val = QLA_SUCCESS;
2696e7b4292SVikas Chaudhary 
2706e7b4292SVikas Chaudhary 	/* Only 128-bit aligned access */
2716e7b4292SVikas Chaudhary 	if (addr & 0xF) {
2726e7b4292SVikas Chaudhary 		ret_val = QLA_ERROR;
2736e7b4292SVikas Chaudhary 		goto exit_ms_mem_write;
2746e7b4292SVikas Chaudhary 	}
2756e7b4292SVikas Chaudhary 
2766e7b4292SVikas Chaudhary 	write_lock_irqsave(&ha->hw_lock, flags);
2776e7b4292SVikas Chaudhary 
2786e7b4292SVikas Chaudhary 	/* Write address */
2796e7b4292SVikas Chaudhary 	ret_val = qla4_83xx_wr_reg_indirect(ha, MD_MIU_TEST_AGT_ADDR_HI, 0);
2806e7b4292SVikas Chaudhary 	if (ret_val == QLA_ERROR) {
2816e7b4292SVikas Chaudhary 		ql4_printk(KERN_ERR, ha, "%s: write to AGT_ADDR_HI failed\n",
2826e7b4292SVikas Chaudhary 			   __func__);
2836e7b4292SVikas Chaudhary 		goto exit_ms_mem_write_unlock;
2846e7b4292SVikas Chaudhary 	}
2856e7b4292SVikas Chaudhary 
2866e7b4292SVikas Chaudhary 	for (i = 0; i < count; i++, addr += 16) {
2876e7b4292SVikas Chaudhary 		if (!((QLA8XXX_ADDR_IN_RANGE(addr, QLA8XXX_ADDR_QDR_NET,
2886e7b4292SVikas Chaudhary 					     QLA8XXX_ADDR_QDR_NET_MAX)) ||
2896e7b4292SVikas Chaudhary 		      (QLA8XXX_ADDR_IN_RANGE(addr, QLA8XXX_ADDR_DDR_NET,
2906e7b4292SVikas Chaudhary 					     QLA8XXX_ADDR_DDR_NET_MAX)))) {
2916e7b4292SVikas Chaudhary 			ret_val = QLA_ERROR;
2926e7b4292SVikas Chaudhary 			goto exit_ms_mem_write_unlock;
2936e7b4292SVikas Chaudhary 		}
2946e7b4292SVikas Chaudhary 
2956e7b4292SVikas Chaudhary 		ret_val = qla4_83xx_wr_reg_indirect(ha, MD_MIU_TEST_AGT_ADDR_LO,
2966e7b4292SVikas Chaudhary 						    addr);
2976e7b4292SVikas Chaudhary 		/* Write data */
2986e7b4292SVikas Chaudhary 		ret_val |= qla4_83xx_wr_reg_indirect(ha,
2996e7b4292SVikas Chaudhary 						     MD_MIU_TEST_AGT_WRDATA_LO,
3006e7b4292SVikas Chaudhary 						     *data++);
3016e7b4292SVikas Chaudhary 		ret_val |= qla4_83xx_wr_reg_indirect(ha,
3026e7b4292SVikas Chaudhary 						     MD_MIU_TEST_AGT_WRDATA_HI,
3036e7b4292SVikas Chaudhary 						     *data++);
3046e7b4292SVikas Chaudhary 		ret_val |= qla4_83xx_wr_reg_indirect(ha,
3056e7b4292SVikas Chaudhary 						     MD_MIU_TEST_AGT_WRDATA_ULO,
3066e7b4292SVikas Chaudhary 						     *data++);
3076e7b4292SVikas Chaudhary 		ret_val |= qla4_83xx_wr_reg_indirect(ha,
3086e7b4292SVikas Chaudhary 						     MD_MIU_TEST_AGT_WRDATA_UHI,
3096e7b4292SVikas Chaudhary 						     *data++);
3106e7b4292SVikas Chaudhary 		if (ret_val == QLA_ERROR) {
3116e7b4292SVikas Chaudhary 			ql4_printk(KERN_ERR, ha, "%s: write to AGT_WRDATA failed\n",
3126e7b4292SVikas Chaudhary 				   __func__);
3136e7b4292SVikas Chaudhary 			goto exit_ms_mem_write_unlock;
3146e7b4292SVikas Chaudhary 		}
3156e7b4292SVikas Chaudhary 
3166e7b4292SVikas Chaudhary 		/* Check write status */
3176e7b4292SVikas Chaudhary 		ret_val = qla4_83xx_wr_reg_indirect(ha, MD_MIU_TEST_AGT_CTRL,
3186e7b4292SVikas Chaudhary 						    MIU_TA_CTL_WRITE_ENABLE);
3196e7b4292SVikas Chaudhary 		ret_val |= qla4_83xx_wr_reg_indirect(ha, MD_MIU_TEST_AGT_CTRL,
3206e7b4292SVikas Chaudhary 						     MIU_TA_CTL_WRITE_START);
3216e7b4292SVikas Chaudhary 		if (ret_val == QLA_ERROR) {
3226e7b4292SVikas Chaudhary 			ql4_printk(KERN_ERR, ha, "%s: write to AGT_CTRL failed\n",
3236e7b4292SVikas Chaudhary 				   __func__);
3246e7b4292SVikas Chaudhary 			goto exit_ms_mem_write_unlock;
3256e7b4292SVikas Chaudhary 		}
3266e7b4292SVikas Chaudhary 
3276e7b4292SVikas Chaudhary 		for (j = 0; j < MAX_CTL_CHECK; j++) {
3286e7b4292SVikas Chaudhary 			ret_val = qla4_83xx_rd_reg_indirect(ha,
3296e7b4292SVikas Chaudhary 							MD_MIU_TEST_AGT_CTRL,
3306e7b4292SVikas Chaudhary 							&agt_ctrl);
3316e7b4292SVikas Chaudhary 			if (ret_val == QLA_ERROR) {
3326e7b4292SVikas Chaudhary 				ql4_printk(KERN_ERR, ha, "%s: failed to read MD_MIU_TEST_AGT_CTRL\n",
3336e7b4292SVikas Chaudhary 					   __func__);
3346e7b4292SVikas Chaudhary 				goto exit_ms_mem_write_unlock;
3356e7b4292SVikas Chaudhary 			}
3366e7b4292SVikas Chaudhary 			if ((agt_ctrl & MIU_TA_CTL_BUSY) == 0)
3376e7b4292SVikas Chaudhary 				break;
3386e7b4292SVikas Chaudhary 		}
3396e7b4292SVikas Chaudhary 
3406e7b4292SVikas Chaudhary 		/* Status check failed */
3416e7b4292SVikas Chaudhary 		if (j >= MAX_CTL_CHECK) {
3426e7b4292SVikas Chaudhary 			printk_ratelimited(KERN_ERR "%s: MS memory write failed!\n",
3436e7b4292SVikas Chaudhary 					   __func__);
3446e7b4292SVikas Chaudhary 			ret_val = QLA_ERROR;
3456e7b4292SVikas Chaudhary 			goto exit_ms_mem_write_unlock;
3466e7b4292SVikas Chaudhary 		}
3476e7b4292SVikas Chaudhary 	}
3486e7b4292SVikas Chaudhary 
3496e7b4292SVikas Chaudhary exit_ms_mem_write_unlock:
3506e7b4292SVikas Chaudhary 	write_unlock_irqrestore(&ha->hw_lock, flags);
3516e7b4292SVikas Chaudhary 
3526e7b4292SVikas Chaudhary exit_ms_mem_write:
3536e7b4292SVikas Chaudhary 	return ret_val;
3546e7b4292SVikas Chaudhary }
3556e7b4292SVikas Chaudhary 
3566e7b4292SVikas Chaudhary #define INTENT_TO_RECOVER	0x01
3576e7b4292SVikas Chaudhary #define PROCEED_TO_RECOVER	0x02
3586e7b4292SVikas Chaudhary 
3596e7b4292SVikas Chaudhary static int qla4_83xx_lock_recovery(struct scsi_qla_host *ha)
3606e7b4292SVikas Chaudhary {
3616e7b4292SVikas Chaudhary 
3626e7b4292SVikas Chaudhary 	uint32_t lock = 0, lockid;
3636e7b4292SVikas Chaudhary 	int ret_val = QLA_ERROR;
3646e7b4292SVikas Chaudhary 
3656e7b4292SVikas Chaudhary 	lockid = ha->isp_ops->rd_reg_direct(ha, QLA83XX_DRV_LOCKRECOVERY);
3666e7b4292SVikas Chaudhary 
3676e7b4292SVikas Chaudhary 	/* Check for other Recovery in progress, go wait */
3686e7b4292SVikas Chaudhary 	if ((lockid & 0x3) != 0)
3696e7b4292SVikas Chaudhary 		goto exit_lock_recovery;
3706e7b4292SVikas Chaudhary 
3716e7b4292SVikas Chaudhary 	/* Intent to Recover */
3726e7b4292SVikas Chaudhary 	ha->isp_ops->wr_reg_direct(ha, QLA83XX_DRV_LOCKRECOVERY,
3736e7b4292SVikas Chaudhary 				   (ha->func_num << 2) | INTENT_TO_RECOVER);
3746e7b4292SVikas Chaudhary 
3756e7b4292SVikas Chaudhary 	msleep(200);
3766e7b4292SVikas Chaudhary 
3776e7b4292SVikas Chaudhary 	/* Check Intent to Recover is advertised */
3786e7b4292SVikas Chaudhary 	lockid = ha->isp_ops->rd_reg_direct(ha, QLA83XX_DRV_LOCKRECOVERY);
3796e7b4292SVikas Chaudhary 	if ((lockid & 0x3C) != (ha->func_num << 2))
3806e7b4292SVikas Chaudhary 		goto exit_lock_recovery;
3816e7b4292SVikas Chaudhary 
3826e7b4292SVikas Chaudhary 	ql4_printk(KERN_INFO, ha, "%s: IDC Lock recovery initiated for func %d\n",
3836e7b4292SVikas Chaudhary 		   __func__, ha->func_num);
3846e7b4292SVikas Chaudhary 
3856e7b4292SVikas Chaudhary 	/* Proceed to Recover */
3866e7b4292SVikas Chaudhary 	ha->isp_ops->wr_reg_direct(ha, QLA83XX_DRV_LOCKRECOVERY,
3876e7b4292SVikas Chaudhary 				   (ha->func_num << 2) | PROCEED_TO_RECOVER);
3886e7b4292SVikas Chaudhary 
3896e7b4292SVikas Chaudhary 	/* Force Unlock */
3906e7b4292SVikas Chaudhary 	ha->isp_ops->wr_reg_direct(ha, QLA83XX_DRV_LOCK_ID, 0xFF);
3916e7b4292SVikas Chaudhary 	ha->isp_ops->rd_reg_direct(ha, QLA83XX_DRV_UNLOCK);
3926e7b4292SVikas Chaudhary 
3936e7b4292SVikas Chaudhary 	/* Clear bits 0-5 in IDC_RECOVERY register*/
3946e7b4292SVikas Chaudhary 	ha->isp_ops->wr_reg_direct(ha, QLA83XX_DRV_LOCKRECOVERY, 0);
3956e7b4292SVikas Chaudhary 
3966e7b4292SVikas Chaudhary 	/* Get lock */
3976e7b4292SVikas Chaudhary 	lock = ha->isp_ops->rd_reg_direct(ha, QLA83XX_DRV_LOCK);
3986e7b4292SVikas Chaudhary 	if (lock) {
3996e7b4292SVikas Chaudhary 		lockid = ha->isp_ops->rd_reg_direct(ha, QLA83XX_DRV_LOCK_ID);
4006e7b4292SVikas Chaudhary 		lockid = ((lockid + (1 << 8)) & ~0xFF) | ha->func_num;
4016e7b4292SVikas Chaudhary 		ha->isp_ops->wr_reg_direct(ha, QLA83XX_DRV_LOCK_ID, lockid);
4026e7b4292SVikas Chaudhary 		ret_val = QLA_SUCCESS;
4036e7b4292SVikas Chaudhary 	}
4046e7b4292SVikas Chaudhary 
4056e7b4292SVikas Chaudhary exit_lock_recovery:
4066e7b4292SVikas Chaudhary 	return ret_val;
4076e7b4292SVikas Chaudhary }
4086e7b4292SVikas Chaudhary 
4096e7b4292SVikas Chaudhary #define	QLA83XX_DRV_LOCK_MSLEEP		200
4106e7b4292SVikas Chaudhary 
4116e7b4292SVikas Chaudhary int qla4_83xx_drv_lock(struct scsi_qla_host *ha)
4126e7b4292SVikas Chaudhary {
4136e7b4292SVikas Chaudhary 	int timeout = 0;
4146e7b4292SVikas Chaudhary 	uint32_t status = 0;
4156e7b4292SVikas Chaudhary 	int ret_val = QLA_SUCCESS;
4166e7b4292SVikas Chaudhary 	uint32_t first_owner = 0;
4176e7b4292SVikas Chaudhary 	uint32_t tmo_owner = 0;
4186e7b4292SVikas Chaudhary 	uint32_t lock_id;
4196e7b4292SVikas Chaudhary 	uint32_t func_num;
4206e7b4292SVikas Chaudhary 	uint32_t lock_cnt;
4216e7b4292SVikas Chaudhary 
4226e7b4292SVikas Chaudhary 	while (status == 0) {
4236e7b4292SVikas Chaudhary 		status = qla4_83xx_rd_reg(ha, QLA83XX_DRV_LOCK);
4246e7b4292SVikas Chaudhary 		if (status) {
4256e7b4292SVikas Chaudhary 			/* Increment Counter (8-31) and update func_num (0-7) on
4266e7b4292SVikas Chaudhary 			 * getting a successful lock  */
4276e7b4292SVikas Chaudhary 			lock_id = qla4_83xx_rd_reg(ha, QLA83XX_DRV_LOCK_ID);
4286e7b4292SVikas Chaudhary 			lock_id = ((lock_id + (1 << 8)) & ~0xFF) | ha->func_num;
4296e7b4292SVikas Chaudhary 			qla4_83xx_wr_reg(ha, QLA83XX_DRV_LOCK_ID, lock_id);
4306e7b4292SVikas Chaudhary 			break;
4316e7b4292SVikas Chaudhary 		}
4326e7b4292SVikas Chaudhary 
4336e7b4292SVikas Chaudhary 		if (timeout == 0)
4346e7b4292SVikas Chaudhary 			/* Save counter + ID of function holding the lock for
4356e7b4292SVikas Chaudhary 			 * first failure */
4366e7b4292SVikas Chaudhary 			first_owner = ha->isp_ops->rd_reg_direct(ha,
4376e7b4292SVikas Chaudhary 							  QLA83XX_DRV_LOCK_ID);
4386e7b4292SVikas Chaudhary 
4396e7b4292SVikas Chaudhary 		if (++timeout >=
4406e7b4292SVikas Chaudhary 		    (QLA83XX_DRV_LOCK_TIMEOUT / QLA83XX_DRV_LOCK_MSLEEP)) {
4416e7b4292SVikas Chaudhary 			tmo_owner = qla4_83xx_rd_reg(ha, QLA83XX_DRV_LOCK_ID);
4426e7b4292SVikas Chaudhary 			func_num = tmo_owner & 0xFF;
4436e7b4292SVikas Chaudhary 			lock_cnt = tmo_owner >> 8;
4446e7b4292SVikas 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",
4456e7b4292SVikas Chaudhary 				   __func__, ha->func_num, func_num, lock_cnt,
4466e7b4292SVikas Chaudhary 				   (first_owner & 0xFF));
4476e7b4292SVikas Chaudhary 
4486e7b4292SVikas Chaudhary 			if (first_owner != tmo_owner) {
4496e7b4292SVikas Chaudhary 				/* Some other driver got lock, OR same driver
4506e7b4292SVikas Chaudhary 				 * got lock again (counter value changed), when
4516e7b4292SVikas Chaudhary 				 * we were waiting for lock.
4526e7b4292SVikas Chaudhary 				 * Retry for another 2 sec */
4536e7b4292SVikas Chaudhary 				ql4_printk(KERN_INFO, ha, "%s: IDC lock failed for func %d\n",
4546e7b4292SVikas Chaudhary 					   __func__, ha->func_num);
4556e7b4292SVikas Chaudhary 				timeout = 0;
4566e7b4292SVikas Chaudhary 			} else {
4576e7b4292SVikas Chaudhary 				/* Same driver holding lock > 2sec.
4586e7b4292SVikas Chaudhary 				 * Force Recovery */
4596e7b4292SVikas Chaudhary 				ret_val = qla4_83xx_lock_recovery(ha);
4606e7b4292SVikas Chaudhary 				if (ret_val == QLA_SUCCESS) {
4616e7b4292SVikas Chaudhary 					/* Recovered and got lock */
4626e7b4292SVikas Chaudhary 					ql4_printk(KERN_INFO, ha, "%s: IDC lock Recovery by %d successful\n",
4636e7b4292SVikas Chaudhary 						   __func__, ha->func_num);
4646e7b4292SVikas Chaudhary 					break;
4656e7b4292SVikas Chaudhary 				}
4666e7b4292SVikas Chaudhary 				/* Recovery Failed, some other function
4676e7b4292SVikas Chaudhary 				 * has the lock, wait for 2secs and retry */
4686e7b4292SVikas Chaudhary 				ql4_printk(KERN_INFO, ha, "%s: IDC lock Recovery by %d failed, Retrying timout\n",
4696e7b4292SVikas Chaudhary 					   __func__, ha->func_num);
4706e7b4292SVikas Chaudhary 				timeout = 0;
4716e7b4292SVikas Chaudhary 			}
4726e7b4292SVikas Chaudhary 		}
4736e7b4292SVikas Chaudhary 		msleep(QLA83XX_DRV_LOCK_MSLEEP);
4746e7b4292SVikas Chaudhary 	}
4756e7b4292SVikas Chaudhary 
4766e7b4292SVikas Chaudhary 	return ret_val;
4776e7b4292SVikas Chaudhary }
4786e7b4292SVikas Chaudhary 
4796e7b4292SVikas Chaudhary void qla4_83xx_drv_unlock(struct scsi_qla_host *ha)
4806e7b4292SVikas Chaudhary {
4816e7b4292SVikas Chaudhary 	int id;
4826e7b4292SVikas Chaudhary 
4836e7b4292SVikas Chaudhary 	id = qla4_83xx_rd_reg(ha, QLA83XX_DRV_LOCK_ID);
4846e7b4292SVikas Chaudhary 
4856e7b4292SVikas Chaudhary 	if ((id & 0xFF) != ha->func_num) {
4866e7b4292SVikas Chaudhary 		ql4_printk(KERN_ERR, ha, "%s: IDC Unlock by %d failed, lock owner is %d\n",
4876e7b4292SVikas Chaudhary 			   __func__, ha->func_num, (id & 0xFF));
4886e7b4292SVikas Chaudhary 		return;
4896e7b4292SVikas Chaudhary 	}
4906e7b4292SVikas Chaudhary 
4916e7b4292SVikas Chaudhary 	/* Keep lock counter value, update the ha->func_num to 0xFF */
4926e7b4292SVikas Chaudhary 	qla4_83xx_wr_reg(ha, QLA83XX_DRV_LOCK_ID, (id | 0xFF));
4936e7b4292SVikas Chaudhary 	qla4_83xx_rd_reg(ha, QLA83XX_DRV_UNLOCK);
4946e7b4292SVikas Chaudhary }
4956e7b4292SVikas Chaudhary 
4966e7b4292SVikas Chaudhary void qla4_83xx_set_idc_dontreset(struct scsi_qla_host *ha)
4976e7b4292SVikas Chaudhary {
4986e7b4292SVikas Chaudhary 	uint32_t idc_ctrl;
4996e7b4292SVikas Chaudhary 
5006e7b4292SVikas Chaudhary 	idc_ctrl = qla4_83xx_rd_reg(ha, QLA83XX_IDC_DRV_CTRL);
5016e7b4292SVikas Chaudhary 	idc_ctrl |= DONTRESET_BIT0;
5026e7b4292SVikas Chaudhary 	qla4_83xx_wr_reg(ha, QLA83XX_IDC_DRV_CTRL, idc_ctrl);
5036e7b4292SVikas Chaudhary 	DEBUG2(ql4_printk(KERN_INFO, ha, "%s: idc_ctrl = %d\n", __func__,
5046e7b4292SVikas Chaudhary 			  idc_ctrl));
5056e7b4292SVikas Chaudhary }
5066e7b4292SVikas Chaudhary 
5076e7b4292SVikas Chaudhary void qla4_83xx_clear_idc_dontreset(struct scsi_qla_host *ha)
5086e7b4292SVikas Chaudhary {
5096e7b4292SVikas Chaudhary 	uint32_t idc_ctrl;
5106e7b4292SVikas Chaudhary 
5116e7b4292SVikas Chaudhary 	idc_ctrl = qla4_83xx_rd_reg(ha, QLA83XX_IDC_DRV_CTRL);
5126e7b4292SVikas Chaudhary 	idc_ctrl &= ~DONTRESET_BIT0;
5136e7b4292SVikas Chaudhary 	qla4_83xx_wr_reg(ha, QLA83XX_IDC_DRV_CTRL, idc_ctrl);
5146e7b4292SVikas Chaudhary 	DEBUG2(ql4_printk(KERN_INFO, ha, "%s: idc_ctrl = %d\n", __func__,
5156e7b4292SVikas Chaudhary 			  idc_ctrl));
5166e7b4292SVikas Chaudhary }
5176e7b4292SVikas Chaudhary 
5186e7b4292SVikas Chaudhary int qla4_83xx_idc_dontreset(struct scsi_qla_host *ha)
5196e7b4292SVikas Chaudhary {
5206e7b4292SVikas Chaudhary 	uint32_t idc_ctrl;
5216e7b4292SVikas Chaudhary 
5226e7b4292SVikas Chaudhary 	idc_ctrl = qla4_83xx_rd_reg(ha, QLA83XX_IDC_DRV_CTRL);
5236e7b4292SVikas Chaudhary 	return idc_ctrl & DONTRESET_BIT0;
5246e7b4292SVikas Chaudhary }
5256e7b4292SVikas Chaudhary 
5266e7b4292SVikas Chaudhary /*-------------------------IDC State Machine ---------------------*/
5276e7b4292SVikas Chaudhary 
5286e7b4292SVikas Chaudhary enum {
5296e7b4292SVikas Chaudhary 	UNKNOWN_CLASS = 0,
5306e7b4292SVikas Chaudhary 	NIC_CLASS,
5316e7b4292SVikas Chaudhary 	FCOE_CLASS,
5326e7b4292SVikas Chaudhary 	ISCSI_CLASS
5336e7b4292SVikas Chaudhary };
5346e7b4292SVikas Chaudhary 
5356e7b4292SVikas Chaudhary struct device_info {
5366e7b4292SVikas Chaudhary 	int func_num;
5376e7b4292SVikas Chaudhary 	int device_type;
5386e7b4292SVikas Chaudhary 	int port_num;
5396e7b4292SVikas Chaudhary };
5406e7b4292SVikas Chaudhary 
5419661975fSVikas Chaudhary int qla4_83xx_can_perform_reset(struct scsi_qla_host *ha)
5426e7b4292SVikas Chaudhary {
5436e7b4292SVikas Chaudhary 	uint32_t drv_active;
5446e7b4292SVikas Chaudhary 	uint32_t dev_part, dev_part1, dev_part2;
5456e7b4292SVikas Chaudhary 	int i;
5466e7b4292SVikas Chaudhary 	struct device_info device_map[16];
5476e7b4292SVikas Chaudhary 	int func_nibble;
5486e7b4292SVikas Chaudhary 	int nibble;
5496e7b4292SVikas Chaudhary 	int nic_present = 0;
5506e7b4292SVikas Chaudhary 	int iscsi_present = 0;
5516e7b4292SVikas Chaudhary 	int iscsi_func_low = 0;
5526e7b4292SVikas Chaudhary 
5536e7b4292SVikas Chaudhary 	/* Use the dev_partition register to determine the PCI function number
5546e7b4292SVikas Chaudhary 	 * and then check drv_active register to see which driver is loaded */
5556e7b4292SVikas Chaudhary 	dev_part1 = qla4_83xx_rd_reg(ha,
5566e7b4292SVikas Chaudhary 				     ha->reg_tbl[QLA8XXX_CRB_DEV_PART_INFO]);
5576e7b4292SVikas Chaudhary 	dev_part2 = qla4_83xx_rd_reg(ha, QLA83XX_CRB_DEV_PART_INFO2);
5586e7b4292SVikas Chaudhary 	drv_active = qla4_83xx_rd_reg(ha, ha->reg_tbl[QLA8XXX_CRB_DRV_ACTIVE]);
5596e7b4292SVikas Chaudhary 
5606e7b4292SVikas Chaudhary 	/* Each function has 4 bits in dev_partition Info register,
5616e7b4292SVikas Chaudhary 	 * Lower 2 bits - device type, Upper 2 bits - physical port number */
5626e7b4292SVikas Chaudhary 	dev_part = dev_part1;
5636e7b4292SVikas Chaudhary 	for (i = nibble = 0; i <= 15; i++, nibble++) {
5646e7b4292SVikas Chaudhary 		func_nibble = dev_part & (0xF << (nibble * 4));
5656e7b4292SVikas Chaudhary 		func_nibble >>= (nibble * 4);
5666e7b4292SVikas Chaudhary 		device_map[i].func_num = i;
5676e7b4292SVikas Chaudhary 		device_map[i].device_type = func_nibble & 0x3;
5686e7b4292SVikas Chaudhary 		device_map[i].port_num = func_nibble & 0xC;
5696e7b4292SVikas Chaudhary 
5706e7b4292SVikas Chaudhary 		if (device_map[i].device_type == NIC_CLASS) {
5716e7b4292SVikas Chaudhary 			if (drv_active & (1 << device_map[i].func_num)) {
5726e7b4292SVikas Chaudhary 				nic_present++;
5736e7b4292SVikas Chaudhary 				break;
5746e7b4292SVikas Chaudhary 			}
5756e7b4292SVikas Chaudhary 		} else if (device_map[i].device_type == ISCSI_CLASS) {
5766e7b4292SVikas Chaudhary 			if (drv_active & (1 << device_map[i].func_num)) {
5776e7b4292SVikas Chaudhary 				if (!iscsi_present ||
5786e7b4292SVikas Chaudhary 				    (iscsi_present &&
5796e7b4292SVikas Chaudhary 				     (iscsi_func_low > device_map[i].func_num)))
5806e7b4292SVikas Chaudhary 					iscsi_func_low = device_map[i].func_num;
5816e7b4292SVikas Chaudhary 
5826e7b4292SVikas Chaudhary 				iscsi_present++;
5836e7b4292SVikas Chaudhary 			}
5846e7b4292SVikas Chaudhary 		}
5856e7b4292SVikas Chaudhary 
5866e7b4292SVikas Chaudhary 		/* For function_num[8..15] get info from dev_part2 register */
5876e7b4292SVikas Chaudhary 		if (nibble == 7) {
5886e7b4292SVikas Chaudhary 			nibble = 0;
5896e7b4292SVikas Chaudhary 			dev_part = dev_part2;
5906e7b4292SVikas Chaudhary 		}
5916e7b4292SVikas Chaudhary 	}
5926e7b4292SVikas Chaudhary 
5936e7b4292SVikas Chaudhary 	/* NIC, iSCSI and FCOE are the Reset owners based on order, NIC gets
5946e7b4292SVikas Chaudhary 	 * precedence over iSCSI and FCOE and iSCSI over FCOE, based on drivers
5956e7b4292SVikas Chaudhary 	 * present. */
5966e7b4292SVikas Chaudhary 	if (!nic_present && (ha->func_num == iscsi_func_low)) {
5976e7b4292SVikas Chaudhary 		DEBUG2(ql4_printk(KERN_INFO, ha,
5986e7b4292SVikas Chaudhary 				  "%s: can reset - NIC not present and lower iSCSI function is %d\n",
5996e7b4292SVikas Chaudhary 				  __func__, ha->func_num));
6006e7b4292SVikas Chaudhary 		return 1;
6016e7b4292SVikas Chaudhary 	}
6026e7b4292SVikas Chaudhary 
6036e7b4292SVikas Chaudhary 	return 0;
6046e7b4292SVikas Chaudhary }
6056e7b4292SVikas Chaudhary 
6066e7b4292SVikas Chaudhary /**
6076e7b4292SVikas Chaudhary  * qla4_83xx_need_reset_handler - Code to start reset sequence
6086e7b4292SVikas Chaudhary  * @ha: pointer to adapter structure
6096e7b4292SVikas Chaudhary  *
6106e7b4292SVikas Chaudhary  * Note: IDC lock must be held upon entry
6116e7b4292SVikas Chaudhary  **/
6126e7b4292SVikas Chaudhary void qla4_83xx_need_reset_handler(struct scsi_qla_host *ha)
6136e7b4292SVikas Chaudhary {
6146e7b4292SVikas Chaudhary 	uint32_t dev_state, drv_state, drv_active;
6156e7b4292SVikas Chaudhary 	unsigned long reset_timeout, dev_init_timeout;
6166e7b4292SVikas Chaudhary 
6176e7b4292SVikas Chaudhary 	ql4_printk(KERN_INFO, ha, "%s: Performing ISP error recovery\n",
6186e7b4292SVikas Chaudhary 		   __func__);
6196e7b4292SVikas Chaudhary 
6206e7b4292SVikas Chaudhary 	if (!test_bit(AF_8XXX_RST_OWNER, &ha->flags)) {
6216e7b4292SVikas Chaudhary 		DEBUG2(ql4_printk(KERN_INFO, ha, "%s: reset acknowledged\n",
6226e7b4292SVikas Chaudhary 				  __func__));
6236e7b4292SVikas Chaudhary 		qla4_8xxx_set_rst_ready(ha);
6246e7b4292SVikas Chaudhary 
6256e7b4292SVikas Chaudhary 		/* Non-reset owners ACK Reset and wait for device INIT state
6266e7b4292SVikas Chaudhary 		 * as part of Reset Recovery by Reset Owner */
6276e7b4292SVikas Chaudhary 		dev_init_timeout = jiffies + (ha->nx_dev_init_timeout * HZ);
6286e7b4292SVikas Chaudhary 
6296e7b4292SVikas Chaudhary 		do {
6306e7b4292SVikas Chaudhary 			if (time_after_eq(jiffies, dev_init_timeout)) {
6316e7b4292SVikas Chaudhary 				ql4_printk(KERN_INFO, ha, "%s: Non Reset owner dev init timeout\n",
6326e7b4292SVikas Chaudhary 					   __func__);
6336e7b4292SVikas Chaudhary 				break;
6346e7b4292SVikas Chaudhary 			}
6356e7b4292SVikas Chaudhary 
6366e7b4292SVikas Chaudhary 			ha->isp_ops->idc_unlock(ha);
6376e7b4292SVikas Chaudhary 			msleep(1000);
6386e7b4292SVikas Chaudhary 			ha->isp_ops->idc_lock(ha);
6396e7b4292SVikas Chaudhary 
6406e7b4292SVikas Chaudhary 			dev_state = qla4_8xxx_rd_direct(ha,
6416e7b4292SVikas Chaudhary 							QLA8XXX_CRB_DEV_STATE);
6426e7b4292SVikas Chaudhary 		} while (dev_state == QLA8XXX_DEV_NEED_RESET);
6436e7b4292SVikas Chaudhary 	} else {
6446e7b4292SVikas Chaudhary 		qla4_8xxx_set_rst_ready(ha);
6456e7b4292SVikas Chaudhary 		reset_timeout = jiffies + (ha->nx_reset_timeout * HZ);
6466e7b4292SVikas Chaudhary 		drv_state = qla4_8xxx_rd_direct(ha, QLA8XXX_CRB_DRV_STATE);
6476e7b4292SVikas Chaudhary 		drv_active = qla4_8xxx_rd_direct(ha, QLA8XXX_CRB_DRV_ACTIVE);
6486e7b4292SVikas Chaudhary 
6496e7b4292SVikas Chaudhary 		ql4_printk(KERN_INFO, ha, "%s: drv_state = 0x%x, drv_active = 0x%x\n",
6506e7b4292SVikas Chaudhary 			   __func__, drv_state, drv_active);
6516e7b4292SVikas Chaudhary 
6526e7b4292SVikas Chaudhary 		while (drv_state != drv_active) {
6536e7b4292SVikas Chaudhary 			if (time_after_eq(jiffies, reset_timeout)) {
6546e7b4292SVikas Chaudhary 				ql4_printk(KERN_INFO, ha, "%s: %s: RESET TIMEOUT! drv_state: 0x%08x, drv_active: 0x%08x\n",
6556e7b4292SVikas Chaudhary 					   __func__, DRIVER_NAME, drv_state,
6566e7b4292SVikas Chaudhary 					   drv_active);
6576e7b4292SVikas Chaudhary 				break;
6586e7b4292SVikas Chaudhary 			}
6596e7b4292SVikas Chaudhary 
6606e7b4292SVikas Chaudhary 			ha->isp_ops->idc_unlock(ha);
6616e7b4292SVikas Chaudhary 			msleep(1000);
6626e7b4292SVikas Chaudhary 			ha->isp_ops->idc_lock(ha);
6636e7b4292SVikas Chaudhary 
6646e7b4292SVikas Chaudhary 			drv_state = qla4_8xxx_rd_direct(ha,
6656e7b4292SVikas Chaudhary 							QLA8XXX_CRB_DRV_STATE);
6666e7b4292SVikas Chaudhary 			drv_active = qla4_8xxx_rd_direct(ha,
6676e7b4292SVikas Chaudhary 							QLA8XXX_CRB_DRV_ACTIVE);
6686e7b4292SVikas Chaudhary 		}
6696e7b4292SVikas Chaudhary 
6706e7b4292SVikas Chaudhary 		if (drv_state != drv_active) {
6716e7b4292SVikas Chaudhary 			ql4_printk(KERN_INFO, ha, "%s: Reset_owner turning off drv_active of non-acking function 0x%x\n",
6726e7b4292SVikas Chaudhary 				   __func__, (drv_active ^ drv_state));
6736e7b4292SVikas Chaudhary 			drv_active = drv_active & drv_state;
6746e7b4292SVikas Chaudhary 			qla4_8xxx_wr_direct(ha, QLA8XXX_CRB_DRV_ACTIVE,
6756e7b4292SVikas Chaudhary 					    drv_active);
6766e7b4292SVikas Chaudhary 		}
6776e7b4292SVikas Chaudhary 
6786e7b4292SVikas Chaudhary 		clear_bit(AF_8XXX_RST_OWNER, &ha->flags);
6796e7b4292SVikas Chaudhary 		/* Start Reset Recovery */
6806e7b4292SVikas Chaudhary 		qla4_8xxx_device_bootstrap(ha);
6816e7b4292SVikas Chaudhary 	}
6826e7b4292SVikas Chaudhary }
6836e7b4292SVikas Chaudhary 
6846e7b4292SVikas Chaudhary void qla4_83xx_get_idc_param(struct scsi_qla_host *ha)
6856e7b4292SVikas Chaudhary {
6866e7b4292SVikas Chaudhary 	uint32_t idc_params, ret_val;
6876e7b4292SVikas Chaudhary 
6886e7b4292SVikas Chaudhary 	ret_val = qla4_83xx_flash_read_u32(ha, QLA83XX_IDC_PARAM_ADDR,
6896e7b4292SVikas Chaudhary 					   (uint8_t *)&idc_params, 1);
6906e7b4292SVikas Chaudhary 	if (ret_val == QLA_SUCCESS) {
6916e7b4292SVikas Chaudhary 		ha->nx_dev_init_timeout = idc_params & 0xFFFF;
6926e7b4292SVikas Chaudhary 		ha->nx_reset_timeout = (idc_params >> 16) & 0xFFFF;
6936e7b4292SVikas Chaudhary 	} else {
6946e7b4292SVikas Chaudhary 		ha->nx_dev_init_timeout = ROM_DEV_INIT_TIMEOUT;
6956e7b4292SVikas Chaudhary 		ha->nx_reset_timeout = ROM_DRV_RESET_ACK_TIMEOUT;
6966e7b4292SVikas Chaudhary 	}
6976e7b4292SVikas Chaudhary 
6986e7b4292SVikas Chaudhary 	DEBUG2(ql4_printk(KERN_DEBUG, ha,
6996e7b4292SVikas Chaudhary 			  "%s: ha->nx_dev_init_timeout = %d, ha->nx_reset_timeout = %d\n",
7006e7b4292SVikas Chaudhary 			  __func__, ha->nx_dev_init_timeout,
7016e7b4292SVikas Chaudhary 			  ha->nx_reset_timeout));
7026e7b4292SVikas Chaudhary }
7036e7b4292SVikas Chaudhary 
7046e7b4292SVikas Chaudhary /*-------------------------Reset Sequence Functions-----------------------*/
7056e7b4292SVikas Chaudhary 
7066e7b4292SVikas Chaudhary static void qla4_83xx_dump_reset_seq_hdr(struct scsi_qla_host *ha)
7076e7b4292SVikas Chaudhary {
7086e7b4292SVikas Chaudhary 	uint8_t *phdr;
7096e7b4292SVikas Chaudhary 
7106e7b4292SVikas Chaudhary 	if (!ha->reset_tmplt.buff) {
7116e7b4292SVikas Chaudhary 		ql4_printk(KERN_ERR, ha, "%s: Error: Invalid reset_seq_template\n",
7126e7b4292SVikas Chaudhary 			   __func__);
7136e7b4292SVikas Chaudhary 		return;
7146e7b4292SVikas Chaudhary 	}
7156e7b4292SVikas Chaudhary 
7166e7b4292SVikas Chaudhary 	phdr = ha->reset_tmplt.buff;
7176e7b4292SVikas Chaudhary 
7186e7b4292SVikas Chaudhary 	DEBUG2(ql4_printk(KERN_INFO, ha,
7196e7b4292SVikas 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",
7206e7b4292SVikas Chaudhary 			  *phdr, *(phdr+1), *(phdr+2), *(phdr+3), *(phdr+4),
7216e7b4292SVikas Chaudhary 			  *(phdr+5), *(phdr+6), *(phdr+7), *(phdr + 8),
7226e7b4292SVikas Chaudhary 			  *(phdr+9), *(phdr+10), *(phdr+11), *(phdr+12),
7236e7b4292SVikas Chaudhary 			  *(phdr+13), *(phdr+14), *(phdr+15)));
7246e7b4292SVikas Chaudhary }
7256e7b4292SVikas Chaudhary 
7266e7b4292SVikas Chaudhary static int qla4_83xx_copy_bootloader(struct scsi_qla_host *ha)
7276e7b4292SVikas Chaudhary {
7286e7b4292SVikas Chaudhary 	uint8_t *p_cache;
7296e7b4292SVikas Chaudhary 	uint32_t src, count, size;
7306e7b4292SVikas Chaudhary 	uint64_t dest;
7316e7b4292SVikas Chaudhary 	int ret_val = QLA_SUCCESS;
7326e7b4292SVikas Chaudhary 
7336e7b4292SVikas Chaudhary 	src = QLA83XX_BOOTLOADER_FLASH_ADDR;
7346e7b4292SVikas Chaudhary 	dest = qla4_83xx_rd_reg(ha, QLA83XX_BOOTLOADER_ADDR);
7356e7b4292SVikas Chaudhary 	size = qla4_83xx_rd_reg(ha, QLA83XX_BOOTLOADER_SIZE);
7366e7b4292SVikas Chaudhary 
7376e7b4292SVikas Chaudhary 	/* 128 bit alignment check */
7386e7b4292SVikas Chaudhary 	if (size & 0xF)
7396e7b4292SVikas Chaudhary 		size = (size + 16) & ~0xF;
7406e7b4292SVikas Chaudhary 
7416e7b4292SVikas Chaudhary 	/* 16 byte count */
7426e7b4292SVikas Chaudhary 	count = size/16;
7436e7b4292SVikas Chaudhary 
7446e7b4292SVikas Chaudhary 	p_cache = vmalloc(size);
7456e7b4292SVikas Chaudhary 	if (p_cache == NULL) {
7466e7b4292SVikas Chaudhary 		ql4_printk(KERN_ERR, ha, "%s: Failed to allocate memory for boot loader cache\n",
7476e7b4292SVikas Chaudhary 			   __func__);
7486e7b4292SVikas Chaudhary 		ret_val = QLA_ERROR;
7496e7b4292SVikas Chaudhary 		goto exit_copy_bootloader;
7506e7b4292SVikas Chaudhary 	}
7516e7b4292SVikas Chaudhary 
7526e7b4292SVikas Chaudhary 	ret_val = qla4_83xx_lockless_flash_read_u32(ha, src, p_cache,
7536e7b4292SVikas Chaudhary 						    size / sizeof(uint32_t));
7546e7b4292SVikas Chaudhary 	if (ret_val == QLA_ERROR) {
7556e7b4292SVikas Chaudhary 		ql4_printk(KERN_ERR, ha, "%s: Error reading firmware from flash\n",
7566e7b4292SVikas Chaudhary 			   __func__);
7576e7b4292SVikas Chaudhary 		goto exit_copy_error;
7586e7b4292SVikas Chaudhary 	}
7596e7b4292SVikas Chaudhary 	DEBUG2(ql4_printk(KERN_INFO, ha, "%s: Read firmware from flash\n",
7606e7b4292SVikas Chaudhary 			  __func__));
7616e7b4292SVikas Chaudhary 
7626e7b4292SVikas Chaudhary 	/* 128 bit/16 byte write to MS memory */
7636e7b4292SVikas Chaudhary 	ret_val = qla4_83xx_ms_mem_write_128b(ha, dest, (uint32_t *)p_cache,
7646e7b4292SVikas Chaudhary 					      count);
7656e7b4292SVikas Chaudhary 	if (ret_val == QLA_ERROR) {
7666e7b4292SVikas Chaudhary 		ql4_printk(KERN_ERR, ha, "%s: Error writing firmware to MS\n",
7676e7b4292SVikas Chaudhary 			   __func__);
7686e7b4292SVikas Chaudhary 		goto exit_copy_error;
7696e7b4292SVikas Chaudhary 	}
7706e7b4292SVikas Chaudhary 
7716e7b4292SVikas Chaudhary 	DEBUG2(ql4_printk(KERN_INFO, ha, "%s: Wrote firmware size %d to MS\n",
7726e7b4292SVikas Chaudhary 			  __func__, size));
7736e7b4292SVikas Chaudhary 
7746e7b4292SVikas Chaudhary exit_copy_error:
7756e7b4292SVikas Chaudhary 	vfree(p_cache);
7766e7b4292SVikas Chaudhary 
7776e7b4292SVikas Chaudhary exit_copy_bootloader:
7786e7b4292SVikas Chaudhary 	return ret_val;
7796e7b4292SVikas Chaudhary }
7806e7b4292SVikas Chaudhary 
7816e7b4292SVikas Chaudhary static int qla4_83xx_check_cmd_peg_status(struct scsi_qla_host *ha)
7826e7b4292SVikas Chaudhary {
7836e7b4292SVikas Chaudhary 	uint32_t val, ret_val = QLA_ERROR;
7846e7b4292SVikas Chaudhary 	int retries = CRB_CMDPEG_CHECK_RETRY_COUNT;
7856e7b4292SVikas Chaudhary 
7866e7b4292SVikas Chaudhary 	do {
7876e7b4292SVikas Chaudhary 		val = qla4_83xx_rd_reg(ha, QLA83XX_CMDPEG_STATE);
7886e7b4292SVikas Chaudhary 		if (val == PHAN_INITIALIZE_COMPLETE) {
7896e7b4292SVikas Chaudhary 			DEBUG2(ql4_printk(KERN_INFO, ha,
7906e7b4292SVikas Chaudhary 					  "%s: Command Peg initialization complete. State=0x%x\n",
7916e7b4292SVikas Chaudhary 					  __func__, val));
7926e7b4292SVikas Chaudhary 			ret_val = QLA_SUCCESS;
7936e7b4292SVikas Chaudhary 			break;
7946e7b4292SVikas Chaudhary 		}
7956e7b4292SVikas Chaudhary 		msleep(CRB_CMDPEG_CHECK_DELAY);
7966e7b4292SVikas Chaudhary 	} while (--retries);
7976e7b4292SVikas Chaudhary 
7986e7b4292SVikas Chaudhary 	return ret_val;
7996e7b4292SVikas Chaudhary }
8006e7b4292SVikas Chaudhary 
8016e7b4292SVikas Chaudhary /**
8026e7b4292SVikas Chaudhary  * qla4_83xx_poll_reg - Poll the given CRB addr for duration msecs till
8036e7b4292SVikas Chaudhary  * value read ANDed with test_mask is equal to test_result.
8046e7b4292SVikas Chaudhary  *
8056e7b4292SVikas Chaudhary  * @ha : Pointer to adapter structure
8066e7b4292SVikas Chaudhary  * @addr : CRB register address
8076e7b4292SVikas Chaudhary  * @duration : Poll for total of "duration" msecs
8086e7b4292SVikas Chaudhary  * @test_mask : Mask value read with "test_mask"
8096e7b4292SVikas Chaudhary  * @test_result : Compare (value&test_mask) with test_result.
8106e7b4292SVikas Chaudhary  **/
8116e7b4292SVikas Chaudhary static int qla4_83xx_poll_reg(struct scsi_qla_host *ha, uint32_t addr,
8126e7b4292SVikas Chaudhary 			      int duration, uint32_t test_mask,
8136e7b4292SVikas Chaudhary 			      uint32_t test_result)
8146e7b4292SVikas Chaudhary {
8156e7b4292SVikas Chaudhary 	uint32_t value;
8166e7b4292SVikas Chaudhary 	uint8_t retries;
8176e7b4292SVikas Chaudhary 	int ret_val = QLA_SUCCESS;
8186e7b4292SVikas Chaudhary 
8196e7b4292SVikas Chaudhary 	ret_val = qla4_83xx_rd_reg_indirect(ha, addr, &value);
8206e7b4292SVikas Chaudhary 	if (ret_val == QLA_ERROR)
8216e7b4292SVikas Chaudhary 		goto exit_poll_reg;
8226e7b4292SVikas Chaudhary 
8236e7b4292SVikas Chaudhary 	retries = duration / 10;
8246e7b4292SVikas Chaudhary 	do {
8256e7b4292SVikas Chaudhary 		if ((value & test_mask) != test_result) {
8266e7b4292SVikas Chaudhary 			msleep(duration / 10);
8276e7b4292SVikas Chaudhary 			ret_val = qla4_83xx_rd_reg_indirect(ha, addr, &value);
8286e7b4292SVikas Chaudhary 			if (ret_val == QLA_ERROR)
8296e7b4292SVikas Chaudhary 				goto exit_poll_reg;
8306e7b4292SVikas Chaudhary 
8316e7b4292SVikas Chaudhary 			ret_val = QLA_ERROR;
8326e7b4292SVikas Chaudhary 		} else {
8336e7b4292SVikas Chaudhary 			ret_val = QLA_SUCCESS;
8346e7b4292SVikas Chaudhary 			break;
8356e7b4292SVikas Chaudhary 		}
8366e7b4292SVikas Chaudhary 	} while (retries--);
8376e7b4292SVikas Chaudhary 
8386e7b4292SVikas Chaudhary exit_poll_reg:
8396e7b4292SVikas Chaudhary 	if (ret_val == QLA_ERROR) {
8406e7b4292SVikas Chaudhary 		ha->reset_tmplt.seq_error++;
8416e7b4292SVikas Chaudhary 		ql4_printk(KERN_ERR, ha, "%s: Poll Failed:  0x%08x 0x%08x 0x%08x\n",
8426e7b4292SVikas Chaudhary 			   __func__, value, test_mask, test_result);
8436e7b4292SVikas Chaudhary 	}
8446e7b4292SVikas Chaudhary 
8456e7b4292SVikas Chaudhary 	return ret_val;
8466e7b4292SVikas Chaudhary }
8476e7b4292SVikas Chaudhary 
8486e7b4292SVikas Chaudhary static int qla4_83xx_reset_seq_checksum_test(struct scsi_qla_host *ha)
8496e7b4292SVikas Chaudhary {
8506e7b4292SVikas Chaudhary 	uint32_t sum =  0;
8516e7b4292SVikas Chaudhary 	uint16_t *buff = (uint16_t *)ha->reset_tmplt.buff;
8526e7b4292SVikas Chaudhary 	int u16_count =  ha->reset_tmplt.hdr->size / sizeof(uint16_t);
8536e7b4292SVikas Chaudhary 	int ret_val;
8546e7b4292SVikas Chaudhary 
8556e7b4292SVikas Chaudhary 	while (u16_count-- > 0)
8566e7b4292SVikas Chaudhary 		sum += *buff++;
8576e7b4292SVikas Chaudhary 
8586e7b4292SVikas Chaudhary 	while (sum >> 16)
8596e7b4292SVikas Chaudhary 		sum = (sum & 0xFFFF) +  (sum >> 16);
8606e7b4292SVikas Chaudhary 
8616e7b4292SVikas Chaudhary 	/* checksum of 0 indicates a valid template */
8626e7b4292SVikas Chaudhary 	if (~sum) {
8636e7b4292SVikas Chaudhary 		ret_val = QLA_SUCCESS;
8646e7b4292SVikas Chaudhary 	} else {
8656e7b4292SVikas Chaudhary 		ql4_printk(KERN_ERR, ha, "%s: Reset seq checksum failed\n",
8666e7b4292SVikas Chaudhary 			   __func__);
8676e7b4292SVikas Chaudhary 		ret_val = QLA_ERROR;
8686e7b4292SVikas Chaudhary 	}
8696e7b4292SVikas Chaudhary 
8706e7b4292SVikas Chaudhary 	return ret_val;
8716e7b4292SVikas Chaudhary }
8726e7b4292SVikas Chaudhary 
8736e7b4292SVikas Chaudhary /**
8746e7b4292SVikas Chaudhary  * qla4_83xx_read_reset_template - Read Reset Template from Flash
8756e7b4292SVikas Chaudhary  * @ha: Pointer to adapter structure
8766e7b4292SVikas Chaudhary  **/
8776e7b4292SVikas Chaudhary void qla4_83xx_read_reset_template(struct scsi_qla_host *ha)
8786e7b4292SVikas Chaudhary {
8796e7b4292SVikas Chaudhary 	uint8_t *p_buff;
8806e7b4292SVikas Chaudhary 	uint32_t addr, tmplt_hdr_def_size, tmplt_hdr_size;
8816e7b4292SVikas Chaudhary 	uint32_t ret_val;
8826e7b4292SVikas Chaudhary 
8836e7b4292SVikas Chaudhary 	ha->reset_tmplt.seq_error = 0;
8846e7b4292SVikas Chaudhary 	ha->reset_tmplt.buff = vmalloc(QLA83XX_RESTART_TEMPLATE_SIZE);
8856e7b4292SVikas Chaudhary 	if (ha->reset_tmplt.buff == NULL) {
8866e7b4292SVikas Chaudhary 		ql4_printk(KERN_ERR, ha, "%s: Failed to allocate reset template resources\n",
8876e7b4292SVikas Chaudhary 			   __func__);
8886e7b4292SVikas Chaudhary 		goto exit_read_reset_template;
8896e7b4292SVikas Chaudhary 	}
8906e7b4292SVikas Chaudhary 
8916e7b4292SVikas Chaudhary 	p_buff = ha->reset_tmplt.buff;
8926e7b4292SVikas Chaudhary 	addr = QLA83XX_RESET_TEMPLATE_ADDR;
8936e7b4292SVikas Chaudhary 
8946e7b4292SVikas Chaudhary 	tmplt_hdr_def_size = sizeof(struct qla4_83xx_reset_template_hdr) /
8956e7b4292SVikas Chaudhary 				    sizeof(uint32_t);
8966e7b4292SVikas Chaudhary 
8976e7b4292SVikas Chaudhary 	DEBUG2(ql4_printk(KERN_INFO, ha,
8986e7b4292SVikas Chaudhary 			  "%s: Read template hdr size %d from Flash\n",
8996e7b4292SVikas Chaudhary 			  __func__, tmplt_hdr_def_size));
9006e7b4292SVikas Chaudhary 
9016e7b4292SVikas Chaudhary 	/* Copy template header from flash */
9026e7b4292SVikas Chaudhary 	ret_val = qla4_83xx_flash_read_u32(ha, addr, p_buff,
9036e7b4292SVikas Chaudhary 					   tmplt_hdr_def_size);
9046e7b4292SVikas Chaudhary 	if (ret_val != QLA_SUCCESS) {
9056e7b4292SVikas Chaudhary 		ql4_printk(KERN_ERR, ha, "%s: Failed to read reset template\n",
9066e7b4292SVikas Chaudhary 			   __func__);
9076e7b4292SVikas Chaudhary 		goto exit_read_template_error;
9086e7b4292SVikas Chaudhary 	}
9096e7b4292SVikas Chaudhary 
9106e7b4292SVikas Chaudhary 	ha->reset_tmplt.hdr =
9116e7b4292SVikas Chaudhary 		(struct qla4_83xx_reset_template_hdr *)ha->reset_tmplt.buff;
9126e7b4292SVikas Chaudhary 
9136e7b4292SVikas Chaudhary 	/* Validate the template header size and signature */
9146e7b4292SVikas Chaudhary 	tmplt_hdr_size = ha->reset_tmplt.hdr->hdr_size/sizeof(uint32_t);
9156e7b4292SVikas Chaudhary 	if ((tmplt_hdr_size != tmplt_hdr_def_size) ||
9166e7b4292SVikas Chaudhary 	    (ha->reset_tmplt.hdr->signature != RESET_TMPLT_HDR_SIGNATURE)) {
9176e7b4292SVikas Chaudhary 		ql4_printk(KERN_ERR, ha, "%s: Template Header size %d is invalid, tmplt_hdr_def_size %d\n",
9186e7b4292SVikas Chaudhary 			   __func__, tmplt_hdr_size, tmplt_hdr_def_size);
9196e7b4292SVikas Chaudhary 		goto exit_read_template_error;
9206e7b4292SVikas Chaudhary 	}
9216e7b4292SVikas Chaudhary 
9226e7b4292SVikas Chaudhary 	addr = QLA83XX_RESET_TEMPLATE_ADDR + ha->reset_tmplt.hdr->hdr_size;
9236e7b4292SVikas Chaudhary 	p_buff = ha->reset_tmplt.buff + ha->reset_tmplt.hdr->hdr_size;
9246e7b4292SVikas Chaudhary 	tmplt_hdr_def_size = (ha->reset_tmplt.hdr->size -
9256e7b4292SVikas Chaudhary 			      ha->reset_tmplt.hdr->hdr_size) / sizeof(uint32_t);
9266e7b4292SVikas Chaudhary 
9276e7b4292SVikas Chaudhary 	DEBUG2(ql4_printk(KERN_INFO, ha,
9286e7b4292SVikas Chaudhary 			  "%s: Read rest of the template size %d\n",
9296e7b4292SVikas Chaudhary 			  __func__, ha->reset_tmplt.hdr->size));
9306e7b4292SVikas Chaudhary 
9316e7b4292SVikas Chaudhary 	/* Copy rest of the template */
9326e7b4292SVikas Chaudhary 	ret_val = qla4_83xx_flash_read_u32(ha, addr, p_buff,
9336e7b4292SVikas Chaudhary 					   tmplt_hdr_def_size);
9346e7b4292SVikas Chaudhary 	if (ret_val != QLA_SUCCESS) {
9356e7b4292SVikas Chaudhary 		ql4_printk(KERN_ERR, ha, "%s: Failed to read reset tempelate\n",
9366e7b4292SVikas Chaudhary 			   __func__);
9376e7b4292SVikas Chaudhary 		goto exit_read_template_error;
9386e7b4292SVikas Chaudhary 	}
9396e7b4292SVikas Chaudhary 
9406e7b4292SVikas Chaudhary 	/* Integrity check */
9416e7b4292SVikas Chaudhary 	if (qla4_83xx_reset_seq_checksum_test(ha)) {
9426e7b4292SVikas Chaudhary 		ql4_printk(KERN_ERR, ha, "%s: Reset Seq checksum failed!\n",
9436e7b4292SVikas Chaudhary 			   __func__);
9446e7b4292SVikas Chaudhary 		goto exit_read_template_error;
9456e7b4292SVikas Chaudhary 	}
9466e7b4292SVikas Chaudhary 	DEBUG2(ql4_printk(KERN_INFO, ha,
9476e7b4292SVikas Chaudhary 			  "%s: Reset Seq checksum passed, Get stop, start and init seq offsets\n",
9486e7b4292SVikas Chaudhary 			  __func__));
9496e7b4292SVikas Chaudhary 
9506e7b4292SVikas Chaudhary 	/* Get STOP, START, INIT sequence offsets */
9516e7b4292SVikas Chaudhary 	ha->reset_tmplt.init_offset = ha->reset_tmplt.buff +
9526e7b4292SVikas Chaudhary 				      ha->reset_tmplt.hdr->init_seq_offset;
9536e7b4292SVikas Chaudhary 	ha->reset_tmplt.start_offset = ha->reset_tmplt.buff +
9546e7b4292SVikas Chaudhary 				       ha->reset_tmplt.hdr->start_seq_offset;
9556e7b4292SVikas Chaudhary 	ha->reset_tmplt.stop_offset = ha->reset_tmplt.buff +
9566e7b4292SVikas Chaudhary 				      ha->reset_tmplt.hdr->hdr_size;
9576e7b4292SVikas Chaudhary 	qla4_83xx_dump_reset_seq_hdr(ha);
9586e7b4292SVikas Chaudhary 
9596e7b4292SVikas Chaudhary 	goto exit_read_reset_template;
9606e7b4292SVikas Chaudhary 
9616e7b4292SVikas Chaudhary exit_read_template_error:
9626e7b4292SVikas Chaudhary 	vfree(ha->reset_tmplt.buff);
9636e7b4292SVikas Chaudhary 
9646e7b4292SVikas Chaudhary exit_read_reset_template:
9656e7b4292SVikas Chaudhary 	return;
9666e7b4292SVikas Chaudhary }
9676e7b4292SVikas Chaudhary 
9686e7b4292SVikas Chaudhary /**
9696e7b4292SVikas Chaudhary  * qla4_83xx_read_write_crb_reg - Read from raddr and write value to waddr.
9706e7b4292SVikas Chaudhary  *
9716e7b4292SVikas Chaudhary  * @ha : Pointer to adapter structure
9726e7b4292SVikas Chaudhary  * @raddr : CRB address to read from
9736e7b4292SVikas Chaudhary  * @waddr : CRB address to write to
9746e7b4292SVikas Chaudhary  **/
9756e7b4292SVikas Chaudhary static void qla4_83xx_read_write_crb_reg(struct scsi_qla_host *ha,
9766e7b4292SVikas Chaudhary 					 uint32_t raddr, uint32_t waddr)
9776e7b4292SVikas Chaudhary {
9786e7b4292SVikas Chaudhary 	uint32_t value;
9796e7b4292SVikas Chaudhary 
9806e7b4292SVikas Chaudhary 	qla4_83xx_rd_reg_indirect(ha, raddr, &value);
9816e7b4292SVikas Chaudhary 	qla4_83xx_wr_reg_indirect(ha, waddr, value);
9826e7b4292SVikas Chaudhary }
9836e7b4292SVikas Chaudhary 
9846e7b4292SVikas Chaudhary /**
9856e7b4292SVikas Chaudhary  * qla4_83xx_rmw_crb_reg - Read Modify Write crb register
9866e7b4292SVikas Chaudhary  *
9876e7b4292SVikas Chaudhary  * This function read value from raddr, AND with test_mask,
9886e7b4292SVikas Chaudhary  * Shift Left,Right/OR/XOR with values RMW header and write value to waddr.
9896e7b4292SVikas Chaudhary  *
9906e7b4292SVikas Chaudhary  * @ha : Pointer to adapter structure
9916e7b4292SVikas Chaudhary  * @raddr : CRB address to read from
9926e7b4292SVikas Chaudhary  * @waddr : CRB address to write to
9936e7b4292SVikas Chaudhary  * @p_rmw_hdr : header with shift/or/xor values.
9946e7b4292SVikas Chaudhary  **/
9956e7b4292SVikas Chaudhary static void qla4_83xx_rmw_crb_reg(struct scsi_qla_host *ha, uint32_t raddr,
9966e7b4292SVikas Chaudhary 				  uint32_t waddr,
9976e7b4292SVikas Chaudhary 				  struct qla4_83xx_rmw *p_rmw_hdr)
9986e7b4292SVikas Chaudhary {
9996e7b4292SVikas Chaudhary 	uint32_t value;
10006e7b4292SVikas Chaudhary 
10016e7b4292SVikas Chaudhary 	if (p_rmw_hdr->index_a)
10026e7b4292SVikas Chaudhary 		value = ha->reset_tmplt.array[p_rmw_hdr->index_a];
10036e7b4292SVikas Chaudhary 	else
10046e7b4292SVikas Chaudhary 		qla4_83xx_rd_reg_indirect(ha, raddr, &value);
10056e7b4292SVikas Chaudhary 
10066e7b4292SVikas Chaudhary 	value &= p_rmw_hdr->test_mask;
10076e7b4292SVikas Chaudhary 	value <<= p_rmw_hdr->shl;
10086e7b4292SVikas Chaudhary 	value >>= p_rmw_hdr->shr;
10096e7b4292SVikas Chaudhary 	value |= p_rmw_hdr->or_value;
10106e7b4292SVikas Chaudhary 	value ^= p_rmw_hdr->xor_value;
10116e7b4292SVikas Chaudhary 
10126e7b4292SVikas Chaudhary 	qla4_83xx_wr_reg_indirect(ha, waddr, value);
10136e7b4292SVikas Chaudhary 
10146e7b4292SVikas Chaudhary 	return;
10156e7b4292SVikas Chaudhary }
10166e7b4292SVikas Chaudhary 
10176e7b4292SVikas Chaudhary static void qla4_83xx_write_list(struct scsi_qla_host *ha,
10186e7b4292SVikas Chaudhary 				 struct qla4_83xx_reset_entry_hdr *p_hdr)
10196e7b4292SVikas Chaudhary {
10206e7b4292SVikas Chaudhary 	struct qla4_83xx_entry *p_entry;
10216e7b4292SVikas Chaudhary 	uint32_t i;
10226e7b4292SVikas Chaudhary 
10236e7b4292SVikas Chaudhary 	p_entry = (struct qla4_83xx_entry *)
10246e7b4292SVikas Chaudhary 		  ((char *)p_hdr + sizeof(struct qla4_83xx_reset_entry_hdr));
10256e7b4292SVikas Chaudhary 
10266e7b4292SVikas Chaudhary 	for (i = 0; i < p_hdr->count; i++, p_entry++) {
10276e7b4292SVikas Chaudhary 		qla4_83xx_wr_reg_indirect(ha, p_entry->arg1, p_entry->arg2);
10286e7b4292SVikas Chaudhary 		if (p_hdr->delay)
10296e7b4292SVikas Chaudhary 			udelay((uint32_t)(p_hdr->delay));
10306e7b4292SVikas Chaudhary 	}
10316e7b4292SVikas Chaudhary }
10326e7b4292SVikas Chaudhary 
10336e7b4292SVikas Chaudhary static void qla4_83xx_read_write_list(struct scsi_qla_host *ha,
10346e7b4292SVikas Chaudhary 				      struct qla4_83xx_reset_entry_hdr *p_hdr)
10356e7b4292SVikas Chaudhary {
10366e7b4292SVikas Chaudhary 	struct qla4_83xx_entry *p_entry;
10376e7b4292SVikas Chaudhary 	uint32_t i;
10386e7b4292SVikas Chaudhary 
10396e7b4292SVikas Chaudhary 	p_entry = (struct qla4_83xx_entry *)
10406e7b4292SVikas Chaudhary 		  ((char *)p_hdr + sizeof(struct qla4_83xx_reset_entry_hdr));
10416e7b4292SVikas Chaudhary 
10426e7b4292SVikas Chaudhary 	for (i = 0; i < p_hdr->count; i++, p_entry++) {
10436e7b4292SVikas Chaudhary 		qla4_83xx_read_write_crb_reg(ha, p_entry->arg1, p_entry->arg2);
10446e7b4292SVikas Chaudhary 		if (p_hdr->delay)
10456e7b4292SVikas Chaudhary 			udelay((uint32_t)(p_hdr->delay));
10466e7b4292SVikas Chaudhary 	}
10476e7b4292SVikas Chaudhary }
10486e7b4292SVikas Chaudhary 
10496e7b4292SVikas Chaudhary static void qla4_83xx_poll_list(struct scsi_qla_host *ha,
10506e7b4292SVikas Chaudhary 				struct qla4_83xx_reset_entry_hdr *p_hdr)
10516e7b4292SVikas Chaudhary {
10526e7b4292SVikas Chaudhary 	long delay;
10536e7b4292SVikas Chaudhary 	struct qla4_83xx_entry *p_entry;
10546e7b4292SVikas Chaudhary 	struct qla4_83xx_poll *p_poll;
10556e7b4292SVikas Chaudhary 	uint32_t i;
10566e7b4292SVikas Chaudhary 	uint32_t value;
10576e7b4292SVikas Chaudhary 
10586e7b4292SVikas Chaudhary 	p_poll = (struct qla4_83xx_poll *)
10596e7b4292SVikas Chaudhary 		 ((char *)p_hdr + sizeof(struct qla4_83xx_reset_entry_hdr));
10606e7b4292SVikas Chaudhary 
10616e7b4292SVikas Chaudhary 	/* Entries start after 8 byte qla4_83xx_poll, poll header contains
10626e7b4292SVikas Chaudhary 	 * the test_mask, test_value. */
10636e7b4292SVikas Chaudhary 	p_entry = (struct qla4_83xx_entry *)((char *)p_poll +
10646e7b4292SVikas Chaudhary 					     sizeof(struct qla4_83xx_poll));
10656e7b4292SVikas Chaudhary 
10666e7b4292SVikas Chaudhary 	delay = (long)p_hdr->delay;
10676e7b4292SVikas Chaudhary 	if (!delay) {
10686e7b4292SVikas Chaudhary 		for (i = 0; i < p_hdr->count; i++, p_entry++) {
10696e7b4292SVikas Chaudhary 			qla4_83xx_poll_reg(ha, p_entry->arg1, delay,
10706e7b4292SVikas Chaudhary 					   p_poll->test_mask,
10716e7b4292SVikas Chaudhary 					   p_poll->test_value);
10726e7b4292SVikas Chaudhary 		}
10736e7b4292SVikas Chaudhary 	} else {
10746e7b4292SVikas Chaudhary 		for (i = 0; i < p_hdr->count; i++, p_entry++) {
10756e7b4292SVikas Chaudhary 			if (qla4_83xx_poll_reg(ha, p_entry->arg1, delay,
10766e7b4292SVikas Chaudhary 					       p_poll->test_mask,
10776e7b4292SVikas Chaudhary 					       p_poll->test_value)) {
10786e7b4292SVikas Chaudhary 				qla4_83xx_rd_reg_indirect(ha, p_entry->arg1,
10796e7b4292SVikas Chaudhary 							  &value);
10806e7b4292SVikas Chaudhary 				qla4_83xx_rd_reg_indirect(ha, p_entry->arg2,
10816e7b4292SVikas Chaudhary 							  &value);
10826e7b4292SVikas Chaudhary 			}
10836e7b4292SVikas Chaudhary 		}
10846e7b4292SVikas Chaudhary 	}
10856e7b4292SVikas Chaudhary }
10866e7b4292SVikas Chaudhary 
10876e7b4292SVikas Chaudhary static void qla4_83xx_poll_write_list(struct scsi_qla_host *ha,
10886e7b4292SVikas Chaudhary 				      struct qla4_83xx_reset_entry_hdr *p_hdr)
10896e7b4292SVikas Chaudhary {
10906e7b4292SVikas Chaudhary 	long delay;
10916e7b4292SVikas Chaudhary 	struct qla4_83xx_quad_entry *p_entry;
10926e7b4292SVikas Chaudhary 	struct qla4_83xx_poll *p_poll;
10936e7b4292SVikas Chaudhary 	uint32_t i;
10946e7b4292SVikas Chaudhary 
10956e7b4292SVikas Chaudhary 	p_poll = (struct qla4_83xx_poll *)
10966e7b4292SVikas Chaudhary 		 ((char *)p_hdr + sizeof(struct qla4_83xx_reset_entry_hdr));
10976e7b4292SVikas Chaudhary 	p_entry = (struct qla4_83xx_quad_entry *)
10986e7b4292SVikas Chaudhary 		  ((char *)p_poll + sizeof(struct qla4_83xx_poll));
10996e7b4292SVikas Chaudhary 	delay = (long)p_hdr->delay;
11006e7b4292SVikas Chaudhary 
11016e7b4292SVikas Chaudhary 	for (i = 0; i < p_hdr->count; i++, p_entry++) {
11026e7b4292SVikas Chaudhary 		qla4_83xx_wr_reg_indirect(ha, p_entry->dr_addr,
11036e7b4292SVikas Chaudhary 					  p_entry->dr_value);
11046e7b4292SVikas Chaudhary 		qla4_83xx_wr_reg_indirect(ha, p_entry->ar_addr,
11056e7b4292SVikas Chaudhary 					  p_entry->ar_value);
11066e7b4292SVikas Chaudhary 		if (delay) {
11076e7b4292SVikas Chaudhary 			if (qla4_83xx_poll_reg(ha, p_entry->ar_addr, delay,
11086e7b4292SVikas Chaudhary 					       p_poll->test_mask,
11096e7b4292SVikas Chaudhary 					       p_poll->test_value)) {
11106e7b4292SVikas Chaudhary 				DEBUG2(ql4_printk(KERN_INFO, ha,
11116e7b4292SVikas Chaudhary 						  "%s: Timeout Error: poll list, item_num %d, entry_num %d\n",
11126e7b4292SVikas Chaudhary 						  __func__, i,
11136e7b4292SVikas Chaudhary 						  ha->reset_tmplt.seq_index));
11146e7b4292SVikas Chaudhary 			}
11156e7b4292SVikas Chaudhary 		}
11166e7b4292SVikas Chaudhary 	}
11176e7b4292SVikas Chaudhary }
11186e7b4292SVikas Chaudhary 
11196e7b4292SVikas Chaudhary static void qla4_83xx_read_modify_write(struct scsi_qla_host *ha,
11206e7b4292SVikas Chaudhary 					struct qla4_83xx_reset_entry_hdr *p_hdr)
11216e7b4292SVikas Chaudhary {
11226e7b4292SVikas Chaudhary 	struct qla4_83xx_entry *p_entry;
11236e7b4292SVikas Chaudhary 	struct qla4_83xx_rmw *p_rmw_hdr;
11246e7b4292SVikas Chaudhary 	uint32_t i;
11256e7b4292SVikas Chaudhary 
11266e7b4292SVikas Chaudhary 	p_rmw_hdr = (struct qla4_83xx_rmw *)
11276e7b4292SVikas Chaudhary 		    ((char *)p_hdr + sizeof(struct qla4_83xx_reset_entry_hdr));
11286e7b4292SVikas Chaudhary 	p_entry = (struct qla4_83xx_entry *)
11296e7b4292SVikas Chaudhary 		  ((char *)p_rmw_hdr + sizeof(struct qla4_83xx_rmw));
11306e7b4292SVikas Chaudhary 
11316e7b4292SVikas Chaudhary 	for (i = 0; i < p_hdr->count; i++, p_entry++) {
11326e7b4292SVikas Chaudhary 		qla4_83xx_rmw_crb_reg(ha, p_entry->arg1, p_entry->arg2,
11336e7b4292SVikas Chaudhary 				      p_rmw_hdr);
11346e7b4292SVikas Chaudhary 		if (p_hdr->delay)
11356e7b4292SVikas Chaudhary 			udelay((uint32_t)(p_hdr->delay));
11366e7b4292SVikas Chaudhary 	}
11376e7b4292SVikas Chaudhary }
11386e7b4292SVikas Chaudhary 
11396e7b4292SVikas Chaudhary static void qla4_83xx_pause(struct scsi_qla_host *ha,
11406e7b4292SVikas Chaudhary 			    struct qla4_83xx_reset_entry_hdr *p_hdr)
11416e7b4292SVikas Chaudhary {
11426e7b4292SVikas Chaudhary 	if (p_hdr->delay)
11436e7b4292SVikas Chaudhary 		mdelay((uint32_t)((long)p_hdr->delay));
11446e7b4292SVikas Chaudhary }
11456e7b4292SVikas Chaudhary 
11466e7b4292SVikas Chaudhary static void qla4_83xx_poll_read_list(struct scsi_qla_host *ha,
11476e7b4292SVikas Chaudhary 				     struct qla4_83xx_reset_entry_hdr *p_hdr)
11486e7b4292SVikas Chaudhary {
11496e7b4292SVikas Chaudhary 	long delay;
11506e7b4292SVikas Chaudhary 	int index;
11516e7b4292SVikas Chaudhary 	struct qla4_83xx_quad_entry *p_entry;
11526e7b4292SVikas Chaudhary 	struct qla4_83xx_poll *p_poll;
11536e7b4292SVikas Chaudhary 	uint32_t i;
11546e7b4292SVikas Chaudhary 	uint32_t value;
11556e7b4292SVikas Chaudhary 
11566e7b4292SVikas Chaudhary 	p_poll = (struct qla4_83xx_poll *)
11576e7b4292SVikas Chaudhary 		 ((char *)p_hdr + sizeof(struct qla4_83xx_reset_entry_hdr));
11586e7b4292SVikas Chaudhary 	p_entry = (struct qla4_83xx_quad_entry *)
11596e7b4292SVikas Chaudhary 		  ((char *)p_poll + sizeof(struct qla4_83xx_poll));
11606e7b4292SVikas Chaudhary 	delay = (long)p_hdr->delay;
11616e7b4292SVikas Chaudhary 
11626e7b4292SVikas Chaudhary 	for (i = 0; i < p_hdr->count; i++, p_entry++) {
11636e7b4292SVikas Chaudhary 		qla4_83xx_wr_reg_indirect(ha, p_entry->ar_addr,
11646e7b4292SVikas Chaudhary 					  p_entry->ar_value);
11656e7b4292SVikas Chaudhary 		if (delay) {
11666e7b4292SVikas Chaudhary 			if (qla4_83xx_poll_reg(ha, p_entry->ar_addr, delay,
11676e7b4292SVikas Chaudhary 					       p_poll->test_mask,
11686e7b4292SVikas Chaudhary 					       p_poll->test_value)) {
11696e7b4292SVikas Chaudhary 				DEBUG2(ql4_printk(KERN_INFO, ha,
11706e7b4292SVikas Chaudhary 						  "%s: Timeout Error: poll list, Item_num %d, entry_num %d\n",
11716e7b4292SVikas Chaudhary 						  __func__, i,
11726e7b4292SVikas Chaudhary 						  ha->reset_tmplt.seq_index));
11736e7b4292SVikas Chaudhary 			} else {
11746e7b4292SVikas Chaudhary 				index = ha->reset_tmplt.array_index;
11756e7b4292SVikas Chaudhary 				qla4_83xx_rd_reg_indirect(ha, p_entry->dr_addr,
11766e7b4292SVikas Chaudhary 							  &value);
11776e7b4292SVikas Chaudhary 				ha->reset_tmplt.array[index++] = value;
11786e7b4292SVikas Chaudhary 
11796e7b4292SVikas Chaudhary 				if (index == QLA83XX_MAX_RESET_SEQ_ENTRIES)
11806e7b4292SVikas Chaudhary 					ha->reset_tmplt.array_index = 1;
11816e7b4292SVikas Chaudhary 			}
11826e7b4292SVikas Chaudhary 		}
11836e7b4292SVikas Chaudhary 	}
11846e7b4292SVikas Chaudhary }
11856e7b4292SVikas Chaudhary 
11866e7b4292SVikas Chaudhary static void qla4_83xx_seq_end(struct scsi_qla_host *ha,
11876e7b4292SVikas Chaudhary 			      struct qla4_83xx_reset_entry_hdr *p_hdr)
11886e7b4292SVikas Chaudhary {
11896e7b4292SVikas Chaudhary 	ha->reset_tmplt.seq_end = 1;
11906e7b4292SVikas Chaudhary }
11916e7b4292SVikas Chaudhary 
11926e7b4292SVikas Chaudhary static void qla4_83xx_template_end(struct scsi_qla_host *ha,
11936e7b4292SVikas Chaudhary 				   struct qla4_83xx_reset_entry_hdr *p_hdr)
11946e7b4292SVikas Chaudhary {
11956e7b4292SVikas Chaudhary 	ha->reset_tmplt.template_end = 1;
11966e7b4292SVikas Chaudhary 
11976e7b4292SVikas Chaudhary 	if (ha->reset_tmplt.seq_error == 0) {
11986e7b4292SVikas Chaudhary 		DEBUG2(ql4_printk(KERN_INFO, ha,
11996e7b4292SVikas Chaudhary 				  "%s: Reset sequence completed SUCCESSFULLY.\n",
12006e7b4292SVikas Chaudhary 				  __func__));
12016e7b4292SVikas Chaudhary 	} else {
12026e7b4292SVikas Chaudhary 		ql4_printk(KERN_ERR, ha, "%s: Reset sequence completed with some timeout errors.\n",
12036e7b4292SVikas Chaudhary 			   __func__);
12046e7b4292SVikas Chaudhary 	}
12056e7b4292SVikas Chaudhary }
12066e7b4292SVikas Chaudhary 
12076e7b4292SVikas Chaudhary /**
12086e7b4292SVikas Chaudhary  * qla4_83xx_process_reset_template - Process reset template.
12096e7b4292SVikas Chaudhary  *
12106e7b4292SVikas Chaudhary  * Process all entries in reset template till entry with SEQ_END opcode,
12116e7b4292SVikas Chaudhary  * which indicates end of the reset template processing. Each entry has a
12126e7b4292SVikas Chaudhary  * Reset Entry header, entry opcode/command, with size of the entry, number
12136e7b4292SVikas Chaudhary  * of entries in sub-sequence and delay in microsecs or timeout in millisecs.
12146e7b4292SVikas Chaudhary  *
12156e7b4292SVikas Chaudhary  * @ha : Pointer to adapter structure
12166e7b4292SVikas Chaudhary  * @p_buff : Common reset entry header.
12176e7b4292SVikas Chaudhary  **/
12186e7b4292SVikas Chaudhary static void qla4_83xx_process_reset_template(struct scsi_qla_host *ha,
12196e7b4292SVikas Chaudhary 					     char *p_buff)
12206e7b4292SVikas Chaudhary {
12216e7b4292SVikas Chaudhary 	int index, entries;
12226e7b4292SVikas Chaudhary 	struct qla4_83xx_reset_entry_hdr *p_hdr;
12236e7b4292SVikas Chaudhary 	char *p_entry = p_buff;
12246e7b4292SVikas Chaudhary 
12256e7b4292SVikas Chaudhary 	ha->reset_tmplt.seq_end = 0;
12266e7b4292SVikas Chaudhary 	ha->reset_tmplt.template_end = 0;
12276e7b4292SVikas Chaudhary 	entries = ha->reset_tmplt.hdr->entries;
12286e7b4292SVikas Chaudhary 	index = ha->reset_tmplt.seq_index;
12296e7b4292SVikas Chaudhary 
12306e7b4292SVikas Chaudhary 	for (; (!ha->reset_tmplt.seq_end) && (index  < entries); index++) {
12316e7b4292SVikas Chaudhary 
12326e7b4292SVikas Chaudhary 		p_hdr = (struct qla4_83xx_reset_entry_hdr *)p_entry;
12336e7b4292SVikas Chaudhary 		switch (p_hdr->cmd) {
12346e7b4292SVikas Chaudhary 		case OPCODE_NOP:
12356e7b4292SVikas Chaudhary 			break;
12366e7b4292SVikas Chaudhary 		case OPCODE_WRITE_LIST:
12376e7b4292SVikas Chaudhary 			qla4_83xx_write_list(ha, p_hdr);
12386e7b4292SVikas Chaudhary 			break;
12396e7b4292SVikas Chaudhary 		case OPCODE_READ_WRITE_LIST:
12406e7b4292SVikas Chaudhary 			qla4_83xx_read_write_list(ha, p_hdr);
12416e7b4292SVikas Chaudhary 			break;
12426e7b4292SVikas Chaudhary 		case OPCODE_POLL_LIST:
12436e7b4292SVikas Chaudhary 			qla4_83xx_poll_list(ha, p_hdr);
12446e7b4292SVikas Chaudhary 			break;
12456e7b4292SVikas Chaudhary 		case OPCODE_POLL_WRITE_LIST:
12466e7b4292SVikas Chaudhary 			qla4_83xx_poll_write_list(ha, p_hdr);
12476e7b4292SVikas Chaudhary 			break;
12486e7b4292SVikas Chaudhary 		case OPCODE_READ_MODIFY_WRITE:
12496e7b4292SVikas Chaudhary 			qla4_83xx_read_modify_write(ha, p_hdr);
12506e7b4292SVikas Chaudhary 			break;
12516e7b4292SVikas Chaudhary 		case OPCODE_SEQ_PAUSE:
12526e7b4292SVikas Chaudhary 			qla4_83xx_pause(ha, p_hdr);
12536e7b4292SVikas Chaudhary 			break;
12546e7b4292SVikas Chaudhary 		case OPCODE_SEQ_END:
12556e7b4292SVikas Chaudhary 			qla4_83xx_seq_end(ha, p_hdr);
12566e7b4292SVikas Chaudhary 			break;
12576e7b4292SVikas Chaudhary 		case OPCODE_TMPL_END:
12586e7b4292SVikas Chaudhary 			qla4_83xx_template_end(ha, p_hdr);
12596e7b4292SVikas Chaudhary 			break;
12606e7b4292SVikas Chaudhary 		case OPCODE_POLL_READ_LIST:
12616e7b4292SVikas Chaudhary 			qla4_83xx_poll_read_list(ha, p_hdr);
12626e7b4292SVikas Chaudhary 			break;
12636e7b4292SVikas Chaudhary 		default:
12646e7b4292SVikas Chaudhary 			ql4_printk(KERN_ERR, ha, "%s: Unknown command ==> 0x%04x on entry = %d\n",
12656e7b4292SVikas Chaudhary 				   __func__, p_hdr->cmd, index);
12666e7b4292SVikas Chaudhary 			break;
12676e7b4292SVikas Chaudhary 		}
12686e7b4292SVikas Chaudhary 
12696e7b4292SVikas Chaudhary 		/* Set pointer to next entry in the sequence. */
12706e7b4292SVikas Chaudhary 		p_entry += p_hdr->size;
12716e7b4292SVikas Chaudhary 	}
12726e7b4292SVikas Chaudhary 
12736e7b4292SVikas Chaudhary 	ha->reset_tmplt.seq_index = index;
12746e7b4292SVikas Chaudhary }
12756e7b4292SVikas Chaudhary 
12766e7b4292SVikas Chaudhary static void qla4_83xx_process_stop_seq(struct scsi_qla_host *ha)
12776e7b4292SVikas Chaudhary {
12786e7b4292SVikas Chaudhary 	ha->reset_tmplt.seq_index = 0;
12796e7b4292SVikas Chaudhary 	qla4_83xx_process_reset_template(ha, ha->reset_tmplt.stop_offset);
12806e7b4292SVikas Chaudhary 
12816e7b4292SVikas Chaudhary 	if (ha->reset_tmplt.seq_end != 1)
12826e7b4292SVikas Chaudhary 		ql4_printk(KERN_ERR, ha, "%s: Abrupt STOP Sub-Sequence end.\n",
12836e7b4292SVikas Chaudhary 			   __func__);
12846e7b4292SVikas Chaudhary }
12856e7b4292SVikas Chaudhary 
12866e7b4292SVikas Chaudhary static void qla4_83xx_process_start_seq(struct scsi_qla_host *ha)
12876e7b4292SVikas Chaudhary {
12886e7b4292SVikas Chaudhary 	qla4_83xx_process_reset_template(ha, ha->reset_tmplt.start_offset);
12896e7b4292SVikas Chaudhary 
12906e7b4292SVikas Chaudhary 	if (ha->reset_tmplt.template_end != 1)
12916e7b4292SVikas Chaudhary 		ql4_printk(KERN_ERR, ha, "%s: Abrupt START Sub-Sequence end.\n",
12926e7b4292SVikas Chaudhary 			   __func__);
12936e7b4292SVikas Chaudhary }
12946e7b4292SVikas Chaudhary 
12956e7b4292SVikas Chaudhary static void qla4_83xx_process_init_seq(struct scsi_qla_host *ha)
12966e7b4292SVikas Chaudhary {
12976e7b4292SVikas Chaudhary 	qla4_83xx_process_reset_template(ha, ha->reset_tmplt.init_offset);
12986e7b4292SVikas Chaudhary 
12996e7b4292SVikas Chaudhary 	if (ha->reset_tmplt.seq_end != 1)
13006e7b4292SVikas Chaudhary 		ql4_printk(KERN_ERR, ha, "%s: Abrupt INIT Sub-Sequence end.\n",
13016e7b4292SVikas Chaudhary 			   __func__);
13026e7b4292SVikas Chaudhary }
13036e7b4292SVikas Chaudhary 
13046e7b4292SVikas Chaudhary static int qla4_83xx_restart(struct scsi_qla_host *ha)
13056e7b4292SVikas Chaudhary {
13066e7b4292SVikas Chaudhary 	int ret_val = QLA_SUCCESS;
13076e7b4292SVikas Chaudhary 
13086e7b4292SVikas Chaudhary 	qla4_83xx_process_stop_seq(ha);
13096e7b4292SVikas Chaudhary 
13106e7b4292SVikas Chaudhary 	/* Collect minidump*/
13116e7b4292SVikas Chaudhary 	if (!test_and_clear_bit(AF_83XX_NO_FW_DUMP, &ha->flags))
13126e7b4292SVikas Chaudhary 		qla4_8xxx_get_minidump(ha);
13136e7b4292SVikas Chaudhary 
13146e7b4292SVikas Chaudhary 	qla4_83xx_process_init_seq(ha);
13156e7b4292SVikas Chaudhary 
13166e7b4292SVikas Chaudhary 	if (qla4_83xx_copy_bootloader(ha)) {
13176e7b4292SVikas Chaudhary 		ql4_printk(KERN_ERR, ha, "%s: Copy bootloader, firmware restart failed!\n",
13186e7b4292SVikas Chaudhary 			   __func__);
13196e7b4292SVikas Chaudhary 		ret_val = QLA_ERROR;
13206e7b4292SVikas Chaudhary 		goto exit_restart;
13216e7b4292SVikas Chaudhary 	}
13226e7b4292SVikas Chaudhary 
13236e7b4292SVikas Chaudhary 	qla4_83xx_wr_reg(ha, QLA83XX_FW_IMAGE_VALID, QLA83XX_BOOT_FROM_FLASH);
13246e7b4292SVikas Chaudhary 	qla4_83xx_process_start_seq(ha);
13256e7b4292SVikas Chaudhary 
13266e7b4292SVikas Chaudhary exit_restart:
13276e7b4292SVikas Chaudhary 	return ret_val;
13286e7b4292SVikas Chaudhary }
13296e7b4292SVikas Chaudhary 
13306e7b4292SVikas Chaudhary int qla4_83xx_start_firmware(struct scsi_qla_host *ha)
13316e7b4292SVikas Chaudhary {
13326e7b4292SVikas Chaudhary 	int ret_val = QLA_SUCCESS;
13336e7b4292SVikas Chaudhary 
13346e7b4292SVikas Chaudhary 	ret_val = qla4_83xx_restart(ha);
13356e7b4292SVikas Chaudhary 	if (ret_val == QLA_ERROR) {
13366e7b4292SVikas Chaudhary 		ql4_printk(KERN_ERR, ha, "%s: Restart error\n", __func__);
13376e7b4292SVikas Chaudhary 		goto exit_start_fw;
13386e7b4292SVikas Chaudhary 	} else {
13396e7b4292SVikas Chaudhary 		DEBUG2(ql4_printk(KERN_INFO, ha, "%s: Restart done\n",
13406e7b4292SVikas Chaudhary 				  __func__));
13416e7b4292SVikas Chaudhary 	}
13426e7b4292SVikas Chaudhary 
13436e7b4292SVikas Chaudhary 	ret_val = qla4_83xx_check_cmd_peg_status(ha);
13446e7b4292SVikas Chaudhary 	if (ret_val == QLA_ERROR)
13456e7b4292SVikas Chaudhary 		ql4_printk(KERN_ERR, ha, "%s: Peg not initialized\n",
13466e7b4292SVikas Chaudhary 			   __func__);
13476e7b4292SVikas Chaudhary 
13486e7b4292SVikas Chaudhary exit_start_fw:
13496e7b4292SVikas Chaudhary 	return ret_val;
13506e7b4292SVikas Chaudhary }
13516e7b4292SVikas Chaudhary 
13526e7b4292SVikas Chaudhary /*----------------------Interrupt Related functions ---------------------*/
13536e7b4292SVikas Chaudhary 
13545c19b92aSVikas Chaudhary static void qla4_83xx_disable_iocb_intrs(struct scsi_qla_host *ha)
13555c19b92aSVikas Chaudhary {
13565c19b92aSVikas Chaudhary 	if (test_and_clear_bit(AF_83XX_IOCB_INTR_ON, &ha->flags))
13575c19b92aSVikas Chaudhary 		qla4_8xxx_intr_disable(ha);
13585c19b92aSVikas Chaudhary }
13595c19b92aSVikas Chaudhary 
13605c19b92aSVikas Chaudhary static void qla4_83xx_disable_mbox_intrs(struct scsi_qla_host *ha)
13616e7b4292SVikas Chaudhary {
13626e7b4292SVikas Chaudhary 	uint32_t mb_int, ret;
13636e7b4292SVikas Chaudhary 
13645c19b92aSVikas Chaudhary 	if (test_and_clear_bit(AF_83XX_MBOX_INTR_ON, &ha->flags)) {
13656e7b4292SVikas Chaudhary 		ret = readl(&ha->qla4_83xx_reg->mbox_int);
13666e7b4292SVikas Chaudhary 		mb_int = ret & ~INT_ENABLE_FW_MB;
13676e7b4292SVikas Chaudhary 		writel(mb_int, &ha->qla4_83xx_reg->mbox_int);
13686e7b4292SVikas Chaudhary 		writel(1, &ha->qla4_83xx_reg->leg_int_mask);
13696e7b4292SVikas Chaudhary 	}
13705c19b92aSVikas Chaudhary }
13716e7b4292SVikas Chaudhary 
13725c19b92aSVikas Chaudhary void qla4_83xx_disable_intrs(struct scsi_qla_host *ha)
13735c19b92aSVikas Chaudhary {
13745c19b92aSVikas Chaudhary 	qla4_83xx_disable_mbox_intrs(ha);
13755c19b92aSVikas Chaudhary 	qla4_83xx_disable_iocb_intrs(ha);
13765c19b92aSVikas Chaudhary }
13775c19b92aSVikas Chaudhary 
13785c19b92aSVikas Chaudhary static void qla4_83xx_enable_iocb_intrs(struct scsi_qla_host *ha)
13795c19b92aSVikas Chaudhary {
13805c19b92aSVikas Chaudhary 	if (!test_bit(AF_83XX_IOCB_INTR_ON, &ha->flags)) {
13815c19b92aSVikas Chaudhary 		qla4_8xxx_intr_enable(ha);
13825c19b92aSVikas Chaudhary 		set_bit(AF_83XX_IOCB_INTR_ON, &ha->flags);
13835c19b92aSVikas Chaudhary 	}
13845c19b92aSVikas Chaudhary }
13855c19b92aSVikas Chaudhary 
13865c19b92aSVikas Chaudhary void qla4_83xx_enable_mbox_intrs(struct scsi_qla_host *ha)
13876e7b4292SVikas Chaudhary {
13886e7b4292SVikas Chaudhary 	uint32_t mb_int;
13896e7b4292SVikas Chaudhary 
13905c19b92aSVikas Chaudhary 	if (!test_bit(AF_83XX_MBOX_INTR_ON, &ha->flags)) {
13916e7b4292SVikas Chaudhary 		mb_int = INT_ENABLE_FW_MB;
13926e7b4292SVikas Chaudhary 		writel(mb_int, &ha->qla4_83xx_reg->mbox_int);
13936e7b4292SVikas Chaudhary 		writel(0, &ha->qla4_83xx_reg->leg_int_mask);
13945c19b92aSVikas Chaudhary 		set_bit(AF_83XX_MBOX_INTR_ON, &ha->flags);
13956e7b4292SVikas Chaudhary 	}
13965c19b92aSVikas Chaudhary }
13975c19b92aSVikas Chaudhary 
13985c19b92aSVikas Chaudhary 
13995c19b92aSVikas Chaudhary void qla4_83xx_enable_intrs(struct scsi_qla_host *ha)
14005c19b92aSVikas Chaudhary {
14015c19b92aSVikas Chaudhary 	qla4_83xx_enable_mbox_intrs(ha);
14025c19b92aSVikas Chaudhary 	qla4_83xx_enable_iocb_intrs(ha);
14035c19b92aSVikas Chaudhary }
14045c19b92aSVikas Chaudhary 
14056e7b4292SVikas Chaudhary 
14066e7b4292SVikas Chaudhary void qla4_83xx_queue_mbox_cmd(struct scsi_qla_host *ha, uint32_t *mbx_cmd,
14076e7b4292SVikas Chaudhary 			      int incount)
14086e7b4292SVikas Chaudhary {
14096e7b4292SVikas Chaudhary 	int i;
14106e7b4292SVikas Chaudhary 
14116e7b4292SVikas Chaudhary 	/* Load all mailbox registers, except mailbox 0. */
14126e7b4292SVikas Chaudhary 	for (i = 1; i < incount; i++)
14136e7b4292SVikas Chaudhary 		writel(mbx_cmd[i], &ha->qla4_83xx_reg->mailbox_in[i]);
14146e7b4292SVikas Chaudhary 
14156e7b4292SVikas Chaudhary 	writel(mbx_cmd[0], &ha->qla4_83xx_reg->mailbox_in[0]);
14166e7b4292SVikas Chaudhary 
14176e7b4292SVikas Chaudhary 	/* Set Host Interrupt register to 1, to tell the firmware that
14186e7b4292SVikas Chaudhary 	 * a mailbox command is pending. Firmware after reading the
14196e7b4292SVikas Chaudhary 	 * mailbox command, clears the host interrupt register */
14206e7b4292SVikas Chaudhary 	writel(HINT_MBX_INT_PENDING, &ha->qla4_83xx_reg->host_intr);
14216e7b4292SVikas Chaudhary }
14226e7b4292SVikas Chaudhary 
14236e7b4292SVikas Chaudhary void qla4_83xx_process_mbox_intr(struct scsi_qla_host *ha, int outcount)
14246e7b4292SVikas Chaudhary {
14256e7b4292SVikas Chaudhary 	int intr_status;
14266e7b4292SVikas Chaudhary 
14276e7b4292SVikas Chaudhary 	intr_status = readl(&ha->qla4_83xx_reg->risc_intr);
14286e7b4292SVikas Chaudhary 	if (intr_status) {
14296e7b4292SVikas Chaudhary 		ha->mbox_status_count = outcount;
14306e7b4292SVikas Chaudhary 		ha->isp_ops->interrupt_service_routine(ha, intr_status);
14316e7b4292SVikas Chaudhary 	}
14326e7b4292SVikas Chaudhary }
14336e7b4292SVikas Chaudhary 
14346e7b4292SVikas Chaudhary /**
14356e7b4292SVikas Chaudhary  * qla4_83xx_isp_reset - Resets ISP and aborts all outstanding commands.
14366e7b4292SVikas Chaudhary  * @ha: pointer to host adapter structure.
14376e7b4292SVikas Chaudhary  **/
14386e7b4292SVikas Chaudhary int qla4_83xx_isp_reset(struct scsi_qla_host *ha)
14396e7b4292SVikas Chaudhary {
14406e7b4292SVikas Chaudhary 	int rval;
14416e7b4292SVikas Chaudhary 	uint32_t dev_state;
14426e7b4292SVikas Chaudhary 
14436e7b4292SVikas Chaudhary 	ha->isp_ops->idc_lock(ha);
14446e7b4292SVikas Chaudhary 	dev_state = qla4_8xxx_rd_direct(ha, QLA8XXX_CRB_DEV_STATE);
14456e7b4292SVikas Chaudhary 
14466e7b4292SVikas Chaudhary 	if (ql4xdontresethba)
14476e7b4292SVikas Chaudhary 		qla4_83xx_set_idc_dontreset(ha);
14486e7b4292SVikas Chaudhary 
14496e7b4292SVikas Chaudhary 	if (dev_state == QLA8XXX_DEV_READY) {
14506e7b4292SVikas Chaudhary 		/* If IDC_CTRL DONTRESETHBA_BIT0 is set dont do reset
14516e7b4292SVikas Chaudhary 		 * recovery */
14526e7b4292SVikas Chaudhary 		if (qla4_83xx_idc_dontreset(ha) == DONTRESET_BIT0) {
14536e7b4292SVikas Chaudhary 			ql4_printk(KERN_ERR, ha, "%s: Reset recovery disabled\n",
14546e7b4292SVikas Chaudhary 				   __func__);
14556e7b4292SVikas Chaudhary 			rval = QLA_ERROR;
14566e7b4292SVikas Chaudhary 			goto exit_isp_reset;
14576e7b4292SVikas Chaudhary 		}
14586e7b4292SVikas Chaudhary 
14596e7b4292SVikas Chaudhary 		DEBUG2(ql4_printk(KERN_INFO, ha, "%s: HW State: NEED RESET\n",
14606e7b4292SVikas Chaudhary 				  __func__));
14616e7b4292SVikas Chaudhary 		qla4_8xxx_wr_direct(ha, QLA8XXX_CRB_DEV_STATE,
14626e7b4292SVikas Chaudhary 				    QLA8XXX_DEV_NEED_RESET);
14636e7b4292SVikas Chaudhary 
14646e7b4292SVikas Chaudhary 	} else {
14656e7b4292SVikas Chaudhary 		/* If device_state is NEED_RESET, go ahead with
14666e7b4292SVikas Chaudhary 		 * Reset,irrespective of ql4xdontresethba. This is to allow a
14676e7b4292SVikas Chaudhary 		 * non-reset-owner to force a reset. Non-reset-owner sets
14686e7b4292SVikas Chaudhary 		 * the IDC_CTRL BIT0 to prevent Reset-owner from doing a Reset
14696e7b4292SVikas Chaudhary 		 * and then forces a Reset by setting device_state to
14706e7b4292SVikas Chaudhary 		 * NEED_RESET. */
14716e7b4292SVikas Chaudhary 		DEBUG2(ql4_printk(KERN_INFO, ha,
14726e7b4292SVikas Chaudhary 				  "%s: HW state already set to NEED_RESET\n",
14736e7b4292SVikas Chaudhary 				  __func__));
14746e7b4292SVikas Chaudhary 	}
14756e7b4292SVikas Chaudhary 
14766e7b4292SVikas Chaudhary 	/* For ISP8324, Reset owner is NIC, iSCSI or FCOE based on priority
14776e7b4292SVikas Chaudhary 	 * and which drivers are present. Unlike ISP8022, the function setting
14786e7b4292SVikas Chaudhary 	 * NEED_RESET, may not be the Reset owner. */
14796e7b4292SVikas Chaudhary 	if (qla4_83xx_can_perform_reset(ha))
14806e7b4292SVikas Chaudhary 		set_bit(AF_8XXX_RST_OWNER, &ha->flags);
14816e7b4292SVikas Chaudhary 
14826e7b4292SVikas Chaudhary 	ha->isp_ops->idc_unlock(ha);
14836e7b4292SVikas Chaudhary 	rval = qla4_8xxx_device_state_handler(ha);
14846e7b4292SVikas Chaudhary 
14856e7b4292SVikas Chaudhary 	ha->isp_ops->idc_lock(ha);
14866e7b4292SVikas Chaudhary 	qla4_8xxx_clear_rst_ready(ha);
14876e7b4292SVikas Chaudhary exit_isp_reset:
14886e7b4292SVikas Chaudhary 	ha->isp_ops->idc_unlock(ha);
14896e7b4292SVikas Chaudhary 
14906e7b4292SVikas Chaudhary 	if (rval == QLA_SUCCESS)
14916e7b4292SVikas Chaudhary 		clear_bit(AF_FW_RECOVERY, &ha->flags);
14926e7b4292SVikas Chaudhary 
14936e7b4292SVikas Chaudhary 	return rval;
14946e7b4292SVikas Chaudhary }
1495546fef27STej Parkash 
1496546fef27STej Parkash static void qla4_83xx_dump_pause_control_regs(struct scsi_qla_host *ha)
1497546fef27STej Parkash {
1498546fef27STej Parkash 	u32 val = 0, val1 = 0;
1499546fef27STej Parkash 	int i, status = QLA_SUCCESS;
1500546fef27STej Parkash 
1501546fef27STej Parkash 	status = qla4_83xx_rd_reg_indirect(ha, QLA83XX_SRE_SHIM_CONTROL, &val);
1502546fef27STej Parkash 	DEBUG2(ql4_printk(KERN_INFO, ha, "SRE-Shim Ctrl:0x%x\n", val));
1503546fef27STej Parkash 
1504546fef27STej Parkash 	/* Port 0 Rx Buffer Pause Threshold Registers. */
1505546fef27STej Parkash 	DEBUG2(ql4_printk(KERN_INFO, ha,
1506546fef27STej Parkash 		"Port 0 Rx Buffer Pause Threshold Registers[TC7..TC0]:"));
1507546fef27STej Parkash 	for (i = 0; i < 8; i++) {
1508546fef27STej Parkash 		status = qla4_83xx_rd_reg_indirect(ha,
1509546fef27STej Parkash 				QLA83XX_PORT0_RXB_PAUSE_THRS + (i * 0x4), &val);
1510546fef27STej Parkash 		DEBUG2(pr_info("0x%x ", val));
1511546fef27STej Parkash 	}
1512546fef27STej Parkash 
1513546fef27STej Parkash 	DEBUG2(pr_info("\n"));
1514546fef27STej Parkash 
1515546fef27STej Parkash 	/* Port 1 Rx Buffer Pause Threshold Registers. */
1516546fef27STej Parkash 	DEBUG2(ql4_printk(KERN_INFO, ha,
1517546fef27STej Parkash 		"Port 1 Rx Buffer Pause Threshold Registers[TC7..TC0]:"));
1518546fef27STej Parkash 	for (i = 0; i < 8; i++) {
1519546fef27STej Parkash 		status = qla4_83xx_rd_reg_indirect(ha,
1520546fef27STej Parkash 				QLA83XX_PORT1_RXB_PAUSE_THRS + (i * 0x4), &val);
1521546fef27STej Parkash 		DEBUG2(pr_info("0x%x  ", val));
1522546fef27STej Parkash 	}
1523546fef27STej Parkash 
1524546fef27STej Parkash 	DEBUG2(pr_info("\n"));
1525546fef27STej Parkash 
1526546fef27STej Parkash 	/* Port 0 RxB Traffic Class Max Cell Registers. */
1527546fef27STej Parkash 	DEBUG2(ql4_printk(KERN_INFO, ha,
1528546fef27STej Parkash 		"Port 0 RxB Traffic Class Max Cell Registers[3..0]:"));
1529546fef27STej Parkash 	for (i = 0; i < 4; i++) {
1530546fef27STej Parkash 		status = qla4_83xx_rd_reg_indirect(ha,
1531546fef27STej Parkash 			       QLA83XX_PORT0_RXB_TC_MAX_CELL + (i * 0x4), &val);
1532546fef27STej Parkash 		DEBUG2(pr_info("0x%x  ", val));
1533546fef27STej Parkash 	}
1534546fef27STej Parkash 
1535546fef27STej Parkash 	DEBUG2(pr_info("\n"));
1536546fef27STej Parkash 
1537546fef27STej Parkash 	/* Port 1 RxB Traffic Class Max Cell Registers. */
1538546fef27STej Parkash 	DEBUG2(ql4_printk(KERN_INFO, ha,
1539546fef27STej Parkash 		"Port 1 RxB Traffic Class Max Cell Registers[3..0]:"));
1540546fef27STej Parkash 	for (i = 0; i < 4; i++) {
1541546fef27STej Parkash 		status = qla4_83xx_rd_reg_indirect(ha,
1542546fef27STej Parkash 			       QLA83XX_PORT1_RXB_TC_MAX_CELL + (i * 0x4), &val);
1543546fef27STej Parkash 		DEBUG2(pr_info("0x%x  ", val));
1544546fef27STej Parkash 	}
1545546fef27STej Parkash 
1546546fef27STej Parkash 	DEBUG2(pr_info("\n"));
1547546fef27STej Parkash 
1548546fef27STej Parkash 	/* Port 0 RxB Rx Traffic Class Stats. */
1549546fef27STej Parkash 	DEBUG2(ql4_printk(KERN_INFO, ha,
1550546fef27STej Parkash 			  "Port 0 RxB Rx Traffic Class Stats [TC7..TC0]"));
1551546fef27STej Parkash 	for (i = 7; i >= 0; i--) {
1552546fef27STej Parkash 		status = qla4_83xx_rd_reg_indirect(ha,
1553546fef27STej Parkash 						   QLA83XX_PORT0_RXB_TC_STATS,
1554546fef27STej Parkash 						   &val);
1555546fef27STej Parkash 		val &= ~(0x7 << 29);    /* Reset bits 29 to 31 */
1556546fef27STej Parkash 		qla4_83xx_wr_reg_indirect(ha, QLA83XX_PORT0_RXB_TC_STATS,
1557546fef27STej Parkash 					  (val | (i << 29)));
1558546fef27STej Parkash 		status = qla4_83xx_rd_reg_indirect(ha,
1559546fef27STej Parkash 						   QLA83XX_PORT0_RXB_TC_STATS,
1560546fef27STej Parkash 						   &val);
1561546fef27STej Parkash 		DEBUG2(pr_info("0x%x  ", val));
1562546fef27STej Parkash 	}
1563546fef27STej Parkash 
1564546fef27STej Parkash 	DEBUG2(pr_info("\n"));
1565546fef27STej Parkash 
1566546fef27STej Parkash 	/* Port 1 RxB Rx Traffic Class Stats. */
1567546fef27STej Parkash 	DEBUG2(ql4_printk(KERN_INFO, ha,
1568546fef27STej Parkash 			  "Port 1 RxB Rx Traffic Class Stats [TC7..TC0]"));
1569546fef27STej Parkash 	for (i = 7; i >= 0; i--) {
1570546fef27STej Parkash 		status = qla4_83xx_rd_reg_indirect(ha,
1571546fef27STej Parkash 						   QLA83XX_PORT1_RXB_TC_STATS,
1572546fef27STej Parkash 						   &val);
1573546fef27STej Parkash 		val &= ~(0x7 << 29);    /* Reset bits 29 to 31 */
1574546fef27STej Parkash 		qla4_83xx_wr_reg_indirect(ha, QLA83XX_PORT1_RXB_TC_STATS,
1575546fef27STej Parkash 					  (val | (i << 29)));
1576546fef27STej Parkash 		status = qla4_83xx_rd_reg_indirect(ha,
1577546fef27STej Parkash 						   QLA83XX_PORT1_RXB_TC_STATS,
1578546fef27STej Parkash 						   &val);
1579546fef27STej Parkash 		DEBUG2(pr_info("0x%x  ", val));
1580546fef27STej Parkash 	}
1581546fef27STej Parkash 
1582546fef27STej Parkash 	DEBUG2(pr_info("\n"));
1583546fef27STej Parkash 
1584546fef27STej Parkash 	status = qla4_83xx_rd_reg_indirect(ha, QLA83XX_PORT2_IFB_PAUSE_THRS,
1585546fef27STej Parkash 					   &val);
1586546fef27STej Parkash 	status = qla4_83xx_rd_reg_indirect(ha, QLA83XX_PORT3_IFB_PAUSE_THRS,
1587546fef27STej Parkash 					   &val1);
1588546fef27STej Parkash 
1589546fef27STej Parkash 	DEBUG2(ql4_printk(KERN_INFO, ha,
1590546fef27STej Parkash 			  "IFB-Pause Thresholds: Port 2:0x%x, Port 3:0x%x\n",
1591546fef27STej Parkash 			  val, val1));
1592546fef27STej Parkash }
1593546fef27STej Parkash 
1594546fef27STej Parkash static void __qla4_83xx_disable_pause(struct scsi_qla_host *ha)
1595546fef27STej Parkash {
1596546fef27STej Parkash 	int i;
1597546fef27STej Parkash 
1598546fef27STej Parkash 	/* set SRE-Shim Control Register */
1599546fef27STej Parkash 	qla4_83xx_wr_reg_indirect(ha, QLA83XX_SRE_SHIM_CONTROL,
1600546fef27STej Parkash 				  QLA83XX_SET_PAUSE_VAL);
1601546fef27STej Parkash 
1602546fef27STej Parkash 	for (i = 0; i < 8; i++) {
1603546fef27STej Parkash 		/* Port 0 Rx Buffer Pause Threshold Registers. */
1604546fef27STej Parkash 		qla4_83xx_wr_reg_indirect(ha,
1605546fef27STej Parkash 				      QLA83XX_PORT0_RXB_PAUSE_THRS + (i * 0x4),
1606546fef27STej Parkash 				      QLA83XX_SET_PAUSE_VAL);
1607546fef27STej Parkash 		/* Port 1 Rx Buffer Pause Threshold Registers. */
1608546fef27STej Parkash 		qla4_83xx_wr_reg_indirect(ha,
1609546fef27STej Parkash 				      QLA83XX_PORT1_RXB_PAUSE_THRS + (i * 0x4),
1610546fef27STej Parkash 				      QLA83XX_SET_PAUSE_VAL);
1611546fef27STej Parkash 	}
1612546fef27STej Parkash 
1613546fef27STej Parkash 	for (i = 0; i < 4; i++) {
1614546fef27STej Parkash 		/* Port 0 RxB Traffic Class Max Cell Registers. */
1615546fef27STej Parkash 		qla4_83xx_wr_reg_indirect(ha,
1616546fef27STej Parkash 				     QLA83XX_PORT0_RXB_TC_MAX_CELL + (i * 0x4),
1617546fef27STej Parkash 				     QLA83XX_SET_TC_MAX_CELL_VAL);
1618546fef27STej Parkash 		/* Port 1 RxB Traffic Class Max Cell Registers. */
1619546fef27STej Parkash 		qla4_83xx_wr_reg_indirect(ha,
1620546fef27STej Parkash 				     QLA83XX_PORT1_RXB_TC_MAX_CELL + (i * 0x4),
1621546fef27STej Parkash 				     QLA83XX_SET_TC_MAX_CELL_VAL);
1622546fef27STej Parkash 	}
1623546fef27STej Parkash 
1624546fef27STej Parkash 	qla4_83xx_wr_reg_indirect(ha, QLA83XX_PORT2_IFB_PAUSE_THRS,
1625546fef27STej Parkash 				  QLA83XX_SET_PAUSE_VAL);
1626546fef27STej Parkash 	qla4_83xx_wr_reg_indirect(ha, QLA83XX_PORT3_IFB_PAUSE_THRS,
1627546fef27STej Parkash 				  QLA83XX_SET_PAUSE_VAL);
1628546fef27STej Parkash 
1629546fef27STej Parkash 	ql4_printk(KERN_INFO, ha, "Disabled pause frames successfully.\n");
1630546fef27STej Parkash }
1631546fef27STej Parkash 
1632c18b78edSManish Dusane /**
1633c18b78edSManish Dusane  * qla4_83xx_eport_init - Initialize EPort.
1634c18b78edSManish Dusane  * @ha: Pointer to host adapter structure.
1635c18b78edSManish Dusane  *
1636c18b78edSManish Dusane  * If EPort hardware is in reset state before disabling pause, there would be
1637c18b78edSManish Dusane  * serious hardware wedging issues. To prevent this perform eport init everytime
1638c18b78edSManish Dusane  * before disabling pause frames.
1639c18b78edSManish Dusane  **/
1640c18b78edSManish Dusane static void qla4_83xx_eport_init(struct scsi_qla_host *ha)
1641c18b78edSManish Dusane {
1642c18b78edSManish Dusane 	/* Clear the 8 registers */
1643c18b78edSManish Dusane 	qla4_83xx_wr_reg_indirect(ha, QLA83XX_RESET_REG, 0x0);
1644c18b78edSManish Dusane 	qla4_83xx_wr_reg_indirect(ha, QLA83XX_RESET_PORT0, 0x0);
1645c18b78edSManish Dusane 	qla4_83xx_wr_reg_indirect(ha, QLA83XX_RESET_PORT1, 0x0);
1646c18b78edSManish Dusane 	qla4_83xx_wr_reg_indirect(ha, QLA83XX_RESET_PORT2, 0x0);
1647c18b78edSManish Dusane 	qla4_83xx_wr_reg_indirect(ha, QLA83XX_RESET_PORT3, 0x0);
1648c18b78edSManish Dusane 	qla4_83xx_wr_reg_indirect(ha, QLA83XX_RESET_SRE_SHIM, 0x0);
1649c18b78edSManish Dusane 	qla4_83xx_wr_reg_indirect(ha, QLA83XX_RESET_EPG_SHIM, 0x0);
1650c18b78edSManish Dusane 	qla4_83xx_wr_reg_indirect(ha, QLA83XX_RESET_ETHER_PCS, 0x0);
1651c18b78edSManish Dusane 
1652c18b78edSManish Dusane 	/* Write any value to Reset Control register */
1653c18b78edSManish Dusane 	qla4_83xx_wr_reg_indirect(ha, QLA83XX_RESET_CONTROL, 0xFF);
1654c18b78edSManish Dusane 
1655c18b78edSManish Dusane 	ql4_printk(KERN_INFO, ha, "EPORT is out of reset.\n");
1656c18b78edSManish Dusane }
1657c18b78edSManish Dusane 
1658546fef27STej Parkash void qla4_83xx_disable_pause(struct scsi_qla_host *ha)
1659546fef27STej Parkash {
1660546fef27STej Parkash 	ha->isp_ops->idc_lock(ha);
1661c18b78edSManish Dusane 	/* Before disabling pause frames, ensure that eport is not in reset */
1662c18b78edSManish Dusane 	qla4_83xx_eport_init(ha);
1663546fef27STej Parkash 	qla4_83xx_dump_pause_control_regs(ha);
1664546fef27STej Parkash 	__qla4_83xx_disable_pause(ha);
1665546fef27STej Parkash 	ha->isp_ops->idc_unlock(ha);
1666546fef27STej Parkash }
1667