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