198944Sobrien// SPDX-License-Identifier: GPL-2.0-or-later
298944Sobrien/*
3130803Smarcel *	Adaptec AAC series RAID controller driver
4130803Smarcel *	(c) Copyright 2001 Red Hat Inc.
598944Sobrien *
698944Sobrien * based on the old aacraid driver that is..
798944Sobrien * Adaptec aacraid device driver for Linux.
898944Sobrien *
998944Sobrien * Copyright (c) 2000-2010 Adaptec, Inc.
1098944Sobrien *               2010-2015 PMC-Sierra, Inc. (aacraid@pmc-sierra.com)
1198944Sobrien *		 2016-2017 Microsemi Corp. (aacraid@microsemi.com)
1298944Sobrien *
1398944Sobrien * Module Name:
1498944Sobrien *  sa.c
1598944Sobrien *
1698944Sobrien * Abstract: Drawbridge specific support functions
1798944Sobrien */
1898944Sobrien
1998944Sobrien#include <linux/kernel.h>
2098944Sobrien#include <linux/init.h>
2198944Sobrien#include <linux/types.h>
2298944Sobrien#include <linux/pci.h>
23130803Smarcel#include <linux/spinlock.h>
24130803Smarcel#include <linux/blkdev.h>
2598944Sobrien#include <linux/delay.h>
2698944Sobrien#include <linux/completion.h>
27130803Smarcel#include <linux/time.h>
2898944Sobrien#include <linux/interrupt.h>
2998944Sobrien
30130803Smarcel#include <scsi/scsi_host.h>
3198944Sobrien
32130803Smarcel#include "aacraid.h"
3398944Sobrien
34130803Smarcelstatic irqreturn_t aac_sa_intr(int irq, void *dev_id)
35130803Smarcel{
36130803Smarcel	struct aac_dev *dev = dev_id;
37130803Smarcel	unsigned short intstat, mask;
38130803Smarcel
39130803Smarcel	intstat = sa_readw(dev, DoorbellReg_p);
40130803Smarcel	/*
4198944Sobrien	 *	Read mask and invert because drawbridge is reversed.
4298944Sobrien	 *	This allows us to only service interrupts that have been enabled.
4398944Sobrien	 */
4498944Sobrien	mask = ~(sa_readw(dev, SaDbCSR.PRISETIRQMASK));
4598944Sobrien
4698944Sobrien	/* Check to see if this is our interrupt.  If it isn't just return */
4798944Sobrien
4898944Sobrien	if (intstat & mask) {
4998944Sobrien		if (intstat & PrintfReady) {
5098944Sobrien			aac_printf(dev, sa_readl(dev, Mailbox5));
5198944Sobrien			sa_writew(dev, DoorbellClrReg_p, PrintfReady); /* clear PrintfReady */
52130803Smarcel			sa_writew(dev, DoorbellReg_s, PrintfDone);
5398944Sobrien		} else if (intstat & DOORBELL_1) {	// dev -> Host Normal Command Ready
5498944Sobrien			sa_writew(dev, DoorbellClrReg_p, DOORBELL_1);
5598944Sobrien			aac_command_normal(&dev->queues->queue[HostNormCmdQueue]);
5698944Sobrien		} else if (intstat & DOORBELL_2) {	// dev -> Host Normal Response Ready
5798944Sobrien			sa_writew(dev, DoorbellClrReg_p, DOORBELL_2);
5898944Sobrien			aac_response_normal(&dev->queues->queue[HostNormRespQueue]);
5998944Sobrien		} else if (intstat & DOORBELL_3) {	// dev -> Host Normal Command Not Full
6098944Sobrien			sa_writew(dev, DoorbellClrReg_p, DOORBELL_3);
6198944Sobrien		} else if (intstat & DOORBELL_4) {	// dev -> Host Normal Response Not Full
6298944Sobrien			sa_writew(dev, DoorbellClrReg_p, DOORBELL_4);
6398944Sobrien		}
6498944Sobrien		return IRQ_HANDLED;
65130803Smarcel	}
6698944Sobrien	return IRQ_NONE;
6798944Sobrien}
68130803Smarcel
69130803Smarcel/**
70130803Smarcel *	aac_sa_disable_interrupt	-	disable interrupt
71130803Smarcel *	@dev: Which adapter to enable.
7298944Sobrien */
73130803Smarcel
7498944Sobrienstatic void aac_sa_disable_interrupt (struct aac_dev *dev)
7598944Sobrien{
7698944Sobrien	sa_writew(dev, SaDbCSR.PRISETIRQMASK, 0xffff);
7798944Sobrien}
7898944Sobrien
79130803Smarcel/**
80130803Smarcel *	aac_sa_enable_interrupt	-	enable interrupt
8198944Sobrien *	@dev: Which adapter to enable.
82130803Smarcel */
8398944Sobrien
8498944Sobrienstatic void aac_sa_enable_interrupt (struct aac_dev *dev)
85130803Smarcel{
86130803Smarcel	sa_writew(dev, SaDbCSR.PRICLEARIRQMASK, (PrintfReady | DOORBELL_1 |
87130803Smarcel				DOORBELL_2 | DOORBELL_3 | DOORBELL_4));
8898944Sobrien}
8998944Sobrien
9098944Sobrien/**
91130803Smarcel *	aac_sa_notify_adapter		-	handle adapter notification
9298944Sobrien *	@dev:	Adapter that notification is for
9398944Sobrien *	@event:	Event to notidy
9498944Sobrien *
9598944Sobrien *	Notify the adapter of an event
9698944Sobrien */
97130803Smarcel
9898944Sobrienstatic void aac_sa_notify_adapter(struct aac_dev *dev, u32 event)
9998944Sobrien{
10098944Sobrien	switch (event) {
101130803Smarcel
10298944Sobrien	case AdapNormCmdQue:
10398944Sobrien		sa_writew(dev, DoorbellReg_s,DOORBELL_1);
10498944Sobrien		break;
105130803Smarcel	case HostNormRespNotFull:
10698944Sobrien		sa_writew(dev, DoorbellReg_s,DOORBELL_4);
10798944Sobrien		break;
108130803Smarcel	case AdapNormRespQue:
109130803Smarcel		sa_writew(dev, DoorbellReg_s,DOORBELL_2);
11098944Sobrien		break;
111130803Smarcel	case HostNormCmdNotFull:
11298944Sobrien		sa_writew(dev, DoorbellReg_s,DOORBELL_3);
11398944Sobrien		break;
11498944Sobrien	case HostShutdown:
11598944Sobrien		/*
11698944Sobrien		sa_sync_cmd(dev, HOST_CRASHING, 0, 0, 0, 0, 0, 0,
11798944Sobrien		NULL, NULL, NULL, NULL, NULL);
11898944Sobrien		*/
119130803Smarcel		break;
12098944Sobrien	case FastIo:
12198944Sobrien		sa_writew(dev, DoorbellReg_s,DOORBELL_6);
12298944Sobrien		break;
123130803Smarcel	case AdapPrintfDone:
12498944Sobrien		sa_writew(dev, DoorbellReg_s,DOORBELL_5);
12598944Sobrien		break;
12698944Sobrien	default:
12798944Sobrien		BUG();
12898944Sobrien		break;
12998944Sobrien	}
13098944Sobrien}
13198944Sobrien
13298944Sobrien
13398944Sobrien/**
13498944Sobrien *	sa_sync_cmd	-	send a command and wait
13598944Sobrien *	@dev: Adapter
13698944Sobrien *	@command: Command to execute
13798944Sobrien *	@p1: first parameter
13898944Sobrien *	@p2: second parameter
13998944Sobrien *	@p3: third parameter
14098944Sobrien *	@p4: forth parameter
14198944Sobrien *	@p5: fifth parameter
14298944Sobrien *	@p6: sixth parameter
14398944Sobrien *	@ret: adapter status
14498944Sobrien *	@r1: first return value
14598944Sobrien *	@r2: second return value
14698944Sobrien *	@r3: third return value
14798944Sobrien *	@r4: forth return value
14898944Sobrien *
14998944Sobrien *	This routine will send a synchronous command to the adapter and wait
15098944Sobrien *	for its	completion.
15198944Sobrien */
15298944Sobrienstatic int sa_sync_cmd(struct aac_dev *dev, u32 command,
153130803Smarcel		u32 p1, u32 p2, u32 p3, u32 p4, u32 p5, u32 p6,
15498944Sobrien		u32 *ret, u32 *r1, u32 *r2, u32 *r3, u32 *r4)
15598944Sobrien{
15698944Sobrien	unsigned long start;
15798944Sobrien 	int ok;
15898944Sobrien	/*
15998944Sobrien	 *	Write the Command into Mailbox 0
160130803Smarcel	 */
161130803Smarcel	sa_writel(dev, Mailbox0, command);
162130803Smarcel	/*
16398944Sobrien	 *	Write the parameters into Mailboxes 1 - 4
164130803Smarcel	 */
165130803Smarcel	sa_writel(dev, Mailbox1, p1);
16698944Sobrien	sa_writel(dev, Mailbox2, p2);
16798944Sobrien	sa_writel(dev, Mailbox3, p3);
16898944Sobrien	sa_writel(dev, Mailbox4, p4);
169130803Smarcel
170130803Smarcel	/*
17198944Sobrien	 *	Clear the synch command doorbell to start on a clean slate.
172130803Smarcel	 */
17398944Sobrien	sa_writew(dev, DoorbellClrReg_p, DOORBELL_0);
174130803Smarcel	/*
17598944Sobrien	 *	Signal that there is a new synch command
176130803Smarcel	 */
177130803Smarcel	sa_writew(dev, DoorbellReg_s, DOORBELL_0);
178130803Smarcel
179130803Smarcel	ok = 0;
18098944Sobrien	start = jiffies;
181130803Smarcel
182130803Smarcel	while(time_before(jiffies, start+30*HZ))
183130803Smarcel	{
18498944Sobrien		/*
18598944Sobrien		 *	Delay 5uS so that the monitor gets access
18698944Sobrien		 */
187130803Smarcel		udelay(5);
18898944Sobrien		/*
18998944Sobrien		 *	Mon110 will set doorbell0 bit when it has
19098944Sobrien		 *	completed the command.
191130803Smarcel		 */
192130803Smarcel		if(sa_readw(dev, DoorbellReg_p) & DOORBELL_0)  {
19398944Sobrien			ok = 1;
194130803Smarcel			break;
195130803Smarcel		}
19698944Sobrien		msleep(1);
19798944Sobrien	}
198130803Smarcel
199130803Smarcel	if (ok != 1)
20098944Sobrien		return -ETIMEDOUT;
20198944Sobrien	/*
20298944Sobrien	 *	Clear the synch command doorbell.
20398944Sobrien	 */
20498944Sobrien	sa_writew(dev, DoorbellClrReg_p, DOORBELL_0);
205130803Smarcel	/*
20698944Sobrien	 *	Pull the synch status from Mailbox 0.
20798944Sobrien	 */
208130803Smarcel	if (ret)
209130803Smarcel		*ret = sa_readl(dev, Mailbox0);
210130803Smarcel	if (r1)
211130803Smarcel		*r1 = sa_readl(dev, Mailbox1);
21298944Sobrien	if (r2)
213130803Smarcel		*r2 = sa_readl(dev, Mailbox2);
21498944Sobrien	if (r3)
21598944Sobrien		*r3 = sa_readl(dev, Mailbox3);
21698944Sobrien	if (r4)
21798944Sobrien		*r4 = sa_readl(dev, Mailbox4);
21898944Sobrien	return 0;
21998944Sobrien}
22098944Sobrien
22198944Sobrien/**
222130803Smarcel *	aac_sa_interrupt_adapter	-	interrupt an adapter
223130803Smarcel *	@dev: Which adapter to enable.
22498944Sobrien *
225130803Smarcel *	Breakpoint an adapter.
226130803Smarcel */
22798944Sobrien
228130803Smarcelstatic void aac_sa_interrupt_adapter (struct aac_dev *dev)
22998944Sobrien{
230130803Smarcel	sa_sync_cmd(dev, BREAKPOINT_REQUEST, 0, 0, 0, 0, 0, 0,
231130803Smarcel			NULL, NULL, NULL, NULL, NULL);
23298944Sobrien}
233130803Smarcel
234130803Smarcel/**
235130803Smarcel *	aac_sa_start_adapter		-	activate adapter
236130803Smarcel *	@dev:	Adapter
237130803Smarcel *
238130803Smarcel *	Start up processing on an ARM based AAC adapter
239130803Smarcel */
240130803Smarcel
24198944Sobrienstatic void aac_sa_start_adapter(struct aac_dev *dev)
24298944Sobrien{
243130803Smarcel	union aac_init *init;
244130803Smarcel	/*
24598944Sobrien	 * Fill in the remaining pieces of the init.
24698944Sobrien	 */
247218822Sdim	init = dev->init;
24898944Sobrien	init->r7.host_elapsed_seconds = cpu_to_le32(ktime_get_real_seconds());
24998944Sobrien	/* We can only use a 32 bit address here */
25098944Sobrien	sa_sync_cmd(dev, INIT_STRUCT_BASE_ADDRESS,
25198944Sobrien			(u32)(ulong)dev->init_pa, 0, 0, 0, 0, 0,
252130803Smarcel			NULL, NULL, NULL, NULL, NULL);
25398944Sobrien}
254130803Smarcel
255130803Smarcelstatic int aac_sa_restart_adapter(struct aac_dev *dev, int bled, u8 reset_type)
256130803Smarcel{
257130803Smarcel	return -EINVAL;
258130803Smarcel}
259130803Smarcel
260130803Smarcel/**
261130803Smarcel *	aac_sa_check_health
262130803Smarcel *	@dev: device to check if healthy
263130803Smarcel *
264130803Smarcel *	Will attempt to determine if the specified adapter is alive and
265130803Smarcel *	capable of handling requests, returning 0 if alive.
266130803Smarcel */
26798944Sobrienstatic int aac_sa_check_health(struct aac_dev *dev)
268130803Smarcel{
269130803Smarcel	long status = sa_readl(dev, Mailbox7);
270130803Smarcel
271130803Smarcel	/*
272130803Smarcel	 *	Check to see if the board failed any self tests.
27398944Sobrien	 */
27498944Sobrien	if (status & SELF_TEST_FAILED)
27598944Sobrien		return -1;
276130803Smarcel	/*
27798944Sobrien	 *	Check to see if the board panic'd while booting.
27898944Sobrien	 */
27998944Sobrien	if (status & KERNEL_PANIC)
28098944Sobrien		return -2;
281130803Smarcel	/*
28298944Sobrien	 *	Wait for the adapter to be up and running. Wait up to 3 minutes
28398944Sobrien	 */
284130803Smarcel	if (!(status & KERNEL_UP_AND_RUNNING))
285130803Smarcel		return -3;
28698944Sobrien	/*
28798944Sobrien	 *	Everything is OK
28898944Sobrien	 */
28998944Sobrien	return 0;
29098944Sobrien}
29198944Sobrien
29298944Sobrien/**
29398944Sobrien *	aac_sa_ioremap
29498944Sobrien *	@dev: device to ioremap
295130803Smarcel *	@size: mapping resize request
29698944Sobrien *
29798944Sobrien */
29898944Sobrienstatic int aac_sa_ioremap(struct aac_dev * dev, u32 size)
29998944Sobrien{
30098944Sobrien	if (!size) {
30198944Sobrien		iounmap(dev->regs.sa);
30298944Sobrien		return 0;
30398944Sobrien	}
30498944Sobrien	dev->base = dev->regs.sa = ioremap(dev->base_start, size);
30598944Sobrien	return (dev->base == NULL) ? -1 : 0;
306130803Smarcel}
30798944Sobrien
30898944Sobrien/**
309130803Smarcel *	aac_sa_init	-	initialize an ARM based AAC card
310130803Smarcel *	@dev: device to configure
311130803Smarcel *
31298944Sobrien *	Allocate and set up resources for the ARM based AAC variants. The
313130803Smarcel *	device_interface in the commregion will be allocated and linked
31498944Sobrien *	to the comm region.
315130803Smarcel */
31698944Sobrien
317130803Smarcelint aac_sa_init(struct aac_dev *dev)
318130803Smarcel{
319130803Smarcel	unsigned long start;
320130803Smarcel	unsigned long status;
32198944Sobrien	int instance;
322130803Smarcel	const char *name;
323130803Smarcel
324130803Smarcel	instance = dev->id;
325130803Smarcel	name     = dev->name;
326130803Smarcel
327130803Smarcel	/*
328130803Smarcel	 *	Fill in the function dispatch table.
32998944Sobrien	 */
33098944Sobrien
331130803Smarcel	dev->a_ops.adapter_interrupt = aac_sa_interrupt_adapter;
33298944Sobrien	dev->a_ops.adapter_disable_int = aac_sa_disable_interrupt;
333130803Smarcel	dev->a_ops.adapter_enable_int = aac_sa_enable_interrupt;
334130803Smarcel	dev->a_ops.adapter_notify = aac_sa_notify_adapter;
335130803Smarcel	dev->a_ops.adapter_sync_cmd = sa_sync_cmd;
336130803Smarcel	dev->a_ops.adapter_check_health = aac_sa_check_health;
33798944Sobrien	dev->a_ops.adapter_restart = aac_sa_restart_adapter;
338130803Smarcel	dev->a_ops.adapter_start = aac_sa_start_adapter;
339130803Smarcel	dev->a_ops.adapter_intr = aac_sa_intr;
340130803Smarcel	dev->a_ops.adapter_deliver = aac_rx_deliver_producer;
341130803Smarcel	dev->a_ops.adapter_ioremap = aac_sa_ioremap;
342130803Smarcel
343130803Smarcel	if (aac_sa_ioremap(dev, dev->base_size)) {
344130803Smarcel		printk(KERN_WARNING "%s: unable to map adapter.\n", name);
345130803Smarcel		goto error_iounmap;
346130803Smarcel	}
347130803Smarcel
348130803Smarcel	/*
349130803Smarcel	 *	Check to see if the board failed any self tests.
35098944Sobrien	 */
351130803Smarcel	if (sa_readl(dev, Mailbox7) & SELF_TEST_FAILED) {
352130803Smarcel		printk(KERN_WARNING "%s%d: adapter self-test failed.\n", name, instance);
353130803Smarcel		goto error_iounmap;
354130803Smarcel	}
355130803Smarcel	/*
356130803Smarcel	 *	Check to see if the board panic'd while booting.
357130803Smarcel	 */
358130803Smarcel	if (sa_readl(dev, Mailbox7) & KERNEL_PANIC) {
359130803Smarcel		printk(KERN_WARNING "%s%d: adapter kernel panic'd.\n", name, instance);
360130803Smarcel		goto error_iounmap;
36198944Sobrien	}
362130803Smarcel	start = jiffies;
36398944Sobrien	/*
36498944Sobrien	 *	Wait for the adapter to be up and running. Wait up to 3 minutes.
365130803Smarcel	 */
36698944Sobrien	while (!(sa_readl(dev, Mailbox7) & KERNEL_UP_AND_RUNNING)) {
367130803Smarcel		if (time_after(jiffies, start+startup_timeout*HZ)) {
368130803Smarcel			status = sa_readl(dev, Mailbox7);
369130803Smarcel			printk(KERN_WARNING "%s%d: adapter kernel failed to start, init status = %lx.\n",
370130803Smarcel					name, instance, status);
371130803Smarcel			goto error_iounmap;
372130803Smarcel		}
37398944Sobrien		msleep(1);
374130803Smarcel	}
375130803Smarcel
376130803Smarcel	/*
37798944Sobrien	 *	First clear out all interrupts.  Then enable the one's that
378130803Smarcel	 *	we can handle.
379130803Smarcel	 */
38098944Sobrien	aac_adapter_disable_int(dev);
381130803Smarcel	aac_adapter_enable_int(dev);
382130803Smarcel
38398944Sobrien	if(aac_init_adapter(dev) == NULL)
38498944Sobrien		goto error_irq;
385130803Smarcel	dev->sync_mode = 0;	/* sync. mode not supported */
386130803Smarcel	if (request_irq(dev->pdev->irq, dev->a_ops.adapter_intr,
387130803Smarcel			IRQF_SHARED, "aacraid", (void *)dev) < 0) {
388130803Smarcel		printk(KERN_WARNING "%s%d: Interrupt unavailable.\n",
389130803Smarcel			name, instance);
39098944Sobrien		goto error_iounmap;
39198944Sobrien	}
39298944Sobrien	dev->dbg_base = dev->base_start;
393130803Smarcel	dev->dbg_base_mapped = dev->base;
394130803Smarcel	dev->dbg_size = dev->base_size;
39598944Sobrien
39698944Sobrien	aac_adapter_enable_int(dev);
397130803Smarcel
39898944Sobrien	/*
39998944Sobrien	 *	Tell the adapter that all is configure, and it can start
40098944Sobrien	 *	accepting requests
40198944Sobrien	 */
402130803Smarcel	aac_sa_start_adapter(dev);
40398944Sobrien	return 0;
40498944Sobrien
40598944Sobrienerror_irq:
40698944Sobrien	aac_sa_disable_interrupt(dev);
40798944Sobrien	free_irq(dev->pdev->irq, (void *)dev);
40898944Sobrien
40998944Sobrienerror_iounmap:
41098944Sobrien
41198944Sobrien	return -1;
41298944Sobrien}
41398944Sobrien
41498944Sobrien