brintos

brintos / linux-shallow public Read only

0
0
Text · 17.1 KiB · e06ff83 Raw
684 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 *  rx.c15 *16 * Abstract: Hardware miniport for Drawbridge specific hardware functions.17 */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_rx_intr_producer(int irq, void *dev_id)35{36	struct aac_dev *dev = dev_id;37	unsigned long bellbits;38	u8 intstat = rx_readb(dev, MUnit.OISR);39 40	/*41	 *	Read mask and invert because drawbridge is reversed.42	 *	This allows us to only service interrupts that have43	 *	been enabled.44	 *	Check to see if this is our interrupt.  If it isn't just return45	 */46	if (likely(intstat & ~(dev->OIMR))) {47		bellbits = rx_readl(dev, OutboundDoorbellReg);48		if (unlikely(bellbits & DoorBellPrintfReady)) {49			aac_printf(dev, readl (&dev->IndexRegs->Mailbox[5]));50			rx_writel(dev, MUnit.ODR,DoorBellPrintfReady);51			rx_writel(dev, InboundDoorbellReg,DoorBellPrintfDone);52		}53		else if (unlikely(bellbits & DoorBellAdapterNormCmdReady)) {54			rx_writel(dev, MUnit.ODR, DoorBellAdapterNormCmdReady);55			aac_command_normal(&dev->queues->queue[HostNormCmdQueue]);56		}57		else if (likely(bellbits & DoorBellAdapterNormRespReady)) {58			rx_writel(dev, MUnit.ODR,DoorBellAdapterNormRespReady);59			aac_response_normal(&dev->queues->queue[HostNormRespQueue]);60		}61		else if (unlikely(bellbits & DoorBellAdapterNormCmdNotFull)) {62			rx_writel(dev, MUnit.ODR, DoorBellAdapterNormCmdNotFull);63		}64		else if (unlikely(bellbits & DoorBellAdapterNormRespNotFull)) {65			rx_writel(dev, MUnit.ODR, DoorBellAdapterNormCmdNotFull);66			rx_writel(dev, MUnit.ODR, DoorBellAdapterNormRespNotFull);67		}68		return IRQ_HANDLED;69	}70	return IRQ_NONE;71}72 73static irqreturn_t aac_rx_intr_message(int irq, void *dev_id)74{75	int isAif, isFastResponse, isSpecial;76	struct aac_dev *dev = dev_id;77	u32 Index = rx_readl(dev, MUnit.OutboundQueue);78	if (unlikely(Index == 0xFFFFFFFFL))79		Index = rx_readl(dev, MUnit.OutboundQueue);80	if (likely(Index != 0xFFFFFFFFL)) {81		do {82			isAif = isFastResponse = isSpecial = 0;83			if (Index & 0x00000002L) {84				isAif = 1;85				if (Index == 0xFFFFFFFEL)86					isSpecial = 1;87				Index &= ~0x00000002L;88			} else {89				if (Index & 0x00000001L)90					isFastResponse = 1;91				Index >>= 2;92			}93			if (!isSpecial) {94				if (unlikely(aac_intr_normal(dev,95						Index, isAif,96						isFastResponse, NULL))) {97					rx_writel(dev,98						MUnit.OutboundQueue,99						Index);100					rx_writel(dev,101						MUnit.ODR,102						DoorBellAdapterNormRespReady);103				}104			}105			Index = rx_readl(dev, MUnit.OutboundQueue);106		} while (Index != 0xFFFFFFFFL);107		return IRQ_HANDLED;108	}109	return IRQ_NONE;110}111 112/**113 *	aac_rx_disable_interrupt	-	Disable interrupts114 *	@dev: Adapter115 */116 117static void aac_rx_disable_interrupt(struct aac_dev *dev)118{119	rx_writeb(dev, MUnit.OIMR, dev->OIMR = 0xff);120}121 122/**123 *	aac_rx_enable_interrupt_producer	-	Enable interrupts124 *	@dev: Adapter125 */126 127static void aac_rx_enable_interrupt_producer(struct aac_dev *dev)128{129	rx_writeb(dev, MUnit.OIMR, dev->OIMR = 0xfb);130}131 132/**133 *	aac_rx_enable_interrupt_message	-	Enable interrupts134 *	@dev: Adapter135 */136 137static void aac_rx_enable_interrupt_message(struct aac_dev *dev)138{139	rx_writeb(dev, MUnit.OIMR, dev->OIMR = 0xf7);140}141 142/**143 *	rx_sync_cmd	-	send a command and wait144 *	@dev: Adapter145 *	@command: Command to execute146 *	@p1: first parameter147 *	@p2: second parameter148 *	@p3: third parameter149 *	@p4: forth parameter150 *	@p5: fifth parameter151 *	@p6: sixth parameter152 *	@status: adapter status153 *	@r1: first return value154 *	@r2: second return value155 *	@r3: third return value156 *	@r4: forth return value157 *158 *	This routine will send a synchronous command to the adapter and wait 159 *	for its	completion.160 */161 162static int rx_sync_cmd(struct aac_dev *dev, u32 command,163	u32 p1, u32 p2, u32 p3, u32 p4, u32 p5, u32 p6,164	u32 *status, u32 * r1, u32 * r2, u32 * r3, u32 * r4)165{166	unsigned long start;167	int ok;168	/*169	 *	Write the command into Mailbox 0170	 */171	writel(command, &dev->IndexRegs->Mailbox[0]);172	/*173	 *	Write the parameters into Mailboxes 1 - 6174	 */175	writel(p1, &dev->IndexRegs->Mailbox[1]);176	writel(p2, &dev->IndexRegs->Mailbox[2]);177	writel(p3, &dev->IndexRegs->Mailbox[3]);178	writel(p4, &dev->IndexRegs->Mailbox[4]);179	/*180	 *	Clear the synch command doorbell to start on a clean slate.181	 */182	rx_writel(dev, OutboundDoorbellReg, OUTBOUNDDOORBELL_0);183	/*184	 *	Disable doorbell interrupts185	 */186	rx_writeb(dev, MUnit.OIMR, dev->OIMR = 0xff);187	/*188	 *	Force the completion of the mask register write before issuing189	 *	the interrupt.190	 */191	rx_readb (dev, MUnit.OIMR);192	/*193	 *	Signal that there is a new synch command194	 */195	rx_writel(dev, InboundDoorbellReg, INBOUNDDOORBELL_0);196 197	ok = 0;198	start = jiffies;199 200	/*201	 *	Wait up to 30 seconds202	 */203	while (time_before(jiffies, start+30*HZ)) 204	{205		udelay(5);	/* Delay 5 microseconds to let Mon960 get info. */206		/*207		 *	Mon960 will set doorbell0 bit when it has completed the command.208		 */209		if (rx_readl(dev, OutboundDoorbellReg) & OUTBOUNDDOORBELL_0) {210			/*211			 *	Clear the doorbell.212			 */213			rx_writel(dev, OutboundDoorbellReg, OUTBOUNDDOORBELL_0);214			ok = 1;215			break;216		}217		/*218		 *	Yield the processor in case we are slow 219		 */220		msleep(1);221	}222	if (unlikely(ok != 1)) {223		/*224		 *	Restore interrupt mask even though we timed out225		 */226		aac_adapter_enable_int(dev);227		return -ETIMEDOUT;228	}229	/*230	 *	Pull the synch status from Mailbox 0.231	 */232	if (status)233		*status = readl(&dev->IndexRegs->Mailbox[0]);234	if (r1)235		*r1 = readl(&dev->IndexRegs->Mailbox[1]);236	if (r2)237		*r2 = readl(&dev->IndexRegs->Mailbox[2]);238	if (r3)239		*r3 = readl(&dev->IndexRegs->Mailbox[3]);240	if (r4)241		*r4 = readl(&dev->IndexRegs->Mailbox[4]);242	/*243	 *	Clear the synch command doorbell.244	 */245	rx_writel(dev, OutboundDoorbellReg, OUTBOUNDDOORBELL_0);246	/*247	 *	Restore interrupt mask248	 */249	aac_adapter_enable_int(dev);250	return 0;251 252}253 254/**255 *	aac_rx_interrupt_adapter	-	interrupt adapter256 *	@dev: Adapter257 *258 *	Send an interrupt to the i960 and breakpoint it.259 */260 261static void aac_rx_interrupt_adapter(struct aac_dev *dev)262{263	rx_sync_cmd(dev, BREAKPOINT_REQUEST, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL);264}265 266/**267 *	aac_rx_notify_adapter		-	send an event to the adapter268 *	@dev: Adapter269 *	@event: Event to send270 *271 *	Notify the i960 that something it probably cares about has272 *	happened.273 */274 275static void aac_rx_notify_adapter(struct aac_dev *dev, u32 event)276{277	switch (event) {278 279	case AdapNormCmdQue:280		rx_writel(dev, MUnit.IDR,INBOUNDDOORBELL_1);281		break;282	case HostNormRespNotFull:283		rx_writel(dev, MUnit.IDR,INBOUNDDOORBELL_4);284		break;285	case AdapNormRespQue:286		rx_writel(dev, MUnit.IDR,INBOUNDDOORBELL_2);287		break;288	case HostNormCmdNotFull:289		rx_writel(dev, MUnit.IDR,INBOUNDDOORBELL_3);290		break;291	case HostShutdown:292		break;293	case FastIo:294		rx_writel(dev, MUnit.IDR,INBOUNDDOORBELL_6);295		break;296	case AdapPrintfDone:297		rx_writel(dev, MUnit.IDR,INBOUNDDOORBELL_5);298		break;299	default:300		BUG();301		break;302	}303}304 305/**306 *	aac_rx_start_adapter		-	activate adapter307 *	@dev:	Adapter308 *309 *	Start up processing on an i960 based AAC adapter310 */311 312static void aac_rx_start_adapter(struct aac_dev *dev)313{314	union aac_init *init;315 316	init = dev->init;317	init->r7.host_elapsed_seconds = cpu_to_le32(ktime_get_real_seconds());318	// We can only use a 32 bit address here319	rx_sync_cmd(dev, INIT_STRUCT_BASE_ADDRESS, (u32)(ulong)dev->init_pa,320	  0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL);321}322 323/**324 *	aac_rx_check_health325 *	@dev: device to check if healthy326 *327 *	Will attempt to determine if the specified adapter is alive and328 *	capable of handling requests, returning 0 if alive.329 */330static int aac_rx_check_health(struct aac_dev *dev)331{332	u32 status = rx_readl(dev, MUnit.OMRx[0]);333 334	/*335	 *	Check to see if the board failed any self tests.336	 */337	if (unlikely(status & SELF_TEST_FAILED))338		return -1;339	/*340	 *	Check to see if the board panic'd.341	 */342	if (unlikely(status & KERNEL_PANIC)) {343		char * buffer;344		struct POSTSTATUS {345			__le32 Post_Command;346			__le32 Post_Address;347		} * post;348		dma_addr_t paddr, baddr;349		int ret;350 351		if (likely((status & 0xFF000000L) == 0xBC000000L))352			return (status >> 16) & 0xFF;353		buffer = dma_alloc_coherent(&dev->pdev->dev, 512, &baddr,354					    GFP_KERNEL);355		ret = -2;356		if (unlikely(buffer == NULL))357			return ret;358		post = dma_alloc_coherent(&dev->pdev->dev,359					  sizeof(struct POSTSTATUS), &paddr,360					  GFP_KERNEL);361		if (unlikely(post == NULL)) {362			dma_free_coherent(&dev->pdev->dev, 512, buffer, baddr);363			return ret;364		}365		memset(buffer, 0, 512);366		post->Post_Command = cpu_to_le32(COMMAND_POST_RESULTS);367		post->Post_Address = cpu_to_le32(baddr);368		rx_writel(dev, MUnit.IMRx[0], paddr);369		rx_sync_cmd(dev, COMMAND_POST_RESULTS, baddr, 0, 0, 0, 0, 0,370		  NULL, NULL, NULL, NULL, NULL);371		dma_free_coherent(&dev->pdev->dev, sizeof(struct POSTSTATUS),372				  post, paddr);373		if (likely((buffer[0] == '0') && ((buffer[1] == 'x') || (buffer[1] == 'X')))) {374			ret = (hex_to_bin(buffer[2]) << 4) +375				hex_to_bin(buffer[3]);376		}377		dma_free_coherent(&dev->pdev->dev, 512, buffer, baddr);378		return ret;379	}380	/*381	 *	Wait for the adapter to be up and running.382	 */383	if (unlikely(!(status & KERNEL_UP_AND_RUNNING)))384		return -3;385	/*386	 *	Everything is OK387	 */388	return 0;389}390 391/**392 *	aac_rx_deliver_producer393 *	@fib: fib to issue394 *395 *	Will send a fib, returning 0 if successful.396 */397int aac_rx_deliver_producer(struct fib * fib)398{399	struct aac_dev *dev = fib->dev;400	struct aac_queue *q = &dev->queues->queue[AdapNormCmdQueue];401	u32 Index;402	unsigned long nointr = 0;403 404	aac_queue_get( dev, &Index, AdapNormCmdQueue, fib->hw_fib_va, 1, fib, &nointr);405 406	atomic_inc(&q->numpending);407	*(q->headers.producer) = cpu_to_le32(Index + 1);408	if (!(nointr & aac_config.irq_mod))409		aac_adapter_notify(dev, AdapNormCmdQueue);410 411	return 0;412}413 414/**415 *	aac_rx_deliver_message416 *	@fib: fib to issue417 *418 *	Will send a fib, returning 0 if successful.419 */420static int aac_rx_deliver_message(struct fib * fib)421{422	struct aac_dev *dev = fib->dev;423	struct aac_queue *q = &dev->queues->queue[AdapNormCmdQueue];424	u32 Index;425	u64 addr;426	volatile void __iomem *device;427 428	unsigned long count = 10000000L; /* 50 seconds */429	atomic_inc(&q->numpending);430	for(;;) {431		Index = rx_readl(dev, MUnit.InboundQueue);432		if (unlikely(Index == 0xFFFFFFFFL))433			Index = rx_readl(dev, MUnit.InboundQueue);434		if (likely(Index != 0xFFFFFFFFL))435			break;436		if (--count == 0) {437			atomic_dec(&q->numpending);438			return -ETIMEDOUT;439		}440		udelay(5);441	}442	device = dev->base + Index;443	addr = fib->hw_fib_pa;444	writel((u32)(addr & 0xffffffff), device);445	device += sizeof(u32);446	writel((u32)(addr >> 32), device);447	device += sizeof(u32);448	writel(le16_to_cpu(fib->hw_fib_va->header.Size), device);449	rx_writel(dev, MUnit.InboundQueue, Index);450	return 0;451}452 453/**454 *	aac_rx_ioremap455 *	@dev: adapter456 *	@size: mapping resize request457 *458 */459static int aac_rx_ioremap(struct aac_dev * dev, u32 size)460{461	if (!size) {462		iounmap(dev->regs.rx);463		return 0;464	}465	dev->base = dev->regs.rx = ioremap(dev->base_start, size);466	if (dev->base == NULL)467		return -1;468	dev->IndexRegs = &dev->regs.rx->IndexRegs;469	return 0;470}471 472static int aac_rx_restart_adapter(struct aac_dev *dev, int bled, u8 reset_type)473{474	u32 var = 0;475 476	if (!(dev->supplement_adapter_info.supported_options2 &477	  AAC_OPTION_MU_RESET) || (bled >= 0) || (bled == -2)) {478		if (bled)479			printk(KERN_ERR "%s%d: adapter kernel panic'd %x.\n",480				dev->name, dev->id, bled);481		else {482			bled = aac_adapter_sync_cmd(dev, IOP_RESET_ALWAYS,483			  0, 0, 0, 0, 0, 0, &var, NULL, NULL, NULL, NULL);484			if (!bled && (var != 0x00000001) && (var != 0x3803000F))485				bled = -EINVAL;486		}487		if (bled && (bled != -ETIMEDOUT))488			bled = aac_adapter_sync_cmd(dev, IOP_RESET,489			  0, 0, 0, 0, 0, 0, &var, NULL, NULL, NULL, NULL);490 491		if (bled && (bled != -ETIMEDOUT))492			return -EINVAL;493	}494	if (bled && (var == 0x3803000F)) { /* USE_OTHER_METHOD */495		rx_writel(dev, MUnit.reserved2, 3);496		msleep(5000); /* Delay 5 seconds */497		var = 0x00000001;498	}499	if (bled && (var != 0x00000001))500		return -EINVAL;501	ssleep(5);502	if (rx_readl(dev, MUnit.OMRx[0]) & KERNEL_PANIC)503		return -ENODEV;504	if (startup_timeout < 300)505		startup_timeout = 300;506	return 0;507}508 509/**510 *	aac_rx_select_comm	-	Select communications method511 *	@dev: Adapter512 *	@comm: communications method513 */514 515int aac_rx_select_comm(struct aac_dev *dev, int comm)516{517	switch (comm) {518	case AAC_COMM_PRODUCER:519		dev->a_ops.adapter_enable_int = aac_rx_enable_interrupt_producer;520		dev->a_ops.adapter_intr = aac_rx_intr_producer;521		dev->a_ops.adapter_deliver = aac_rx_deliver_producer;522		break;523	case AAC_COMM_MESSAGE:524		dev->a_ops.adapter_enable_int = aac_rx_enable_interrupt_message;525		dev->a_ops.adapter_intr = aac_rx_intr_message;526		dev->a_ops.adapter_deliver = aac_rx_deliver_message;527		break;528	default:529		return 1;530	}531	return 0;532}533 534/**535 *	_aac_rx_init	-	initialize an i960 based AAC card536 *	@dev: device to configure537 *538 *	Allocate and set up resources for the i960 based AAC variants. The 539 *	device_interface in the commregion will be allocated and linked 540 *	to the comm region.541 */542 543int _aac_rx_init(struct aac_dev *dev)544{545	unsigned long start;546	unsigned long status;547	int restart = 0;548	int instance = dev->id;549	const char * name = dev->name;550 551	if (aac_adapter_ioremap(dev, dev->base_size)) {552		printk(KERN_WARNING "%s: unable to map adapter.\n", name);553		goto error_iounmap;554	}555 556	/* Failure to reset here is an option ... */557	dev->a_ops.adapter_sync_cmd = rx_sync_cmd;558	dev->a_ops.adapter_enable_int = aac_rx_disable_interrupt;559	dev->OIMR = status = rx_readb (dev, MUnit.OIMR);560 561	if (((status & 0x0c) != 0x0c) || dev->init_reset) {562		dev->init_reset = false;563		if (!aac_rx_restart_adapter(dev, 0, IOP_HWSOFT_RESET)) {564			/* Make sure the Hardware FIFO is empty */565			while ((++restart < 512) &&566			       (rx_readl(dev, MUnit.OutboundQueue) != 0xFFFFFFFFL));567		}568	}569 570	/*571	 *	Check to see if the board panic'd while booting.572	 */573	status = rx_readl(dev, MUnit.OMRx[0]);574	if (status & KERNEL_PANIC) {575		if (aac_rx_restart_adapter(dev,576			aac_rx_check_health(dev), IOP_HWSOFT_RESET))577			goto error_iounmap;578		++restart;579	}580	/*581	 *	Check to see if the board failed any self tests.582	 */583	status = rx_readl(dev, MUnit.OMRx[0]);584	if (status & SELF_TEST_FAILED) {585		printk(KERN_ERR "%s%d: adapter self-test failed.\n", dev->name, instance);586		goto error_iounmap;587	}588	/*589	 *	Check to see if the monitor panic'd while booting.590	 */591	if (status & MONITOR_PANIC) {592		printk(KERN_ERR "%s%d: adapter monitor panic.\n", dev->name, instance);593		goto error_iounmap;594	}595	start = jiffies;596	/*597	 *	Wait for the adapter to be up and running. Wait up to 3 minutes598	 */599	while (!((status = rx_readl(dev, MUnit.OMRx[0])) & KERNEL_UP_AND_RUNNING))600	{601		if ((restart &&602		  (status & (KERNEL_PANIC|SELF_TEST_FAILED|MONITOR_PANIC))) ||603		  time_after(jiffies, start+HZ*startup_timeout)) {604			printk(KERN_ERR "%s%d: adapter kernel failed to start, init status = %lx.\n", 605					dev->name, instance, status);606			goto error_iounmap;607		}608		if (!restart &&609		  ((status & (KERNEL_PANIC|SELF_TEST_FAILED|MONITOR_PANIC)) ||610		  time_after(jiffies, start + HZ *611		  ((startup_timeout > 60)612		    ? (startup_timeout - 60)613		    : (startup_timeout / 2))))) {614			if (likely(!aac_rx_restart_adapter(dev,615				aac_rx_check_health(dev), IOP_HWSOFT_RESET)))616				start = jiffies;617			++restart;618		}619		msleep(1);620	}621	if (restart && aac_commit)622		aac_commit = 1;623	/*624	 *	Fill in the common function dispatch table.625	 */626	dev->a_ops.adapter_interrupt = aac_rx_interrupt_adapter;627	dev->a_ops.adapter_disable_int = aac_rx_disable_interrupt;628	dev->a_ops.adapter_notify = aac_rx_notify_adapter;629	dev->a_ops.adapter_sync_cmd = rx_sync_cmd;630	dev->a_ops.adapter_check_health = aac_rx_check_health;631	dev->a_ops.adapter_restart = aac_rx_restart_adapter;632	dev->a_ops.adapter_start = aac_rx_start_adapter;633 634	/*635	 *	First clear out all interrupts.  Then enable the one's that we636	 *	can handle.637	 */638	aac_adapter_comm(dev, AAC_COMM_PRODUCER);639	aac_adapter_disable_int(dev);640	rx_writel(dev, MUnit.ODR, 0xffffffff);641	aac_adapter_enable_int(dev);642 643	if (aac_init_adapter(dev) == NULL)644		goto error_iounmap;645	aac_adapter_comm(dev, dev->comm_interface);646	dev->sync_mode = 0;	/* sync. mode not supported */647	dev->msi = aac_msi && !pci_enable_msi(dev->pdev);648	if (request_irq(dev->pdev->irq, dev->a_ops.adapter_intr,649			IRQF_SHARED, "aacraid", dev) < 0) {650		if (dev->msi)651			pci_disable_msi(dev->pdev);652		printk(KERN_ERR "%s%d: Interrupt unavailable.\n",653			name, instance);654		goto error_iounmap;655	}656	dev->dbg_base = dev->base_start;657	dev->dbg_base_mapped = dev->base;658	dev->dbg_size = dev->base_size;659 660	aac_adapter_enable_int(dev);661	/*662	 *	Tell the adapter that all is configured, and it can663	 * start accepting requests664	 */665	aac_rx_start_adapter(dev);666 667	return 0;668 669error_iounmap:670 671	return -1;672}673 674int aac_rx_init(struct aac_dev *dev)675{676	/*677	 *	Fill in the function dispatch table.678	 */679	dev->a_ops.adapter_ioremap = aac_rx_ioremap;680	dev->a_ops.adapter_comm = aac_rx_select_comm;681 682	return _aac_rx_init(dev);683}684