OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [rc203soc/] [sw/] [uClinux/] [drivers/] [scsi/] [a3000.c] - Blame information for rev 1765

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1626 jcastillo
#include <linux/types.h>
2
#include <linux/mm.h>
3
#include <linux/blk.h>
4
#include <linux/version.h>
5
 
6
#include <asm/page.h>
7
#include <asm/pgtable.h>
8
#include <asm/bootinfo.h>
9
#include <asm/amigaints.h>
10
#include <asm/amigahw.h>
11
#include <asm/irq.h>
12
 
13
#include "scsi.h"
14
#include "hosts.h"
15
#include "wd33c93.h"
16
#include "a3000.h"
17
 
18
#include<linux/stat.h>
19
 
20
struct proc_dir_entry proc_scsi_a3000 = {
21
    PROC_SCSI_A3000, 5, "A3000",
22
    S_IFDIR | S_IRUGO | S_IXUGO, 2
23
};
24
 
25
#define DMA(ptr) ((a3000_scsiregs *)((ptr)->base))
26
#define HDATA(ptr) ((struct WD33C93_hostdata *)((ptr)->hostdata))
27
 
28
static struct Scsi_Host *a3000_host = NULL;
29
 
30
static void a3000_intr (int irq, struct pt_regs *fp, void *dummy)
31
{
32
    unsigned int status = DMA(a3000_host)->ISTR;
33
 
34
    if (!(status & ISTR_INT_P))
35
        return;
36
 
37
    if (status & ISTR_INTS)
38
    {
39
        /* disable PORTS interrupt */
40
        custom.intena = IF_PORTS;
41
        wd33c93_intr (a3000_host);
42
        /* enable PORTS interrupt */
43
        custom.intena = IF_SETCLR | IF_PORTS;
44
    } else {
45
      printk("Non-serviced A3000 SCSI-interrupt? ISTR = %02x\n", status);
46
    }
47
}
48
 
49
static int dma_setup (Scsi_Cmnd *cmd, int dir_in)
50
{
51
    unsigned short cntr = CNTR_PDMD | CNTR_INTEN;
52
    unsigned long addr = VTOP(cmd->SCp.ptr);
53
 
54
    /*
55
     * if the physical address has the wrong alignment, or if
56
     * physical address is bad, or if it is a write and at the
57
     * end of a physical memory chunk, then allocate a bounce
58
     * buffer
59
     */
60
    if (addr & A3000_XFER_MASK ||
61
        (!dir_in && mm_end_of_chunk (addr, cmd->SCp.this_residual)))
62
    {
63
        HDATA(a3000_host)->dma_bounce_len = (cmd->SCp.this_residual + 511)
64
            & ~0x1ff;
65
        HDATA(a3000_host)->dma_bounce_buffer =
66
            scsi_malloc (HDATA(a3000_host)->dma_bounce_len);
67
 
68
        /* can't allocate memory; use PIO */
69
        if (!HDATA(a3000_host)->dma_bounce_buffer) {
70
            HDATA(a3000_host)->dma_bounce_len = 0;
71
            return 1;
72
        }
73
 
74
        if (!dir_in) {
75
            /* copy to bounce buffer for a write */
76
            if (cmd->use_sg) {
77
                memcpy (HDATA(a3000_host)->dma_bounce_buffer,
78
                        cmd->SCp.ptr, cmd->SCp.this_residual);
79
            } else
80
                memcpy (HDATA(a3000_host)->dma_bounce_buffer,
81
                        cmd->request_buffer, cmd->request_bufflen);
82
        }
83
 
84
        addr = VTOP(HDATA(a3000_host)->dma_bounce_buffer);
85
    }
86
 
87
    /* setup dma direction */
88
    if (!dir_in)
89
        cntr |= CNTR_DDIR;
90
 
91
    /* remember direction */
92
    HDATA(a3000_host)->dma_dir = dir_in;
93
 
94
    DMA(a3000_host)->CNTR = cntr;
95
 
96
    /* setup DMA *physical* address */
97
    DMA(a3000_host)->ACR = addr;
98
 
99
 
100
    if (dir_in)
101
      {
102
        /* invalidate any cache */
103
        /*
104
         * On the 68040 it's not ok to use cache_clear, as it just invalidates
105
         * cache-lines, and thereby trashing them. We need to use cache_push
106
         * to avoid problems/crashes.
107
         * This was a real bitch to catch :-( -Jes
108
         */
109
 
110
        if (boot_info.cputype & CPU_68040)
111
          cache_push (addr, cmd->SCp.this_residual);
112
        else
113
          cache_clear (addr, cmd->SCp.this_residual);
114
      }
115
    else
116
      /* push any dirty cache */
117
      cache_push (addr, cmd->SCp.this_residual);
118
 
119
 
120
    /* start DMA */
121
    DMA(a3000_host)->ST_DMA = 1;
122
 
123
    /* return success */
124
    return 0;
125
}
126
 
