brintos

brintos / linux-shallow public Read only

0
0
Text · 9.8 KiB · c9a1dad Raw
414 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 *	Adaptec AAC series RAID controller driver4 *	(c) Copyright 2001 Red Hat Inc.5 *6 * based on the old aacraid driver that is..7 * Adaptec aacraid device driver for Linux.8 *9 * Copyright (c) 2000-2010 Adaptec, Inc.10 *               2010-2015 PMC-Sierra, Inc. (aacraid@pmc-sierra.com)11 *		 2016-2017 Microsemi Corp. (aacraid@microsemi.com)12 *13 * Module Name:14 *  sa.c15 *16 * Abstract: Drawbridge specific support functions17 */18 19#include <linux/kernel.h>20#include <linux/init.h>21#include <linux/types.h>22#include <linux/pci.h>23#include <linux/spinlock.h>24#include <linux/blkdev.h>25#include <linux/delay.h>26#include <linux/completion.h>27#include <linux/time.h>28#include <linux/interrupt.h>29 30#include <scsi/scsi_host.h>31 32#include "aacraid.h"33 34static irqreturn_t aac_sa_intr(int irq, void *dev_id)35{36	struct aac_dev *dev = dev_id;37	unsigned short intstat, mask;38 39	intstat = sa_readw(dev, DoorbellReg_p);40	/*41	 *	Read mask and invert because drawbridge is reversed.42	 *	This allows us to only service interrupts that have been enabled.43	 */44	mask = ~(sa_readw(dev, SaDbCSR.PRISETIRQMASK));45 46	/* Check to see if this is our interrupt.  If it isn't just return */47 48	if (intstat & mask) {49		if (intstat & PrintfReady) {50			aac_printf(dev, sa_readl(dev, Mailbox5));51			sa_writew(dev, DoorbellClrReg_p, PrintfReady); /* clear PrintfReady */52			sa_writew(dev, DoorbellReg_s, PrintfDone);53		} else if (intstat & DOORBELL_1) {	// dev -> Host Normal Command Ready54			sa_writew(dev, DoorbellClrReg_p, DOORBELL_1);55			aac_command_normal(&dev->queues->queue[HostNormCmdQueue]);56		} else if (intstat & DOORBELL_2) {	// dev -> Host Normal Response Ready57			sa_writew(dev, DoorbellClrReg_p, DOORBELL_2);58			aac_response_normal(&dev->queues->queue[HostNormRespQueue]);59		} else if (intstat & DOORBELL_3) {	// dev -> Host Normal Command Not Full60			sa_writew(dev, DoorbellClrReg_p, DOORBELL_3);61		} else if (intstat & DOORBELL_4) {	// dev -> Host Normal Response Not Full62			sa_writew(dev, DoorbellClrReg_p, DOORBELL_4);63		}64		return IRQ_HANDLED;65	}66	return IRQ_NONE;67}68 69/**70 *	aac_sa_disable_interrupt	-	disable interrupt71 *	@dev: Which adapter to enable.72 */73 74static void aac_sa_disable_interrupt (struct aac_dev *dev)75{76	sa_writew(dev, SaDbCSR.PRISETIRQMASK, 0xffff);77}78 79/**80 *	aac_sa_enable_interrupt	-	enable interrupt81 *	@dev: Which adapter to enable.82 */83 84static void aac_sa_enable_interrupt (struct aac_dev *dev)85{86	sa_writew(dev, SaDbCSR.PRICLEARIRQMASK, (PrintfReady | DOORBELL_1 |87				DOORBELL_2 | DOORBELL_3 | DOORBELL_4));88}89 90/**91 *	aac_sa_notify_adapter		-	handle adapter notification92 *	@dev:	Adapter that notification is for93 *	@event:	Event to notidy94 *95 *	Notify the adapter of an event96 */97 98static void aac_sa_notify_adapter(struct aac_dev *dev, u32 event)99{100	switch (event) {101 102	case AdapNormCmdQue:103		sa_writew(dev, DoorbellReg_s,DOORBELL_1);104		break;105	case HostNormRespNotFull:106		sa_writew(dev, DoorbellReg_s,DOORBELL_4);107		break;108	case AdapNormRespQue:109		sa_writew(dev, DoorbellReg_s,DOORBELL_2);110		break;111	case HostNormCmdNotFull:112		sa_writew(dev, DoorbellReg_s,DOORBELL_3);113		break;114	case HostShutdown:115		/*116		sa_sync_cmd(dev, HOST_CRASHING, 0, 0, 0, 0, 0, 0,117		NULL, NULL, NULL, NULL, NULL);118		*/119		break;120	case FastIo:121		sa_writew(dev, DoorbellReg_s,DOORBELL_6);122		break;123	case AdapPrintfDone:124		sa_writew(dev, DoorbellReg_s,DOORBELL_5);125		break;126	default:127		BUG();128		break;129	}130}131 132 133/**134 *	sa_sync_cmd	-	send a command and wait135 *	@dev: Adapter136 *	@command: Command to execute137 *	@p1: first parameter138 *	@p2: second parameter139 *	@p3: third parameter140 *	@p4: forth parameter141 *	@p5: fifth parameter142 *	@p6: sixth parameter143 *	@ret: adapter status144 *	@r1: first return value145 *	@r2: second return value146 *	@r3: third return value147 *	@r4: forth return value148 *149 *	This routine will send a synchronous command to the adapter and wait150 *	for its	completion.151 */152static int sa_sync_cmd(struct aac_dev *dev, u32 command,153		u32 p1, u32 p2, u32 p3, u32 p4, u32 p5, u32 p6,154		u32 *ret, u32 *r1, u32 *r2, u32 *r3, u32 *r4)155{156	unsigned long start;157 	int ok;158	/*159	 *	Write the Command into Mailbox 0160	 */161	sa_writel(dev, Mailbox0, command);162	/*163	 *	Write the parameters into Mailboxes 1 - 4164	 */165	sa_writel(dev, Mailbox1, p1);166	sa_writel(dev, Mailbox2, p2);167	sa_writel(dev, Mailbox3, p3);168	sa_writel(dev, Mailbox4, p4);169 170	/*171	 *	Clear the synch command doorbell to start on a clean slate.172	 */173	sa_writew(dev, DoorbellClrReg_p, DOORBELL_0);174	/*175	 *	Signal that there is a new synch command176	 */177	sa_writew(dev, DoorbellReg_s, DOORBELL_0);178 179	ok = 0;180	start = jiffies;181 182	while(time_before(jiffies, start+30*HZ))183	{184		/*185		 *	Delay 5uS so that the monitor gets access186		 */187		udelay(5);188		/*189		 *	Mon110 will set doorbell0 bit when it has 190		 *	completed the command.191		 */192		if(sa_readw(dev, DoorbellReg_p) & DOORBELL_0)  {193			ok = 1;194			break;195		}196		msleep(1);197	}198 199	if (ok != 1)200		return -ETIMEDOUT;201	/*202	 *	Clear the synch command doorbell.203	 */204	sa_writew(dev, DoorbellClrReg_p, DOORBELL_0);205	/*206	 *	Pull the synch status from Mailbox 0.207	 */208	if (ret)209		*ret = sa_readl(dev, Mailbox0);210	if (r1)211		*r1 = sa_readl(dev, Mailbox1);212	if (r2)213		*r2 = sa_readl(dev, Mailbox2);214	if (r3)215		*r3 = sa_readl(dev, Mailbox3);216	if (r4)217		*r4 = sa_readl(dev, Mailbox4);218	return 0;219}220 221/**222 *	aac_sa_interrupt_adapter	-	interrupt an adapter223 *	@dev: Which adapter to enable.224 *225 *	Breakpoint an adapter.226 */227 228static void aac_sa_interrupt_adapter (struct aac_dev *dev)229{230	sa_sync_cmd(dev, BREAKPOINT_REQUEST, 0, 0, 0, 0, 0, 0,231			NULL, NULL, NULL, NULL, NULL);232}233 234/**235 *	aac_sa_start_adapter		-	activate adapter236 *	@dev:	Adapter237 *238 *	Start up processing on an ARM based AAC adapter239 */240 241static void aac_sa_start_adapter(struct aac_dev *dev)242{243	union aac_init *init;244	/*245	 * Fill in the remaining pieces of the init.246	 */247	init = dev->init;248	init->r7.host_elapsed_seconds = cpu_to_le32(ktime_get_real_seconds());249	/* We can only use a 32 bit address here */250	sa_sync_cmd(dev, INIT_STRUCT_BASE_ADDRESS, 251			(u32)(ulong)dev->init_pa, 0, 0, 0, 0, 0,252			NULL, NULL, NULL, NULL, NULL);253}254 255static int aac_sa_restart_adapter(struct aac_dev *dev, int bled, u8 reset_type)256{257	return -EINVAL;258}259 260/**261 *	aac_sa_check_health262 *	@dev: device to check if healthy263 *264 *	Will attempt to determine if the specified adapter is alive and265 *	capable of handling requests, returning 0 if alive.266 */267static int aac_sa_check_health(struct aac_dev *dev)268{269	long status = sa_readl(dev, Mailbox7);270 271	/*272	 *	Check to see if the board failed any self tests.273	 */274	if (status & SELF_TEST_FAILED)275		return -1;276	/*277	 *	Check to see if the board panic'd while booting.278	 */279	if (status & KERNEL_PANIC)280		return -2;281	/*282	 *	Wait for the adapter to be up and running. Wait up to 3 minutes283	 */284	if (!(status & KERNEL_UP_AND_RUNNING))285		return -3;286	/*287	 *	Everything is OK288	 */289	return 0;290}291 292/**293 *	aac_sa_ioremap294 *	@dev: device to ioremap295 *	@size: mapping resize request296 *297 */298static int aac_sa_ioremap(struct aac_dev * dev, u32 size)299{300	if (!size) {301		iounmap(dev->regs.sa);302		return 0;303	}304	dev->base = dev->regs.sa = ioremap(dev->base_start, size);305	return (dev->base == NULL) ? -1 : 0;306}307 308/**309 *	aac_sa_init	-	initialize an ARM based AAC card310 *	@dev: device to configure311 *312 *	Allocate and set up resources for the ARM based AAC variants. The313 *	device_interface in the commregion will be allocated and linked314 *	to the comm region.315 */316 317int aac_sa_init(struct aac_dev *dev)318{319	unsigned long start;320	unsigned long status;321	int instance;322	const char *name;323 324	instance = dev->id;325	name     = dev->name;326 327	/*328	 *	Fill in the function dispatch table.329	 */330 331	dev->a_ops.adapter_interrupt = aac_sa_interrupt_adapter;332	dev->a_ops.adapter_disable_int = aac_sa_disable_interrupt;333	dev->a_ops.adapter_enable_int = aac_sa_enable_interrupt;334	dev->a_ops.adapter_notify = aac_sa_notify_adapter;335	dev->a_ops.adapter_sync_cmd = sa_sync_cmd;336	dev->a_ops.adapter_check_health = aac_sa_check_health;337	dev->a_ops.adapter_restart = aac_sa_restart_adapter;338	dev->a_ops.adapter_start = aac_sa_start_adapter;339	dev->a_ops.adapter_intr = aac_sa_intr;340	dev->a_ops.adapter_deliver = aac_rx_deliver_producer;341	dev->a_ops.adapter_ioremap = aac_sa_ioremap;342 343	if (aac_sa_ioremap(dev, dev->base_size)) {344		printk(KERN_WARNING "%s: unable to map adapter.\n", name);345		goto error_iounmap;346	}347 348	/*349	 *	Check to see if the board failed any self tests.350	 */351	if (sa_readl(dev, Mailbox7) & SELF_TEST_FAILED) {352		printk(KERN_WARNING "%s%d: adapter self-test failed.\n", name, instance);353		goto error_iounmap;354	}355	/*356	 *	Check to see if the board panic'd while booting.357	 */358	if (sa_readl(dev, Mailbox7) & KERNEL_PANIC) {359		printk(KERN_WARNING "%s%d: adapter kernel panic'd.\n", name, instance);360		goto error_iounmap;361	}362	start = jiffies;363	/*364	 *	Wait for the adapter to be up and running. Wait up to 3 minutes.365	 */366	while (!(sa_readl(dev, Mailbox7) & KERNEL_UP_AND_RUNNING)) {367		if (time_after(jiffies, start+startup_timeout*HZ)) {368			status = sa_readl(dev, Mailbox7);369			printk(KERN_WARNING "%s%d: adapter kernel failed to start, init status = %lx.\n", 370					name, instance, status);371			goto error_iounmap;372		}373		msleep(1);374	}375 376	/*377	 *	First clear out all interrupts.  Then enable the one's that 378	 *	we can handle.379	 */380	aac_adapter_disable_int(dev);381	aac_adapter_enable_int(dev);382 383	if(aac_init_adapter(dev) == NULL)384		goto error_irq;385	dev->sync_mode = 0;	/* sync. mode not supported */386	if (request_irq(dev->pdev->irq, dev->a_ops.adapter_intr,387			IRQF_SHARED, "aacraid", (void *)dev) < 0) {388		printk(KERN_WARNING "%s%d: Interrupt unavailable.\n",389			name, instance);390		goto error_iounmap;391	}392	dev->dbg_base = dev->base_start;393	dev->dbg_base_mapped = dev->base;394	dev->dbg_size = dev->base_size;395 396	aac_adapter_enable_int(dev);397 398	/*399	 *	Tell the adapter that all is configure, and it can start 400	 *	accepting requests401	 */402	aac_sa_start_adapter(dev);403	return 0;404 405error_irq:406	aac_sa_disable_interrupt(dev);407	free_irq(dev->pdev->irq, (void *)dev);408 409error_iounmap:410 411	return -1;412}413 414