linux/drivers/scsi/sgiwd93.c
<<
>>
Prefs
   1/*
   2 * This file is subject to the terms and conditions of the GNU General Public
   3 * License.  See the file "COPYING" in the main directory of this archive
   4 * for more details.
   5 *
   6 * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
   7 * Copyright (C) 1999 Andrew R. Baker (andrewb@uab.edu)
   8 * Copyright (C) 2001 Florian Lohoff (flo@rfc822.org)
   9 * Copyright (C) 2003, 07 Ralf Baechle (ralf@linux-mips.org)
  10 * 
  11 * (In all truth, Jed Schimmel wrote all this code.)
  12 */
  13
  14#undef DEBUG
  15
  16#include <linux/delay.h>
  17#include <linux/dma-mapping.h>
  18#include <linux/gfp.h>
  19#include <linux/interrupt.h>
  20#include <linux/init.h>
  21#include <linux/kernel.h>
  22#include <linux/types.h>
  23#include <linux/module.h>
  24#include <linux/platform_device.h>
  25#include <linux/spinlock.h>
  26
  27#include <asm/sgi/hpc3.h>
  28#include <asm/sgi/ip22.h>
  29#include <asm/sgi/wd.h>
  30
  31#include "scsi.h"
  32#include "wd33c93.h"
  33
  34struct ip22_hostdata {
  35        struct WD33C93_hostdata wh;
  36        struct hpc_data {
  37                dma_addr_t      dma;
  38                void            *cpu;
  39        } hd;
  40};
  41
  42#define host_to_hostdata(host) ((struct ip22_hostdata *)((host)->hostdata))
  43
  44struct hpc_chunk {
  45        struct hpc_dma_desc desc;
  46        u32 _padding;   /* align to quadword boundary */
  47};
  48
  49static irqreturn_t sgiwd93_intr(int irq, void *dev_id)
  50{
  51        struct Scsi_Host * host = dev_id;
  52        unsigned long flags;
  53
  54        spin_lock_irqsave(host->host_lock, flags);
  55        wd33c93_intr(host);
  56        spin_unlock_irqrestore(host->host_lock, flags);
  57
  58        return IRQ_HANDLED;
  59}
  60
  61static inline
  62void fill_hpc_entries(struct hpc_chunk *hcp, struct scsi_cmnd *cmd, int datainp)
  63{
  64        unsigned long len = cmd->SCp.this_residual;
  65        void *addr = cmd->SCp.ptr;
  66        dma_addr_t physaddr;
  67        unsigned long count;
  68
  69        physaddr = dma_map_single(NULL, addr, len, cmd->sc_data_direction);
  70        cmd->SCp.dma_handle = physaddr;
  71
  72        while (len) {
  73                /*
  74                 * even cntinfo could be up to 16383, without
  75                 * magic only 8192 works correctly
  76                 */
  77                count = len > 8192 ? 8192 : len;
  78                hcp->desc.pbuf = physaddr;
  79                hcp->desc.cntinfo = count;
  80                hcp++;
  81                len -= count;
  82                physaddr += count;
  83        }
  84
  85        /*
  86         * To make sure, if we trip an HPC bug, that we transfer every single
  87         * byte, we tag on an extra zero length dma descriptor at the end of
  88         * the chain.
  89         */
  90        hcp->desc.pbuf = 0;
  91        hcp->desc.cntinfo = HPCDMA_EOX;
  92}
  93
  94static int dma_setup(struct scsi_cmnd *cmd, int datainp)
  95{
  96        struct ip22_hostdata *hdata = host_to_hostdata(cmd->device->host);
  97        struct hpc3_scsiregs *hregs =
  98                (struct hpc3_scsiregs *) cmd->device->host->base;
  99        struct hpc_chunk *hcp = (struct hpc_chunk *) hdata->hd.cpu;
 100
 101        pr_debug("dma_setup: datainp<%d> hcp<%p> ", datainp, hcp);
 102
 103        hdata->wh.dma_dir = datainp;
 104
 105        /*
 106         * wd33c93 shouldn't pass us bogus dma_setups, but it does:-(  The
 107         * other wd33c93 drivers deal with it the same way (which isn't that
 108         * obvious).  IMHO a better fix would be, not to do these dma setups
 109         * in the first place.
 110         */
 111        if (cmd->SCp.ptr == NULL || cmd->SCp.this_residual == 0)
 112                return 1;
 113
 114        fill_hpc_entries(hcp, cmd, datainp);
 115
 116        pr_debug(" HPCGO\n");
 117
 118        /* Start up the HPC. */
 119        hregs->ndptr = hdata->hd.dma;
 120        if (datainp)
 121                hregs->ctrl = HPC3_SCTRL_ACTIVE;
 122        else
 123                hregs->ctrl = HPC3_SCTRL_ACTIVE | HPC3_SCTRL_DIR;
 124
 125        return 0;
 126}
 127
 128static void dma_stop(struct Scsi_Host *instance, struct scsi_cmnd *SCpnt,
 129                     int status)
 130{
 131        struct ip22_hostdata *hdata = host_to_hostdata(instance);
 132        struct hpc3_scsiregs *hregs;
 133
 134        if (!SCpnt)
 135                return;
 136
 137        hregs = (struct hpc3_scsiregs *) SCpnt->device->host->base;
 138
 139        pr_debug("dma_stop: status<%d> ", status);
 140
 141        /* First stop the HPC and flush it's FIFO. */
 142        if (hdata->wh.dma_dir) {
 143                hregs->ctrl |= HPC3_SCTRL_FLUSH;
 144                while (hregs->ctrl & HPC3_SCTRL_ACTIVE)
 145                        barrier();
 146        }
 147        hregs->ctrl = 0;
 148        dma_unmap_single(NULL, SCpnt->SCp.dma_handle, SCpnt->SCp.this_residual,
 149                         SCpnt->sc_data_direction);
 150
 151        pr_debug("\n");
 152}
 153
 154void sgiwd93_reset(unsigned long base)
 155{
 156        struct hpc3_scsiregs *hregs = (struct hpc3_scsiregs *) base;
 157
 158        hregs->ctrl = HPC3_SCTRL_CRESET;
 159        udelay(50);
 160        hregs->ctrl = 0;
 161}
 162
 163static inline void init_hpc_chain(struct hpc_data *hd)
 164{
 165        struct hpc_chunk *hcp = (struct hpc_chunk *) hd->cpu;
 166        struct hpc_chunk *dma = (struct hpc_chunk *) hd->dma;
 167        unsigned long start, end;
 168
 169        start = (unsigned long) hcp;
 170        end = start + PAGE_SIZE;
 171        while (start < end) {
 172                hcp->desc.pnext = (u32) (dma + 1);
 173                hcp->desc.cntinfo = HPCDMA_EOX;
 174                hcp++; dma++;
 175                start += sizeof(struct hpc_chunk);
 176        };
 177        hcp--;
 178        hcp->desc.pnext = hd->dma;
 179}
 180
 181static int sgiwd93_bus_reset(struct scsi_cmnd *cmd)
 182{
 183        /* FIXME perform bus-specific reset */
 184
 185        /* FIXME 2: kill this function, and let midlayer fallback
 186           to the same result, calling wd33c93_host_reset() */
 187
 188        spin_lock_irq(cmd->device->host->host_lock);
 189        wd33c93_host_reset(cmd);
 190        spin_unlock_irq(cmd->device->host->host_lock);
 191
 192        return SUCCESS;
 193}
 194
 195/*
 196 * Kludge alert - the SCSI code calls the abort and reset method with int
 197 * arguments not with pointers.  So this is going to blow up beautyfully
 198 * on 64-bit systems with memory outside the compat address spaces.
 199 */
 200static struct scsi_host_template sgiwd93_template = {
 201        .module                 = THIS_MODULE,
 202        .proc_name              = "SGIWD93",
 203        .name                   = "SGI WD93",
 204        .queuecommand           = wd33c93_queuecommand,
 205        .eh_abort_handler       = wd33c93_abort,
 206        .eh_bus_reset_handler   = sgiwd93_bus_reset,
 207        .eh_host_reset_handler  = wd33c93_host_reset,
 208        .can_queue              = 16,
 209        .this_id                = 7,
 210        .sg_tablesize           = SG_ALL,
 211        .cmd_per_lun            = 8,
 212        .use_clustering         = DISABLE_CLUSTERING,
 213};
 214
 215static int __init sgiwd93_probe(struct platform_device *pdev)
 216{
 217        struct sgiwd93_platform_data *pd = pdev->dev.platform_data;
 218        unsigned char *wdregs = pd->wdregs;
 219        struct hpc3_scsiregs *hregs = pd->hregs;
 220        struct ip22_hostdata *hdata;
 221        struct Scsi_Host *host;
 222        wd33c93_regs regs;
 223        unsigned int unit = pd->unit;
 224        unsigned int irq = pd->irq;
 225        int err;
 226
 227        host = scsi_host_alloc(&sgiwd93_template, sizeof(struct ip22_hostdata));
 228        if (!host) {
 229                err = -ENOMEM;
 230                goto out;
 231        }
 232
 233        host->base = (unsigned long) hregs;
 234        host->irq = irq;
 235
 236        hdata = host_to_hostdata(host);
 237        hdata->hd.cpu = dma_alloc_coherent(&pdev->dev, PAGE_SIZE,
 238                                           &hdata->hd.dma, GFP_KERNEL);
 239        if (!hdata->hd.cpu) {
 240                printk(KERN_WARNING "sgiwd93: Could not allocate memory for "
 241                       "host %d buffer.\n", unit);
 242                err = -ENOMEM;
 243                goto out_put;
 244        }
 245
 246        init_hpc_chain(&hdata->hd);
 247
 248        regs.SASR = wdregs + 3;
 249        regs.SCMD = wdregs + 7;
 250
 251        wd33c93_init(host, regs, dma_setup, dma_stop, WD33C93_FS_MHZ(20));
 252
 253        if (hdata->wh.no_sync == 0xff)
 254                hdata->wh.no_sync = 0;
 255
 256        err = request_irq(irq, sgiwd93_intr, 0, "SGI WD93", host);
 257        if (err) {
 258                printk(KERN_WARNING "sgiwd93: Could not register irq %d "
 259                       "for host %d.\n", irq, unit);
 260                goto out_free;
 261        }
 262
 263        platform_set_drvdata(pdev, host);
 264
 265        err = scsi_add_host(host, NULL);
 266        if (err)
 267                goto out_irq;
 268
 269        scsi_scan_host(host);
 270
 271        return 0;
 272
 273out_irq:
 274        free_irq(irq, host);
 275out_free:
 276        dma_free_coherent(NULL, PAGE_SIZE, hdata->hd.cpu, hdata->hd.dma);
 277out_put:
 278        scsi_host_put(host);
 279out:
 280
 281        return err;
 282}
 283
 284static void __exit sgiwd93_remove(struct platform_device *pdev)
 285{
 286        struct Scsi_Host *host = platform_get_drvdata(pdev);
 287        struct ip22_hostdata *hdata = (struct ip22_hostdata *) host->hostdata;
 288        struct sgiwd93_platform_data *pd = pdev->dev.platform_data;
 289
 290        scsi_remove_host(host);
 291        free_irq(pd->irq, host);
 292        dma_free_coherent(&pdev->dev, PAGE_SIZE, hdata->hd.cpu, hdata->hd.dma);
 293        scsi_host_put(host);
 294}
 295
 296static struct platform_driver sgiwd93_driver = {
 297        .probe  = sgiwd93_probe,
 298        .remove = __devexit_p(sgiwd93_remove),
 299        .driver = {
 300                .name   = "sgiwd93"
 301        }
 302};
 303
 304static int __init sgiwd93_module_init(void)
 305{
 306        return platform_driver_register(&sgiwd93_driver);
 307}
 308
 309static void __exit sgiwd93_module_exit(void)
 310{
 311        return platform_driver_unregister(&sgiwd93_driver);
 312}
 313
 314module_init(sgiwd93_module_init);
 315module_exit(sgiwd93_module_exit);
 316
 317MODULE_DESCRIPTION("SGI WD33C93 driver");
 318MODULE_AUTHOR("Ralf Baechle <ralf@linux-mips.org>");
 319MODULE_LICENSE("GPL");
 320