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