127
static void dma_stop (struct Scsi_Host *instance, Scsi_Cmnd *SCpnt,
128
                      int status)
129
{
130
    /* disable SCSI interrupts */
131
    unsigned short cntr = CNTR_PDMD;
132
 
133
    if (!HDATA(instance)->dma_dir)
134
        cntr |= CNTR_DDIR;
135
 
136
    DMA(instance)->CNTR = cntr;
137
 
138
    /* flush if we were reading */
139
    if (HDATA(instance)->dma_dir) {
140
        DMA(instance)->FLUSH = 1;
141
        while (!(DMA(instance)->ISTR & ISTR_FE_FLG))
142
            ;
143
    }
144
 
145
    /* clear a possible interrupt */
146
    /* I think that this CINT is only necessary if you are
147
     * using the terminal count features.   HM 7 Mar 1994
148
     */
149
    DMA(instance)->CINT = 1;
150
 
151
    /* stop DMA */
152
    DMA(instance)->SP_DMA = 1;
153
 
154
    /* restore the CONTROL bits (minus the direction flag) */
155
    DMA(instance)->CNTR = CNTR_PDMD | CNTR_INTEN;
156
 
157
    /* copy from a bounce buffer, if necessary */
158
    if (status && HDATA(instance)->dma_bounce_buffer) {
159
        if (SCpnt && SCpnt->use_sg) {
160
            if (HDATA(instance)->dma_dir && SCpnt)
161
                memcpy (SCpnt->SCp.ptr,
162
                        HDATA(instance)->dma_bounce_buffer,
163
                        SCpnt->SCp.this_residual);
164
            scsi_free (HDATA(instance)->dma_bounce_buffer,
165
                       HDATA(instance)->dma_bounce_len);
166
            HDATA(instance)->dma_bounce_buffer = NULL;
167
            HDATA(instance)->dma_bounce_len = 0;
168
        } else {
169
            if (HDATA(instance)->dma_dir && SCpnt)
170
                memcpy (SCpnt->request_buffer,
171
                        HDATA(instance)->dma_bounce_buffer,
172
                        SCpnt->request_bufflen);
173
 
174
            scsi_free (HDATA(instance)->dma_bounce_buffer,
175
                       HDATA(instance)->dma_bounce_len);
176
            HDATA(instance)->dma_bounce_buffer = NULL;
177
            HDATA(instance)->dma_bounce_len = 0;
178
        }
179
    }
180
}
181
 
182
int a3000_detect(Scsi_Host_Template *tpnt)
183
{
184
    static unsigned char called = 0;
185
 
186
    if (called)
187
        return 0;
188
 
189
    if  (!MACH_IS_AMIGA || !AMIGAHW_PRESENT(A3000_SCSI))
190
        return 0;
191
 
192
    tpnt->proc_dir = &proc_scsi_a3000;
193
 
194
    a3000_host = scsi_register (tpnt, sizeof(struct WD33C93_hostdata));
195
    a3000_host->base = (unsigned char *)ZTWO_VADDR(0xDD0000);
196
    DMA(a3000_host)->DAWR = DAWR_A3000;
197
    wd33c93_init(a3000_host, (wd33c93_regs *)&(DMA(a3000_host)->SASR),
198
                 dma_setup, dma_stop, WD33C93_FS_12_15);
199
    add_isr(IRQ_AMIGA_PORTS, a3000_intr, 0, NULL, "A3000 SCSI");
200
    DMA(a3000_host)->CNTR = CNTR_PDMD | CNTR_INTEN;
201
    called = 1;
202
 
203
    return 1;
204
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.