linux/drivers/scsi/aacraid/sa.c
<<
>>
Prefs
   1/*
   2 *      Adaptec AAC series RAID controller driver
   3 *      (c) Copyright 2001 Red Hat Inc.
   4 *
   5 * based on the old aacraid driver that is..
   6 * Adaptec aacraid device driver for Linux.
   7 *
   8 * Copyright (c) 2000-2010 Adaptec, Inc.
   9 *               2010-2015 PMC-Sierra, Inc. (aacraid@pmc-sierra.com)
  10 *               2016-2017 Microsemi Corp. (aacraid@microsemi.com)
  11 *
  12 * This program is free software; you can redistribute it and/or modify
  13 * it under the terms of the GNU General Public License as published by
  14 * the Free Software Foundation; either version 2, or (at your option)
  15 * any later version.
  16 *
  17 * This program is distributed in the hope that it will be useful,
  18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  20 * GNU General Public License for more details.
  21 *
  22 * You should have received a copy of the GNU General Public License
  23 * along with this program; see the file COPYING.  If not, write to
  24 * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
  25 *
  26 * Module Name:
  27 *  sa.c
  28 *
  29 * Abstract: Drawbridge specific support functions
  30 *
  31 */
  32
  33#include <linux/kernel.h>
  34#include <linux/init.h>
  35#include <linux/types.h>
  36#include <linux/pci.h>
  37#include <linux/spinlock.h>
  38#include <linux/blkdev.h>
  39#include <linux/delay.h>
  40#include <linux/completion.h>
  41#include <linux/time.h>
  42#include <linux/interrupt.h>
  43
  44#include <scsi/scsi_host.h>
  45
  46#include "aacraid.h"
  47
  48static irqreturn_t aac_sa_intr(int irq, void *dev_id)
  49{
  50        struct aac_dev *dev = dev_id;
  51        unsigned short intstat, mask;
  52
  53        intstat = sa_readw(dev, DoorbellReg_p);
  54        /*
  55         *      Read mask and invert because drawbridge is reversed.
  56         *      This allows us to only service interrupts that have been enabled.
  57         */
  58        mask = ~(sa_readw(dev, SaDbCSR.PRISETIRQMASK));
  59
  60        /* Check to see if this is our interrupt.  If it isn't just return */
  61
  62        if (intstat & mask) {
  63                if (intstat & PrintfReady) {
  64                        aac_printf(dev, sa_readl(dev, Mailbox5));
  65                        sa_writew(dev, DoorbellClrReg_p, PrintfReady); /* clear PrintfReady */
  66                        sa_writew(dev, DoorbellReg_s, PrintfDone);
  67                } else if (intstat & DOORBELL_1) {      // dev -> Host Normal Command Ready
  68                        sa_writew(dev, DoorbellClrReg_p, DOORBELL_1);
  69                        aac_command_normal(&dev->queues->queue[HostNormCmdQueue]);
  70                } else if (intstat & DOORBELL_2) {      // dev -> Host Normal Response Ready
  71                        sa_writew(dev, DoorbellClrReg_p, DOORBELL_2);
  72                        aac_response_normal(&dev->queues->queue[HostNormRespQueue]);
  73                } else if (intstat & DOORBELL_3) {      // dev -> Host Normal Command Not Full
  74                        sa_writew(dev, DoorbellClrReg_p, DOORBELL_3);
  75                } else if (intstat & DOORBELL_4) {      // dev -> Host Normal Response Not Full
  76                        sa_writew(dev, DoorbellClrReg_p, DOORBELL_4);
  77                }
  78                return IRQ_HANDLED;
  79        }
  80        return IRQ_NONE;
  81}
  82
  83/**
  84 *      aac_sa_disable_interrupt        -       disable interrupt
  85 *      @dev: Which adapter to enable.
  86 */
  87
  88static void aac_sa_disable_interrupt (struct aac_dev *dev)
  89{
  90        sa_writew(dev, SaDbCSR.PRISETIRQMASK, 0xffff);
  91}
  92
  93/**
  94 *      aac_sa_enable_interrupt -       enable interrupt
  95 *      @dev: Which adapter to enable.
  96 */
  97
  98static void aac_sa_enable_interrupt (struct aac_dev *dev)
  99{
 100        sa_writew(dev, SaDbCSR.PRICLEARIRQMASK, (PrintfReady | DOORBELL_1 |
 101                                DOORBELL_2 | DOORBELL_3 | DOORBELL_4));
 102}
 103
 104/**
 105 *      aac_sa_notify_adapter           -       handle adapter notification
 106 *      @dev:   Adapter that notification is for
 107 *      @event: Event to notidy
 108 *
 109 *      Notify the adapter of an event
 110 */
 111 
 112static void aac_sa_notify_adapter(struct aac_dev *dev, u32 event)
 113{
 114        switch (event) {
 115
 116        case AdapNormCmdQue:
 117                sa_writew(dev, DoorbellReg_s,DOORBELL_1);
 118                break;
 119        case HostNormRespNotFull:
 120                sa_writew(dev, DoorbellReg_s,DOORBELL_4);
 121                break;
 122        case AdapNormRespQue:
 123                sa_writew(dev, DoorbellReg_s,DOORBELL_2);
 124                break;
 125        case HostNormCmdNotFull:
 126                sa_writew(dev, DoorbellReg_s,DOORBELL_3);
 127                break;
 128        case HostShutdown:
 129                /*
 130                sa_sync_cmd(dev, HOST_CRASHING, 0, 0, 0, 0, 0, 0,
 131                NULL, NULL, NULL, NULL, NULL);
 132                */
 133                break;
 134        case FastIo:
 135                sa_writew(dev, DoorbellReg_s,DOORBELL_6);
 136                break;
 137        case AdapPrintfDone:
 138                sa_writew(dev, DoorbellReg_s,DOORBELL_5);
 139                break;
 140        default:
 141                BUG();
 142                break;
 143        }
 144}
 145
 146
 147/**
 148 *      sa_sync_cmd     -       send a command and wait
 149 *      @dev: Adapter
 150 *      @command: Command to execute
 151 *      @p1: first parameter
 152 *      @ret: adapter status
 153 *
 154 *      This routine will send a synchronous command to the adapter and wait 
 155 *      for its completion.
 156 */
 157
 158static int sa_sync_cmd(struct aac_dev *dev, u32 command, 
 159                u32 p1, u32 p2, u32 p3, u32 p4, u32 p5, u32 p6,
 160                u32 *ret, u32 *r1, u32 *r2, u32 *r3, u32 *r4)
 161{
 162        unsigned long start;
 163        int ok;
 164        /*
 165         *      Write the Command into Mailbox 0
 166         */
 167        sa_writel(dev, Mailbox0, command);
 168        /*
 169         *      Write the parameters into Mailboxes 1 - 4
 170         */
 171        sa_writel(dev, Mailbox1, p1);
 172        sa_writel(dev, Mailbox2, p2);
 173        sa_writel(dev, Mailbox3, p3);
 174        sa_writel(dev, Mailbox4, p4);
 175
 176        /*
 177         *      Clear the synch command doorbell to start on a clean slate.
 178         */
 179        sa_writew(dev, DoorbellClrReg_p, DOORBELL_0);
 180        /*
 181         *      Signal that there is a new synch command
 182         */
 183        sa_writew(dev, DoorbellReg_s, DOORBELL_0);
 184
 185        ok = 0;
 186        start = jiffies;
 187
 188        while(time_before(jiffies, start+30*HZ))
 189        {
 190                /*
 191                 *      Delay 5uS so that the monitor gets access
 192                 */
 193                udelay(5);
 194                /*
 195                 *      Mon110 will set doorbell0 bit when it has 
 196                 *      completed the command.
 197                 */
 198                if(sa_readw(dev, DoorbellReg_p) & DOORBELL_0)  {
 199                        ok = 1;
 200                        break;
 201                }
 202                msleep(1);
 203        }
 204
 205        if (ok != 1)
 206                return -ETIMEDOUT;
 207        /*
 208         *      Clear the synch command doorbell.
 209         */
 210        sa_writew(dev, DoorbellClrReg_p, DOORBELL_0);
 211        /*
 212         *      Pull the synch status from Mailbox 0.
 213         */
 214        if (ret)
 215                *ret = sa_readl(dev, Mailbox0);
 216        if (r1)
 217                *r1 = sa_readl(dev, Mailbox1);
 218        if (r2)
 219                *r2 = sa_readl(dev, Mailbox2);
 220        if (r3)
 221                *r3 = sa_readl(dev, Mailbox3);
 222        if (r4)
 223                *r4 = sa_readl(dev, Mailbox4);
 224        return 0;
 225}
 226
 227/**
 228 *      aac_sa_interrupt_adapter        -       interrupt an adapter
 229 *      @dev: Which adapter to enable.
 230 *
 231 *      Breakpoint an adapter.
 232 */
 233 
 234static void aac_sa_interrupt_adapter (struct aac_dev *dev)
 235{
 236        sa_sync_cmd(dev, BREAKPOINT_REQUEST, 0, 0, 0, 0, 0, 0,
 237                        NULL, NULL, NULL, NULL, NULL);
 238}
 239
 240/**
 241 *      aac_sa_start_adapter            -       activate adapter
 242 *      @dev:   Adapter
 243 *
 244 *      Start up processing on an ARM based AAC adapter
 245 */
 246
 247static void aac_sa_start_adapter(struct aac_dev *dev)
 248{
 249        union aac_init *init;
 250        /*
 251         * Fill in the remaining pieces of the init.
 252         */
 253        init = dev->init;
 254        init->r7.host_elapsed_seconds = cpu_to_le32(get_seconds());
 255        /* We can only use a 32 bit address here */
 256        sa_sync_cmd(dev, INIT_STRUCT_BASE_ADDRESS, 
 257                        (u32)(ulong)dev->init_pa, 0, 0, 0, 0, 0,
 258                        NULL, NULL, NULL, NULL, NULL);
 259}
 260
 261static int aac_sa_restart_adapter(struct aac_dev *dev, int bled, u8 reset_type)
 262{
 263        return -EINVAL;
 264}
 265
 266/**
 267 *      aac_sa_check_health
 268 *      @dev: device to check if healthy
 269 *
 270 *      Will attempt to determine if the specified adapter is alive and
 271 *      capable of handling requests, returning 0 if alive.
 272 */
 273static int aac_sa_check_health(struct aac_dev *dev)
 274{
 275        long status = sa_readl(dev, Mailbox7);
 276
 277        /*
 278         *      Check to see if the board failed any self tests.
 279         */
 280        if (status & SELF_TEST_FAILED)
 281                return -1;
 282        /*
 283         *      Check to see if the board panic'd while booting.
 284         */
 285        if (status & KERNEL_PANIC)
 286                return -2;
 287        /*
 288         *      Wait for the adapter to be up and running. Wait up to 3 minutes
 289         */
 290        if (!(status & KERNEL_UP_AND_RUNNING))
 291                return -3;
 292        /*
 293         *      Everything is OK
 294         */
 295        return 0;
 296}
 297
 298/**
 299 *      aac_sa_ioremap
 300 *      @size: mapping resize request
 301 *
 302 */
 303static int aac_sa_ioremap(struct aac_dev * dev, u32 size)
 304{
 305        if (!size) {
 306                iounmap(dev->regs.sa);
 307                return 0;
 308        }
 309        dev->base = dev->regs.sa = ioremap(dev->base_start, size);
 310        return (dev->base == NULL) ? -1 : 0;
 311}
 312
 313/**
 314 *      aac_sa_init     -       initialize an ARM based AAC card
 315 *      @dev: device to configure
 316 *
 317 *      Allocate and set up resources for the ARM based AAC variants. The 
 318 *      device_interface in the commregion will be allocated and linked 
 319 *      to the comm region.
 320 */
 321
 322int aac_sa_init(struct aac_dev *dev)
 323{
 324        unsigned long start;
 325        unsigned long status;
 326        int instance;
 327        const char *name;
 328
 329        instance = dev->id;
 330        name     = dev->name;
 331
 332        /*
 333         *      Fill in the function dispatch table.
 334         */
 335
 336        dev->a_ops.adapter_interrupt = aac_sa_interrupt_adapter;
 337        dev->a_ops.adapter_disable_int = aac_sa_disable_interrupt;
 338        dev->a_ops.adapter_enable_int = aac_sa_enable_interrupt;
 339        dev->a_ops.adapter_notify = aac_sa_notify_adapter;
 340        dev->a_ops.adapter_sync_cmd = sa_sync_cmd;
 341        dev->a_ops.adapter_check_health = aac_sa_check_health;
 342        dev->a_ops.adapter_restart = aac_sa_restart_adapter;
 343        dev->a_ops.adapter_start = aac_sa_start_adapter;
 344        dev->a_ops.adapter_intr = aac_sa_intr;
 345        dev->a_ops.adapter_deliver = aac_rx_deliver_producer;
 346        dev->a_ops.adapter_ioremap = aac_sa_ioremap;
 347
 348        if (aac_sa_ioremap(dev, dev->base_size)) {
 349                printk(KERN_WARNING "%s: unable to map adapter.\n", name);
 350                goto error_iounmap;
 351        }
 352
 353        /*
 354         *      Check to see if the board failed any self tests.
 355         */
 356        if (sa_readl(dev, Mailbox7) & SELF_TEST_FAILED) {
 357                printk(KERN_WARNING "%s%d: adapter self-test failed.\n", name, instance);
 358                goto error_iounmap;
 359        }
 360        /*
 361         *      Check to see if the board panic'd while booting.
 362         */
 363        if (sa_readl(dev, Mailbox7) & KERNEL_PANIC) {
 364                printk(KERN_WARNING "%s%d: adapter kernel panic'd.\n", name, instance);
 365                goto error_iounmap;
 366        }
 367        start = jiffies;
 368        /*
 369         *      Wait for the adapter to be up and running. Wait up to 3 minutes.
 370         */
 371        while (!(sa_readl(dev, Mailbox7) & KERNEL_UP_AND_RUNNING)) {
 372                if (time_after(jiffies, start+startup_timeout*HZ)) {
 373                        status = sa_readl(dev, Mailbox7);
 374                        printk(KERN_WARNING "%s%d: adapter kernel failed to start, init status = %lx.\n", 
 375                                        name, instance, status);
 376                        goto error_iounmap;
 377                }
 378                msleep(1);
 379        }
 380
 381        /*
 382         *      First clear out all interrupts.  Then enable the one's that 
 383         *      we can handle.
 384         */
 385        aac_adapter_disable_int(dev);
 386        aac_adapter_enable_int(dev);
 387
 388        if(aac_init_adapter(dev) == NULL)
 389                goto error_irq;
 390        dev->sync_mode = 0;     /* sync. mode not supported */
 391        if (request_irq(dev->pdev->irq, dev->a_ops.adapter_intr,
 392                        IRQF_SHARED, "aacraid", (void *)dev) < 0) {
 393                printk(KERN_WARNING "%s%d: Interrupt unavailable.\n",
 394                        name, instance);
 395                goto error_iounmap;
 396        }
 397        dev->dbg_base = dev->base_start;
 398        dev->dbg_base_mapped = dev->base;
 399        dev->dbg_size = dev->base_size;
 400
 401        aac_adapter_enable_int(dev);
 402
 403        /*
 404         *      Tell the adapter that all is configure, and it can start 
 405         *      accepting requests
 406         */
 407        aac_sa_start_adapter(dev);
 408        return 0;
 409
 410error_irq:
 411        aac_sa_disable_interrupt(dev);
 412        free_irq(dev->pdev->irq, (void *)dev);
 413
 414error_iounmap:
 415
 416        return -1;
 417}
 418
 419