diff options
Diffstat (limited to 'drivers/scsi/sun3x_esp.c')
-rw-r--r-- | drivers/scsi/sun3x_esp.c | 546 |
1 files changed, 235 insertions, 311 deletions
diff --git a/drivers/scsi/sun3x_esp.c b/drivers/scsi/sun3x_esp.c index 1bc41907a038..06152c7fa689 100644 --- a/drivers/scsi/sun3x_esp.c +++ b/drivers/scsi/sun3x_esp.c | |||
@@ -1,392 +1,316 @@ | |||
1 | /* sun3x_esp.c: EnhancedScsiProcessor Sun3x SCSI driver code. | 1 | /* sun3x_esp.c: ESP front-end for Sun3x systems. |
2 | * | 2 | * |
3 | * (C) 1999 Thomas Bogendoerfer (tsbogend@alpha.franken.de) | 3 | * Copyright (C) 2007,2008 Thomas Bogendoerfer (tsbogend@alpha.franken.de) |
4 | * | ||
5 | * Based on David S. Miller's esp driver | ||
6 | */ | 4 | */ |
7 | 5 | ||
8 | #include <linux/kernel.h> | 6 | #include <linux/kernel.h> |
9 | #include <linux/types.h> | 7 | #include <linux/types.h> |
10 | #include <linux/string.h> | ||
11 | #include <linux/slab.h> | ||
12 | #include <linux/blkdev.h> | ||
13 | #include <linux/proc_fs.h> | ||
14 | #include <linux/stat.h> | ||
15 | #include <linux/delay.h> | 8 | #include <linux/delay.h> |
9 | #include <linux/module.h> | ||
10 | #include <linux/init.h> | ||
11 | #include <linux/platform_device.h> | ||
12 | #include <linux/dma-mapping.h> | ||
16 | #include <linux/interrupt.h> | 13 | #include <linux/interrupt.h> |
17 | 14 | ||
18 | #include "scsi.h" | ||
19 | #include <scsi/scsi_host.h> | ||
20 | #include "NCR53C9x.h" | ||
21 | |||
22 | #include <asm/sun3x.h> | 15 | #include <asm/sun3x.h> |
16 | #include <asm/io.h> | ||
17 | #include <asm/dma.h> | ||
23 | #include <asm/dvma.h> | 18 | #include <asm/dvma.h> |
24 | #include <asm/irq.h> | ||
25 | |||
26 | static void dma_barrier(struct NCR_ESP *esp); | ||
27 | static int dma_bytes_sent(struct NCR_ESP *esp, int fifo_count); | ||
28 | static int dma_can_transfer(struct NCR_ESP *esp, Scsi_Cmnd *sp); | ||
29 | static void dma_drain(struct NCR_ESP *esp); | ||
30 | static void dma_invalidate(struct NCR_ESP *esp); | ||
31 | static void dma_dump_state(struct NCR_ESP *esp); | ||
32 | static void dma_init_read(struct NCR_ESP *esp, __u32 vaddress, int length); | ||
33 | static void dma_init_write(struct NCR_ESP *esp, __u32 vaddress, int length); | ||
34 | static void dma_ints_off(struct NCR_ESP *esp); | ||
35 | static void dma_ints_on(struct NCR_ESP *esp); | ||
36 | static int dma_irq_p(struct NCR_ESP *esp); | ||
37 | static void dma_poll(struct NCR_ESP *esp, unsigned char *vaddr); | ||
38 | static int dma_ports_p(struct NCR_ESP *esp); | ||
39 | static void dma_reset(struct NCR_ESP *esp); | ||
40 | static void dma_setup(struct NCR_ESP *esp, __u32 addr, int count, int write); | ||
41 | static void dma_mmu_get_scsi_one (struct NCR_ESP *esp, Scsi_Cmnd *sp); | ||
42 | static void dma_mmu_get_scsi_sgl (struct NCR_ESP *esp, Scsi_Cmnd *sp); | ||
43 | static void dma_mmu_release_scsi_one (struct NCR_ESP *esp, Scsi_Cmnd *sp); | ||
44 | static void dma_mmu_release_scsi_sgl (struct NCR_ESP *esp, Scsi_Cmnd *sp); | ||
45 | static void dma_advance_sg (Scsi_Cmnd *sp); | ||
46 | |||
47 | /* Detecting ESP chips on the machine. This is the simple and easy | ||
48 | * version. | ||
49 | */ | ||
50 | int sun3x_esp_detect(struct scsi_host_template *tpnt) | ||
51 | { | ||
52 | struct NCR_ESP *esp; | ||
53 | struct ConfigDev *esp_dev; | ||
54 | |||
55 | esp_dev = 0; | ||
56 | esp = esp_allocate(tpnt, esp_dev, 0); | ||
57 | |||
58 | /* Do command transfer with DMA */ | ||
59 | esp->do_pio_cmds = 0; | ||
60 | |||
61 | /* Required functions */ | ||
62 | esp->dma_bytes_sent = &dma_bytes_sent; | ||
63 | esp->dma_can_transfer = &dma_can_transfer; | ||
64 | esp->dma_dump_state = &dma_dump_state; | ||
65 | esp->dma_init_read = &dma_init_read; | ||
66 | esp->dma_init_write = &dma_init_write; | ||
67 | esp->dma_ints_off = &dma_ints_off; | ||
68 | esp->dma_ints_on = &dma_ints_on; | ||
69 | esp->dma_irq_p = &dma_irq_p; | ||
70 | esp->dma_ports_p = &dma_ports_p; | ||
71 | esp->dma_setup = &dma_setup; | ||
72 | |||
73 | /* Optional functions */ | ||
74 | esp->dma_barrier = &dma_barrier; | ||
75 | esp->dma_invalidate = &dma_invalidate; | ||
76 | esp->dma_drain = &dma_drain; | ||
77 | esp->dma_irq_entry = 0; | ||
78 | esp->dma_irq_exit = 0; | ||
79 | esp->dma_led_on = 0; | ||
80 | esp->dma_led_off = 0; | ||
81 | esp->dma_poll = &dma_poll; | ||
82 | esp->dma_reset = &dma_reset; | ||
83 | |||
84 | /* virtual DMA functions */ | ||
85 | esp->dma_mmu_get_scsi_one = &dma_mmu_get_scsi_one; | ||
86 | esp->dma_mmu_get_scsi_sgl = &dma_mmu_get_scsi_sgl; | ||
87 | esp->dma_mmu_release_scsi_one = &dma_mmu_release_scsi_one; | ||
88 | esp->dma_mmu_release_scsi_sgl = &dma_mmu_release_scsi_sgl; | ||
89 | esp->dma_advance_sg = &dma_advance_sg; | ||
90 | |||
91 | /* SCSI chip speed */ | ||
92 | esp->cfreq = 20000000; | ||
93 | esp->eregs = (struct ESP_regs *)(SUN3X_ESP_BASE); | ||
94 | esp->dregs = (void *)SUN3X_ESP_DMA; | ||
95 | 19 | ||
96 | esp->esp_command = (volatile unsigned char *)dvma_malloc(DVMA_PAGE_SIZE); | 20 | /* DMA controller reg offsets */ |
97 | esp->esp_command_dvma = dvma_vtob((unsigned long)esp->esp_command); | 21 | #define DMA_CSR 0x00UL /* rw DMA control/status register 0x00 */ |
98 | 22 | #define DMA_ADDR 0x04UL /* rw DMA transfer address register 0x04 */ | |
99 | esp->irq = 2; | 23 | #define DMA_COUNT 0x08UL /* rw DMA transfer count register 0x08 */ |
100 | if (request_irq(esp->irq, esp_intr, IRQF_DISABLED, | 24 | #define DMA_TEST 0x0cUL /* rw DMA test/debug register 0x0c */ |
101 | "SUN3X SCSI", esp->ehost)) { | ||
102 | esp_deallocate(esp); | ||
103 | return 0; | ||
104 | } | ||
105 | 25 | ||
106 | esp->scsi_id = 7; | 26 | #include <scsi/scsi_host.h> |
107 | esp->diff = 0; | ||
108 | 27 | ||
109 | esp_initialize(esp); | 28 | #include "esp_scsi.h" |
110 | 29 | ||
111 | /* for reasons beyond my knowledge (and which should likely be fixed) | 30 | #define DRV_MODULE_NAME "sun3x_esp" |
112 | sync mode doesn't work on a 3/80 at 5mhz. but it does at 4. */ | 31 | #define PFX DRV_MODULE_NAME ": " |
113 | esp->sync_defp = 0x3f; | 32 | #define DRV_VERSION "1.000" |
33 | #define DRV_MODULE_RELDATE "Nov 1, 2007" | ||
114 | 34 | ||
115 | printk("ESP: Total of %d ESP hosts found, %d actually in use.\n", nesps, | 35 | /* |
116 | esps_in_use); | 36 | * m68k always assumes readl/writel operate on little endian |
117 | esps_running = esps_in_use; | 37 | * mmio space; this is wrong at least for Sun3x, so we |
118 | return esps_in_use; | 38 | * need to workaround this until a proper way is found |
39 | */ | ||
40 | #if 0 | ||
41 | #define dma_read32(REG) \ | ||
42 | readl(esp->dma_regs + (REG)) | ||
43 | #define dma_write32(VAL, REG) \ | ||
44 | writel((VAL), esp->dma_regs + (REG)) | ||
45 | #else | ||
46 | #define dma_read32(REG) \ | ||
47 | *(volatile u32 *)(esp->dma_regs + (REG)) | ||
48 | #define dma_write32(VAL, REG) \ | ||
49 | do { *(volatile u32 *)(esp->dma_regs + (REG)) = (VAL); } while (0) | ||
50 | #endif | ||
51 | |||
52 | static void sun3x_esp_write8(struct esp *esp, u8 val, unsigned long reg) | ||
53 | { | ||
54 | writeb(val, esp->regs + (reg * 4UL)); | ||
119 | } | 55 | } |
120 | 56 | ||
121 | static void dma_do_drain(struct NCR_ESP *esp) | 57 | static u8 sun3x_esp_read8(struct esp *esp, unsigned long reg) |
122 | { | 58 | { |
123 | struct sparc_dma_registers *dregs = | 59 | return readb(esp->regs + (reg * 4UL)); |
124 | (struct sparc_dma_registers *) esp->dregs; | ||
125 | |||
126 | int count = 500000; | ||
127 | |||
128 | while((dregs->cond_reg & DMA_PEND_READ) && (--count > 0)) | ||
129 | udelay(1); | ||
130 | |||
131 | if(!count) { | ||
132 | printk("%s:%d timeout CSR %08lx\n", __FILE__, __LINE__, dregs->cond_reg); | ||
133 | } | ||
134 | |||
135 | dregs->cond_reg |= DMA_FIFO_STDRAIN; | ||
136 | |||
137 | count = 500000; | ||
138 | |||
139 | while((dregs->cond_reg & DMA_FIFO_ISDRAIN) && (--count > 0)) | ||
140 | udelay(1); | ||
141 | |||
142 | if(!count) { | ||
143 | printk("%s:%d timeout CSR %08lx\n", __FILE__, __LINE__, dregs->cond_reg); | ||
144 | } | ||
145 | |||
146 | } | 60 | } |
147 | 61 | ||
148 | static void dma_barrier(struct NCR_ESP *esp) | 62 | static dma_addr_t sun3x_esp_map_single(struct esp *esp, void *buf, |
63 | size_t sz, int dir) | ||
149 | { | 64 | { |
150 | struct sparc_dma_registers *dregs = | 65 | return dma_map_single(esp->dev, buf, sz, dir); |
151 | (struct sparc_dma_registers *) esp->dregs; | ||
152 | int count = 500000; | ||
153 | |||
154 | while((dregs->cond_reg & DMA_PEND_READ) && (--count > 0)) | ||
155 | udelay(1); | ||
156 | |||
157 | if(!count) { | ||
158 | printk("%s:%d timeout CSR %08lx\n", __FILE__, __LINE__, dregs->cond_reg); | ||
159 | } | ||
160 | |||
161 | dregs->cond_reg &= ~(DMA_ENABLE); | ||
162 | } | 66 | } |
163 | 67 | ||
164 | /* This uses various DMA csr fields and the fifo flags count value to | 68 | static int sun3x_esp_map_sg(struct esp *esp, struct scatterlist *sg, |
165 | * determine how many bytes were successfully sent/received by the ESP. | 69 | int num_sg, int dir) |
166 | */ | ||
167 | static int dma_bytes_sent(struct NCR_ESP *esp, int fifo_count) | ||
168 | { | 70 | { |
169 | struct sparc_dma_registers *dregs = | 71 | return dma_map_sg(esp->dev, sg, num_sg, dir); |
170 | (struct sparc_dma_registers *) esp->dregs; | ||
171 | |||
172 | int rval = dregs->st_addr - esp->esp_command_dvma; | ||
173 | |||
174 | return rval - fifo_count; | ||
175 | } | 72 | } |
176 | 73 | ||
177 | static int dma_can_transfer(struct NCR_ESP *esp, Scsi_Cmnd *sp) | 74 | static void sun3x_esp_unmap_single(struct esp *esp, dma_addr_t addr, |
75 | size_t sz, int dir) | ||
178 | { | 76 | { |
179 | return sp->SCp.this_residual; | 77 | dma_unmap_single(esp->dev, addr, sz, dir); |
180 | } | 78 | } |
181 | 79 | ||
182 | static void dma_drain(struct NCR_ESP *esp) | 80 | static void sun3x_esp_unmap_sg(struct esp *esp, struct scatterlist *sg, |
81 | int num_sg, int dir) | ||
183 | { | 82 | { |
184 | struct sparc_dma_registers *dregs = | 83 | dma_unmap_sg(esp->dev, sg, num_sg, dir); |
185 | (struct sparc_dma_registers *) esp->dregs; | ||
186 | int count = 500000; | ||
187 | |||
188 | if(dregs->cond_reg & DMA_FIFO_ISDRAIN) { | ||
189 | dregs->cond_reg |= DMA_FIFO_STDRAIN; | ||
190 | while((dregs->cond_reg & DMA_FIFO_ISDRAIN) && (--count > 0)) | ||
191 | udelay(1); | ||
192 | if(!count) { | ||
193 | printk("%s:%d timeout CSR %08lx\n", __FILE__, __LINE__, dregs->cond_reg); | ||
194 | } | ||
195 | |||
196 | } | ||
197 | } | 84 | } |
198 | 85 | ||
199 | static void dma_invalidate(struct NCR_ESP *esp) | 86 | static int sun3x_esp_irq_pending(struct esp *esp) |
200 | { | 87 | { |
201 | struct sparc_dma_registers *dregs = | 88 | if (dma_read32(DMA_CSR) & (DMA_HNDL_INTR | DMA_HNDL_ERROR)) |
202 | (struct sparc_dma_registers *) esp->dregs; | 89 | return 1; |
203 | 90 | return 0; | |
204 | __u32 tmp; | 91 | } |
205 | int count = 500000; | ||
206 | |||
207 | while(((tmp = dregs->cond_reg) & DMA_PEND_READ) && (--count > 0)) | ||
208 | udelay(1); | ||
209 | 92 | ||
210 | if(!count) { | 93 | static void sun3x_esp_reset_dma(struct esp *esp) |
211 | printk("%s:%d timeout CSR %08lx\n", __FILE__, __LINE__, dregs->cond_reg); | 94 | { |
212 | } | 95 | u32 val; |
213 | 96 | ||
214 | dregs->cond_reg = tmp | DMA_FIFO_INV; | 97 | val = dma_read32(DMA_CSR); |
215 | dregs->cond_reg &= ~DMA_FIFO_INV; | 98 | dma_write32(val | DMA_RST_SCSI, DMA_CSR); |
99 | dma_write32(val & ~DMA_RST_SCSI, DMA_CSR); | ||
216 | 100 | ||
101 | /* Enable interrupts. */ | ||
102 | val = dma_read32(DMA_CSR); | ||
103 | dma_write32(val | DMA_INT_ENAB, DMA_CSR); | ||
217 | } | 104 | } |
218 | 105 | ||
219 | static void dma_dump_state(struct NCR_ESP *esp) | 106 | static void sun3x_esp_dma_drain(struct esp *esp) |
220 | { | 107 | { |
221 | struct sparc_dma_registers *dregs = | 108 | u32 csr; |
222 | (struct sparc_dma_registers *) esp->dregs; | 109 | int lim; |
223 | 110 | ||
224 | ESPLOG(("esp%d: dma -- cond_reg<%08lx> addr<%08lx>\n", | 111 | csr = dma_read32(DMA_CSR); |
225 | esp->esp_id, dregs->cond_reg, dregs->st_addr)); | 112 | if (!(csr & DMA_FIFO_ISDRAIN)) |
226 | } | 113 | return; |
227 | 114 | ||
228 | static void dma_init_read(struct NCR_ESP *esp, __u32 vaddress, int length) | 115 | dma_write32(csr | DMA_FIFO_STDRAIN, DMA_CSR); |
229 | { | ||
230 | struct sparc_dma_registers *dregs = | ||
231 | (struct sparc_dma_registers *) esp->dregs; | ||
232 | 116 | ||
233 | dregs->st_addr = vaddress; | 117 | lim = 1000; |
234 | dregs->cond_reg |= (DMA_ST_WRITE | DMA_ENABLE); | 118 | while (dma_read32(DMA_CSR) & DMA_FIFO_ISDRAIN) { |
119 | if (--lim == 0) { | ||
120 | printk(KERN_ALERT PFX "esp%d: DMA will not drain!\n", | ||
121 | esp->host->unique_id); | ||
122 | break; | ||
123 | } | ||
124 | udelay(1); | ||
125 | } | ||
235 | } | 126 | } |
236 | 127 | ||
237 | static void dma_init_write(struct NCR_ESP *esp, __u32 vaddress, int length) | 128 | static void sun3x_esp_dma_invalidate(struct esp *esp) |
238 | { | 129 | { |
239 | struct sparc_dma_registers *dregs = | 130 | u32 val; |
240 | (struct sparc_dma_registers *) esp->dregs; | 131 | int lim; |
241 | 132 | ||
242 | /* Set up the DMA counters */ | 133 | lim = 1000; |
134 | while ((val = dma_read32(DMA_CSR)) & DMA_PEND_READ) { | ||
135 | if (--lim == 0) { | ||
136 | printk(KERN_ALERT PFX "esp%d: DMA will not " | ||
137 | "invalidate!\n", esp->host->unique_id); | ||
138 | break; | ||
139 | } | ||
140 | udelay(1); | ||
141 | } | ||
243 | 142 | ||
244 | dregs->st_addr = vaddress; | 143 | val &= ~(DMA_ENABLE | DMA_ST_WRITE | DMA_BCNT_ENAB); |
245 | dregs->cond_reg = ((dregs->cond_reg & ~(DMA_ST_WRITE)) | DMA_ENABLE); | 144 | val |= DMA_FIFO_INV; |
145 | dma_write32(val, DMA_CSR); | ||
146 | val &= ~DMA_FIFO_INV; | ||
147 | dma_write32(val, DMA_CSR); | ||
246 | } | 148 | } |
247 | 149 | ||
248 | static void dma_ints_off(struct NCR_ESP *esp) | 150 | static void sun3x_esp_send_dma_cmd(struct esp *esp, u32 addr, u32 esp_count, |
151 | u32 dma_count, int write, u8 cmd) | ||
249 | { | 152 | { |
250 | DMA_INTSOFF((struct sparc_dma_registers *) esp->dregs); | 153 | u32 csr; |
154 | |||
155 | BUG_ON(!(cmd & ESP_CMD_DMA)); | ||
156 | |||
157 | sun3x_esp_write8(esp, (esp_count >> 0) & 0xff, ESP_TCLOW); | ||
158 | sun3x_esp_write8(esp, (esp_count >> 8) & 0xff, ESP_TCMED); | ||
159 | csr = dma_read32(DMA_CSR); | ||
160 | csr |= DMA_ENABLE; | ||
161 | if (write) | ||
162 | csr |= DMA_ST_WRITE; | ||
163 | else | ||
164 | csr &= ~DMA_ST_WRITE; | ||
165 | dma_write32(csr, DMA_CSR); | ||
166 | dma_write32(addr, DMA_ADDR); | ||
167 | |||
168 | scsi_esp_cmd(esp, cmd); | ||
251 | } | 169 | } |
252 | 170 | ||
253 | static void dma_ints_on(struct NCR_ESP *esp) | 171 | static int sun3x_esp_dma_error(struct esp *esp) |
254 | { | 172 | { |
255 | DMA_INTSON((struct sparc_dma_registers *) esp->dregs); | 173 | u32 csr = dma_read32(DMA_CSR); |
256 | } | ||
257 | 174 | ||
258 | static int dma_irq_p(struct NCR_ESP *esp) | 175 | if (csr & DMA_HNDL_ERROR) |
259 | { | 176 | return 1; |
260 | return DMA_IRQ_P((struct sparc_dma_registers *) esp->dregs); | 177 | |
178 | return 0; | ||
261 | } | 179 | } |
262 | 180 | ||
263 | static void dma_poll(struct NCR_ESP *esp, unsigned char *vaddr) | 181 | static const struct esp_driver_ops sun3x_esp_ops = { |
182 | .esp_write8 = sun3x_esp_write8, | ||
183 | .esp_read8 = sun3x_esp_read8, | ||
184 | .map_single = sun3x_esp_map_single, | ||
185 | .map_sg = sun3x_esp_map_sg, | ||
186 | .unmap_single = sun3x_esp_unmap_single, | ||
187 | .unmap_sg = sun3x_esp_unmap_sg, | ||
188 | .irq_pending = sun3x_esp_irq_pending, | ||
189 | .reset_dma = sun3x_esp_reset_dma, | ||
190 | .dma_drain = sun3x_esp_dma_drain, | ||
191 | .dma_invalidate = sun3x_esp_dma_invalidate, | ||
192 | .send_dma_cmd = sun3x_esp_send_dma_cmd, | ||
193 | .dma_error = sun3x_esp_dma_error, | ||
194 | }; | ||
195 | |||
196 | static int __devinit esp_sun3x_probe(struct platform_device *dev) | ||
264 | { | 197 | { |
265 | int count = 50; | 198 | struct scsi_host_template *tpnt = &scsi_esp_template; |
266 | dma_do_drain(esp); | 199 | struct Scsi_Host *host; |
200 | struct esp *esp; | ||
201 | struct resource *res; | ||
202 | int err = -ENOMEM; | ||
267 | 203 | ||
268 | /* Wait till the first bits settle. */ | 204 | host = scsi_host_alloc(tpnt, sizeof(struct esp)); |
269 | while((*(volatile unsigned char *)vaddr == 0xff) && (--count > 0)) | 205 | if (!host) |
270 | udelay(1); | 206 | goto fail; |
271 | 207 | ||
272 | if(!count) { | 208 | host->max_id = 8; |
273 | // printk("%s:%d timeout expire (data %02x)\n", __FILE__, __LINE__, | 209 | esp = shost_priv(host); |
274 | // esp_read(esp->eregs->esp_fdata)); | ||
275 | //mach_halt(); | ||
276 | vaddr[0] = esp_read(esp->eregs->esp_fdata); | ||
277 | vaddr[1] = esp_read(esp->eregs->esp_fdata); | ||
278 | } | ||
279 | 210 | ||
280 | } | 211 | esp->host = host; |
212 | esp->dev = dev; | ||
213 | esp->ops = &sun3x_esp_ops; | ||
281 | 214 | ||
282 | static int dma_ports_p(struct NCR_ESP *esp) | 215 | res = platform_get_resource(dev, IORESOURCE_MEM, 0); |
283 | { | 216 | if (!res && !res->start) |
284 | return (((struct sparc_dma_registers *) esp->dregs)->cond_reg | 217 | goto fail_unlink; |
285 | & DMA_INT_ENAB); | ||
286 | } | ||
287 | 218 | ||
288 | /* Resetting various pieces of the ESP scsi driver chipset/buses. */ | 219 | esp->regs = ioremap_nocache(res->start, 0x20); |
289 | static void dma_reset(struct NCR_ESP *esp) | 220 | if (!esp->regs) |
290 | { | 221 | goto fail_unmap_regs; |
291 | struct sparc_dma_registers *dregs = | ||
292 | (struct sparc_dma_registers *)esp->dregs; | ||
293 | 222 | ||
294 | /* Punt the DVMA into a known state. */ | 223 | res = platform_get_resource(dev, IORESOURCE_MEM, 1); |
295 | dregs->cond_reg |= DMA_RST_SCSI; | 224 | if (!res && !res->start) |
296 | dregs->cond_reg &= ~(DMA_RST_SCSI); | 225 | goto fail_unmap_regs; |
297 | DMA_INTSON(dregs); | ||
298 | } | ||
299 | 226 | ||
300 | static void dma_setup(struct NCR_ESP *esp, __u32 addr, int count, int write) | 227 | esp->dma_regs = ioremap_nocache(res->start, 0x10); |
301 | { | ||
302 | struct sparc_dma_registers *dregs = | ||
303 | (struct sparc_dma_registers *) esp->dregs; | ||
304 | unsigned long nreg = dregs->cond_reg; | ||
305 | 228 | ||
306 | // printk("dma_setup %c addr %08x cnt %08x\n", | 229 | esp->command_block = dma_alloc_coherent(esp->dev, 16, |
307 | // write ? 'W' : 'R', addr, count); | 230 | &esp->command_block_dma, |
231 | GFP_KERNEL); | ||
232 | if (!esp->command_block) | ||
233 | goto fail_unmap_regs_dma; | ||
308 | 234 | ||
309 | dma_do_drain(esp); | 235 | host->irq = platform_get_irq(dev, 0); |
236 | err = request_irq(host->irq, scsi_esp_intr, IRQF_SHARED, | ||
237 | "SUN3X ESP", esp); | ||
238 | if (err < 0) | ||
239 | goto fail_unmap_command_block; | ||
310 | 240 | ||
311 | if(write) | 241 | esp->scsi_id = 7; |
312 | nreg |= DMA_ST_WRITE; | 242 | esp->host->this_id = esp->scsi_id; |
313 | else { | 243 | esp->scsi_id_mask = (1 << esp->scsi_id); |
314 | nreg &= ~(DMA_ST_WRITE); | 244 | esp->cfreq = 20000000; |
315 | } | ||
316 | |||
317 | nreg |= DMA_ENABLE; | ||
318 | dregs->cond_reg = nreg; | ||
319 | dregs->st_addr = addr; | ||
320 | } | ||
321 | 245 | ||
322 | static void dma_mmu_get_scsi_one (struct NCR_ESP *esp, Scsi_Cmnd *sp) | 246 | dev_set_drvdata(&dev->dev, esp); |
323 | { | 247 | |
324 | sp->SCp.have_data_in = dvma_map((unsigned long)sp->SCp.buffer, | 248 | err = scsi_esp_register(esp, &dev->dev); |
325 | sp->SCp.this_residual); | 249 | if (err) |
326 | sp->SCp.ptr = (char *)((unsigned long)sp->SCp.have_data_in); | 250 | goto fail_free_irq; |
251 | |||
252 | return 0; | ||
253 | |||
254 | fail_free_irq: | ||
255 | free_irq(host->irq, esp); | ||
256 | fail_unmap_command_block: | ||
257 | dma_free_coherent(esp->dev, 16, | ||
258 | esp->command_block, | ||
259 | esp->command_block_dma); | ||
260 | fail_unmap_regs_dma: | ||
261 | iounmap(esp->dma_regs); | ||
262 | fail_unmap_regs: | ||
263 | iounmap(esp->regs); | ||
264 | fail_unlink: | ||
265 | scsi_host_put(host); | ||
266 | fail: | ||
267 | return err; | ||
327 | } | 268 | } |
328 | 269 | ||
329 | static void dma_mmu_get_scsi_sgl (struct NCR_ESP *esp, Scsi_Cmnd *sp) | 270 | static int __devexit esp_sun3x_remove(struct platform_device *dev) |
330 | { | 271 | { |
331 | int sz = sp->SCp.buffers_residual; | 272 | struct esp *esp = dev_get_drvdata(&dev->dev); |
332 | struct scatterlist *sg = sp->SCp.buffer; | 273 | unsigned int irq = esp->host->irq; |
333 | 274 | u32 val; | |
334 | while (sz >= 0) { | ||
335 | sg[sz].dma_address = dvma_map((unsigned long)sg_virt(&sg[sz]), | ||
336 | sg[sz].length); | ||
337 | sz--; | ||
338 | } | ||
339 | sp->SCp.ptr=(char *)((unsigned long)sp->SCp.buffer->dma_address); | ||
340 | } | ||
341 | 275 | ||
342 | static void dma_mmu_release_scsi_one (struct NCR_ESP *esp, Scsi_Cmnd *sp) | 276 | scsi_esp_unregister(esp); |
343 | { | ||
344 | dvma_unmap((char *)sp->SCp.have_data_in); | ||
345 | } | ||
346 | 277 | ||
347 | static void dma_mmu_release_scsi_sgl (struct NCR_ESP *esp, Scsi_Cmnd *sp) | 278 | /* Disable interrupts. */ |
348 | { | 279 | val = dma_read32(DMA_CSR); |
349 | int sz = sp->use_sg - 1; | 280 | dma_write32(val & ~DMA_INT_ENAB, DMA_CSR); |
350 | struct scatterlist *sg = (struct scatterlist *)sp->request_buffer; | ||
351 | |||
352 | while(sz >= 0) { | ||
353 | dvma_unmap((char *)sg[sz].dma_address); | ||
354 | sz--; | ||
355 | } | ||
356 | } | ||
357 | 281 | ||
358 | static void dma_advance_sg (Scsi_Cmnd *sp) | 282 | free_irq(irq, esp); |
359 | { | 283 | dma_free_coherent(esp->dev, 16, |
360 | sp->SCp.ptr = (char *)((unsigned long)sp->SCp.buffer->dma_address); | 284 | esp->command_block, |
361 | } | 285 | esp->command_block_dma); |
362 | 286 | ||
363 | static int sun3x_esp_release(struct Scsi_Host *instance) | 287 | scsi_host_put(esp->host); |
364 | { | ||
365 | /* this code does not support being compiled as a module */ | ||
366 | return 1; | ||
367 | 288 | ||
289 | return 0; | ||
368 | } | 290 | } |
369 | 291 | ||
370 | static struct scsi_host_template driver_template = { | 292 | static struct platform_driver esp_sun3x_driver = { |
371 | .proc_name = "sun3x_esp", | 293 | .probe = esp_sun3x_probe, |
372 | .proc_info = &esp_proc_info, | 294 | .remove = __devexit_p(esp_sun3x_remove), |
373 | .name = "Sun ESP 100/100a/200", | 295 | .driver = { |
374 | .detect = sun3x_esp_detect, | 296 | .name = "sun3x_esp", |
375 | .release = sun3x_esp_release, | 297 | }, |
376 | .slave_alloc = esp_slave_alloc, | ||
377 | .slave_destroy = esp_slave_destroy, | ||
378 | .info = esp_info, | ||
379 | .queuecommand = esp_queue, | ||
380 | .eh_abort_handler = esp_abort, | ||
381 | .eh_bus_reset_handler = esp_reset, | ||
382 | .can_queue = 7, | ||
383 | .this_id = 7, | ||
384 | .sg_tablesize = SG_ALL, | ||
385 | .cmd_per_lun = 1, | ||
386 | .use_clustering = DISABLE_CLUSTERING, | ||
387 | }; | 298 | }; |
388 | 299 | ||
300 | static int __init sun3x_esp_init(void) | ||
301 | { | ||
302 | return platform_driver_register(&esp_sun3x_driver); | ||
303 | } | ||
389 | 304 | ||
390 | #include "scsi_module.c" | 305 | static void __exit sun3x_esp_exit(void) |
306 | { | ||
307 | platform_driver_unregister(&esp_sun3x_driver); | ||
308 | } | ||
391 | 309 | ||
310 | MODULE_DESCRIPTION("Sun3x ESP SCSI driver"); | ||
311 | MODULE_AUTHOR("Thomas Bogendoerfer (tsbogend@alpha.franken.de)"); | ||
392 | MODULE_LICENSE("GPL"); | 312 | MODULE_LICENSE("GPL"); |
313 | MODULE_VERSION(DRV_VERSION); | ||
314 | |||
315 | module_init(sun3x_esp_init); | ||
316 | module_exit(sun3x_esp_exit); | ||