18c2ecf20Sopenharmony_ci/*
28c2ecf20Sopenharmony_ci *  linux/drivers/scsi/esas2r/esas2r_init.c
38c2ecf20Sopenharmony_ci *      For use with ATTO ExpressSAS R6xx SAS/SATA RAID controllers
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci *  Copyright (c) 2001-2013 ATTO Technology, Inc.
68c2ecf20Sopenharmony_ci *  (mailto:linuxdrivers@attotech.com)mpt3sas/mpt3sas_trigger_diag.
78c2ecf20Sopenharmony_ci *
88c2ecf20Sopenharmony_ci * This program is free software; you can redistribute it and/or
98c2ecf20Sopenharmony_ci * modify it under the terms of the GNU General Public License
108c2ecf20Sopenharmony_ci * as published by the Free Software Foundation; either version 2
118c2ecf20Sopenharmony_ci * of the License, or (at your option) any later version.
128c2ecf20Sopenharmony_ci *
138c2ecf20Sopenharmony_ci * This program is distributed in the hope that it will be useful,
148c2ecf20Sopenharmony_ci * but WITHOUT ANY WARRANTY; without even the implied warranty of
158c2ecf20Sopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
168c2ecf20Sopenharmony_ci * GNU General Public License for more details.
178c2ecf20Sopenharmony_ci *
188c2ecf20Sopenharmony_ci * NO WARRANTY
198c2ecf20Sopenharmony_ci * THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
208c2ecf20Sopenharmony_ci * CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
218c2ecf20Sopenharmony_ci * LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
228c2ecf20Sopenharmony_ci * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
238c2ecf20Sopenharmony_ci * solely responsible for determining the appropriateness of using and
248c2ecf20Sopenharmony_ci * distributing the Program and assumes all risks associated with its
258c2ecf20Sopenharmony_ci * exercise of rights under this Agreement, including but not limited to
268c2ecf20Sopenharmony_ci * the risks and costs of program errors, damage to or loss of data,
278c2ecf20Sopenharmony_ci * programs or equipment, and unavailability or interruption of operations.
288c2ecf20Sopenharmony_ci *
298c2ecf20Sopenharmony_ci * DISCLAIMER OF LIABILITY
308c2ecf20Sopenharmony_ci * NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
318c2ecf20Sopenharmony_ci * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
328c2ecf20Sopenharmony_ci * DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND
338c2ecf20Sopenharmony_ci * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
348c2ecf20Sopenharmony_ci * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
358c2ecf20Sopenharmony_ci * USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
368c2ecf20Sopenharmony_ci * HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES
378c2ecf20Sopenharmony_ci *
388c2ecf20Sopenharmony_ci * You should have received a copy of the GNU General Public License
398c2ecf20Sopenharmony_ci * along with this program; if not, write to the Free Software
408c2ecf20Sopenharmony_ci * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,
418c2ecf20Sopenharmony_ci * USA.
428c2ecf20Sopenharmony_ci */
438c2ecf20Sopenharmony_ci
448c2ecf20Sopenharmony_ci#include "esas2r.h"
458c2ecf20Sopenharmony_ci
468c2ecf20Sopenharmony_cistatic bool esas2r_initmem_alloc(struct esas2r_adapter *a,
478c2ecf20Sopenharmony_ci				 struct esas2r_mem_desc *mem_desc,
488c2ecf20Sopenharmony_ci				 u32 align)
498c2ecf20Sopenharmony_ci{
508c2ecf20Sopenharmony_ci	mem_desc->esas2r_param = mem_desc->size + align;
518c2ecf20Sopenharmony_ci	mem_desc->virt_addr = NULL;
528c2ecf20Sopenharmony_ci	mem_desc->phys_addr = 0;
538c2ecf20Sopenharmony_ci	mem_desc->esas2r_data = dma_alloc_coherent(&a->pcid->dev,
548c2ecf20Sopenharmony_ci						   (size_t)mem_desc->
558c2ecf20Sopenharmony_ci						   esas2r_param,
568c2ecf20Sopenharmony_ci						   (dma_addr_t *)&mem_desc->
578c2ecf20Sopenharmony_ci						   phys_addr,
588c2ecf20Sopenharmony_ci						   GFP_KERNEL);
598c2ecf20Sopenharmony_ci
608c2ecf20Sopenharmony_ci	if (mem_desc->esas2r_data == NULL) {
618c2ecf20Sopenharmony_ci		esas2r_log(ESAS2R_LOG_CRIT,
628c2ecf20Sopenharmony_ci			   "failed to allocate %lu bytes of consistent memory!",
638c2ecf20Sopenharmony_ci			   (long
648c2ecf20Sopenharmony_ci			    unsigned
658c2ecf20Sopenharmony_ci			    int)mem_desc->esas2r_param);
668c2ecf20Sopenharmony_ci		return false;
678c2ecf20Sopenharmony_ci	}
688c2ecf20Sopenharmony_ci
698c2ecf20Sopenharmony_ci	mem_desc->virt_addr = PTR_ALIGN(mem_desc->esas2r_data, align);
708c2ecf20Sopenharmony_ci	mem_desc->phys_addr = ALIGN(mem_desc->phys_addr, align);
718c2ecf20Sopenharmony_ci	memset(mem_desc->virt_addr, 0, mem_desc->size);
728c2ecf20Sopenharmony_ci	return true;
738c2ecf20Sopenharmony_ci}
748c2ecf20Sopenharmony_ci
758c2ecf20Sopenharmony_cistatic void esas2r_initmem_free(struct esas2r_adapter *a,
768c2ecf20Sopenharmony_ci				struct esas2r_mem_desc *mem_desc)
778c2ecf20Sopenharmony_ci{
788c2ecf20Sopenharmony_ci	if (mem_desc->virt_addr == NULL)
798c2ecf20Sopenharmony_ci		return;
808c2ecf20Sopenharmony_ci
818c2ecf20Sopenharmony_ci	/*
828c2ecf20Sopenharmony_ci	 * Careful!  phys_addr and virt_addr may have been adjusted from the
838c2ecf20Sopenharmony_ci	 * original allocation in order to return the desired alignment.  That
848c2ecf20Sopenharmony_ci	 * means we have to use the original address (in esas2r_data) and size
858c2ecf20Sopenharmony_ci	 * (esas2r_param) and calculate the original physical address based on
868c2ecf20Sopenharmony_ci	 * the difference between the requested and actual allocation size.
878c2ecf20Sopenharmony_ci	 */
888c2ecf20Sopenharmony_ci	if (mem_desc->phys_addr) {
898c2ecf20Sopenharmony_ci		int unalign = ((u8 *)mem_desc->virt_addr) -
908c2ecf20Sopenharmony_ci			      ((u8 *)mem_desc->esas2r_data);
918c2ecf20Sopenharmony_ci
928c2ecf20Sopenharmony_ci		dma_free_coherent(&a->pcid->dev,
938c2ecf20Sopenharmony_ci				  (size_t)mem_desc->esas2r_param,
948c2ecf20Sopenharmony_ci				  mem_desc->esas2r_data,
958c2ecf20Sopenharmony_ci				  (dma_addr_t)(mem_desc->phys_addr - unalign));
968c2ecf20Sopenharmony_ci	} else {
978c2ecf20Sopenharmony_ci		kfree(mem_desc->esas2r_data);
988c2ecf20Sopenharmony_ci	}
998c2ecf20Sopenharmony_ci
1008c2ecf20Sopenharmony_ci	mem_desc->virt_addr = NULL;
1018c2ecf20Sopenharmony_ci}
1028c2ecf20Sopenharmony_ci
1038c2ecf20Sopenharmony_cistatic bool alloc_vda_req(struct esas2r_adapter *a,
1048c2ecf20Sopenharmony_ci			  struct esas2r_request *rq)
1058c2ecf20Sopenharmony_ci{
1068c2ecf20Sopenharmony_ci	struct esas2r_mem_desc *memdesc = kzalloc(
1078c2ecf20Sopenharmony_ci		sizeof(struct esas2r_mem_desc), GFP_KERNEL);
1088c2ecf20Sopenharmony_ci
1098c2ecf20Sopenharmony_ci	if (memdesc == NULL) {
1108c2ecf20Sopenharmony_ci		esas2r_hdebug("could not alloc mem for vda request memdesc\n");
1118c2ecf20Sopenharmony_ci		return false;
1128c2ecf20Sopenharmony_ci	}
1138c2ecf20Sopenharmony_ci
1148c2ecf20Sopenharmony_ci	memdesc->size = sizeof(union atto_vda_req) +
1158c2ecf20Sopenharmony_ci			ESAS2R_DATA_BUF_LEN;
1168c2ecf20Sopenharmony_ci
1178c2ecf20Sopenharmony_ci	if (!esas2r_initmem_alloc(a, memdesc, 256)) {
1188c2ecf20Sopenharmony_ci		esas2r_hdebug("could not alloc mem for vda request\n");
1198c2ecf20Sopenharmony_ci		kfree(memdesc);
1208c2ecf20Sopenharmony_ci		return false;
1218c2ecf20Sopenharmony_ci	}
1228c2ecf20Sopenharmony_ci
1238c2ecf20Sopenharmony_ci	a->num_vrqs++;
1248c2ecf20Sopenharmony_ci	list_add(&memdesc->next_desc, &a->vrq_mds_head);
1258c2ecf20Sopenharmony_ci
1268c2ecf20Sopenharmony_ci	rq->vrq_md = memdesc;
1278c2ecf20Sopenharmony_ci	rq->vrq = (union atto_vda_req *)memdesc->virt_addr;
1288c2ecf20Sopenharmony_ci	rq->vrq->scsi.handle = a->num_vrqs;
1298c2ecf20Sopenharmony_ci
1308c2ecf20Sopenharmony_ci	return true;
1318c2ecf20Sopenharmony_ci}
1328c2ecf20Sopenharmony_ci
1338c2ecf20Sopenharmony_cistatic void esas2r_unmap_regions(struct esas2r_adapter *a)
1348c2ecf20Sopenharmony_ci{
1358c2ecf20Sopenharmony_ci	if (a->regs)
1368c2ecf20Sopenharmony_ci		iounmap((void __iomem *)a->regs);
1378c2ecf20Sopenharmony_ci
1388c2ecf20Sopenharmony_ci	a->regs = NULL;
1398c2ecf20Sopenharmony_ci
1408c2ecf20Sopenharmony_ci	pci_release_region(a->pcid, 2);
1418c2ecf20Sopenharmony_ci
1428c2ecf20Sopenharmony_ci	if (a->data_window)
1438c2ecf20Sopenharmony_ci		iounmap((void __iomem *)a->data_window);
1448c2ecf20Sopenharmony_ci
1458c2ecf20Sopenharmony_ci	a->data_window = NULL;
1468c2ecf20Sopenharmony_ci
1478c2ecf20Sopenharmony_ci	pci_release_region(a->pcid, 0);
1488c2ecf20Sopenharmony_ci}
1498c2ecf20Sopenharmony_ci
1508c2ecf20Sopenharmony_cistatic int esas2r_map_regions(struct esas2r_adapter *a)
1518c2ecf20Sopenharmony_ci{
1528c2ecf20Sopenharmony_ci	int error;
1538c2ecf20Sopenharmony_ci
1548c2ecf20Sopenharmony_ci	a->regs = NULL;
1558c2ecf20Sopenharmony_ci	a->data_window = NULL;
1568c2ecf20Sopenharmony_ci
1578c2ecf20Sopenharmony_ci	error = pci_request_region(a->pcid, 2, a->name);
1588c2ecf20Sopenharmony_ci	if (error != 0) {
1598c2ecf20Sopenharmony_ci		esas2r_log(ESAS2R_LOG_CRIT,
1608c2ecf20Sopenharmony_ci			   "pci_request_region(2) failed, error %d",
1618c2ecf20Sopenharmony_ci			   error);
1628c2ecf20Sopenharmony_ci
1638c2ecf20Sopenharmony_ci		return error;
1648c2ecf20Sopenharmony_ci	}
1658c2ecf20Sopenharmony_ci
1668c2ecf20Sopenharmony_ci	a->regs = (void __force *)ioremap(pci_resource_start(a->pcid, 2),
1678c2ecf20Sopenharmony_ci					  pci_resource_len(a->pcid, 2));
1688c2ecf20Sopenharmony_ci	if (a->regs == NULL) {
1698c2ecf20Sopenharmony_ci		esas2r_log(ESAS2R_LOG_CRIT,
1708c2ecf20Sopenharmony_ci			   "ioremap failed for regs mem region\n");
1718c2ecf20Sopenharmony_ci		pci_release_region(a->pcid, 2);
1728c2ecf20Sopenharmony_ci		return -EFAULT;
1738c2ecf20Sopenharmony_ci	}
1748c2ecf20Sopenharmony_ci
1758c2ecf20Sopenharmony_ci	error = pci_request_region(a->pcid, 0, a->name);
1768c2ecf20Sopenharmony_ci	if (error != 0) {
1778c2ecf20Sopenharmony_ci		esas2r_log(ESAS2R_LOG_CRIT,
1788c2ecf20Sopenharmony_ci			   "pci_request_region(2) failed, error %d",
1798c2ecf20Sopenharmony_ci			   error);
1808c2ecf20Sopenharmony_ci		esas2r_unmap_regions(a);
1818c2ecf20Sopenharmony_ci		return error;
1828c2ecf20Sopenharmony_ci	}
1838c2ecf20Sopenharmony_ci
1848c2ecf20Sopenharmony_ci	a->data_window = (void __force *)ioremap(pci_resource_start(a->pcid,
1858c2ecf20Sopenharmony_ci								    0),
1868c2ecf20Sopenharmony_ci						 pci_resource_len(a->pcid, 0));
1878c2ecf20Sopenharmony_ci	if (a->data_window == NULL) {
1888c2ecf20Sopenharmony_ci		esas2r_log(ESAS2R_LOG_CRIT,
1898c2ecf20Sopenharmony_ci			   "ioremap failed for data_window mem region\n");
1908c2ecf20Sopenharmony_ci		esas2r_unmap_regions(a);
1918c2ecf20Sopenharmony_ci		return -EFAULT;
1928c2ecf20Sopenharmony_ci	}
1938c2ecf20Sopenharmony_ci
1948c2ecf20Sopenharmony_ci	return 0;
1958c2ecf20Sopenharmony_ci}
1968c2ecf20Sopenharmony_ci
1978c2ecf20Sopenharmony_cistatic void esas2r_setup_interrupts(struct esas2r_adapter *a, int intr_mode)
1988c2ecf20Sopenharmony_ci{
1998c2ecf20Sopenharmony_ci	int i;
2008c2ecf20Sopenharmony_ci
2018c2ecf20Sopenharmony_ci	/* Set up interrupt mode based on the requested value */
2028c2ecf20Sopenharmony_ci	switch (intr_mode) {
2038c2ecf20Sopenharmony_ci	case INTR_MODE_LEGACY:
2048c2ecf20Sopenharmony_ciuse_legacy_interrupts:
2058c2ecf20Sopenharmony_ci		a->intr_mode = INTR_MODE_LEGACY;
2068c2ecf20Sopenharmony_ci		break;
2078c2ecf20Sopenharmony_ci
2088c2ecf20Sopenharmony_ci	case INTR_MODE_MSI:
2098c2ecf20Sopenharmony_ci		i = pci_enable_msi(a->pcid);
2108c2ecf20Sopenharmony_ci		if (i != 0) {
2118c2ecf20Sopenharmony_ci			esas2r_log(ESAS2R_LOG_WARN,
2128c2ecf20Sopenharmony_ci				   "failed to enable MSI for adapter %d, "
2138c2ecf20Sopenharmony_ci				   "falling back to legacy interrupts "
2148c2ecf20Sopenharmony_ci				   "(err=%d)", a->index,
2158c2ecf20Sopenharmony_ci				   i);
2168c2ecf20Sopenharmony_ci			goto use_legacy_interrupts;
2178c2ecf20Sopenharmony_ci		}
2188c2ecf20Sopenharmony_ci		a->intr_mode = INTR_MODE_MSI;
2198c2ecf20Sopenharmony_ci		set_bit(AF2_MSI_ENABLED, &a->flags2);
2208c2ecf20Sopenharmony_ci		break;
2218c2ecf20Sopenharmony_ci
2228c2ecf20Sopenharmony_ci
2238c2ecf20Sopenharmony_ci	default:
2248c2ecf20Sopenharmony_ci		esas2r_log(ESAS2R_LOG_WARN,
2258c2ecf20Sopenharmony_ci			   "unknown interrupt_mode %d requested, "
2268c2ecf20Sopenharmony_ci			   "falling back to legacy interrupt",
2278c2ecf20Sopenharmony_ci			   interrupt_mode);
2288c2ecf20Sopenharmony_ci		goto use_legacy_interrupts;
2298c2ecf20Sopenharmony_ci	}
2308c2ecf20Sopenharmony_ci}
2318c2ecf20Sopenharmony_ci
2328c2ecf20Sopenharmony_cistatic void esas2r_claim_interrupts(struct esas2r_adapter *a)
2338c2ecf20Sopenharmony_ci{
2348c2ecf20Sopenharmony_ci	unsigned long flags = 0;
2358c2ecf20Sopenharmony_ci
2368c2ecf20Sopenharmony_ci	if (a->intr_mode == INTR_MODE_LEGACY)
2378c2ecf20Sopenharmony_ci		flags |= IRQF_SHARED;
2388c2ecf20Sopenharmony_ci
2398c2ecf20Sopenharmony_ci	esas2r_log(ESAS2R_LOG_INFO,
2408c2ecf20Sopenharmony_ci		   "esas2r_claim_interrupts irq=%d (%p, %s, %lx)",
2418c2ecf20Sopenharmony_ci		   a->pcid->irq, a, a->name, flags);
2428c2ecf20Sopenharmony_ci
2438c2ecf20Sopenharmony_ci	if (request_irq(a->pcid->irq,
2448c2ecf20Sopenharmony_ci			(a->intr_mode ==
2458c2ecf20Sopenharmony_ci			 INTR_MODE_LEGACY) ? esas2r_interrupt :
2468c2ecf20Sopenharmony_ci			esas2r_msi_interrupt,
2478c2ecf20Sopenharmony_ci			flags,
2488c2ecf20Sopenharmony_ci			a->name,
2498c2ecf20Sopenharmony_ci			a)) {
2508c2ecf20Sopenharmony_ci		esas2r_log(ESAS2R_LOG_CRIT, "unable to request IRQ %02X",
2518c2ecf20Sopenharmony_ci			   a->pcid->irq);
2528c2ecf20Sopenharmony_ci		return;
2538c2ecf20Sopenharmony_ci	}
2548c2ecf20Sopenharmony_ci
2558c2ecf20Sopenharmony_ci	set_bit(AF2_IRQ_CLAIMED, &a->flags2);
2568c2ecf20Sopenharmony_ci	esas2r_log(ESAS2R_LOG_INFO,
2578c2ecf20Sopenharmony_ci		   "claimed IRQ %d flags: 0x%lx",
2588c2ecf20Sopenharmony_ci		   a->pcid->irq, flags);
2598c2ecf20Sopenharmony_ci}
2608c2ecf20Sopenharmony_ci
2618c2ecf20Sopenharmony_ciint esas2r_init_adapter(struct Scsi_Host *host, struct pci_dev *pcid,
2628c2ecf20Sopenharmony_ci			int index)
2638c2ecf20Sopenharmony_ci{
2648c2ecf20Sopenharmony_ci	struct esas2r_adapter *a;
2658c2ecf20Sopenharmony_ci	u64 bus_addr = 0;
2668c2ecf20Sopenharmony_ci	int i;
2678c2ecf20Sopenharmony_ci	void *next_uncached;
2688c2ecf20Sopenharmony_ci	struct esas2r_request *first_request, *last_request;
2698c2ecf20Sopenharmony_ci	bool dma64 = false;
2708c2ecf20Sopenharmony_ci
2718c2ecf20Sopenharmony_ci	if (index >= MAX_ADAPTERS) {
2728c2ecf20Sopenharmony_ci		esas2r_log(ESAS2R_LOG_CRIT,
2738c2ecf20Sopenharmony_ci			   "tried to init invalid adapter index %u!",
2748c2ecf20Sopenharmony_ci			   index);
2758c2ecf20Sopenharmony_ci		return 0;
2768c2ecf20Sopenharmony_ci	}
2778c2ecf20Sopenharmony_ci
2788c2ecf20Sopenharmony_ci	if (esas2r_adapters[index]) {
2798c2ecf20Sopenharmony_ci		esas2r_log(ESAS2R_LOG_CRIT,
2808c2ecf20Sopenharmony_ci			   "tried to init existing adapter index %u!",
2818c2ecf20Sopenharmony_ci			   index);
2828c2ecf20Sopenharmony_ci		return 0;
2838c2ecf20Sopenharmony_ci	}
2848c2ecf20Sopenharmony_ci
2858c2ecf20Sopenharmony_ci	a = (struct esas2r_adapter *)host->hostdata;
2868c2ecf20Sopenharmony_ci	memset(a, 0, sizeof(struct esas2r_adapter));
2878c2ecf20Sopenharmony_ci	a->pcid = pcid;
2888c2ecf20Sopenharmony_ci	a->host = host;
2898c2ecf20Sopenharmony_ci
2908c2ecf20Sopenharmony_ci	if (sizeof(dma_addr_t) > 4 &&
2918c2ecf20Sopenharmony_ci	    dma_get_required_mask(&pcid->dev) > DMA_BIT_MASK(32) &&
2928c2ecf20Sopenharmony_ci	    !dma_set_mask_and_coherent(&pcid->dev, DMA_BIT_MASK(64)))
2938c2ecf20Sopenharmony_ci		dma64 = true;
2948c2ecf20Sopenharmony_ci
2958c2ecf20Sopenharmony_ci	if (!dma64 && dma_set_mask_and_coherent(&pcid->dev, DMA_BIT_MASK(32))) {
2968c2ecf20Sopenharmony_ci		esas2r_log(ESAS2R_LOG_CRIT, "failed to set DMA mask");
2978c2ecf20Sopenharmony_ci		esas2r_kill_adapter(index);
2988c2ecf20Sopenharmony_ci		return 0;
2998c2ecf20Sopenharmony_ci	}
3008c2ecf20Sopenharmony_ci
3018c2ecf20Sopenharmony_ci	esas2r_log_dev(ESAS2R_LOG_INFO, &pcid->dev,
3028c2ecf20Sopenharmony_ci		       "%s-bit PCI addressing enabled\n", dma64 ? "64" : "32");
3038c2ecf20Sopenharmony_ci
3048c2ecf20Sopenharmony_ci	esas2r_adapters[index] = a;
3058c2ecf20Sopenharmony_ci	sprintf(a->name, ESAS2R_DRVR_NAME "_%02d", index);
3068c2ecf20Sopenharmony_ci	esas2r_debug("new adapter %p, name %s", a, a->name);
3078c2ecf20Sopenharmony_ci	spin_lock_init(&a->request_lock);
3088c2ecf20Sopenharmony_ci	spin_lock_init(&a->fw_event_lock);
3098c2ecf20Sopenharmony_ci	mutex_init(&a->fm_api_mutex);
3108c2ecf20Sopenharmony_ci	mutex_init(&a->fs_api_mutex);
3118c2ecf20Sopenharmony_ci	sema_init(&a->nvram_semaphore, 1);
3128c2ecf20Sopenharmony_ci
3138c2ecf20Sopenharmony_ci	esas2r_fw_event_off(a);
3148c2ecf20Sopenharmony_ci	snprintf(a->fw_event_q_name, ESAS2R_KOBJ_NAME_LEN, "esas2r/%d",
3158c2ecf20Sopenharmony_ci		 a->index);
3168c2ecf20Sopenharmony_ci	a->fw_event_q = create_singlethread_workqueue(a->fw_event_q_name);
3178c2ecf20Sopenharmony_ci
3188c2ecf20Sopenharmony_ci	init_waitqueue_head(&a->buffered_ioctl_waiter);
3198c2ecf20Sopenharmony_ci	init_waitqueue_head(&a->nvram_waiter);
3208c2ecf20Sopenharmony_ci	init_waitqueue_head(&a->fm_api_waiter);
3218c2ecf20Sopenharmony_ci	init_waitqueue_head(&a->fs_api_waiter);
3228c2ecf20Sopenharmony_ci	init_waitqueue_head(&a->vda_waiter);
3238c2ecf20Sopenharmony_ci
3248c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&a->general_req.req_list);
3258c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&a->active_list);
3268c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&a->defer_list);
3278c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&a->free_sg_list_head);
3288c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&a->avail_request);
3298c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&a->vrq_mds_head);
3308c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&a->fw_event_list);
3318c2ecf20Sopenharmony_ci
3328c2ecf20Sopenharmony_ci	first_request = (struct esas2r_request *)((u8 *)(a + 1));
3338c2ecf20Sopenharmony_ci
3348c2ecf20Sopenharmony_ci	for (last_request = first_request, i = 1; i < num_requests;
3358c2ecf20Sopenharmony_ci	     last_request++, i++) {
3368c2ecf20Sopenharmony_ci		INIT_LIST_HEAD(&last_request->req_list);
3378c2ecf20Sopenharmony_ci		list_add_tail(&last_request->comp_list, &a->avail_request);
3388c2ecf20Sopenharmony_ci		if (!alloc_vda_req(a, last_request)) {
3398c2ecf20Sopenharmony_ci			esas2r_log(ESAS2R_LOG_CRIT,
3408c2ecf20Sopenharmony_ci				   "failed to allocate a VDA request!");
3418c2ecf20Sopenharmony_ci			esas2r_kill_adapter(index);
3428c2ecf20Sopenharmony_ci			return 0;
3438c2ecf20Sopenharmony_ci		}
3448c2ecf20Sopenharmony_ci	}
3458c2ecf20Sopenharmony_ci
3468c2ecf20Sopenharmony_ci	esas2r_debug("requests: %p to %p (%d, %d)", first_request,
3478c2ecf20Sopenharmony_ci		     last_request,
3488c2ecf20Sopenharmony_ci		     sizeof(*first_request),
3498c2ecf20Sopenharmony_ci		     num_requests);
3508c2ecf20Sopenharmony_ci
3518c2ecf20Sopenharmony_ci	if (esas2r_map_regions(a) != 0) {
3528c2ecf20Sopenharmony_ci		esas2r_log(ESAS2R_LOG_CRIT, "could not map PCI regions!");
3538c2ecf20Sopenharmony_ci		esas2r_kill_adapter(index);
3548c2ecf20Sopenharmony_ci		return 0;
3558c2ecf20Sopenharmony_ci	}
3568c2ecf20Sopenharmony_ci
3578c2ecf20Sopenharmony_ci	a->index = index;
3588c2ecf20Sopenharmony_ci
3598c2ecf20Sopenharmony_ci	/* interrupts will be disabled until we are done with init */
3608c2ecf20Sopenharmony_ci	atomic_inc(&a->dis_ints_cnt);
3618c2ecf20Sopenharmony_ci	atomic_inc(&a->disable_cnt);
3628c2ecf20Sopenharmony_ci	set_bit(AF_CHPRST_PENDING, &a->flags);
3638c2ecf20Sopenharmony_ci	set_bit(AF_DISC_PENDING, &a->flags);
3648c2ecf20Sopenharmony_ci	set_bit(AF_FIRST_INIT, &a->flags);
3658c2ecf20Sopenharmony_ci	set_bit(AF_LEGACY_SGE_MODE, &a->flags);
3668c2ecf20Sopenharmony_ci
3678c2ecf20Sopenharmony_ci	a->init_msg = ESAS2R_INIT_MSG_START;
3688c2ecf20Sopenharmony_ci	a->max_vdareq_size = 128;
3698c2ecf20Sopenharmony_ci	a->build_sgl = esas2r_build_sg_list_sge;
3708c2ecf20Sopenharmony_ci
3718c2ecf20Sopenharmony_ci	esas2r_setup_interrupts(a, interrupt_mode);
3728c2ecf20Sopenharmony_ci
3738c2ecf20Sopenharmony_ci	a->uncached_size = esas2r_get_uncached_size(a);
3748c2ecf20Sopenharmony_ci	a->uncached = dma_alloc_coherent(&pcid->dev,
3758c2ecf20Sopenharmony_ci					 (size_t)a->uncached_size,
3768c2ecf20Sopenharmony_ci					 (dma_addr_t *)&bus_addr,
3778c2ecf20Sopenharmony_ci					 GFP_KERNEL);
3788c2ecf20Sopenharmony_ci	if (a->uncached == NULL) {
3798c2ecf20Sopenharmony_ci		esas2r_log(ESAS2R_LOG_CRIT,
3808c2ecf20Sopenharmony_ci			   "failed to allocate %d bytes of consistent memory!",
3818c2ecf20Sopenharmony_ci			   a->uncached_size);
3828c2ecf20Sopenharmony_ci		esas2r_kill_adapter(index);
3838c2ecf20Sopenharmony_ci		return 0;
3848c2ecf20Sopenharmony_ci	}
3858c2ecf20Sopenharmony_ci
3868c2ecf20Sopenharmony_ci	a->uncached_phys = bus_addr;
3878c2ecf20Sopenharmony_ci
3888c2ecf20Sopenharmony_ci	esas2r_debug("%d bytes uncached memory allocated @ %p (%x:%x)",
3898c2ecf20Sopenharmony_ci		     a->uncached_size,
3908c2ecf20Sopenharmony_ci		     a->uncached,
3918c2ecf20Sopenharmony_ci		     upper_32_bits(bus_addr),
3928c2ecf20Sopenharmony_ci		     lower_32_bits(bus_addr));
3938c2ecf20Sopenharmony_ci	memset(a->uncached, 0, a->uncached_size);
3948c2ecf20Sopenharmony_ci	next_uncached = a->uncached;
3958c2ecf20Sopenharmony_ci
3968c2ecf20Sopenharmony_ci	if (!esas2r_init_adapter_struct(a,
3978c2ecf20Sopenharmony_ci					&next_uncached)) {
3988c2ecf20Sopenharmony_ci		esas2r_log(ESAS2R_LOG_CRIT,
3998c2ecf20Sopenharmony_ci			   "failed to initialize adapter structure (2)!");
4008c2ecf20Sopenharmony_ci		esas2r_kill_adapter(index);
4018c2ecf20Sopenharmony_ci		return 0;
4028c2ecf20Sopenharmony_ci	}
4038c2ecf20Sopenharmony_ci
4048c2ecf20Sopenharmony_ci	tasklet_init(&a->tasklet,
4058c2ecf20Sopenharmony_ci		     esas2r_adapter_tasklet,
4068c2ecf20Sopenharmony_ci		     (unsigned long)a);
4078c2ecf20Sopenharmony_ci
4088c2ecf20Sopenharmony_ci	/*
4098c2ecf20Sopenharmony_ci	 * Disable chip interrupts to prevent spurious interrupts
4108c2ecf20Sopenharmony_ci	 * until we claim the IRQ.
4118c2ecf20Sopenharmony_ci	 */
4128c2ecf20Sopenharmony_ci	esas2r_disable_chip_interrupts(a);
4138c2ecf20Sopenharmony_ci	esas2r_check_adapter(a);
4148c2ecf20Sopenharmony_ci
4158c2ecf20Sopenharmony_ci	if (!esas2r_init_adapter_hw(a, true))
4168c2ecf20Sopenharmony_ci		esas2r_log(ESAS2R_LOG_CRIT, "failed to initialize hardware!");
4178c2ecf20Sopenharmony_ci	else
4188c2ecf20Sopenharmony_ci		esas2r_debug("esas2r_init_adapter ok");
4198c2ecf20Sopenharmony_ci
4208c2ecf20Sopenharmony_ci	esas2r_claim_interrupts(a);
4218c2ecf20Sopenharmony_ci
4228c2ecf20Sopenharmony_ci	if (test_bit(AF2_IRQ_CLAIMED, &a->flags2))
4238c2ecf20Sopenharmony_ci		esas2r_enable_chip_interrupts(a);
4248c2ecf20Sopenharmony_ci
4258c2ecf20Sopenharmony_ci	set_bit(AF2_INIT_DONE, &a->flags2);
4268c2ecf20Sopenharmony_ci	if (!test_bit(AF_DEGRADED_MODE, &a->flags))
4278c2ecf20Sopenharmony_ci		esas2r_kickoff_timer(a);
4288c2ecf20Sopenharmony_ci	esas2r_debug("esas2r_init_adapter done for %p (%d)",
4298c2ecf20Sopenharmony_ci		     a, a->disable_cnt);
4308c2ecf20Sopenharmony_ci
4318c2ecf20Sopenharmony_ci	return 1;
4328c2ecf20Sopenharmony_ci}
4338c2ecf20Sopenharmony_ci
4348c2ecf20Sopenharmony_cistatic void esas2r_adapter_power_down(struct esas2r_adapter *a,
4358c2ecf20Sopenharmony_ci				      int power_management)
4368c2ecf20Sopenharmony_ci{
4378c2ecf20Sopenharmony_ci	struct esas2r_mem_desc *memdesc, *next;
4388c2ecf20Sopenharmony_ci
4398c2ecf20Sopenharmony_ci	if ((test_bit(AF2_INIT_DONE, &a->flags2))
4408c2ecf20Sopenharmony_ci	    &&  (!test_bit(AF_DEGRADED_MODE, &a->flags))) {
4418c2ecf20Sopenharmony_ci		if (!power_management) {
4428c2ecf20Sopenharmony_ci			del_timer_sync(&a->timer);
4438c2ecf20Sopenharmony_ci			tasklet_kill(&a->tasklet);
4448c2ecf20Sopenharmony_ci		}
4458c2ecf20Sopenharmony_ci		esas2r_power_down(a);
4468c2ecf20Sopenharmony_ci
4478c2ecf20Sopenharmony_ci		/*
4488c2ecf20Sopenharmony_ci		 * There are versions of firmware that do not handle the sync
4498c2ecf20Sopenharmony_ci		 * cache command correctly.  Stall here to ensure that the
4508c2ecf20Sopenharmony_ci		 * cache is lazily flushed.
4518c2ecf20Sopenharmony_ci		 */
4528c2ecf20Sopenharmony_ci		mdelay(500);
4538c2ecf20Sopenharmony_ci		esas2r_debug("chip halted");
4548c2ecf20Sopenharmony_ci	}
4558c2ecf20Sopenharmony_ci
4568c2ecf20Sopenharmony_ci	/* Remove sysfs binary files */
4578c2ecf20Sopenharmony_ci	if (a->sysfs_fw_created) {
4588c2ecf20Sopenharmony_ci		sysfs_remove_bin_file(&a->host->shost_dev.kobj, &bin_attr_fw);
4598c2ecf20Sopenharmony_ci		a->sysfs_fw_created = 0;
4608c2ecf20Sopenharmony_ci	}
4618c2ecf20Sopenharmony_ci
4628c2ecf20Sopenharmony_ci	if (a->sysfs_fs_created) {
4638c2ecf20Sopenharmony_ci		sysfs_remove_bin_file(&a->host->shost_dev.kobj, &bin_attr_fs);
4648c2ecf20Sopenharmony_ci		a->sysfs_fs_created = 0;
4658c2ecf20Sopenharmony_ci	}
4668c2ecf20Sopenharmony_ci
4678c2ecf20Sopenharmony_ci	if (a->sysfs_vda_created) {
4688c2ecf20Sopenharmony_ci		sysfs_remove_bin_file(&a->host->shost_dev.kobj, &bin_attr_vda);
4698c2ecf20Sopenharmony_ci		a->sysfs_vda_created = 0;
4708c2ecf20Sopenharmony_ci	}
4718c2ecf20Sopenharmony_ci
4728c2ecf20Sopenharmony_ci	if (a->sysfs_hw_created) {
4738c2ecf20Sopenharmony_ci		sysfs_remove_bin_file(&a->host->shost_dev.kobj, &bin_attr_hw);
4748c2ecf20Sopenharmony_ci		a->sysfs_hw_created = 0;
4758c2ecf20Sopenharmony_ci	}
4768c2ecf20Sopenharmony_ci
4778c2ecf20Sopenharmony_ci	if (a->sysfs_live_nvram_created) {
4788c2ecf20Sopenharmony_ci		sysfs_remove_bin_file(&a->host->shost_dev.kobj,
4798c2ecf20Sopenharmony_ci				      &bin_attr_live_nvram);
4808c2ecf20Sopenharmony_ci		a->sysfs_live_nvram_created = 0;
4818c2ecf20Sopenharmony_ci	}
4828c2ecf20Sopenharmony_ci
4838c2ecf20Sopenharmony_ci	if (a->sysfs_default_nvram_created) {
4848c2ecf20Sopenharmony_ci		sysfs_remove_bin_file(&a->host->shost_dev.kobj,
4858c2ecf20Sopenharmony_ci				      &bin_attr_default_nvram);
4868c2ecf20Sopenharmony_ci		a->sysfs_default_nvram_created = 0;
4878c2ecf20Sopenharmony_ci	}
4888c2ecf20Sopenharmony_ci
4898c2ecf20Sopenharmony_ci	/* Clean up interrupts */
4908c2ecf20Sopenharmony_ci	if (test_bit(AF2_IRQ_CLAIMED, &a->flags2)) {
4918c2ecf20Sopenharmony_ci		esas2r_log_dev(ESAS2R_LOG_INFO,
4928c2ecf20Sopenharmony_ci			       &(a->pcid->dev),
4938c2ecf20Sopenharmony_ci			       "free_irq(%d) called", a->pcid->irq);
4948c2ecf20Sopenharmony_ci
4958c2ecf20Sopenharmony_ci		free_irq(a->pcid->irq, a);
4968c2ecf20Sopenharmony_ci		esas2r_debug("IRQ released");
4978c2ecf20Sopenharmony_ci		clear_bit(AF2_IRQ_CLAIMED, &a->flags2);
4988c2ecf20Sopenharmony_ci	}
4998c2ecf20Sopenharmony_ci
5008c2ecf20Sopenharmony_ci	if (test_bit(AF2_MSI_ENABLED, &a->flags2)) {
5018c2ecf20Sopenharmony_ci		pci_disable_msi(a->pcid);
5028c2ecf20Sopenharmony_ci		clear_bit(AF2_MSI_ENABLED, &a->flags2);
5038c2ecf20Sopenharmony_ci		esas2r_debug("MSI disabled");
5048c2ecf20Sopenharmony_ci	}
5058c2ecf20Sopenharmony_ci
5068c2ecf20Sopenharmony_ci	if (a->inbound_list_md.virt_addr)
5078c2ecf20Sopenharmony_ci		esas2r_initmem_free(a, &a->inbound_list_md);
5088c2ecf20Sopenharmony_ci
5098c2ecf20Sopenharmony_ci	if (a->outbound_list_md.virt_addr)
5108c2ecf20Sopenharmony_ci		esas2r_initmem_free(a, &a->outbound_list_md);
5118c2ecf20Sopenharmony_ci
5128c2ecf20Sopenharmony_ci	list_for_each_entry_safe(memdesc, next, &a->free_sg_list_head,
5138c2ecf20Sopenharmony_ci				 next_desc) {
5148c2ecf20Sopenharmony_ci		esas2r_initmem_free(a, memdesc);
5158c2ecf20Sopenharmony_ci	}
5168c2ecf20Sopenharmony_ci
5178c2ecf20Sopenharmony_ci	/* Following frees everything allocated via alloc_vda_req */
5188c2ecf20Sopenharmony_ci	list_for_each_entry_safe(memdesc, next, &a->vrq_mds_head, next_desc) {
5198c2ecf20Sopenharmony_ci		esas2r_initmem_free(a, memdesc);
5208c2ecf20Sopenharmony_ci		list_del(&memdesc->next_desc);
5218c2ecf20Sopenharmony_ci		kfree(memdesc);
5228c2ecf20Sopenharmony_ci	}
5238c2ecf20Sopenharmony_ci
5248c2ecf20Sopenharmony_ci	kfree(a->first_ae_req);
5258c2ecf20Sopenharmony_ci	a->first_ae_req = NULL;
5268c2ecf20Sopenharmony_ci
5278c2ecf20Sopenharmony_ci	kfree(a->sg_list_mds);
5288c2ecf20Sopenharmony_ci	a->sg_list_mds = NULL;
5298c2ecf20Sopenharmony_ci
5308c2ecf20Sopenharmony_ci	kfree(a->req_table);
5318c2ecf20Sopenharmony_ci	a->req_table = NULL;
5328c2ecf20Sopenharmony_ci
5338c2ecf20Sopenharmony_ci	if (a->regs) {
5348c2ecf20Sopenharmony_ci		esas2r_unmap_regions(a);
5358c2ecf20Sopenharmony_ci		a->regs = NULL;
5368c2ecf20Sopenharmony_ci		a->data_window = NULL;
5378c2ecf20Sopenharmony_ci		esas2r_debug("regions unmapped");
5388c2ecf20Sopenharmony_ci	}
5398c2ecf20Sopenharmony_ci}
5408c2ecf20Sopenharmony_ci
5418c2ecf20Sopenharmony_ci/* Release/free allocated resources for specified adapters. */
5428c2ecf20Sopenharmony_civoid esas2r_kill_adapter(int i)
5438c2ecf20Sopenharmony_ci{
5448c2ecf20Sopenharmony_ci	struct esas2r_adapter *a = esas2r_adapters[i];
5458c2ecf20Sopenharmony_ci
5468c2ecf20Sopenharmony_ci	if (a) {
5478c2ecf20Sopenharmony_ci		unsigned long flags;
5488c2ecf20Sopenharmony_ci		struct workqueue_struct *wq;
5498c2ecf20Sopenharmony_ci		esas2r_debug("killing adapter %p [%d] ", a, i);
5508c2ecf20Sopenharmony_ci		esas2r_fw_event_off(a);
5518c2ecf20Sopenharmony_ci		esas2r_adapter_power_down(a, 0);
5528c2ecf20Sopenharmony_ci		if (esas2r_buffered_ioctl &&
5538c2ecf20Sopenharmony_ci		    (a->pcid == esas2r_buffered_ioctl_pcid)) {
5548c2ecf20Sopenharmony_ci			dma_free_coherent(&a->pcid->dev,
5558c2ecf20Sopenharmony_ci					  (size_t)esas2r_buffered_ioctl_size,
5568c2ecf20Sopenharmony_ci					  esas2r_buffered_ioctl,
5578c2ecf20Sopenharmony_ci					  esas2r_buffered_ioctl_addr);
5588c2ecf20Sopenharmony_ci			esas2r_buffered_ioctl = NULL;
5598c2ecf20Sopenharmony_ci		}
5608c2ecf20Sopenharmony_ci
5618c2ecf20Sopenharmony_ci		if (a->vda_buffer) {
5628c2ecf20Sopenharmony_ci			dma_free_coherent(&a->pcid->dev,
5638c2ecf20Sopenharmony_ci					  (size_t)VDA_MAX_BUFFER_SIZE,
5648c2ecf20Sopenharmony_ci					  a->vda_buffer,
5658c2ecf20Sopenharmony_ci					  (dma_addr_t)a->ppvda_buffer);
5668c2ecf20Sopenharmony_ci			a->vda_buffer = NULL;
5678c2ecf20Sopenharmony_ci		}
5688c2ecf20Sopenharmony_ci		if (a->fs_api_buffer) {
5698c2ecf20Sopenharmony_ci			dma_free_coherent(&a->pcid->dev,
5708c2ecf20Sopenharmony_ci					  (size_t)a->fs_api_buffer_size,
5718c2ecf20Sopenharmony_ci					  a->fs_api_buffer,
5728c2ecf20Sopenharmony_ci					  (dma_addr_t)a->ppfs_api_buffer);
5738c2ecf20Sopenharmony_ci			a->fs_api_buffer = NULL;
5748c2ecf20Sopenharmony_ci		}
5758c2ecf20Sopenharmony_ci
5768c2ecf20Sopenharmony_ci		kfree(a->local_atto_ioctl);
5778c2ecf20Sopenharmony_ci		a->local_atto_ioctl = NULL;
5788c2ecf20Sopenharmony_ci
5798c2ecf20Sopenharmony_ci		spin_lock_irqsave(&a->fw_event_lock, flags);
5808c2ecf20Sopenharmony_ci		wq = a->fw_event_q;
5818c2ecf20Sopenharmony_ci		a->fw_event_q = NULL;
5828c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(&a->fw_event_lock, flags);
5838c2ecf20Sopenharmony_ci		if (wq)
5848c2ecf20Sopenharmony_ci			destroy_workqueue(wq);
5858c2ecf20Sopenharmony_ci
5868c2ecf20Sopenharmony_ci		if (a->uncached) {
5878c2ecf20Sopenharmony_ci			dma_free_coherent(&a->pcid->dev,
5888c2ecf20Sopenharmony_ci					  (size_t)a->uncached_size,
5898c2ecf20Sopenharmony_ci					  a->uncached,
5908c2ecf20Sopenharmony_ci					  (dma_addr_t)a->uncached_phys);
5918c2ecf20Sopenharmony_ci			a->uncached = NULL;
5928c2ecf20Sopenharmony_ci			esas2r_debug("uncached area freed");
5938c2ecf20Sopenharmony_ci		}
5948c2ecf20Sopenharmony_ci
5958c2ecf20Sopenharmony_ci		esas2r_log_dev(ESAS2R_LOG_INFO,
5968c2ecf20Sopenharmony_ci			       &(a->pcid->dev),
5978c2ecf20Sopenharmony_ci			       "pci_disable_device() called.  msix_enabled: %d "
5988c2ecf20Sopenharmony_ci			       "msi_enabled: %d irq: %d pin: %d",
5998c2ecf20Sopenharmony_ci			       a->pcid->msix_enabled,
6008c2ecf20Sopenharmony_ci			       a->pcid->msi_enabled,
6018c2ecf20Sopenharmony_ci			       a->pcid->irq,
6028c2ecf20Sopenharmony_ci			       a->pcid->pin);
6038c2ecf20Sopenharmony_ci
6048c2ecf20Sopenharmony_ci		esas2r_log_dev(ESAS2R_LOG_INFO,
6058c2ecf20Sopenharmony_ci			       &(a->pcid->dev),
6068c2ecf20Sopenharmony_ci			       "before pci_disable_device() enable_cnt: %d",
6078c2ecf20Sopenharmony_ci			       a->pcid->enable_cnt.counter);
6088c2ecf20Sopenharmony_ci
6098c2ecf20Sopenharmony_ci		pci_disable_device(a->pcid);
6108c2ecf20Sopenharmony_ci		esas2r_log_dev(ESAS2R_LOG_INFO,
6118c2ecf20Sopenharmony_ci			       &(a->pcid->dev),
6128c2ecf20Sopenharmony_ci			       "after pci_disable_device() enable_cnt: %d",
6138c2ecf20Sopenharmony_ci			       a->pcid->enable_cnt.counter);
6148c2ecf20Sopenharmony_ci
6158c2ecf20Sopenharmony_ci		esas2r_log_dev(ESAS2R_LOG_INFO,
6168c2ecf20Sopenharmony_ci			       &(a->pcid->dev),
6178c2ecf20Sopenharmony_ci			       "pci_set_drv_data(%p, NULL) called",
6188c2ecf20Sopenharmony_ci			       a->pcid);
6198c2ecf20Sopenharmony_ci
6208c2ecf20Sopenharmony_ci		pci_set_drvdata(a->pcid, NULL);
6218c2ecf20Sopenharmony_ci		esas2r_adapters[i] = NULL;
6228c2ecf20Sopenharmony_ci
6238c2ecf20Sopenharmony_ci		if (test_bit(AF2_INIT_DONE, &a->flags2)) {
6248c2ecf20Sopenharmony_ci			clear_bit(AF2_INIT_DONE, &a->flags2);
6258c2ecf20Sopenharmony_ci
6268c2ecf20Sopenharmony_ci			set_bit(AF_DEGRADED_MODE, &a->flags);
6278c2ecf20Sopenharmony_ci
6288c2ecf20Sopenharmony_ci			esas2r_log_dev(ESAS2R_LOG_INFO,
6298c2ecf20Sopenharmony_ci				       &(a->host->shost_gendev),
6308c2ecf20Sopenharmony_ci				       "scsi_remove_host() called");
6318c2ecf20Sopenharmony_ci
6328c2ecf20Sopenharmony_ci			scsi_remove_host(a->host);
6338c2ecf20Sopenharmony_ci
6348c2ecf20Sopenharmony_ci			esas2r_log_dev(ESAS2R_LOG_INFO,
6358c2ecf20Sopenharmony_ci				       &(a->host->shost_gendev),
6368c2ecf20Sopenharmony_ci				       "scsi_host_put() called");
6378c2ecf20Sopenharmony_ci
6388c2ecf20Sopenharmony_ci			scsi_host_put(a->host);
6398c2ecf20Sopenharmony_ci		}
6408c2ecf20Sopenharmony_ci	}
6418c2ecf20Sopenharmony_ci}
6428c2ecf20Sopenharmony_ci
6438c2ecf20Sopenharmony_ciint esas2r_suspend(struct pci_dev *pdev, pm_message_t state)
6448c2ecf20Sopenharmony_ci{
6458c2ecf20Sopenharmony_ci	struct Scsi_Host *host = pci_get_drvdata(pdev);
6468c2ecf20Sopenharmony_ci	u32 device_state;
6478c2ecf20Sopenharmony_ci	struct esas2r_adapter *a = (struct esas2r_adapter *)host->hostdata;
6488c2ecf20Sopenharmony_ci
6498c2ecf20Sopenharmony_ci	esas2r_log_dev(ESAS2R_LOG_INFO, &(pdev->dev), "suspending adapter()");
6508c2ecf20Sopenharmony_ci	if (!a)
6518c2ecf20Sopenharmony_ci		return -ENODEV;
6528c2ecf20Sopenharmony_ci
6538c2ecf20Sopenharmony_ci	esas2r_adapter_power_down(a, 1);
6548c2ecf20Sopenharmony_ci	device_state = pci_choose_state(pdev, state);
6558c2ecf20Sopenharmony_ci	esas2r_log_dev(ESAS2R_LOG_INFO, &(pdev->dev),
6568c2ecf20Sopenharmony_ci		       "pci_save_state() called");
6578c2ecf20Sopenharmony_ci	pci_save_state(pdev);
6588c2ecf20Sopenharmony_ci	esas2r_log_dev(ESAS2R_LOG_INFO, &(pdev->dev),
6598c2ecf20Sopenharmony_ci		       "pci_disable_device() called");
6608c2ecf20Sopenharmony_ci	pci_disable_device(pdev);
6618c2ecf20Sopenharmony_ci	esas2r_log_dev(ESAS2R_LOG_INFO, &(pdev->dev),
6628c2ecf20Sopenharmony_ci		       "pci_set_power_state() called");
6638c2ecf20Sopenharmony_ci	pci_set_power_state(pdev, device_state);
6648c2ecf20Sopenharmony_ci	esas2r_log_dev(ESAS2R_LOG_INFO, &(pdev->dev), "esas2r_suspend(): 0");
6658c2ecf20Sopenharmony_ci	return 0;
6668c2ecf20Sopenharmony_ci}
6678c2ecf20Sopenharmony_ci
6688c2ecf20Sopenharmony_ciint esas2r_resume(struct pci_dev *pdev)
6698c2ecf20Sopenharmony_ci{
6708c2ecf20Sopenharmony_ci	struct Scsi_Host *host = pci_get_drvdata(pdev);
6718c2ecf20Sopenharmony_ci	struct esas2r_adapter *a = (struct esas2r_adapter *)host->hostdata;
6728c2ecf20Sopenharmony_ci	int rez;
6738c2ecf20Sopenharmony_ci
6748c2ecf20Sopenharmony_ci	esas2r_log_dev(ESAS2R_LOG_INFO, &(pdev->dev), "resuming adapter()");
6758c2ecf20Sopenharmony_ci	esas2r_log_dev(ESAS2R_LOG_INFO, &(pdev->dev),
6768c2ecf20Sopenharmony_ci		       "pci_set_power_state(PCI_D0) "
6778c2ecf20Sopenharmony_ci		       "called");
6788c2ecf20Sopenharmony_ci	pci_set_power_state(pdev, PCI_D0);
6798c2ecf20Sopenharmony_ci	esas2r_log_dev(ESAS2R_LOG_INFO, &(pdev->dev),
6808c2ecf20Sopenharmony_ci		       "pci_enable_wake(PCI_D0, 0) "
6818c2ecf20Sopenharmony_ci		       "called");
6828c2ecf20Sopenharmony_ci	pci_enable_wake(pdev, PCI_D0, 0);
6838c2ecf20Sopenharmony_ci	esas2r_log_dev(ESAS2R_LOG_INFO, &(pdev->dev),
6848c2ecf20Sopenharmony_ci		       "pci_restore_state() called");
6858c2ecf20Sopenharmony_ci	pci_restore_state(pdev);
6868c2ecf20Sopenharmony_ci	esas2r_log_dev(ESAS2R_LOG_INFO, &(pdev->dev),
6878c2ecf20Sopenharmony_ci		       "pci_enable_device() called");
6888c2ecf20Sopenharmony_ci	rez = pci_enable_device(pdev);
6898c2ecf20Sopenharmony_ci	pci_set_master(pdev);
6908c2ecf20Sopenharmony_ci
6918c2ecf20Sopenharmony_ci	if (!a) {
6928c2ecf20Sopenharmony_ci		rez = -ENODEV;
6938c2ecf20Sopenharmony_ci		goto error_exit;
6948c2ecf20Sopenharmony_ci	}
6958c2ecf20Sopenharmony_ci
6968c2ecf20Sopenharmony_ci	if (esas2r_map_regions(a) != 0) {
6978c2ecf20Sopenharmony_ci		esas2r_log(ESAS2R_LOG_CRIT, "could not re-map PCI regions!");
6988c2ecf20Sopenharmony_ci		rez = -ENOMEM;
6998c2ecf20Sopenharmony_ci		goto error_exit;
7008c2ecf20Sopenharmony_ci	}
7018c2ecf20Sopenharmony_ci
7028c2ecf20Sopenharmony_ci	/* Set up interupt mode */
7038c2ecf20Sopenharmony_ci	esas2r_setup_interrupts(a, a->intr_mode);
7048c2ecf20Sopenharmony_ci
7058c2ecf20Sopenharmony_ci	/*
7068c2ecf20Sopenharmony_ci	 * Disable chip interrupts to prevent spurious interrupts until we
7078c2ecf20Sopenharmony_ci	 * claim the IRQ.
7088c2ecf20Sopenharmony_ci	 */
7098c2ecf20Sopenharmony_ci	esas2r_disable_chip_interrupts(a);
7108c2ecf20Sopenharmony_ci	if (!esas2r_power_up(a, true)) {
7118c2ecf20Sopenharmony_ci		esas2r_debug("yikes, esas2r_power_up failed");
7128c2ecf20Sopenharmony_ci		rez = -ENOMEM;
7138c2ecf20Sopenharmony_ci		goto error_exit;
7148c2ecf20Sopenharmony_ci	}
7158c2ecf20Sopenharmony_ci
7168c2ecf20Sopenharmony_ci	esas2r_claim_interrupts(a);
7178c2ecf20Sopenharmony_ci
7188c2ecf20Sopenharmony_ci	if (test_bit(AF2_IRQ_CLAIMED, &a->flags2)) {
7198c2ecf20Sopenharmony_ci		/*
7208c2ecf20Sopenharmony_ci		 * Now that system interrupt(s) are claimed, we can enable
7218c2ecf20Sopenharmony_ci		 * chip interrupts.
7228c2ecf20Sopenharmony_ci		 */
7238c2ecf20Sopenharmony_ci		esas2r_enable_chip_interrupts(a);
7248c2ecf20Sopenharmony_ci		esas2r_kickoff_timer(a);
7258c2ecf20Sopenharmony_ci	} else {
7268c2ecf20Sopenharmony_ci		esas2r_debug("yikes, unable to claim IRQ");
7278c2ecf20Sopenharmony_ci		esas2r_log(ESAS2R_LOG_CRIT, "could not re-claim IRQ!");
7288c2ecf20Sopenharmony_ci		rez = -ENOMEM;
7298c2ecf20Sopenharmony_ci		goto error_exit;
7308c2ecf20Sopenharmony_ci	}
7318c2ecf20Sopenharmony_ci
7328c2ecf20Sopenharmony_cierror_exit:
7338c2ecf20Sopenharmony_ci	esas2r_log_dev(ESAS2R_LOG_CRIT, &(pdev->dev), "esas2r_resume(): %d",
7348c2ecf20Sopenharmony_ci		       rez);
7358c2ecf20Sopenharmony_ci	return rez;
7368c2ecf20Sopenharmony_ci}
7378c2ecf20Sopenharmony_ci
7388c2ecf20Sopenharmony_cibool esas2r_set_degraded_mode(struct esas2r_adapter *a, char *error_str)
7398c2ecf20Sopenharmony_ci{
7408c2ecf20Sopenharmony_ci	set_bit(AF_DEGRADED_MODE, &a->flags);
7418c2ecf20Sopenharmony_ci	esas2r_log(ESAS2R_LOG_CRIT,
7428c2ecf20Sopenharmony_ci		   "setting adapter to degraded mode: %s\n", error_str);
7438c2ecf20Sopenharmony_ci	return false;
7448c2ecf20Sopenharmony_ci}
7458c2ecf20Sopenharmony_ci
7468c2ecf20Sopenharmony_ciu32 esas2r_get_uncached_size(struct esas2r_adapter *a)
7478c2ecf20Sopenharmony_ci{
7488c2ecf20Sopenharmony_ci	return sizeof(struct esas2r_sas_nvram)
7498c2ecf20Sopenharmony_ci	       + ALIGN(ESAS2R_DISC_BUF_LEN, 8)
7508c2ecf20Sopenharmony_ci	       + ALIGN(sizeof(u32), 8) /* outbound list copy pointer */
7518c2ecf20Sopenharmony_ci	       + 8
7528c2ecf20Sopenharmony_ci	       + (num_sg_lists * (u16)sgl_page_size)
7538c2ecf20Sopenharmony_ci	       + ALIGN((num_requests + num_ae_requests + 1 +
7548c2ecf20Sopenharmony_ci			ESAS2R_LIST_EXTRA) *
7558c2ecf20Sopenharmony_ci		       sizeof(struct esas2r_inbound_list_source_entry),
7568c2ecf20Sopenharmony_ci		       8)
7578c2ecf20Sopenharmony_ci	       + ALIGN((num_requests + num_ae_requests + 1 +
7588c2ecf20Sopenharmony_ci			ESAS2R_LIST_EXTRA) *
7598c2ecf20Sopenharmony_ci		       sizeof(struct atto_vda_ob_rsp), 8)
7608c2ecf20Sopenharmony_ci	       + 256; /* VDA request and buffer align */
7618c2ecf20Sopenharmony_ci}
7628c2ecf20Sopenharmony_ci
7638c2ecf20Sopenharmony_cistatic void esas2r_init_pci_cfg_space(struct esas2r_adapter *a)
7648c2ecf20Sopenharmony_ci{
7658c2ecf20Sopenharmony_ci	if (pci_is_pcie(a->pcid)) {
7668c2ecf20Sopenharmony_ci		u16 devcontrol;
7678c2ecf20Sopenharmony_ci
7688c2ecf20Sopenharmony_ci		pcie_capability_read_word(a->pcid, PCI_EXP_DEVCTL, &devcontrol);
7698c2ecf20Sopenharmony_ci
7708c2ecf20Sopenharmony_ci		if ((devcontrol & PCI_EXP_DEVCTL_READRQ) >
7718c2ecf20Sopenharmony_ci		     PCI_EXP_DEVCTL_READRQ_512B) {
7728c2ecf20Sopenharmony_ci			esas2r_log(ESAS2R_LOG_INFO,
7738c2ecf20Sopenharmony_ci				   "max read request size > 512B");
7748c2ecf20Sopenharmony_ci
7758c2ecf20Sopenharmony_ci			devcontrol &= ~PCI_EXP_DEVCTL_READRQ;
7768c2ecf20Sopenharmony_ci			devcontrol |= PCI_EXP_DEVCTL_READRQ_512B;
7778c2ecf20Sopenharmony_ci			pcie_capability_write_word(a->pcid, PCI_EXP_DEVCTL,
7788c2ecf20Sopenharmony_ci						   devcontrol);
7798c2ecf20Sopenharmony_ci		}
7808c2ecf20Sopenharmony_ci	}
7818c2ecf20Sopenharmony_ci}
7828c2ecf20Sopenharmony_ci
7838c2ecf20Sopenharmony_ci/*
7848c2ecf20Sopenharmony_ci * Determine the organization of the uncached data area and
7858c2ecf20Sopenharmony_ci * finish initializing the adapter structure
7868c2ecf20Sopenharmony_ci */
7878c2ecf20Sopenharmony_cibool esas2r_init_adapter_struct(struct esas2r_adapter *a,
7888c2ecf20Sopenharmony_ci				void **uncached_area)
7898c2ecf20Sopenharmony_ci{
7908c2ecf20Sopenharmony_ci	u32 i;
7918c2ecf20Sopenharmony_ci	u8 *high;
7928c2ecf20Sopenharmony_ci	struct esas2r_inbound_list_source_entry *element;
7938c2ecf20Sopenharmony_ci	struct esas2r_request *rq;
7948c2ecf20Sopenharmony_ci	struct esas2r_mem_desc *sgl;
7958c2ecf20Sopenharmony_ci
7968c2ecf20Sopenharmony_ci	spin_lock_init(&a->sg_list_lock);
7978c2ecf20Sopenharmony_ci	spin_lock_init(&a->mem_lock);
7988c2ecf20Sopenharmony_ci	spin_lock_init(&a->queue_lock);
7998c2ecf20Sopenharmony_ci
8008c2ecf20Sopenharmony_ci	a->targetdb_end = &a->targetdb[ESAS2R_MAX_TARGETS];
8018c2ecf20Sopenharmony_ci
8028c2ecf20Sopenharmony_ci	if (!alloc_vda_req(a, &a->general_req)) {
8038c2ecf20Sopenharmony_ci		esas2r_hdebug(
8048c2ecf20Sopenharmony_ci			"failed to allocate a VDA request for the general req!");
8058c2ecf20Sopenharmony_ci		return false;
8068c2ecf20Sopenharmony_ci	}
8078c2ecf20Sopenharmony_ci
8088c2ecf20Sopenharmony_ci	/* allocate requests for asynchronous events */
8098c2ecf20Sopenharmony_ci	a->first_ae_req =
8108c2ecf20Sopenharmony_ci		kcalloc(num_ae_requests, sizeof(struct esas2r_request),
8118c2ecf20Sopenharmony_ci			GFP_KERNEL);
8128c2ecf20Sopenharmony_ci
8138c2ecf20Sopenharmony_ci	if (a->first_ae_req == NULL) {
8148c2ecf20Sopenharmony_ci		esas2r_log(ESAS2R_LOG_CRIT,
8158c2ecf20Sopenharmony_ci			   "failed to allocate memory for asynchronous events");
8168c2ecf20Sopenharmony_ci		return false;
8178c2ecf20Sopenharmony_ci	}
8188c2ecf20Sopenharmony_ci
8198c2ecf20Sopenharmony_ci	/* allocate the S/G list memory descriptors */
8208c2ecf20Sopenharmony_ci	a->sg_list_mds = kcalloc(num_sg_lists, sizeof(struct esas2r_mem_desc),
8218c2ecf20Sopenharmony_ci				 GFP_KERNEL);
8228c2ecf20Sopenharmony_ci
8238c2ecf20Sopenharmony_ci	if (a->sg_list_mds == NULL) {
8248c2ecf20Sopenharmony_ci		esas2r_log(ESAS2R_LOG_CRIT,
8258c2ecf20Sopenharmony_ci			   "failed to allocate memory for s/g list descriptors");
8268c2ecf20Sopenharmony_ci		return false;
8278c2ecf20Sopenharmony_ci	}
8288c2ecf20Sopenharmony_ci
8298c2ecf20Sopenharmony_ci	/* allocate the request table */
8308c2ecf20Sopenharmony_ci	a->req_table =
8318c2ecf20Sopenharmony_ci		kcalloc(num_requests + num_ae_requests + 1,
8328c2ecf20Sopenharmony_ci			sizeof(struct esas2r_request *),
8338c2ecf20Sopenharmony_ci			GFP_KERNEL);
8348c2ecf20Sopenharmony_ci
8358c2ecf20Sopenharmony_ci	if (a->req_table == NULL) {
8368c2ecf20Sopenharmony_ci		esas2r_log(ESAS2R_LOG_CRIT,
8378c2ecf20Sopenharmony_ci			   "failed to allocate memory for the request table");
8388c2ecf20Sopenharmony_ci		return false;
8398c2ecf20Sopenharmony_ci	}
8408c2ecf20Sopenharmony_ci
8418c2ecf20Sopenharmony_ci	/* initialize PCI configuration space */
8428c2ecf20Sopenharmony_ci	esas2r_init_pci_cfg_space(a);
8438c2ecf20Sopenharmony_ci
8448c2ecf20Sopenharmony_ci	/*
8458c2ecf20Sopenharmony_ci	 * the thunder_stream boards all have a serial flash part that has a
8468c2ecf20Sopenharmony_ci	 * different base address on the AHB bus.
8478c2ecf20Sopenharmony_ci	 */
8488c2ecf20Sopenharmony_ci	if ((a->pcid->subsystem_vendor == ATTO_VENDOR_ID)
8498c2ecf20Sopenharmony_ci	    && (a->pcid->subsystem_device & ATTO_SSDID_TBT))
8508c2ecf20Sopenharmony_ci		a->flags2 |= AF2_THUNDERBOLT;
8518c2ecf20Sopenharmony_ci
8528c2ecf20Sopenharmony_ci	if (test_bit(AF2_THUNDERBOLT, &a->flags2))
8538c2ecf20Sopenharmony_ci		a->flags2 |= AF2_SERIAL_FLASH;
8548c2ecf20Sopenharmony_ci
8558c2ecf20Sopenharmony_ci	if (a->pcid->subsystem_device == ATTO_TLSH_1068)
8568c2ecf20Sopenharmony_ci		a->flags2 |= AF2_THUNDERLINK;
8578c2ecf20Sopenharmony_ci
8588c2ecf20Sopenharmony_ci	/* Uncached Area */
8598c2ecf20Sopenharmony_ci	high = (u8 *)*uncached_area;
8608c2ecf20Sopenharmony_ci
8618c2ecf20Sopenharmony_ci	/* initialize the scatter/gather table pages */
8628c2ecf20Sopenharmony_ci
8638c2ecf20Sopenharmony_ci	for (i = 0, sgl = a->sg_list_mds; i < num_sg_lists; i++, sgl++) {
8648c2ecf20Sopenharmony_ci		sgl->size = sgl_page_size;
8658c2ecf20Sopenharmony_ci
8668c2ecf20Sopenharmony_ci		list_add_tail(&sgl->next_desc, &a->free_sg_list_head);
8678c2ecf20Sopenharmony_ci
8688c2ecf20Sopenharmony_ci		if (!esas2r_initmem_alloc(a, sgl, ESAS2R_SGL_ALIGN)) {
8698c2ecf20Sopenharmony_ci			/* Allow the driver to load if the minimum count met. */
8708c2ecf20Sopenharmony_ci			if (i < NUM_SGL_MIN)
8718c2ecf20Sopenharmony_ci				return false;
8728c2ecf20Sopenharmony_ci			break;
8738c2ecf20Sopenharmony_ci		}
8748c2ecf20Sopenharmony_ci	}
8758c2ecf20Sopenharmony_ci
8768c2ecf20Sopenharmony_ci	/* compute the size of the lists */
8778c2ecf20Sopenharmony_ci	a->list_size = num_requests + ESAS2R_LIST_EXTRA;
8788c2ecf20Sopenharmony_ci
8798c2ecf20Sopenharmony_ci	/* allocate the inbound list */
8808c2ecf20Sopenharmony_ci	a->inbound_list_md.size = a->list_size *
8818c2ecf20Sopenharmony_ci				  sizeof(struct
8828c2ecf20Sopenharmony_ci					 esas2r_inbound_list_source_entry);
8838c2ecf20Sopenharmony_ci
8848c2ecf20Sopenharmony_ci	if (!esas2r_initmem_alloc(a, &a->inbound_list_md, ESAS2R_LIST_ALIGN)) {
8858c2ecf20Sopenharmony_ci		esas2r_hdebug("failed to allocate IB list");
8868c2ecf20Sopenharmony_ci		return false;
8878c2ecf20Sopenharmony_ci	}
8888c2ecf20Sopenharmony_ci
8898c2ecf20Sopenharmony_ci	/* allocate the outbound list */
8908c2ecf20Sopenharmony_ci	a->outbound_list_md.size = a->list_size *
8918c2ecf20Sopenharmony_ci				   sizeof(struct atto_vda_ob_rsp);
8928c2ecf20Sopenharmony_ci
8938c2ecf20Sopenharmony_ci	if (!esas2r_initmem_alloc(a, &a->outbound_list_md,
8948c2ecf20Sopenharmony_ci				  ESAS2R_LIST_ALIGN)) {
8958c2ecf20Sopenharmony_ci		esas2r_hdebug("failed to allocate IB list");
8968c2ecf20Sopenharmony_ci		return false;
8978c2ecf20Sopenharmony_ci	}
8988c2ecf20Sopenharmony_ci
8998c2ecf20Sopenharmony_ci	/* allocate the NVRAM structure */
9008c2ecf20Sopenharmony_ci	a->nvram = (struct esas2r_sas_nvram *)high;
9018c2ecf20Sopenharmony_ci	high += sizeof(struct esas2r_sas_nvram);
9028c2ecf20Sopenharmony_ci
9038c2ecf20Sopenharmony_ci	/* allocate the discovery buffer */
9048c2ecf20Sopenharmony_ci	a->disc_buffer = high;
9058c2ecf20Sopenharmony_ci	high += ESAS2R_DISC_BUF_LEN;
9068c2ecf20Sopenharmony_ci	high = PTR_ALIGN(high, 8);
9078c2ecf20Sopenharmony_ci
9088c2ecf20Sopenharmony_ci	/* allocate the outbound list copy pointer */
9098c2ecf20Sopenharmony_ci	a->outbound_copy = (u32 volatile *)high;
9108c2ecf20Sopenharmony_ci	high += sizeof(u32);
9118c2ecf20Sopenharmony_ci
9128c2ecf20Sopenharmony_ci	if (!test_bit(AF_NVR_VALID, &a->flags))
9138c2ecf20Sopenharmony_ci		esas2r_nvram_set_defaults(a);
9148c2ecf20Sopenharmony_ci
9158c2ecf20Sopenharmony_ci	/* update the caller's uncached memory area pointer */
9168c2ecf20Sopenharmony_ci	*uncached_area = (void *)high;
9178c2ecf20Sopenharmony_ci
9188c2ecf20Sopenharmony_ci	/* initialize the allocated memory */
9198c2ecf20Sopenharmony_ci	if (test_bit(AF_FIRST_INIT, &a->flags)) {
9208c2ecf20Sopenharmony_ci		esas2r_targ_db_initialize(a);
9218c2ecf20Sopenharmony_ci
9228c2ecf20Sopenharmony_ci		/* prime parts of the inbound list */
9238c2ecf20Sopenharmony_ci		element =
9248c2ecf20Sopenharmony_ci			(struct esas2r_inbound_list_source_entry *)a->
9258c2ecf20Sopenharmony_ci			inbound_list_md.
9268c2ecf20Sopenharmony_ci			virt_addr;
9278c2ecf20Sopenharmony_ci
9288c2ecf20Sopenharmony_ci		for (i = 0; i < a->list_size; i++) {
9298c2ecf20Sopenharmony_ci			element->address = 0;
9308c2ecf20Sopenharmony_ci			element->reserved = 0;
9318c2ecf20Sopenharmony_ci			element->length = cpu_to_le32(HWILSE_INTERFACE_F0
9328c2ecf20Sopenharmony_ci						      | (sizeof(union
9338c2ecf20Sopenharmony_ci								atto_vda_req)
9348c2ecf20Sopenharmony_ci							 /
9358c2ecf20Sopenharmony_ci							 sizeof(u32)));
9368c2ecf20Sopenharmony_ci			element++;
9378c2ecf20Sopenharmony_ci		}
9388c2ecf20Sopenharmony_ci
9398c2ecf20Sopenharmony_ci		/* init the AE requests */
9408c2ecf20Sopenharmony_ci		for (rq = a->first_ae_req, i = 0; i < num_ae_requests; rq++,
9418c2ecf20Sopenharmony_ci		     i++) {
9428c2ecf20Sopenharmony_ci			INIT_LIST_HEAD(&rq->req_list);
9438c2ecf20Sopenharmony_ci			if (!alloc_vda_req(a, rq)) {
9448c2ecf20Sopenharmony_ci				esas2r_hdebug(
9458c2ecf20Sopenharmony_ci					"failed to allocate a VDA request!");
9468c2ecf20Sopenharmony_ci				return false;
9478c2ecf20Sopenharmony_ci			}
9488c2ecf20Sopenharmony_ci
9498c2ecf20Sopenharmony_ci			esas2r_rq_init_request(rq, a);
9508c2ecf20Sopenharmony_ci
9518c2ecf20Sopenharmony_ci			/* override the completion function */
9528c2ecf20Sopenharmony_ci			rq->comp_cb = esas2r_ae_complete;
9538c2ecf20Sopenharmony_ci		}
9548c2ecf20Sopenharmony_ci	}
9558c2ecf20Sopenharmony_ci
9568c2ecf20Sopenharmony_ci	return true;
9578c2ecf20Sopenharmony_ci}
9588c2ecf20Sopenharmony_ci
9598c2ecf20Sopenharmony_ci/* This code will verify that the chip is operational. */
9608c2ecf20Sopenharmony_cibool esas2r_check_adapter(struct esas2r_adapter *a)
9618c2ecf20Sopenharmony_ci{
9628c2ecf20Sopenharmony_ci	u32 starttime;
9638c2ecf20Sopenharmony_ci	u32 doorbell;
9648c2ecf20Sopenharmony_ci	u64 ppaddr;
9658c2ecf20Sopenharmony_ci	u32 dw;
9668c2ecf20Sopenharmony_ci
9678c2ecf20Sopenharmony_ci	/*
9688c2ecf20Sopenharmony_ci	 * if the chip reset detected flag is set, we can bypass a bunch of
9698c2ecf20Sopenharmony_ci	 * stuff.
9708c2ecf20Sopenharmony_ci	 */
9718c2ecf20Sopenharmony_ci	if (test_bit(AF_CHPRST_DETECTED, &a->flags))
9728c2ecf20Sopenharmony_ci		goto skip_chip_reset;
9738c2ecf20Sopenharmony_ci
9748c2ecf20Sopenharmony_ci	/*
9758c2ecf20Sopenharmony_ci	 * BEFORE WE DO ANYTHING, disable the chip interrupts!  the boot driver
9768c2ecf20Sopenharmony_ci	 * may have left them enabled or we may be recovering from a fault.
9778c2ecf20Sopenharmony_ci	 */
9788c2ecf20Sopenharmony_ci	esas2r_write_register_dword(a, MU_INT_MASK_OUT, ESAS2R_INT_DIS_MASK);
9798c2ecf20Sopenharmony_ci	esas2r_flush_register_dword(a, MU_INT_MASK_OUT);
9808c2ecf20Sopenharmony_ci
9818c2ecf20Sopenharmony_ci	/*
9828c2ecf20Sopenharmony_ci	 * wait for the firmware to become ready by forcing an interrupt and
9838c2ecf20Sopenharmony_ci	 * waiting for a response.
9848c2ecf20Sopenharmony_ci	 */
9858c2ecf20Sopenharmony_ci	starttime = jiffies_to_msecs(jiffies);
9868c2ecf20Sopenharmony_ci
9878c2ecf20Sopenharmony_ci	while (true) {
9888c2ecf20Sopenharmony_ci		esas2r_force_interrupt(a);
9898c2ecf20Sopenharmony_ci		doorbell = esas2r_read_register_dword(a, MU_DOORBELL_OUT);
9908c2ecf20Sopenharmony_ci		if (doorbell == 0xFFFFFFFF) {
9918c2ecf20Sopenharmony_ci			/*
9928c2ecf20Sopenharmony_ci			 * Give the firmware up to two seconds to enable
9938c2ecf20Sopenharmony_ci			 * register access after a reset.
9948c2ecf20Sopenharmony_ci			 */
9958c2ecf20Sopenharmony_ci			if ((jiffies_to_msecs(jiffies) - starttime) > 2000)
9968c2ecf20Sopenharmony_ci				return esas2r_set_degraded_mode(a,
9978c2ecf20Sopenharmony_ci								"unable to access registers");
9988c2ecf20Sopenharmony_ci		} else if (doorbell & DRBL_FORCE_INT) {
9998c2ecf20Sopenharmony_ci			u32 ver = (doorbell & DRBL_FW_VER_MSK);
10008c2ecf20Sopenharmony_ci
10018c2ecf20Sopenharmony_ci			/*
10028c2ecf20Sopenharmony_ci			 * This driver supports version 0 and version 1 of
10038c2ecf20Sopenharmony_ci			 * the API
10048c2ecf20Sopenharmony_ci			 */
10058c2ecf20Sopenharmony_ci			esas2r_write_register_dword(a, MU_DOORBELL_OUT,
10068c2ecf20Sopenharmony_ci						    doorbell);
10078c2ecf20Sopenharmony_ci
10088c2ecf20Sopenharmony_ci			if (ver == DRBL_FW_VER_0) {
10098c2ecf20Sopenharmony_ci				set_bit(AF_LEGACY_SGE_MODE, &a->flags);
10108c2ecf20Sopenharmony_ci
10118c2ecf20Sopenharmony_ci				a->max_vdareq_size = 128;
10128c2ecf20Sopenharmony_ci				a->build_sgl = esas2r_build_sg_list_sge;
10138c2ecf20Sopenharmony_ci			} else if (ver == DRBL_FW_VER_1) {
10148c2ecf20Sopenharmony_ci				clear_bit(AF_LEGACY_SGE_MODE, &a->flags);
10158c2ecf20Sopenharmony_ci
10168c2ecf20Sopenharmony_ci				a->max_vdareq_size = 1024;
10178c2ecf20Sopenharmony_ci				a->build_sgl = esas2r_build_sg_list_prd;
10188c2ecf20Sopenharmony_ci			} else {
10198c2ecf20Sopenharmony_ci				return esas2r_set_degraded_mode(a,
10208c2ecf20Sopenharmony_ci								"unknown firmware version");
10218c2ecf20Sopenharmony_ci			}
10228c2ecf20Sopenharmony_ci			break;
10238c2ecf20Sopenharmony_ci		}
10248c2ecf20Sopenharmony_ci
10258c2ecf20Sopenharmony_ci		schedule_timeout_interruptible(msecs_to_jiffies(100));
10268c2ecf20Sopenharmony_ci
10278c2ecf20Sopenharmony_ci		if ((jiffies_to_msecs(jiffies) - starttime) > 180000) {
10288c2ecf20Sopenharmony_ci			esas2r_hdebug("FW ready TMO");
10298c2ecf20Sopenharmony_ci			esas2r_bugon();
10308c2ecf20Sopenharmony_ci
10318c2ecf20Sopenharmony_ci			return esas2r_set_degraded_mode(a,
10328c2ecf20Sopenharmony_ci							"firmware start has timed out");
10338c2ecf20Sopenharmony_ci		}
10348c2ecf20Sopenharmony_ci	}
10358c2ecf20Sopenharmony_ci
10368c2ecf20Sopenharmony_ci	/* purge any asynchronous events since we will repost them later */
10378c2ecf20Sopenharmony_ci	esas2r_write_register_dword(a, MU_DOORBELL_IN, DRBL_MSG_IFC_DOWN);
10388c2ecf20Sopenharmony_ci	starttime = jiffies_to_msecs(jiffies);
10398c2ecf20Sopenharmony_ci
10408c2ecf20Sopenharmony_ci	while (true) {
10418c2ecf20Sopenharmony_ci		doorbell = esas2r_read_register_dword(a, MU_DOORBELL_OUT);
10428c2ecf20Sopenharmony_ci		if (doorbell & DRBL_MSG_IFC_DOWN) {
10438c2ecf20Sopenharmony_ci			esas2r_write_register_dword(a, MU_DOORBELL_OUT,
10448c2ecf20Sopenharmony_ci						    doorbell);
10458c2ecf20Sopenharmony_ci			break;
10468c2ecf20Sopenharmony_ci		}
10478c2ecf20Sopenharmony_ci
10488c2ecf20Sopenharmony_ci		schedule_timeout_interruptible(msecs_to_jiffies(50));
10498c2ecf20Sopenharmony_ci
10508c2ecf20Sopenharmony_ci		if ((jiffies_to_msecs(jiffies) - starttime) > 3000) {
10518c2ecf20Sopenharmony_ci			esas2r_hdebug("timeout waiting for interface down");
10528c2ecf20Sopenharmony_ci			break;
10538c2ecf20Sopenharmony_ci		}
10548c2ecf20Sopenharmony_ci	}
10558c2ecf20Sopenharmony_ciskip_chip_reset:
10568c2ecf20Sopenharmony_ci	/*
10578c2ecf20Sopenharmony_ci	 * first things first, before we go changing any of these registers
10588c2ecf20Sopenharmony_ci	 * disable the communication lists.
10598c2ecf20Sopenharmony_ci	 */
10608c2ecf20Sopenharmony_ci	dw = esas2r_read_register_dword(a, MU_IN_LIST_CONFIG);
10618c2ecf20Sopenharmony_ci	dw &= ~MU_ILC_ENABLE;
10628c2ecf20Sopenharmony_ci	esas2r_write_register_dword(a, MU_IN_LIST_CONFIG, dw);
10638c2ecf20Sopenharmony_ci	dw = esas2r_read_register_dword(a, MU_OUT_LIST_CONFIG);
10648c2ecf20Sopenharmony_ci	dw &= ~MU_OLC_ENABLE;
10658c2ecf20Sopenharmony_ci	esas2r_write_register_dword(a, MU_OUT_LIST_CONFIG, dw);
10668c2ecf20Sopenharmony_ci
10678c2ecf20Sopenharmony_ci	/* configure the communication list addresses */
10688c2ecf20Sopenharmony_ci	ppaddr = a->inbound_list_md.phys_addr;
10698c2ecf20Sopenharmony_ci	esas2r_write_register_dword(a, MU_IN_LIST_ADDR_LO,
10708c2ecf20Sopenharmony_ci				    lower_32_bits(ppaddr));
10718c2ecf20Sopenharmony_ci	esas2r_write_register_dword(a, MU_IN_LIST_ADDR_HI,
10728c2ecf20Sopenharmony_ci				    upper_32_bits(ppaddr));
10738c2ecf20Sopenharmony_ci	ppaddr = a->outbound_list_md.phys_addr;
10748c2ecf20Sopenharmony_ci	esas2r_write_register_dword(a, MU_OUT_LIST_ADDR_LO,
10758c2ecf20Sopenharmony_ci				    lower_32_bits(ppaddr));
10768c2ecf20Sopenharmony_ci	esas2r_write_register_dword(a, MU_OUT_LIST_ADDR_HI,
10778c2ecf20Sopenharmony_ci				    upper_32_bits(ppaddr));
10788c2ecf20Sopenharmony_ci	ppaddr = a->uncached_phys +
10798c2ecf20Sopenharmony_ci		 ((u8 *)a->outbound_copy - a->uncached);
10808c2ecf20Sopenharmony_ci	esas2r_write_register_dword(a, MU_OUT_LIST_COPY_PTR_LO,
10818c2ecf20Sopenharmony_ci				    lower_32_bits(ppaddr));
10828c2ecf20Sopenharmony_ci	esas2r_write_register_dword(a, MU_OUT_LIST_COPY_PTR_HI,
10838c2ecf20Sopenharmony_ci				    upper_32_bits(ppaddr));
10848c2ecf20Sopenharmony_ci
10858c2ecf20Sopenharmony_ci	/* reset the read and write pointers */
10868c2ecf20Sopenharmony_ci	*a->outbound_copy =
10878c2ecf20Sopenharmony_ci		a->last_write =
10888c2ecf20Sopenharmony_ci			a->last_read = a->list_size - 1;
10898c2ecf20Sopenharmony_ci	set_bit(AF_COMM_LIST_TOGGLE, &a->flags);
10908c2ecf20Sopenharmony_ci	esas2r_write_register_dword(a, MU_IN_LIST_WRITE, MU_ILW_TOGGLE |
10918c2ecf20Sopenharmony_ci				    a->last_write);
10928c2ecf20Sopenharmony_ci	esas2r_write_register_dword(a, MU_OUT_LIST_COPY, MU_OLC_TOGGLE |
10938c2ecf20Sopenharmony_ci				    a->last_write);
10948c2ecf20Sopenharmony_ci	esas2r_write_register_dword(a, MU_IN_LIST_READ, MU_ILR_TOGGLE |
10958c2ecf20Sopenharmony_ci				    a->last_write);
10968c2ecf20Sopenharmony_ci	esas2r_write_register_dword(a, MU_OUT_LIST_WRITE,
10978c2ecf20Sopenharmony_ci				    MU_OLW_TOGGLE | a->last_write);
10988c2ecf20Sopenharmony_ci
10998c2ecf20Sopenharmony_ci	/* configure the interface select fields */
11008c2ecf20Sopenharmony_ci	dw = esas2r_read_register_dword(a, MU_IN_LIST_IFC_CONFIG);
11018c2ecf20Sopenharmony_ci	dw &= ~(MU_ILIC_LIST | MU_ILIC_DEST);
11028c2ecf20Sopenharmony_ci	esas2r_write_register_dword(a, MU_IN_LIST_IFC_CONFIG,
11038c2ecf20Sopenharmony_ci				    (dw | MU_ILIC_LIST_F0 | MU_ILIC_DEST_DDR));
11048c2ecf20Sopenharmony_ci	dw = esas2r_read_register_dword(a, MU_OUT_LIST_IFC_CONFIG);
11058c2ecf20Sopenharmony_ci	dw &= ~(MU_OLIC_LIST | MU_OLIC_SOURCE);
11068c2ecf20Sopenharmony_ci	esas2r_write_register_dword(a, MU_OUT_LIST_IFC_CONFIG,
11078c2ecf20Sopenharmony_ci				    (dw | MU_OLIC_LIST_F0 |
11088c2ecf20Sopenharmony_ci				     MU_OLIC_SOURCE_DDR));
11098c2ecf20Sopenharmony_ci
11108c2ecf20Sopenharmony_ci	/* finish configuring the communication lists */
11118c2ecf20Sopenharmony_ci	dw = esas2r_read_register_dword(a, MU_IN_LIST_CONFIG);
11128c2ecf20Sopenharmony_ci	dw &= ~(MU_ILC_ENTRY_MASK | MU_ILC_NUMBER_MASK);
11138c2ecf20Sopenharmony_ci	dw |= MU_ILC_ENTRY_4_DW | MU_ILC_DYNAMIC_SRC
11148c2ecf20Sopenharmony_ci	      | (a->list_size << MU_ILC_NUMBER_SHIFT);
11158c2ecf20Sopenharmony_ci	esas2r_write_register_dword(a, MU_IN_LIST_CONFIG, dw);
11168c2ecf20Sopenharmony_ci	dw = esas2r_read_register_dword(a, MU_OUT_LIST_CONFIG);
11178c2ecf20Sopenharmony_ci	dw &= ~(MU_OLC_ENTRY_MASK | MU_OLC_NUMBER_MASK);
11188c2ecf20Sopenharmony_ci	dw |= MU_OLC_ENTRY_4_DW | (a->list_size << MU_OLC_NUMBER_SHIFT);
11198c2ecf20Sopenharmony_ci	esas2r_write_register_dword(a, MU_OUT_LIST_CONFIG, dw);
11208c2ecf20Sopenharmony_ci
11218c2ecf20Sopenharmony_ci	/*
11228c2ecf20Sopenharmony_ci	 * notify the firmware that we're done setting up the communication
11238c2ecf20Sopenharmony_ci	 * list registers.  wait here until the firmware is done configuring
11248c2ecf20Sopenharmony_ci	 * its lists.  it will signal that it is done by enabling the lists.
11258c2ecf20Sopenharmony_ci	 */
11268c2ecf20Sopenharmony_ci	esas2r_write_register_dword(a, MU_DOORBELL_IN, DRBL_MSG_IFC_INIT);
11278c2ecf20Sopenharmony_ci	starttime = jiffies_to_msecs(jiffies);
11288c2ecf20Sopenharmony_ci
11298c2ecf20Sopenharmony_ci	while (true) {
11308c2ecf20Sopenharmony_ci		doorbell = esas2r_read_register_dword(a, MU_DOORBELL_OUT);
11318c2ecf20Sopenharmony_ci		if (doorbell & DRBL_MSG_IFC_INIT) {
11328c2ecf20Sopenharmony_ci			esas2r_write_register_dword(a, MU_DOORBELL_OUT,
11338c2ecf20Sopenharmony_ci						    doorbell);
11348c2ecf20Sopenharmony_ci			break;
11358c2ecf20Sopenharmony_ci		}
11368c2ecf20Sopenharmony_ci
11378c2ecf20Sopenharmony_ci		schedule_timeout_interruptible(msecs_to_jiffies(100));
11388c2ecf20Sopenharmony_ci
11398c2ecf20Sopenharmony_ci		if ((jiffies_to_msecs(jiffies) - starttime) > 3000) {
11408c2ecf20Sopenharmony_ci			esas2r_hdebug(
11418c2ecf20Sopenharmony_ci				"timeout waiting for communication list init");
11428c2ecf20Sopenharmony_ci			esas2r_bugon();
11438c2ecf20Sopenharmony_ci			return esas2r_set_degraded_mode(a,
11448c2ecf20Sopenharmony_ci							"timeout waiting for communication list init");
11458c2ecf20Sopenharmony_ci		}
11468c2ecf20Sopenharmony_ci	}
11478c2ecf20Sopenharmony_ci
11488c2ecf20Sopenharmony_ci	/*
11498c2ecf20Sopenharmony_ci	 * flag whether the firmware supports the power down doorbell.  we
11508c2ecf20Sopenharmony_ci	 * determine this by reading the inbound doorbell enable mask.
11518c2ecf20Sopenharmony_ci	 */
11528c2ecf20Sopenharmony_ci	doorbell = esas2r_read_register_dword(a, MU_DOORBELL_IN_ENB);
11538c2ecf20Sopenharmony_ci	if (doorbell & DRBL_POWER_DOWN)
11548c2ecf20Sopenharmony_ci		set_bit(AF2_VDA_POWER_DOWN, &a->flags2);
11558c2ecf20Sopenharmony_ci	else
11568c2ecf20Sopenharmony_ci		clear_bit(AF2_VDA_POWER_DOWN, &a->flags2);
11578c2ecf20Sopenharmony_ci
11588c2ecf20Sopenharmony_ci	/*
11598c2ecf20Sopenharmony_ci	 * enable assertion of outbound queue and doorbell interrupts in the
11608c2ecf20Sopenharmony_ci	 * main interrupt cause register.
11618c2ecf20Sopenharmony_ci	 */
11628c2ecf20Sopenharmony_ci	esas2r_write_register_dword(a, MU_OUT_LIST_INT_MASK, MU_OLIS_MASK);
11638c2ecf20Sopenharmony_ci	esas2r_write_register_dword(a, MU_DOORBELL_OUT_ENB, DRBL_ENB_MASK);
11648c2ecf20Sopenharmony_ci	return true;
11658c2ecf20Sopenharmony_ci}
11668c2ecf20Sopenharmony_ci
11678c2ecf20Sopenharmony_ci/* Process the initialization message just completed and format the next one. */
11688c2ecf20Sopenharmony_cistatic bool esas2r_format_init_msg(struct esas2r_adapter *a,
11698c2ecf20Sopenharmony_ci				   struct esas2r_request *rq)
11708c2ecf20Sopenharmony_ci{
11718c2ecf20Sopenharmony_ci	u32 msg = a->init_msg;
11728c2ecf20Sopenharmony_ci	struct atto_vda_cfg_init *ci;
11738c2ecf20Sopenharmony_ci
11748c2ecf20Sopenharmony_ci	a->init_msg = 0;
11758c2ecf20Sopenharmony_ci
11768c2ecf20Sopenharmony_ci	switch (msg) {
11778c2ecf20Sopenharmony_ci	case ESAS2R_INIT_MSG_START:
11788c2ecf20Sopenharmony_ci	case ESAS2R_INIT_MSG_REINIT:
11798c2ecf20Sopenharmony_ci	{
11808c2ecf20Sopenharmony_ci		esas2r_hdebug("CFG init");
11818c2ecf20Sopenharmony_ci		esas2r_build_cfg_req(a,
11828c2ecf20Sopenharmony_ci				     rq,
11838c2ecf20Sopenharmony_ci				     VDA_CFG_INIT,
11848c2ecf20Sopenharmony_ci				     0,
11858c2ecf20Sopenharmony_ci				     NULL);
11868c2ecf20Sopenharmony_ci		ci = (struct atto_vda_cfg_init *)&rq->vrq->cfg.data.init;
11878c2ecf20Sopenharmony_ci		ci->sgl_page_size = cpu_to_le32(sgl_page_size);
11888c2ecf20Sopenharmony_ci		/* firmware interface overflows in y2106 */
11898c2ecf20Sopenharmony_ci		ci->epoch_time = cpu_to_le32(ktime_get_real_seconds());
11908c2ecf20Sopenharmony_ci		rq->flags |= RF_FAILURE_OK;
11918c2ecf20Sopenharmony_ci		a->init_msg = ESAS2R_INIT_MSG_INIT;
11928c2ecf20Sopenharmony_ci		break;
11938c2ecf20Sopenharmony_ci	}
11948c2ecf20Sopenharmony_ci
11958c2ecf20Sopenharmony_ci	case ESAS2R_INIT_MSG_INIT:
11968c2ecf20Sopenharmony_ci		if (rq->req_stat == RS_SUCCESS) {
11978c2ecf20Sopenharmony_ci			u32 major;
11988c2ecf20Sopenharmony_ci			u32 minor;
11998c2ecf20Sopenharmony_ci			u16 fw_release;
12008c2ecf20Sopenharmony_ci
12018c2ecf20Sopenharmony_ci			a->fw_version = le16_to_cpu(
12028c2ecf20Sopenharmony_ci				rq->func_rsp.cfg_rsp.vda_version);
12038c2ecf20Sopenharmony_ci			a->fw_build = rq->func_rsp.cfg_rsp.fw_build;
12048c2ecf20Sopenharmony_ci			fw_release = le16_to_cpu(
12058c2ecf20Sopenharmony_ci				rq->func_rsp.cfg_rsp.fw_release);
12068c2ecf20Sopenharmony_ci			major = LOBYTE(fw_release);
12078c2ecf20Sopenharmony_ci			minor = HIBYTE(fw_release);
12088c2ecf20Sopenharmony_ci			a->fw_version += (major << 16) + (minor << 24);
12098c2ecf20Sopenharmony_ci		} else {
12108c2ecf20Sopenharmony_ci			esas2r_hdebug("FAILED");
12118c2ecf20Sopenharmony_ci		}
12128c2ecf20Sopenharmony_ci
12138c2ecf20Sopenharmony_ci		/*
12148c2ecf20Sopenharmony_ci		 * the 2.71 and earlier releases of R6xx firmware did not error
12158c2ecf20Sopenharmony_ci		 * unsupported config requests correctly.
12168c2ecf20Sopenharmony_ci		 */
12178c2ecf20Sopenharmony_ci
12188c2ecf20Sopenharmony_ci		if ((test_bit(AF2_THUNDERBOLT, &a->flags2))
12198c2ecf20Sopenharmony_ci		    || (be32_to_cpu(a->fw_version) > 0x00524702)) {
12208c2ecf20Sopenharmony_ci			esas2r_hdebug("CFG get init");
12218c2ecf20Sopenharmony_ci			esas2r_build_cfg_req(a,
12228c2ecf20Sopenharmony_ci					     rq,
12238c2ecf20Sopenharmony_ci					     VDA_CFG_GET_INIT2,
12248c2ecf20Sopenharmony_ci					     sizeof(struct atto_vda_cfg_init),
12258c2ecf20Sopenharmony_ci					     NULL);
12268c2ecf20Sopenharmony_ci
12278c2ecf20Sopenharmony_ci			rq->vrq->cfg.sg_list_offset = offsetof(
12288c2ecf20Sopenharmony_ci				struct atto_vda_cfg_req,
12298c2ecf20Sopenharmony_ci				data.sge);
12308c2ecf20Sopenharmony_ci			rq->vrq->cfg.data.prde.ctl_len =
12318c2ecf20Sopenharmony_ci				cpu_to_le32(sizeof(struct atto_vda_cfg_init));
12328c2ecf20Sopenharmony_ci			rq->vrq->cfg.data.prde.address = cpu_to_le64(
12338c2ecf20Sopenharmony_ci				rq->vrq_md->phys_addr +
12348c2ecf20Sopenharmony_ci				sizeof(union atto_vda_req));
12358c2ecf20Sopenharmony_ci			rq->flags |= RF_FAILURE_OK;
12368c2ecf20Sopenharmony_ci			a->init_msg = ESAS2R_INIT_MSG_GET_INIT;
12378c2ecf20Sopenharmony_ci			break;
12388c2ecf20Sopenharmony_ci		}
12398c2ecf20Sopenharmony_ci		fallthrough;
12408c2ecf20Sopenharmony_ci
12418c2ecf20Sopenharmony_ci	case ESAS2R_INIT_MSG_GET_INIT:
12428c2ecf20Sopenharmony_ci		if (msg == ESAS2R_INIT_MSG_GET_INIT) {
12438c2ecf20Sopenharmony_ci			ci = (struct atto_vda_cfg_init *)rq->data_buf;
12448c2ecf20Sopenharmony_ci			if (rq->req_stat == RS_SUCCESS) {
12458c2ecf20Sopenharmony_ci				a->num_targets_backend =
12468c2ecf20Sopenharmony_ci					le32_to_cpu(ci->num_targets_backend);
12478c2ecf20Sopenharmony_ci				a->ioctl_tunnel =
12488c2ecf20Sopenharmony_ci					le32_to_cpu(ci->ioctl_tunnel);
12498c2ecf20Sopenharmony_ci			} else {
12508c2ecf20Sopenharmony_ci				esas2r_hdebug("FAILED");
12518c2ecf20Sopenharmony_ci			}
12528c2ecf20Sopenharmony_ci		}
12538c2ecf20Sopenharmony_ci		fallthrough;
12548c2ecf20Sopenharmony_ci
12558c2ecf20Sopenharmony_ci	default:
12568c2ecf20Sopenharmony_ci		rq->req_stat = RS_SUCCESS;
12578c2ecf20Sopenharmony_ci		return false;
12588c2ecf20Sopenharmony_ci	}
12598c2ecf20Sopenharmony_ci	return true;
12608c2ecf20Sopenharmony_ci}
12618c2ecf20Sopenharmony_ci
12628c2ecf20Sopenharmony_ci/*
12638c2ecf20Sopenharmony_ci * Perform initialization messages via the request queue.  Messages are
12648c2ecf20Sopenharmony_ci * performed with interrupts disabled.
12658c2ecf20Sopenharmony_ci */
12668c2ecf20Sopenharmony_cibool esas2r_init_msgs(struct esas2r_adapter *a)
12678c2ecf20Sopenharmony_ci{
12688c2ecf20Sopenharmony_ci	bool success = true;
12698c2ecf20Sopenharmony_ci	struct esas2r_request *rq = &a->general_req;
12708c2ecf20Sopenharmony_ci
12718c2ecf20Sopenharmony_ci	esas2r_rq_init_request(rq, a);
12728c2ecf20Sopenharmony_ci	rq->comp_cb = esas2r_dummy_complete;
12738c2ecf20Sopenharmony_ci
12748c2ecf20Sopenharmony_ci	if (a->init_msg == 0)
12758c2ecf20Sopenharmony_ci		a->init_msg = ESAS2R_INIT_MSG_REINIT;
12768c2ecf20Sopenharmony_ci
12778c2ecf20Sopenharmony_ci	while (a->init_msg) {
12788c2ecf20Sopenharmony_ci		if (esas2r_format_init_msg(a, rq)) {
12798c2ecf20Sopenharmony_ci			unsigned long flags;
12808c2ecf20Sopenharmony_ci			while (true) {
12818c2ecf20Sopenharmony_ci				spin_lock_irqsave(&a->queue_lock, flags);
12828c2ecf20Sopenharmony_ci				esas2r_start_vda_request(a, rq);
12838c2ecf20Sopenharmony_ci				spin_unlock_irqrestore(&a->queue_lock, flags);
12848c2ecf20Sopenharmony_ci				esas2r_wait_request(a, rq);
12858c2ecf20Sopenharmony_ci				if (rq->req_stat != RS_PENDING)
12868c2ecf20Sopenharmony_ci					break;
12878c2ecf20Sopenharmony_ci			}
12888c2ecf20Sopenharmony_ci		}
12898c2ecf20Sopenharmony_ci
12908c2ecf20Sopenharmony_ci		if (rq->req_stat == RS_SUCCESS
12918c2ecf20Sopenharmony_ci		    || ((rq->flags & RF_FAILURE_OK)
12928c2ecf20Sopenharmony_ci			&& rq->req_stat != RS_TIMEOUT))
12938c2ecf20Sopenharmony_ci			continue;
12948c2ecf20Sopenharmony_ci
12958c2ecf20Sopenharmony_ci		esas2r_log(ESAS2R_LOG_CRIT, "init message %x failed (%x, %x)",
12968c2ecf20Sopenharmony_ci			   a->init_msg, rq->req_stat, rq->flags);
12978c2ecf20Sopenharmony_ci		a->init_msg = ESAS2R_INIT_MSG_START;
12988c2ecf20Sopenharmony_ci		success = false;
12998c2ecf20Sopenharmony_ci		break;
13008c2ecf20Sopenharmony_ci	}
13018c2ecf20Sopenharmony_ci
13028c2ecf20Sopenharmony_ci	esas2r_rq_destroy_request(rq, a);
13038c2ecf20Sopenharmony_ci	return success;
13048c2ecf20Sopenharmony_ci}
13058c2ecf20Sopenharmony_ci
13068c2ecf20Sopenharmony_ci/* Initialize the adapter chip */
13078c2ecf20Sopenharmony_cibool esas2r_init_adapter_hw(struct esas2r_adapter *a, bool init_poll)
13088c2ecf20Sopenharmony_ci{
13098c2ecf20Sopenharmony_ci	bool rslt = false;
13108c2ecf20Sopenharmony_ci	struct esas2r_request *rq;
13118c2ecf20Sopenharmony_ci	u32 i;
13128c2ecf20Sopenharmony_ci
13138c2ecf20Sopenharmony_ci	if (test_bit(AF_DEGRADED_MODE, &a->flags))
13148c2ecf20Sopenharmony_ci		goto exit;
13158c2ecf20Sopenharmony_ci
13168c2ecf20Sopenharmony_ci	if (!test_bit(AF_NVR_VALID, &a->flags)) {
13178c2ecf20Sopenharmony_ci		if (!esas2r_nvram_read_direct(a))
13188c2ecf20Sopenharmony_ci			esas2r_log(ESAS2R_LOG_WARN,
13198c2ecf20Sopenharmony_ci				   "invalid/missing NVRAM parameters");
13208c2ecf20Sopenharmony_ci	}
13218c2ecf20Sopenharmony_ci
13228c2ecf20Sopenharmony_ci	if (!esas2r_init_msgs(a)) {
13238c2ecf20Sopenharmony_ci		esas2r_set_degraded_mode(a, "init messages failed");
13248c2ecf20Sopenharmony_ci		goto exit;
13258c2ecf20Sopenharmony_ci	}
13268c2ecf20Sopenharmony_ci
13278c2ecf20Sopenharmony_ci	/* The firmware is ready. */
13288c2ecf20Sopenharmony_ci	clear_bit(AF_DEGRADED_MODE, &a->flags);
13298c2ecf20Sopenharmony_ci	clear_bit(AF_CHPRST_PENDING, &a->flags);
13308c2ecf20Sopenharmony_ci
13318c2ecf20Sopenharmony_ci	/* Post all the async event requests */
13328c2ecf20Sopenharmony_ci	for (i = 0, rq = a->first_ae_req; i < num_ae_requests; i++, rq++)
13338c2ecf20Sopenharmony_ci		esas2r_start_ae_request(a, rq);
13348c2ecf20Sopenharmony_ci
13358c2ecf20Sopenharmony_ci	if (!a->flash_rev[0])
13368c2ecf20Sopenharmony_ci		esas2r_read_flash_rev(a);
13378c2ecf20Sopenharmony_ci
13388c2ecf20Sopenharmony_ci	if (!a->image_type[0])
13398c2ecf20Sopenharmony_ci		esas2r_read_image_type(a);
13408c2ecf20Sopenharmony_ci
13418c2ecf20Sopenharmony_ci	if (a->fw_version == 0)
13428c2ecf20Sopenharmony_ci		a->fw_rev[0] = 0;
13438c2ecf20Sopenharmony_ci	else
13448c2ecf20Sopenharmony_ci		sprintf(a->fw_rev, "%1d.%02d",
13458c2ecf20Sopenharmony_ci			(int)LOBYTE(HIWORD(a->fw_version)),
13468c2ecf20Sopenharmony_ci			(int)HIBYTE(HIWORD(a->fw_version)));
13478c2ecf20Sopenharmony_ci
13488c2ecf20Sopenharmony_ci	esas2r_hdebug("firmware revision: %s", a->fw_rev);
13498c2ecf20Sopenharmony_ci
13508c2ecf20Sopenharmony_ci	if (test_bit(AF_CHPRST_DETECTED, &a->flags)
13518c2ecf20Sopenharmony_ci	    && (test_bit(AF_FIRST_INIT, &a->flags))) {
13528c2ecf20Sopenharmony_ci		esas2r_enable_chip_interrupts(a);
13538c2ecf20Sopenharmony_ci		return true;
13548c2ecf20Sopenharmony_ci	}
13558c2ecf20Sopenharmony_ci
13568c2ecf20Sopenharmony_ci	/* initialize discovery */
13578c2ecf20Sopenharmony_ci	esas2r_disc_initialize(a);
13588c2ecf20Sopenharmony_ci
13598c2ecf20Sopenharmony_ci	/*
13608c2ecf20Sopenharmony_ci	 * wait for the device wait time to expire here if requested.  this is
13618c2ecf20Sopenharmony_ci	 * usually requested during initial driver load and possibly when
13628c2ecf20Sopenharmony_ci	 * resuming from a low power state.  deferred device waiting will use
13638c2ecf20Sopenharmony_ci	 * interrupts.  chip reset recovery always defers device waiting to
13648c2ecf20Sopenharmony_ci	 * avoid being in a TASKLET too long.
13658c2ecf20Sopenharmony_ci	 */
13668c2ecf20Sopenharmony_ci	if (init_poll) {
13678c2ecf20Sopenharmony_ci		u32 currtime = a->disc_start_time;
13688c2ecf20Sopenharmony_ci		u32 nexttick = 100;
13698c2ecf20Sopenharmony_ci		u32 deltatime;
13708c2ecf20Sopenharmony_ci
13718c2ecf20Sopenharmony_ci		/*
13728c2ecf20Sopenharmony_ci		 * Block Tasklets from getting scheduled and indicate this is
13738c2ecf20Sopenharmony_ci		 * polled discovery.
13748c2ecf20Sopenharmony_ci		 */
13758c2ecf20Sopenharmony_ci		set_bit(AF_TASKLET_SCHEDULED, &a->flags);
13768c2ecf20Sopenharmony_ci		set_bit(AF_DISC_POLLED, &a->flags);
13778c2ecf20Sopenharmony_ci
13788c2ecf20Sopenharmony_ci		/*
13798c2ecf20Sopenharmony_ci		 * Temporarily bring the disable count to zero to enable
13808c2ecf20Sopenharmony_ci		 * deferred processing.  Note that the count is already zero
13818c2ecf20Sopenharmony_ci		 * after the first initialization.
13828c2ecf20Sopenharmony_ci		 */
13838c2ecf20Sopenharmony_ci		if (test_bit(AF_FIRST_INIT, &a->flags))
13848c2ecf20Sopenharmony_ci			atomic_dec(&a->disable_cnt);
13858c2ecf20Sopenharmony_ci
13868c2ecf20Sopenharmony_ci		while (test_bit(AF_DISC_PENDING, &a->flags)) {
13878c2ecf20Sopenharmony_ci			schedule_timeout_interruptible(msecs_to_jiffies(100));
13888c2ecf20Sopenharmony_ci
13898c2ecf20Sopenharmony_ci			/*
13908c2ecf20Sopenharmony_ci			 * Determine the need for a timer tick based on the
13918c2ecf20Sopenharmony_ci			 * delta time between this and the last iteration of
13928c2ecf20Sopenharmony_ci			 * this loop.  We don't use the absolute time because
13938c2ecf20Sopenharmony_ci			 * then we would have to worry about when nexttick
13948c2ecf20Sopenharmony_ci			 * wraps and currtime hasn't yet.
13958c2ecf20Sopenharmony_ci			 */
13968c2ecf20Sopenharmony_ci			deltatime = jiffies_to_msecs(jiffies) - currtime;
13978c2ecf20Sopenharmony_ci			currtime += deltatime;
13988c2ecf20Sopenharmony_ci
13998c2ecf20Sopenharmony_ci			/*
14008c2ecf20Sopenharmony_ci			 * Process any waiting discovery as long as the chip is
14018c2ecf20Sopenharmony_ci			 * up.  If a chip reset happens during initial polling,
14028c2ecf20Sopenharmony_ci			 * we have to make sure the timer tick processes the
14038c2ecf20Sopenharmony_ci			 * doorbell indicating the firmware is ready.
14048c2ecf20Sopenharmony_ci			 */
14058c2ecf20Sopenharmony_ci			if (!test_bit(AF_CHPRST_PENDING, &a->flags))
14068c2ecf20Sopenharmony_ci				esas2r_disc_check_for_work(a);
14078c2ecf20Sopenharmony_ci
14088c2ecf20Sopenharmony_ci			/* Simulate a timer tick. */
14098c2ecf20Sopenharmony_ci			if (nexttick <= deltatime) {
14108c2ecf20Sopenharmony_ci
14118c2ecf20Sopenharmony_ci				/* Time for a timer tick */
14128c2ecf20Sopenharmony_ci				nexttick += 100;
14138c2ecf20Sopenharmony_ci				esas2r_timer_tick(a);
14148c2ecf20Sopenharmony_ci			}
14158c2ecf20Sopenharmony_ci
14168c2ecf20Sopenharmony_ci			if (nexttick > deltatime)
14178c2ecf20Sopenharmony_ci				nexttick -= deltatime;
14188c2ecf20Sopenharmony_ci
14198c2ecf20Sopenharmony_ci			/* Do any deferred processing */
14208c2ecf20Sopenharmony_ci			if (esas2r_is_tasklet_pending(a))
14218c2ecf20Sopenharmony_ci				esas2r_do_tasklet_tasks(a);
14228c2ecf20Sopenharmony_ci
14238c2ecf20Sopenharmony_ci		}
14248c2ecf20Sopenharmony_ci
14258c2ecf20Sopenharmony_ci		if (test_bit(AF_FIRST_INIT, &a->flags))
14268c2ecf20Sopenharmony_ci			atomic_inc(&a->disable_cnt);
14278c2ecf20Sopenharmony_ci
14288c2ecf20Sopenharmony_ci		clear_bit(AF_DISC_POLLED, &a->flags);
14298c2ecf20Sopenharmony_ci		clear_bit(AF_TASKLET_SCHEDULED, &a->flags);
14308c2ecf20Sopenharmony_ci	}
14318c2ecf20Sopenharmony_ci
14328c2ecf20Sopenharmony_ci
14338c2ecf20Sopenharmony_ci	esas2r_targ_db_report_changes(a);
14348c2ecf20Sopenharmony_ci
14358c2ecf20Sopenharmony_ci	/*
14368c2ecf20Sopenharmony_ci	 * For cases where (a) the initialization messages processing may
14378c2ecf20Sopenharmony_ci	 * handle an interrupt for a port event and a discovery is waiting, but
14388c2ecf20Sopenharmony_ci	 * we are not waiting for devices, or (b) the device wait time has been
14398c2ecf20Sopenharmony_ci	 * exhausted but there is still discovery pending, start any leftover
14408c2ecf20Sopenharmony_ci	 * discovery in interrupt driven mode.
14418c2ecf20Sopenharmony_ci	 */
14428c2ecf20Sopenharmony_ci	esas2r_disc_start_waiting(a);
14438c2ecf20Sopenharmony_ci
14448c2ecf20Sopenharmony_ci	/* Enable chip interrupts */
14458c2ecf20Sopenharmony_ci	a->int_mask = ESAS2R_INT_STS_MASK;
14468c2ecf20Sopenharmony_ci	esas2r_enable_chip_interrupts(a);
14478c2ecf20Sopenharmony_ci	esas2r_enable_heartbeat(a);
14488c2ecf20Sopenharmony_ci	rslt = true;
14498c2ecf20Sopenharmony_ci
14508c2ecf20Sopenharmony_ciexit:
14518c2ecf20Sopenharmony_ci	/*
14528c2ecf20Sopenharmony_ci	 * Regardless of whether initialization was successful, certain things
14538c2ecf20Sopenharmony_ci	 * need to get done before we exit.
14548c2ecf20Sopenharmony_ci	 */
14558c2ecf20Sopenharmony_ci
14568c2ecf20Sopenharmony_ci	if (test_bit(AF_CHPRST_DETECTED, &a->flags) &&
14578c2ecf20Sopenharmony_ci	    test_bit(AF_FIRST_INIT, &a->flags)) {
14588c2ecf20Sopenharmony_ci		/*
14598c2ecf20Sopenharmony_ci		 * Reinitialization was performed during the first
14608c2ecf20Sopenharmony_ci		 * initialization.  Only clear the chip reset flag so the
14618c2ecf20Sopenharmony_ci		 * original device polling is not cancelled.
14628c2ecf20Sopenharmony_ci		 */
14638c2ecf20Sopenharmony_ci		if (!rslt)
14648c2ecf20Sopenharmony_ci			clear_bit(AF_CHPRST_PENDING, &a->flags);
14658c2ecf20Sopenharmony_ci	} else {
14668c2ecf20Sopenharmony_ci		/* First initialization or a subsequent re-init is complete. */
14678c2ecf20Sopenharmony_ci		if (!rslt) {
14688c2ecf20Sopenharmony_ci			clear_bit(AF_CHPRST_PENDING, &a->flags);
14698c2ecf20Sopenharmony_ci			clear_bit(AF_DISC_PENDING, &a->flags);
14708c2ecf20Sopenharmony_ci		}
14718c2ecf20Sopenharmony_ci
14728c2ecf20Sopenharmony_ci
14738c2ecf20Sopenharmony_ci		/* Enable deferred processing after the first initialization. */
14748c2ecf20Sopenharmony_ci		if (test_bit(AF_FIRST_INIT, &a->flags)) {
14758c2ecf20Sopenharmony_ci			clear_bit(AF_FIRST_INIT, &a->flags);
14768c2ecf20Sopenharmony_ci
14778c2ecf20Sopenharmony_ci			if (atomic_dec_return(&a->disable_cnt) == 0)
14788c2ecf20Sopenharmony_ci				esas2r_do_deferred_processes(a);
14798c2ecf20Sopenharmony_ci		}
14808c2ecf20Sopenharmony_ci	}
14818c2ecf20Sopenharmony_ci
14828c2ecf20Sopenharmony_ci	return rslt;
14838c2ecf20Sopenharmony_ci}
14848c2ecf20Sopenharmony_ci
14858c2ecf20Sopenharmony_civoid esas2r_reset_adapter(struct esas2r_adapter *a)
14868c2ecf20Sopenharmony_ci{
14878c2ecf20Sopenharmony_ci	set_bit(AF_OS_RESET, &a->flags);
14888c2ecf20Sopenharmony_ci	esas2r_local_reset_adapter(a);
14898c2ecf20Sopenharmony_ci	esas2r_schedule_tasklet(a);
14908c2ecf20Sopenharmony_ci}
14918c2ecf20Sopenharmony_ci
14928c2ecf20Sopenharmony_civoid esas2r_reset_chip(struct esas2r_adapter *a)
14938c2ecf20Sopenharmony_ci{
14948c2ecf20Sopenharmony_ci	if (!esas2r_is_adapter_present(a))
14958c2ecf20Sopenharmony_ci		return;
14968c2ecf20Sopenharmony_ci
14978c2ecf20Sopenharmony_ci	/*
14988c2ecf20Sopenharmony_ci	 * Before we reset the chip, save off the VDA core dump.  The VDA core
14998c2ecf20Sopenharmony_ci	 * dump is located in the upper 512KB of the onchip SRAM.  Make sure
15008c2ecf20Sopenharmony_ci	 * to not overwrite a previous crash that was saved.
15018c2ecf20Sopenharmony_ci	 */
15028c2ecf20Sopenharmony_ci	if (test_bit(AF2_COREDUMP_AVAIL, &a->flags2) &&
15038c2ecf20Sopenharmony_ci	    !test_bit(AF2_COREDUMP_SAVED, &a->flags2)) {
15048c2ecf20Sopenharmony_ci		esas2r_read_mem_block(a,
15058c2ecf20Sopenharmony_ci				      a->fw_coredump_buff,
15068c2ecf20Sopenharmony_ci				      MW_DATA_ADDR_SRAM + 0x80000,
15078c2ecf20Sopenharmony_ci				      ESAS2R_FWCOREDUMP_SZ);
15088c2ecf20Sopenharmony_ci
15098c2ecf20Sopenharmony_ci		set_bit(AF2_COREDUMP_SAVED, &a->flags2);
15108c2ecf20Sopenharmony_ci	}
15118c2ecf20Sopenharmony_ci
15128c2ecf20Sopenharmony_ci	clear_bit(AF2_COREDUMP_AVAIL, &a->flags2);
15138c2ecf20Sopenharmony_ci
15148c2ecf20Sopenharmony_ci	/* Reset the chip */
15158c2ecf20Sopenharmony_ci	if (a->pcid->revision == MVR_FREY_B2)
15168c2ecf20Sopenharmony_ci		esas2r_write_register_dword(a, MU_CTL_STATUS_IN_B2,
15178c2ecf20Sopenharmony_ci					    MU_CTL_IN_FULL_RST2);
15188c2ecf20Sopenharmony_ci	else
15198c2ecf20Sopenharmony_ci		esas2r_write_register_dword(a, MU_CTL_STATUS_IN,
15208c2ecf20Sopenharmony_ci					    MU_CTL_IN_FULL_RST);
15218c2ecf20Sopenharmony_ci
15228c2ecf20Sopenharmony_ci
15238c2ecf20Sopenharmony_ci	/* Stall a little while to let the reset condition clear */
15248c2ecf20Sopenharmony_ci	mdelay(10);
15258c2ecf20Sopenharmony_ci}
15268c2ecf20Sopenharmony_ci
15278c2ecf20Sopenharmony_cistatic void esas2r_power_down_notify_firmware(struct esas2r_adapter *a)
15288c2ecf20Sopenharmony_ci{
15298c2ecf20Sopenharmony_ci	u32 starttime;
15308c2ecf20Sopenharmony_ci	u32 doorbell;
15318c2ecf20Sopenharmony_ci
15328c2ecf20Sopenharmony_ci	esas2r_write_register_dword(a, MU_DOORBELL_IN, DRBL_POWER_DOWN);
15338c2ecf20Sopenharmony_ci	starttime = jiffies_to_msecs(jiffies);
15348c2ecf20Sopenharmony_ci
15358c2ecf20Sopenharmony_ci	while (true) {
15368c2ecf20Sopenharmony_ci		doorbell = esas2r_read_register_dword(a, MU_DOORBELL_OUT);
15378c2ecf20Sopenharmony_ci		if (doorbell & DRBL_POWER_DOWN) {
15388c2ecf20Sopenharmony_ci			esas2r_write_register_dword(a, MU_DOORBELL_OUT,
15398c2ecf20Sopenharmony_ci						    doorbell);
15408c2ecf20Sopenharmony_ci			break;
15418c2ecf20Sopenharmony_ci		}
15428c2ecf20Sopenharmony_ci
15438c2ecf20Sopenharmony_ci		schedule_timeout_interruptible(msecs_to_jiffies(100));
15448c2ecf20Sopenharmony_ci
15458c2ecf20Sopenharmony_ci		if ((jiffies_to_msecs(jiffies) - starttime) > 30000) {
15468c2ecf20Sopenharmony_ci			esas2r_hdebug("Timeout waiting for power down");
15478c2ecf20Sopenharmony_ci			break;
15488c2ecf20Sopenharmony_ci		}
15498c2ecf20Sopenharmony_ci	}
15508c2ecf20Sopenharmony_ci}
15518c2ecf20Sopenharmony_ci
15528c2ecf20Sopenharmony_ci/*
15538c2ecf20Sopenharmony_ci * Perform power management processing including managing device states, adapter
15548c2ecf20Sopenharmony_ci * states, interrupts, and I/O.
15558c2ecf20Sopenharmony_ci */
15568c2ecf20Sopenharmony_civoid esas2r_power_down(struct esas2r_adapter *a)
15578c2ecf20Sopenharmony_ci{
15588c2ecf20Sopenharmony_ci	set_bit(AF_POWER_MGT, &a->flags);
15598c2ecf20Sopenharmony_ci	set_bit(AF_POWER_DOWN, &a->flags);
15608c2ecf20Sopenharmony_ci
15618c2ecf20Sopenharmony_ci	if (!test_bit(AF_DEGRADED_MODE, &a->flags)) {
15628c2ecf20Sopenharmony_ci		u32 starttime;
15638c2ecf20Sopenharmony_ci		u32 doorbell;
15648c2ecf20Sopenharmony_ci
15658c2ecf20Sopenharmony_ci		/*
15668c2ecf20Sopenharmony_ci		 * We are currently running OK and will be reinitializing later.
15678c2ecf20Sopenharmony_ci		 * increment the disable count to coordinate with
15688c2ecf20Sopenharmony_ci		 * esas2r_init_adapter.  We don't have to do this in degraded
15698c2ecf20Sopenharmony_ci		 * mode since we never enabled interrupts in the first place.
15708c2ecf20Sopenharmony_ci		 */
15718c2ecf20Sopenharmony_ci		esas2r_disable_chip_interrupts(a);
15728c2ecf20Sopenharmony_ci		esas2r_disable_heartbeat(a);
15738c2ecf20Sopenharmony_ci
15748c2ecf20Sopenharmony_ci		/* wait for any VDA activity to clear before continuing */
15758c2ecf20Sopenharmony_ci		esas2r_write_register_dword(a, MU_DOORBELL_IN,
15768c2ecf20Sopenharmony_ci					    DRBL_MSG_IFC_DOWN);
15778c2ecf20Sopenharmony_ci		starttime = jiffies_to_msecs(jiffies);
15788c2ecf20Sopenharmony_ci
15798c2ecf20Sopenharmony_ci		while (true) {
15808c2ecf20Sopenharmony_ci			doorbell =
15818c2ecf20Sopenharmony_ci				esas2r_read_register_dword(a, MU_DOORBELL_OUT);
15828c2ecf20Sopenharmony_ci			if (doorbell & DRBL_MSG_IFC_DOWN) {
15838c2ecf20Sopenharmony_ci				esas2r_write_register_dword(a, MU_DOORBELL_OUT,
15848c2ecf20Sopenharmony_ci							    doorbell);
15858c2ecf20Sopenharmony_ci				break;
15868c2ecf20Sopenharmony_ci			}
15878c2ecf20Sopenharmony_ci
15888c2ecf20Sopenharmony_ci			schedule_timeout_interruptible(msecs_to_jiffies(100));
15898c2ecf20Sopenharmony_ci
15908c2ecf20Sopenharmony_ci			if ((jiffies_to_msecs(jiffies) - starttime) > 3000) {
15918c2ecf20Sopenharmony_ci				esas2r_hdebug(
15928c2ecf20Sopenharmony_ci					"timeout waiting for interface down");
15938c2ecf20Sopenharmony_ci				break;
15948c2ecf20Sopenharmony_ci			}
15958c2ecf20Sopenharmony_ci		}
15968c2ecf20Sopenharmony_ci
15978c2ecf20Sopenharmony_ci		/*
15988c2ecf20Sopenharmony_ci		 * For versions of firmware that support it tell them the driver
15998c2ecf20Sopenharmony_ci		 * is powering down.
16008c2ecf20Sopenharmony_ci		 */
16018c2ecf20Sopenharmony_ci		if (test_bit(AF2_VDA_POWER_DOWN, &a->flags2))
16028c2ecf20Sopenharmony_ci			esas2r_power_down_notify_firmware(a);
16038c2ecf20Sopenharmony_ci	}
16048c2ecf20Sopenharmony_ci
16058c2ecf20Sopenharmony_ci	/* Suspend I/O processing. */
16068c2ecf20Sopenharmony_ci	set_bit(AF_OS_RESET, &a->flags);
16078c2ecf20Sopenharmony_ci	set_bit(AF_DISC_PENDING, &a->flags);
16088c2ecf20Sopenharmony_ci	set_bit(AF_CHPRST_PENDING, &a->flags);
16098c2ecf20Sopenharmony_ci
16108c2ecf20Sopenharmony_ci	esas2r_process_adapter_reset(a);
16118c2ecf20Sopenharmony_ci
16128c2ecf20Sopenharmony_ci	/* Remove devices now that I/O is cleaned up. */
16138c2ecf20Sopenharmony_ci	a->prev_dev_cnt = esas2r_targ_db_get_tgt_cnt(a);
16148c2ecf20Sopenharmony_ci	esas2r_targ_db_remove_all(a, false);
16158c2ecf20Sopenharmony_ci}
16168c2ecf20Sopenharmony_ci
16178c2ecf20Sopenharmony_ci/*
16188c2ecf20Sopenharmony_ci * Perform power management processing including managing device states, adapter
16198c2ecf20Sopenharmony_ci * states, interrupts, and I/O.
16208c2ecf20Sopenharmony_ci */
16218c2ecf20Sopenharmony_cibool esas2r_power_up(struct esas2r_adapter *a, bool init_poll)
16228c2ecf20Sopenharmony_ci{
16238c2ecf20Sopenharmony_ci	bool ret;
16248c2ecf20Sopenharmony_ci
16258c2ecf20Sopenharmony_ci	clear_bit(AF_POWER_DOWN, &a->flags);
16268c2ecf20Sopenharmony_ci	esas2r_init_pci_cfg_space(a);
16278c2ecf20Sopenharmony_ci	set_bit(AF_FIRST_INIT, &a->flags);
16288c2ecf20Sopenharmony_ci	atomic_inc(&a->disable_cnt);
16298c2ecf20Sopenharmony_ci
16308c2ecf20Sopenharmony_ci	/* reinitialize the adapter */
16318c2ecf20Sopenharmony_ci	ret = esas2r_check_adapter(a);
16328c2ecf20Sopenharmony_ci	if (!esas2r_init_adapter_hw(a, init_poll))
16338c2ecf20Sopenharmony_ci		ret = false;
16348c2ecf20Sopenharmony_ci
16358c2ecf20Sopenharmony_ci	/* send the reset asynchronous event */
16368c2ecf20Sopenharmony_ci	esas2r_send_reset_ae(a, true);
16378c2ecf20Sopenharmony_ci
16388c2ecf20Sopenharmony_ci	/* clear this flag after initialization. */
16398c2ecf20Sopenharmony_ci	clear_bit(AF_POWER_MGT, &a->flags);
16408c2ecf20Sopenharmony_ci	return ret;
16418c2ecf20Sopenharmony_ci}
16428c2ecf20Sopenharmony_ci
16438c2ecf20Sopenharmony_cibool esas2r_is_adapter_present(struct esas2r_adapter *a)
16448c2ecf20Sopenharmony_ci{
16458c2ecf20Sopenharmony_ci	if (test_bit(AF_NOT_PRESENT, &a->flags))
16468c2ecf20Sopenharmony_ci		return false;
16478c2ecf20Sopenharmony_ci
16488c2ecf20Sopenharmony_ci	if (esas2r_read_register_dword(a, MU_DOORBELL_OUT) == 0xFFFFFFFF) {
16498c2ecf20Sopenharmony_ci		set_bit(AF_NOT_PRESENT, &a->flags);
16508c2ecf20Sopenharmony_ci
16518c2ecf20Sopenharmony_ci		return false;
16528c2ecf20Sopenharmony_ci	}
16538c2ecf20Sopenharmony_ci	return true;
16548c2ecf20Sopenharmony_ci}
16558c2ecf20Sopenharmony_ci
16568c2ecf20Sopenharmony_ciconst char *esas2r_get_model_name(struct esas2r_adapter *a)
16578c2ecf20Sopenharmony_ci{
16588c2ecf20Sopenharmony_ci	switch (a->pcid->subsystem_device) {
16598c2ecf20Sopenharmony_ci	case ATTO_ESAS_R680:
16608c2ecf20Sopenharmony_ci		return "ATTO ExpressSAS R680";
16618c2ecf20Sopenharmony_ci
16628c2ecf20Sopenharmony_ci	case ATTO_ESAS_R608:
16638c2ecf20Sopenharmony_ci		return "ATTO ExpressSAS R608";
16648c2ecf20Sopenharmony_ci
16658c2ecf20Sopenharmony_ci	case ATTO_ESAS_R60F:
16668c2ecf20Sopenharmony_ci		return "ATTO ExpressSAS R60F";
16678c2ecf20Sopenharmony_ci
16688c2ecf20Sopenharmony_ci	case ATTO_ESAS_R6F0:
16698c2ecf20Sopenharmony_ci		return "ATTO ExpressSAS R6F0";
16708c2ecf20Sopenharmony_ci
16718c2ecf20Sopenharmony_ci	case ATTO_ESAS_R644:
16728c2ecf20Sopenharmony_ci		return "ATTO ExpressSAS R644";
16738c2ecf20Sopenharmony_ci
16748c2ecf20Sopenharmony_ci	case ATTO_ESAS_R648:
16758c2ecf20Sopenharmony_ci		return "ATTO ExpressSAS R648";
16768c2ecf20Sopenharmony_ci
16778c2ecf20Sopenharmony_ci	case ATTO_TSSC_3808:
16788c2ecf20Sopenharmony_ci		return "ATTO ThunderStream SC 3808D";
16798c2ecf20Sopenharmony_ci
16808c2ecf20Sopenharmony_ci	case ATTO_TSSC_3808E:
16818c2ecf20Sopenharmony_ci		return "ATTO ThunderStream SC 3808E";
16828c2ecf20Sopenharmony_ci
16838c2ecf20Sopenharmony_ci	case ATTO_TLSH_1068:
16848c2ecf20Sopenharmony_ci		return "ATTO ThunderLink SH 1068";
16858c2ecf20Sopenharmony_ci	}
16868c2ecf20Sopenharmony_ci
16878c2ecf20Sopenharmony_ci	return "ATTO SAS Controller";
16888c2ecf20Sopenharmony_ci}
16898c2ecf20Sopenharmony_ci
16908c2ecf20Sopenharmony_ciconst char *esas2r_get_model_name_short(struct esas2r_adapter *a)
16918c2ecf20Sopenharmony_ci{
16928c2ecf20Sopenharmony_ci	switch (a->pcid->subsystem_device) {
16938c2ecf20Sopenharmony_ci	case ATTO_ESAS_R680:
16948c2ecf20Sopenharmony_ci		return "R680";
16958c2ecf20Sopenharmony_ci
16968c2ecf20Sopenharmony_ci	case ATTO_ESAS_R608:
16978c2ecf20Sopenharmony_ci		return "R608";
16988c2ecf20Sopenharmony_ci
16998c2ecf20Sopenharmony_ci	case ATTO_ESAS_R60F:
17008c2ecf20Sopenharmony_ci		return "R60F";
17018c2ecf20Sopenharmony_ci
17028c2ecf20Sopenharmony_ci	case ATTO_ESAS_R6F0:
17038c2ecf20Sopenharmony_ci		return "R6F0";
17048c2ecf20Sopenharmony_ci
17058c2ecf20Sopenharmony_ci	case ATTO_ESAS_R644:
17068c2ecf20Sopenharmony_ci		return "R644";
17078c2ecf20Sopenharmony_ci
17088c2ecf20Sopenharmony_ci	case ATTO_ESAS_R648:
17098c2ecf20Sopenharmony_ci		return "R648";
17108c2ecf20Sopenharmony_ci
17118c2ecf20Sopenharmony_ci	case ATTO_TSSC_3808:
17128c2ecf20Sopenharmony_ci		return "SC 3808D";
17138c2ecf20Sopenharmony_ci
17148c2ecf20Sopenharmony_ci	case ATTO_TSSC_3808E:
17158c2ecf20Sopenharmony_ci		return "SC 3808E";
17168c2ecf20Sopenharmony_ci
17178c2ecf20Sopenharmony_ci	case ATTO_TLSH_1068:
17188c2ecf20Sopenharmony_ci		return "SH 1068";
17198c2ecf20Sopenharmony_ci	}
17208c2ecf20Sopenharmony_ci
17218c2ecf20Sopenharmony_ci	return "unknown";
17228c2ecf20Sopenharmony_ci}
1723