scsi: qla2xxx: remove double assignment in qla2x00_update_fcport
[linux-2.6-microblaze.git] / drivers / scsi / sun3x_esp.c
1 /* sun3x_esp.c: ESP front-end for Sun3x systems.
2  *
3  * Copyright (C) 2007,2008 Thomas Bogendoerfer (tsbogend@alpha.franken.de)
4  */
5
6 #include <linux/kernel.h>
7 #include <linux/gfp.h>
8 #include <linux/types.h>
9 #include <linux/delay.h>
10 #include <linux/module.h>
11 #include <linux/init.h>
12 #include <linux/platform_device.h>
13 #include <linux/dma-mapping.h>
14 #include <linux/interrupt.h>
15 #include <linux/io.h>
16
17 #include <asm/sun3x.h>
18 #include <asm/dma.h>
19 #include <asm/dvma.h>
20
21 /* DMA controller reg offsets */
22 #define DMA_CSR         0x00UL  /* rw  DMA control/status register    0x00   */
23 #define DMA_ADDR        0x04UL  /* rw  DMA transfer address register  0x04   */
24 #define DMA_COUNT       0x08UL  /* rw  DMA transfer count register    0x08   */
25 #define DMA_TEST        0x0cUL  /* rw  DMA test/debug register        0x0c   */
26
27 #include <scsi/scsi_host.h>
28
29 #include "esp_scsi.h"
30
31 #define DRV_MODULE_NAME         "sun3x_esp"
32 #define PFX DRV_MODULE_NAME     ": "
33 #define DRV_VERSION             "1.000"
34 #define DRV_MODULE_RELDATE      "Nov 1, 2007"
35
36 /*
37  * m68k always assumes readl/writel operate on little endian
38  * mmio space; this is wrong at least for Sun3x, so we
39  * need to workaround this until a proper way is found
40  */
41 #if 0
42 #define dma_read32(REG) \
43         readl(esp->dma_regs + (REG))
44 #define dma_write32(VAL, REG) \
45         writel((VAL), esp->dma_regs + (REG))
46 #else
47 #define dma_read32(REG) \
48         *(volatile u32 *)(esp->dma_regs + (REG))
49 #define dma_write32(VAL, REG) \
50         do { *(volatile u32 *)(esp->dma_regs + (REG)) = (VAL); } while (0)
51 #endif
52
53 static void sun3x_esp_write8(struct esp *esp, u8 val, unsigned long reg)
54 {
55         writeb(val, esp->regs + (reg * 4UL));
56 }
57
58 static u8 sun3x_esp_read8(struct esp *esp, unsigned long reg)
59 {
60         return readb(esp->regs + (reg * 4UL));
61 }
62
63 static int sun3x_esp_irq_pending(struct esp *esp)
64 {
65         if (dma_read32(DMA_CSR) & (DMA_HNDL_INTR | DMA_HNDL_ERROR))
66                 return 1;
67         return 0;
68 }
69
70 static void sun3x_esp_reset_dma(struct esp *esp)
71 {
72         u32 val;
73
74         val = dma_read32(DMA_CSR);
75         dma_write32(val | DMA_RST_SCSI, DMA_CSR);
76         dma_write32(val & ~DMA_RST_SCSI, DMA_CSR);
77
78         /* Enable interrupts.  */
79         val = dma_read32(DMA_CSR);
80         dma_write32(val | DMA_INT_ENAB, DMA_CSR);
81 }
82
83 static void sun3x_esp_dma_drain(struct esp *esp)
84 {
85         u32 csr;
86         int lim;
87
88         csr = dma_read32(DMA_CSR);
89         if (!(csr & DMA_FIFO_ISDRAIN))
90                 return;
91
92         dma_write32(csr | DMA_FIFO_STDRAIN, DMA_CSR);
93
94         lim = 1000;
95         while (dma_read32(DMA_CSR) & DMA_FIFO_ISDRAIN) {
96                 if (--lim == 0) {
97                         printk(KERN_ALERT PFX "esp%d: DMA will not drain!\n",
98                                esp->host->unique_id);
99                         break;
100                 }
101                 udelay(1);
102         }
103 }
104
105 static void sun3x_esp_dma_invalidate(struct esp *esp)
106 {
107         u32 val;
108         int lim;
109
110         lim = 1000;
111         while ((val = dma_read32(DMA_CSR)) & DMA_PEND_READ) {
112                 if (--lim == 0) {
113                         printk(KERN_ALERT PFX "esp%d: DMA will not "
114                                "invalidate!\n", esp->host->unique_id);
115                         break;
116                 }
117                 udelay(1);
118         }
119
120         val &= ~(DMA_ENABLE | DMA_ST_WRITE | DMA_BCNT_ENAB);
121         val |= DMA_FIFO_INV;
122         dma_write32(val, DMA_CSR);
123         val &= ~DMA_FIFO_INV;
124         dma_write32(val, DMA_CSR);
125 }
126
127 static void sun3x_esp_send_dma_cmd(struct esp *esp, u32 addr, u32 esp_count,
128                                   u32 dma_count, int write, u8 cmd)
129 {
130         u32 csr;
131
132         BUG_ON(!(cmd & ESP_CMD_DMA));
133
134         sun3x_esp_write8(esp, (esp_count >> 0) & 0xff, ESP_TCLOW);
135         sun3x_esp_write8(esp, (esp_count >> 8) & 0xff, ESP_TCMED);
136         csr = dma_read32(DMA_CSR);
137         csr |= DMA_ENABLE;
138         if (write)
139                 csr |= DMA_ST_WRITE;
140         else
141                 csr &= ~DMA_ST_WRITE;
142         dma_write32(csr, DMA_CSR);
143         dma_write32(addr, DMA_ADDR);
144
145         scsi_esp_cmd(esp, cmd);
146 }
147
148 static int sun3x_esp_dma_error(struct esp *esp)
149 {
150         u32 csr = dma_read32(DMA_CSR);
151
152         if (csr & DMA_HNDL_ERROR)
153                 return 1;
154
155         return 0;
156 }
157
158 static const struct esp_driver_ops sun3x_esp_ops = {
159         .esp_write8     =       sun3x_esp_write8,
160         .esp_read8      =       sun3x_esp_read8,
161         .irq_pending    =       sun3x_esp_irq_pending,
162         .reset_dma      =       sun3x_esp_reset_dma,
163         .dma_drain      =       sun3x_esp_dma_drain,
164         .dma_invalidate =       sun3x_esp_dma_invalidate,
165         .send_dma_cmd   =       sun3x_esp_send_dma_cmd,
166         .dma_error      =       sun3x_esp_dma_error,
167 };
168
169 static int esp_sun3x_probe(struct platform_device *dev)
170 {
171         struct scsi_host_template *tpnt = &scsi_esp_template;
172         struct Scsi_Host *host;
173         struct esp *esp;
174         struct resource *res;
175         int err = -ENOMEM;
176
177         host = scsi_host_alloc(tpnt, sizeof(struct esp));
178         if (!host)
179                 goto fail;
180
181         host->max_id = 8;
182         esp = shost_priv(host);
183
184         esp->host = host;
185         esp->dev = &dev->dev;
186         esp->ops = &sun3x_esp_ops;
187
188         res = platform_get_resource(dev, IORESOURCE_MEM, 0);
189         if (!res || !res->start)
190                 goto fail_unlink;
191
192         esp->regs = ioremap_nocache(res->start, 0x20);
193         if (!esp->regs)
194                 goto fail_unmap_regs;
195
196         res = platform_get_resource(dev, IORESOURCE_MEM, 1);
197         if (!res || !res->start)
198                 goto fail_unmap_regs;
199
200         esp->dma_regs = ioremap_nocache(res->start, 0x10);
201
202         esp->command_block = dma_alloc_coherent(esp->dev, 16,
203                                                 &esp->command_block_dma,
204                                                 GFP_KERNEL);
205         if (!esp->command_block)
206                 goto fail_unmap_regs_dma;
207
208         host->irq = platform_get_irq(dev, 0);
209         err = request_irq(host->irq, scsi_esp_intr, IRQF_SHARED,
210                           "SUN3X ESP", esp);
211         if (err < 0)
212                 goto fail_unmap_command_block;
213
214         esp->scsi_id = 7;
215         esp->host->this_id = esp->scsi_id;
216         esp->scsi_id_mask = (1 << esp->scsi_id);
217         esp->cfreq = 20000000;
218
219         dev_set_drvdata(&dev->dev, esp);
220
221         err = scsi_esp_register(esp);
222         if (err)
223                 goto fail_free_irq;
224
225         return 0;
226
227 fail_free_irq:
228         free_irq(host->irq, esp);
229 fail_unmap_command_block:
230         dma_free_coherent(esp->dev, 16,
231                           esp->command_block,
232                           esp->command_block_dma);
233 fail_unmap_regs_dma:
234         iounmap(esp->dma_regs);
235 fail_unmap_regs:
236         iounmap(esp->regs);
237 fail_unlink:
238         scsi_host_put(host);
239 fail:
240         return err;
241 }
242
243 static int esp_sun3x_remove(struct platform_device *dev)
244 {
245         struct esp *esp = dev_get_drvdata(&dev->dev);
246         unsigned int irq = esp->host->irq;
247         u32 val;
248
249         scsi_esp_unregister(esp);
250
251         /* Disable interrupts.  */
252         val = dma_read32(DMA_CSR);
253         dma_write32(val & ~DMA_INT_ENAB, DMA_CSR);
254
255         free_irq(irq, esp);
256         dma_free_coherent(esp->dev, 16,
257                           esp->command_block,
258                           esp->command_block_dma);
259
260         scsi_host_put(esp->host);
261
262         return 0;
263 }
264
265 static struct platform_driver esp_sun3x_driver = {
266         .probe          = esp_sun3x_probe,
267         .remove         = esp_sun3x_remove,
268         .driver = {
269                 .name   = "sun3x_esp",
270         },
271 };
272
273 static int __init sun3x_esp_init(void)
274 {
275         return platform_driver_register(&esp_sun3x_driver);
276 }
277
278 static void __exit sun3x_esp_exit(void)
279 {
280         platform_driver_unregister(&esp_sun3x_driver);
281 }
282
283 MODULE_DESCRIPTION("Sun3x ESP SCSI driver");
284 MODULE_AUTHOR("Thomas Bogendoerfer (tsbogend@alpha.franken.de)");
285 MODULE_LICENSE("GPL");
286 MODULE_VERSION(DRV_VERSION);
287
288 module_init(sun3x_esp_init);
289 module_exit(sun3x_esp_exit);
290 MODULE_ALIAS("platform:sun3x_esp");