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 *      @ret: adapter status
 139 *
 140 *      This routine will send a synchronous command to the adapter and wait 
 141 *      for its completion.
 142 */
 143
 144static int sa_sync_cmd(struct aac_dev *dev, u32 command, 
 145                u32 p1, u32 p2, u32 p3, u32 p4, u32 p5, u32 p6,
 146                u32 *ret, u32 *r1, u32 *r2, u32 *r3, u32 *r4)
 147{
 148        unsigned long start;
 149        int ok;
 150        /*
 151         *      Write the Command into Mailbox 0
 152         */
 153        sa_writel(dev, Mailbox0, command);
 154        /*
 155         *      Write the parameters into Mailboxes 1 - 4
 156         */
 157        sa_writel(dev, Mailbox1, p1);
 158        sa_writel(dev, Mailbox2, p2);
 159        sa_writel(dev, Mailbox3, p3);
 160        sa_writel(dev, Mailbox4, p4);
 161
 162        /*
 163         *      Clear the synch command doorbell to start on a clean slate.
 164         */
 165        sa_writew(dev, DoorbellClrReg_p, DOORBELL_0);
 166        /*
 167         *      Signal that there is a new synch command
 168         */
 169        sa_writew(dev, DoorbellReg_s, DOORBELL_0);
 170
 171        ok = 0;
 172        start = jiffies;
 173
 174        while(time_before(jiffies, start+30*HZ))
 175        {
 176                /*
 177                 *      Delay 5uS so that the monitor gets access
 178                 */
 179                udelay(5);
 180                /*
 181                 *      Mon110 will set doorbell0 bit when it has 
 182                 *      completed the command.
 183                 */
 184                if(sa_readw(dev, DoorbellReg_p) & DOORBELL_0)  {
 185                        ok = 1;
 186                        break;
 187                }
 188                msleep(1);
 189        }
 190
 191        if (ok != 1)
 192                return -ETIMEDOUT;
 193        /*
 194         *      Clear the synch command doorbell.
 195         */
 196        sa_writew(dev, DoorbellClrReg_p, DOORBELL_0);
 197        /*
 198         *      Pull the synch status from Mailbox 0.
 199         */
 200        if (ret)
 201                *ret = sa_readl(dev, Mailbox0);
 202        if (r1)
 203                *r1 = sa_readl(dev, Mailbox1);
 204        if (r2)
 205                *r2 = sa_readl(dev, Mailbox2);
 206        if (r3)
 207                *r3 = sa_readl(dev, Mailbox3);
 208        if (r4)
 209                *r4 = sa_readl(dev, Mailbox4);
 210        return 0;
 211}
 212
 213/**
 214 *      aac_sa_interrupt_adapter        -       interrupt an adapter
 215 *      @dev: Which adapter to enable.
 216 *
 217 *      Breakpoint an adapter.
 218 */
 219 
 220static void aac_sa_interrupt_adapter (struct aac_dev *dev)
 221{
 222        sa_sync_cmd(dev, BREAKPOINT_REQUEST, 0, 0, 0, 0, 0, 0,
 223                        NULL, NULL, NULL, NULL, NULL);
 224}
 225
 226/**
 227 *      aac_sa_start_adapter            -       activate adapter
 228 *      @dev:   Adapter
 229 *
 230 *      Start up processing on an ARM based AAC adapter
 231 */
 232
 233static void aac_sa_start_adapter(struct aac_dev *dev)
 234{
 235        union aac_init *init;
 236        /*
 237         * Fill in the remaining pieces of the init.
 238         */
 239        init = dev->init;
 240        init->r7.host_elapsed_seconds = cpu_to_le32(ktime_get_real_seconds());
 241        /* We can only use a 32 bit address here */
 242        sa_sync_cmd(dev, INIT_STRUCT_BASE_ADDRESS, 
 243                        (u32)(ulong)dev->init_pa, 0, 0, 0, 0, 0,
 244                        NULL, NULL, NULL, NULL, NULL);
 245}
 246
 247static int aac_sa_restart_adapter(struct aac_dev *dev, int bled, u8 reset_type)
 248{
 249        return -EINVAL;
 250}
 251
 252/**
 253 *      aac_sa_check_health
 254 *      @dev: device to check if healthy
 255 *
 256 *      Will attempt to determine if the specified adapter is alive and
 257 *      capable of handling requests, returning 0 if alive.
 258 */
 259static int aac_sa_check_health(struct aac_dev *dev)
 260{
 261        long status = sa_readl(dev, Mailbox7);
 262
 263        /*
 264         *      Check to see if the board failed any self tests.
 265         */
 266        if (status & SELF_TEST_FAILED)
 267                return -1;
 268        /*
 269         *      Check to see if the board panic'd while booting.
 270         */
 271        if (status & KERNEL_PANIC)
 272                return -2;
 273        /*
 274         *      Wait for the adapter to be up and running. Wait up to 3 minutes
 275         */
 276        if (!(status & KERNEL_UP_AND_RUNNING))
 277                return -3;
 278        /*
 279         *      Everything is OK
 280         */
 281        return 0;
 282}
 283
 284/**
 285 *      aac_sa_ioremap
 286 *      @size: mapping resize request
 287 *
 288 */
 289static int aac_sa_ioremap(struct aac_dev * dev, u32 size)
 290{
 291        if (!size) {
 292                iounmap(dev->regs.sa);
 293                return 0;
 294        }
 295        dev->base = dev->regs.sa = ioremap(dev->base_start, size);
 296        return (dev->base == NULL) ? -1 : 0;
 297}
 298
 299/**
 300 *      aac_sa_init     -       initialize an ARM based AAC card
 301 *      @dev: device to configure
 302 *
 303 *      Allocate and set up resources for the ARM based AAC variants. The 
 304 *      device_interface in the commregion will be allocated and linked 
 305 *      to the comm region.
 306 */
 307
 308int aac_sa_init(struct aac_dev *dev)
 309{
 310        unsigned long start;
 311        unsigned long status;
 312        int instance;
 313        const char *name;
 314
 315        instance = dev->id;
 316        name     = dev->name;
 317
 318        /*
 319         *      Fill in the function dispatch table.
 320         */
 321
 322        dev->a_ops.adapter_interrupt = aac_sa_interrupt_adapter;
 323        dev->a_ops.adapter_disable_int = aac_sa_disable_interrupt;
 324        dev->a_ops.adapter_enable_int = aac_sa_enable_interrupt;
 325        dev->a_ops.adapter_notify = aac_sa_notify_adapter;
 326        dev->a_ops.adapter_sync_cmd = sa_sync_cmd;
 327        dev->a_ops.adapter_check_health = aac_sa_check_health;
 328        dev->a_ops.adapter_restart = aac_sa_restart_adapter;
 329        dev->a_ops.adapter_start = aac_sa_start_adapter;
 330        dev->a_ops.adapter_intr = aac_sa_intr;
 331        dev->a_ops.adapter_deliver = aac_rx_deliver_producer;
 332        dev->a_ops.adapter_ioremap = aac_sa_ioremap;
 333
 334        if (aac_sa_ioremap(dev, dev->base_size)) {
 335                printk(KERN_WARNING "%s: unable to map adapter.\n", name);
 336                goto error_iounmap;
 337        }
 338
 339        /*
 340         *      Check to see if the board failed any self tests.
 341         */
 342        if (sa_readl(dev, Mailbox7) & SELF_TEST_FAILED) {
 343                printk(KERN_WARNING "%s%d: adapter self-test failed.\n", name, instance);
 344                goto error_iounmap;
 345        }
 346        /*
 347         *      Check to see if the board panic'd while booting.
 348         */
 349        if (sa_readl(dev, Mailbox7) & KERNEL_PANIC) {
 350                printk(KERN_WARNING "%s%d: adapter kernel panic'd.\n", name, instance);
 351                goto error_iounmap;
 352        }
 353        start = jiffies;
 354        /*
 355         *      Wait for the adapter to be up and running. Wait up to 3 minutes.
 356         */
 357        while (!(sa_readl(dev, Mailbox7) & KERNEL_UP_AND_RUNNING)) {
 358                if (time_after(jiffies, start+startup_timeout*HZ)) {
 359                        status = sa_readl(dev, Mailbox7);
 360                        printk(KERN_WARNING "%s%d: adapter kernel failed to start, init status = %lx.\n", 
 361                                        name, instance, status);
 362                        goto error_iounmap;
 363                }
 364                msleep(1);
 365        }
 366
 367        /*
 368         *      First clear out all interrupts.  Then enable the one's that 
 369         *      we can handle.
 370         */
 371        aac_adapter_disable_int(dev);
 372        aac_adapter_enable_int(dev);
 373
 374        if(aac_init_adapter(dev) == NULL)
 375                goto error_irq;
 376        dev->sync_mode = 0;     /* sync. mode not supported */
 377        if (request_irq(dev->pdev->irq, dev->a_ops.adapter_intr,
 378                        IRQF_SHARED, "aacraid", (void *)dev) < 0) {
 379                printk(KERN_WARNING "%s%d: Interrupt unavailable.\n",
 380                        name, instance);
 381                goto error_iounmap;
 382        }
 383        dev->dbg_base = dev->base_start;
 384        dev->dbg_base_mapped = dev->base;
 385        dev->dbg_size = dev->base_size;
 386
 387        aac_adapter_enable_int(dev);
 388
 389        /*
 390         *      Tell the adapter that all is configure, and it can start 
 391         *      accepting requests
 392         */
 393        aac_sa_start_adapter(dev);
 394        return 0;
 395
 396error_irq:
 397        aac_sa_disable_interrupt(dev);
 398        free_irq(dev->pdev->irq, (void *)dev);
 399
 400error_iounmap:
 401
 402        return -1;
 403}
 404
 405