linux/drivers/scsi/aacraid/sa.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-or-later
   2/*
   3 *      Adaptec AAC series RAID controller driver
   4 *      (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.c
  15 *
  16 * Abstract: Drawbridge specific support 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_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 Ready
  54                        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 Ready
  57                        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 Full
  60                        sa_writew(dev, DoorbellClrReg_p, DOORBELL_3);
  61                } else if (intstat & DOORBELL_4) {      // dev -> Host Normal Response Not Full
  62                        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 interrupt
  71 *      @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 interrupt
  81 *      @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 notification
  92 *      @dev:   Adapter that notification is for
  93 *      @event: Event to notidy
  94 *
  95 *      Notify the adapter of an event
  96 */
  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 wait
 135 *      @dev: Adapter
 136 *      @command: Command to execute
 137 *      @p1: first parameter
 138 *      @p2: second parameter
 139 *      @p3: third parameter
 140 *      @p4: forth parameter
 141 *      @p5: fifth parameter
 142 *      @p6: sixth parameter
 143 *      @ret: adapter status
 144 *      @r1: first return value
 145 *      @r2: second return value
 146 *      @r3: third return value
 147 *      @r4: forth return value
 148 *
 149 *      This routine will send a synchronous command to the adapter and wait
 150 *      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 0
 160         */
 161        sa_writel(dev, Mailbox0, command);
 162        /*
 163         *      Write the parameters into Mailboxes 1 - 4
 164         */
 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 command
 176         */
 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 access
 186                 */
 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 adapter
 223 *      @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 adapter
 236 *      @dev:   Adapter
 237 *
 238 *      Start up processing on an ARM based AAC adapter
 239 */
 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_health
 262 *      @dev: device to check if healthy
 263 *
 264 *      Will attempt to determine if the specified adapter is alive and
 265 *      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 minutes
 283         */
 284        if (!(status & KERNEL_UP_AND_RUNNING))
 285                return -3;
 286        /*
 287         *      Everything is OK
 288         */
 289        return 0;
 290}
 291
 292/**
 293 *      aac_sa_ioremap
 294 *      @dev: device to ioremap
 295 *      @size: mapping resize request
 296 *
 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 card
 310 *      @dev: device to configure
 311 *
 312 *      Allocate and set up resources for the ARM based AAC variants. The
 313 *      device_interface in the commregion will be allocated and linked
 314 *      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 requests
 401         */
 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