linux/drivers/scsi/mvme147.c
<<
>>
Prefs
   1#include <linux/types.h>
   2#include <linux/mm.h>
   3#include <linux/blkdev.h>
   4#include <linux/interrupt.h>
   5
   6#include <asm/page.h>
   7#include <asm/pgtable.h>
   8#include <asm/mvme147hw.h>
   9#include <asm/irq.h>
  10
  11#include "scsi.h"
  12#include <scsi/scsi_host.h>
  13#include "wd33c93.h"
  14#include "mvme147.h"
  15
  16#include <linux/stat.h>
  17
  18
  19static irqreturn_t mvme147_intr(int irq, void *data)
  20{
  21        struct Scsi_Host *instance = data;
  22
  23        if (irq == MVME147_IRQ_SCSI_PORT)
  24                wd33c93_intr(instance);
  25        else
  26                m147_pcc->dma_intr = 0x89;      /* Ack and enable ints */
  27        return IRQ_HANDLED;
  28}
  29
  30static int dma_setup(struct scsi_cmnd *cmd, int dir_in)
  31{
  32        struct Scsi_Host *instance = cmd->device->host;
  33        struct WD33C93_hostdata *hdata = shost_priv(instance);
  34        unsigned char flags = 0x01;
  35        unsigned long addr = virt_to_bus(cmd->SCp.ptr);
  36
  37        /* setup dma direction */
  38        if (!dir_in)
  39                flags |= 0x04;
  40
  41        /* remember direction */
  42        hdata->dma_dir = dir_in;
  43
  44        if (dir_in) {
  45                /* invalidate any cache */
  46                cache_clear(addr, cmd->SCp.this_residual);
  47        } else {
  48                /* push any dirty cache */
  49                cache_push(addr, cmd->SCp.this_residual);
  50        }
  51
  52        /* start DMA */
  53        m147_pcc->dma_bcr = cmd->SCp.this_residual | (1 << 24);
  54        m147_pcc->dma_dadr = addr;
  55        m147_pcc->dma_cntrl = flags;
  56
  57        /* return success */
  58        return 0;
  59}
  60
  61static void dma_stop(struct Scsi_Host *instance, struct scsi_cmnd *SCpnt,
  62                     int status)
  63{
  64        m147_pcc->dma_cntrl = 0;
  65}
  66
  67int mvme147_detect(struct scsi_host_template *tpnt)
  68{
  69        static unsigned char called = 0;
  70        struct Scsi_Host *instance;
  71        wd33c93_regs regs;
  72        struct WD33C93_hostdata *hdata;
  73
  74        if (!MACH_IS_MVME147 || called)
  75                return 0;
  76        called++;
  77
  78        tpnt->proc_name = "MVME147";
  79        tpnt->show_info = wd33c93_show_info,
  80        tpnt->write_info = wd33c93_write_info,
  81
  82        instance = scsi_register(tpnt, sizeof(struct WD33C93_hostdata));
  83        if (!instance)
  84                goto err_out;
  85
  86        instance->base = 0xfffe4000;
  87        instance->irq = MVME147_IRQ_SCSI_PORT;
  88        regs.SASR = (volatile unsigned char *)0xfffe4000;
  89        regs.SCMD = (volatile unsigned char *)0xfffe4001;
  90        hdata = shost_priv(instance);
  91        hdata->no_sync = 0xff;
  92        hdata->fast = 0;
  93        hdata->dma_mode = CTRL_DMA;
  94        wd33c93_init(instance, regs, dma_setup, dma_stop, WD33C93_FS_8_10);
  95
  96        if (request_irq(MVME147_IRQ_SCSI_PORT, mvme147_intr, 0,
  97                        "MVME147 SCSI PORT", instance))
  98                goto err_unregister;
  99        if (request_irq(MVME147_IRQ_SCSI_DMA, mvme147_intr, 0,
 100                        "MVME147 SCSI DMA", instance))
 101                goto err_free_irq;
 102#if 0   /* Disabled; causes problems booting */
 103        m147_pcc->scsi_interrupt = 0x10;        /* Assert SCSI bus reset */
 104        udelay(100);
 105        m147_pcc->scsi_interrupt = 0x00;        /* Negate SCSI bus reset */
 106        udelay(2000);
 107        m147_pcc->scsi_interrupt = 0x40;        /* Clear bus reset interrupt */
 108#endif
 109        m147_pcc->scsi_interrupt = 0x09;        /* Enable interrupt */
 110
 111        m147_pcc->dma_cntrl = 0x00;     /* ensure DMA is stopped */
 112        m147_pcc->dma_intr = 0x89;      /* Ack and enable ints */
 113
 114        return 1;
 115
 116err_free_irq:
 117        free_irq(MVME147_IRQ_SCSI_PORT, mvme147_intr);
 118err_unregister:
 119        scsi_unregister(instance);
 120err_out:
 121        return 0;
 122}
 123
 124static int mvme147_bus_reset(struct scsi_cmnd *cmd)
 125{
 126        /* FIXME perform bus-specific reset */
 127
 128        /* FIXME 2: kill this function, and let midlayer fallback to
 129           the same result, calling wd33c93_host_reset() */
 130
 131        spin_lock_irq(cmd->device->host->host_lock);
 132        wd33c93_host_reset(cmd);
 133        spin_unlock_irq(cmd->device->host->host_lock);
 134
 135        return SUCCESS;
 136}
 137
 138
 139static struct scsi_host_template driver_template = {
 140        .proc_name              = "MVME147",
 141        .name                   = "MVME147 built-in SCSI",
 142        .detect                 = mvme147_detect,
 143        .release                = mvme147_release,
 144        .queuecommand           = wd33c93_queuecommand,
 145        .eh_abort_handler       = wd33c93_abort,
 146        .eh_bus_reset_handler   = mvme147_bus_reset,
 147        .eh_host_reset_handler  = wd33c93_host_reset,
 148        .can_queue              = CAN_QUEUE,
 149        .this_id                = 7,
 150        .sg_tablesize           = SG_ALL,
 151        .cmd_per_lun            = CMD_PER_LUN,
 152        .use_clustering         = ENABLE_CLUSTERING
 153};
 154
 155
 156#include "scsi_module.c"
 157
 158int mvme147_release(struct Scsi_Host *instance)
 159{
 160#ifdef MODULE
 161        /* XXX Make sure DMA is stopped! */
 162        free_irq(MVME147_IRQ_SCSI_PORT, mvme147_intr);
 163        free_irq(MVME147_IRQ_SCSI_DMA, mvme147_intr);
 164#endif
 165        return 1;
 166}
 167