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