aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi/a3000.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/scsi/a3000.c')
-rw-r--r--drivers/scsi/a3000.c285
1 files changed, 143 insertions, 142 deletions
diff --git a/drivers/scsi/a3000.c b/drivers/scsi/a3000.c
index c35fc55f1c96..bc6eb69f5fd0 100644
--- a/drivers/scsi/a3000.c
+++ b/drivers/scsi/a3000.c
@@ -19,26 +19,25 @@
19#include "wd33c93.h" 19#include "wd33c93.h"
20#include "a3000.h" 20#include "a3000.h"
21 21
22#include<linux/stat.h> 22#include <linux/stat.h>
23 23
24#define DMA(ptr) ((a3000_scsiregs *)((ptr)->base)) 24
25#define HDATA(ptr) ((struct WD33C93_hostdata *)((ptr)->hostdata)) 25#define DMA(ptr) ((a3000_scsiregs *)((ptr)->base))
26 26
27static struct Scsi_Host *a3000_host = NULL; 27static struct Scsi_Host *a3000_host = NULL;
28 28
29static int a3000_release(struct Scsi_Host *instance); 29static int a3000_release(struct Scsi_Host *instance);
30 30
31static irqreturn_t a3000_intr (int irq, void *dummy) 31static irqreturn_t a3000_intr(int irq, void *dummy)
32{ 32{
33 unsigned long flags; 33 unsigned long flags;
34 unsigned int status = DMA(a3000_host)->ISTR; 34 unsigned int status = DMA(a3000_host)->ISTR;
35 35
36 if (!(status & ISTR_INT_P)) 36 if (!(status & ISTR_INT_P))
37 return IRQ_NONE; 37 return IRQ_NONE;
38 if (status & ISTR_INTS) 38 if (status & ISTR_INTS) {
39 {
40 spin_lock_irqsave(a3000_host->host_lock, flags); 39 spin_lock_irqsave(a3000_host->host_lock, flags);
41 wd33c93_intr (a3000_host); 40 wd33c93_intr(a3000_host);
42 spin_unlock_irqrestore(a3000_host->host_lock, flags); 41 spin_unlock_irqrestore(a3000_host->host_lock, flags);
43 return IRQ_HANDLED; 42 return IRQ_HANDLED;
44 } 43 }
@@ -48,162 +47,165 @@ static irqreturn_t a3000_intr (int irq, void *dummy)
48 47
49static int dma_setup(struct scsi_cmnd *cmd, int dir_in) 48static int dma_setup(struct scsi_cmnd *cmd, int dir_in)
50{ 49{
51 unsigned short cntr = CNTR_PDMD | CNTR_INTEN; 50 struct WD33C93_hostdata *hdata = shost_priv(a3000_host);
52 unsigned long addr = virt_to_bus(cmd->SCp.ptr); 51 unsigned short cntr = CNTR_PDMD | CNTR_INTEN;
53 52 unsigned long addr = virt_to_bus(cmd->SCp.ptr);
54 /* 53
55 * if the physical address has the wrong alignment, or if 54 /*
56 * physical address is bad, or if it is a write and at the 55 * if the physical address has the wrong alignment, or if
57 * end of a physical memory chunk, then allocate a bounce 56 * physical address is bad, or if it is a write and at the
58 * buffer 57 * end of a physical memory chunk, then allocate a bounce
59 */ 58 * buffer
60 if (addr & A3000_XFER_MASK) 59 */
61 { 60 if (addr & A3000_XFER_MASK) {
62 HDATA(a3000_host)->dma_bounce_len = (cmd->SCp.this_residual + 511) 61 hdata->dma_bounce_len = (cmd->SCp.this_residual + 511) & ~0x1ff;
63 & ~0x1ff; 62 hdata->dma_bounce_buffer = kmalloc(hdata->dma_bounce_len,
64 HDATA(a3000_host)->dma_bounce_buffer = 63 GFP_KERNEL);
65 kmalloc (HDATA(a3000_host)->dma_bounce_len, GFP_KERNEL); 64
66 65 /* can't allocate memory; use PIO */
67 /* can't allocate memory; use PIO */ 66 if (!hdata->dma_bounce_buffer) {
68 if (!HDATA(a3000_host)->dma_bounce_buffer) { 67 hdata->dma_bounce_len = 0;
69 HDATA(a3000_host)->dma_bounce_len = 0; 68 return 1;
70 return 1; 69 }
71 } 70
72 71 if (!dir_in) {
73 if (!dir_in) { 72 /* copy to bounce buffer for a write */
74 /* copy to bounce buffer for a write */ 73 memcpy(hdata->dma_bounce_buffer, cmd->SCp.ptr,
75 memcpy (HDATA(a3000_host)->dma_bounce_buffer, 74 cmd->SCp.this_residual);
76 cmd->SCp.ptr, cmd->SCp.this_residual); 75 }
76
77 addr = virt_to_bus(hdata->dma_bounce_buffer);
77 } 78 }
78 79
79 addr = virt_to_bus(HDATA(a3000_host)->dma_bounce_buffer); 80 /* setup dma direction */
80 } 81 if (!dir_in)
82 cntr |= CNTR_DDIR;
81 83
82 /* setup dma direction */ 84 /* remember direction */
83 if (!dir_in) 85 hdata->dma_dir = dir_in;
84 cntr |= CNTR_DDIR;
85 86
86 /* remember direction */ 87 DMA(a3000_host)->CNTR = cntr;
87 HDATA(a3000_host)->dma_dir = dir_in;
88 88
89 DMA(a3000_host)->CNTR = cntr; 89 /* setup DMA *physical* address */
90 DMA(a3000_host)->ACR = addr;
90 91
91 /* setup DMA *physical* address */ 92 if (dir_in) {
92 DMA(a3000_host)->ACR = addr; 93 /* invalidate any cache */
93 94 cache_clear(addr, cmd->SCp.this_residual);
94 if (dir_in) 95 } else {
95 /* invalidate any cache */ 96 /* push any dirty cache */
96 cache_clear (addr, cmd->SCp.this_residual); 97 cache_push(addr, cmd->SCp.this_residual);
97 else 98 }
98 /* push any dirty cache */
99 cache_push (addr, cmd->SCp.this_residual);
100 99
101 /* start DMA */ 100 /* start DMA */
102 mb(); /* make sure setup is completed */ 101 mb(); /* make sure setup is completed */
103 DMA(a3000_host)->ST_DMA = 1; 102 DMA(a3000_host)->ST_DMA = 1;
104 mb(); /* make sure DMA has started before next IO */ 103 mb(); /* make sure DMA has started before next IO */
105 104
106 /* return success */ 105 /* return success */
107 return 0; 106 return 0;
108} 107}
109 108
110static void dma_stop(struct Scsi_Host *instance, struct scsi_cmnd *SCpnt, 109static void dma_stop(struct Scsi_Host *instance, struct scsi_cmnd *SCpnt,
111 int status) 110 int status)
112{ 111{
113 /* disable SCSI interrupts */ 112 struct WD33C93_hostdata *hdata = shost_priv(instance);
114 unsigned short cntr = CNTR_PDMD; 113
115 114 /* disable SCSI interrupts */
116 if (!HDATA(instance)->dma_dir) 115 unsigned short cntr = CNTR_PDMD;
117 cntr |= CNTR_DDIR; 116
118 117 if (!hdata->dma_dir)
119 DMA(instance)->CNTR = cntr; 118 cntr |= CNTR_DDIR;
120 mb(); /* make sure CNTR is updated before next IO */ 119
121 120 DMA(instance)->CNTR = cntr;
122 /* flush if we were reading */ 121 mb(); /* make sure CNTR is updated before next IO */
123 if (HDATA(instance)->dma_dir) { 122
124 DMA(instance)->FLUSH = 1; 123 /* flush if we were reading */
125 mb(); /* don't allow prefetch */ 124 if (hdata->dma_dir) {
126 while (!(DMA(instance)->ISTR & ISTR_FE_FLG)) 125 DMA(instance)->FLUSH = 1;
127 barrier(); 126 mb(); /* don't allow prefetch */
128 mb(); /* no IO until FLUSH is done */ 127 while (!(DMA(instance)->ISTR & ISTR_FE_FLG))
129 } 128 barrier();
130 129 mb(); /* no IO until FLUSH is done */
131 /* clear a possible interrupt */ 130 }
132 /* I think that this CINT is only necessary if you are 131
133 * using the terminal count features. HM 7 Mar 1994 132 /* clear a possible interrupt */
134 */ 133 /* I think that this CINT is only necessary if you are
135 DMA(instance)->CINT = 1; 134 * using the terminal count features. HM 7 Mar 1994
136 135 */
137 /* stop DMA */ 136 DMA(instance)->CINT = 1;
138 DMA(instance)->SP_DMA = 1; 137
139 mb(); /* make sure DMA is stopped before next IO */ 138 /* stop DMA */
140 139 DMA(instance)->SP_DMA = 1;
141 /* restore the CONTROL bits (minus the direction flag) */ 140 mb(); /* make sure DMA is stopped before next IO */
142 DMA(instance)->CNTR = CNTR_PDMD | CNTR_INTEN; 141
143 mb(); /* make sure CNTR is updated before next IO */ 142 /* restore the CONTROL bits (minus the direction flag) */
144 143 DMA(instance)->CNTR = CNTR_PDMD | CNTR_INTEN;
145 /* copy from a bounce buffer, if necessary */ 144 mb(); /* make sure CNTR is updated before next IO */
146 if (status && HDATA(instance)->dma_bounce_buffer) { 145
147 if (SCpnt) { 146 /* copy from a bounce buffer, if necessary */
148 if (HDATA(instance)->dma_dir && SCpnt) 147 if (status && hdata->dma_bounce_buffer) {
149 memcpy (SCpnt->SCp.ptr, 148 if (SCpnt) {
150 HDATA(instance)->dma_bounce_buffer, 149 if (hdata->dma_dir && SCpnt)
151 SCpnt->SCp.this_residual); 150 memcpy(SCpnt->SCp.ptr,
152 kfree (HDATA(instance)->dma_bounce_buffer); 151 hdata->dma_bounce_buffer,
153 HDATA(instance)->dma_bounce_buffer = NULL; 152 SCpnt->SCp.this_residual);
154 HDATA(instance)->dma_bounce_len = 0; 153 kfree(hdata->dma_bounce_buffer);
155 } else { 154 hdata->dma_bounce_buffer = NULL;
156 kfree (HDATA(instance)->dma_bounce_buffer); 155 hdata->dma_bounce_len = 0;
157 HDATA(instance)->dma_bounce_buffer = NULL; 156 } else {
158 HDATA(instance)->dma_bounce_len = 0; 157 kfree(hdata->dma_bounce_buffer);
158 hdata->dma_bounce_buffer = NULL;
159 hdata->dma_bounce_len = 0;
160 }
159 } 161 }
160 }
161} 162}
162 163
163static int __init a3000_detect(struct scsi_host_template *tpnt) 164static int __init a3000_detect(struct scsi_host_template *tpnt)
164{ 165{
165 wd33c93_regs regs; 166 wd33c93_regs regs;
166 167 struct WD33C93_hostdata *hdata;
167 if (!MACH_IS_AMIGA || !AMIGAHW_PRESENT(A3000_SCSI)) 168
168 return 0; 169 if (!MACH_IS_AMIGA || !AMIGAHW_PRESENT(A3000_SCSI))
169 if (!request_mem_region(0xDD0000, 256, "wd33c93")) 170 return 0;
170 return 0; 171 if (!request_mem_region(0xDD0000, 256, "wd33c93"))
171 172 return 0;
172 tpnt->proc_name = "A3000"; 173
173 tpnt->proc_info = &wd33c93_proc_info; 174 tpnt->proc_name = "A3000";
174 175 tpnt->proc_info = &wd33c93_proc_info;
175 a3000_host = scsi_register (tpnt, sizeof(struct WD33C93_hostdata)); 176
176 if (a3000_host == NULL) 177 a3000_host = scsi_register(tpnt, sizeof(struct WD33C93_hostdata));
177 goto fail_register; 178 if (a3000_host == NULL)
178 179 goto fail_register;
179 a3000_host->base = ZTWO_VADDR(0xDD0000); 180
180 a3000_host->irq = IRQ_AMIGA_PORTS; 181 a3000_host->base = ZTWO_VADDR(0xDD0000);
181 DMA(a3000_host)->DAWR = DAWR_A3000; 182 a3000_host->irq = IRQ_AMIGA_PORTS;
182 regs.SASR = &(DMA(a3000_host)->SASR); 183 DMA(a3000_host)->DAWR = DAWR_A3000;
183 regs.SCMD = &(DMA(a3000_host)->SCMD); 184 regs.SASR = &(DMA(a3000_host)->SASR);
184 HDATA(a3000_host)->no_sync = 0xff; 185 regs.SCMD = &(DMA(a3000_host)->SCMD);
185 HDATA(a3000_host)->fast = 0; 186 hdata = shost_priv(a3000_host);
186 HDATA(a3000_host)->dma_mode = CTRL_DMA; 187 hdata->no_sync = 0xff;
187 wd33c93_init(a3000_host, regs, dma_setup, dma_stop, WD33C93_FS_12_15); 188 hdata->fast = 0;
188 if (request_irq(IRQ_AMIGA_PORTS, a3000_intr, IRQF_SHARED, "A3000 SCSI", 189 hdata->dma_mode = CTRL_DMA;
189 a3000_intr)) 190 wd33c93_init(a3000_host, regs, dma_setup, dma_stop, WD33C93_FS_12_15);
190 goto fail_irq; 191 if (request_irq(IRQ_AMIGA_PORTS, a3000_intr, IRQF_SHARED, "A3000 SCSI",
191 DMA(a3000_host)->CNTR = CNTR_PDMD | CNTR_INTEN; 192 a3000_intr))
192 193 goto fail_irq;
193 return 1; 194 DMA(a3000_host)->CNTR = CNTR_PDMD | CNTR_INTEN;
195
196 return 1;
194 197
195fail_irq: 198fail_irq:
196 wd33c93_release(); 199 scsi_unregister(a3000_host);
197 scsi_unregister(a3000_host);
198fail_register: 200fail_register:
199 release_mem_region(0xDD0000, 256); 201 release_mem_region(0xDD0000, 256);
200 return 0; 202 return 0;
201} 203}
202 204
203static int a3000_bus_reset(struct scsi_cmnd *cmd) 205static int a3000_bus_reset(struct scsi_cmnd *cmd)
204{ 206{
205 /* FIXME perform bus-specific reset */ 207 /* FIXME perform bus-specific reset */
206 208
207 /* FIXME 2: kill this entire function, which should 209 /* FIXME 2: kill this entire function, which should
208 cause mid-layer to call wd33c93_host_reset anyway? */ 210 cause mid-layer to call wd33c93_host_reset anyway? */
209 211
@@ -237,11 +239,10 @@ static struct scsi_host_template driver_template = {
237 239
238static int a3000_release(struct Scsi_Host *instance) 240static int a3000_release(struct Scsi_Host *instance)
239{ 241{
240 wd33c93_release(); 242 DMA(instance)->CNTR = 0;
241 DMA(instance)->CNTR = 0; 243 release_mem_region(0xDD0000, 256);
242 release_mem_region(0xDD0000, 256); 244 free_irq(IRQ_AMIGA_PORTS, a3000_intr);
243 free_irq(IRQ_AMIGA_PORTS, a3000_intr); 245 return 1;
244 return 1;
245} 246}
246 247
247MODULE_LICENSE("GPL"); 248MODULE_LICENSE("GPL");