2 * This file is subject to the terms and conditions of the GNU General Public
3 * License. See the file "COPYING" in the main directory of this archive
6 * Copyright (C) 1996 David S. Miller (davem@davemloft.net)
7 * Copyright (C) 1999 Andrew R. Baker (andrewb@uab.edu)
8 * Copyright (C) 2001 Florian Lohoff (flo@rfc822.org)
9 * Copyright (C) 2003, 07 Ralf Baechle (ralf@linux-mips.org)
11 * (In all truth, Jed Schimmel wrote all this code.)
16 #include <linux/delay.h>
17 #include <linux/dma-mapping.h>
18 #include <linux/gfp.h>
19 #include <linux/interrupt.h>
20 #include <linux/init.h>
21 #include <linux/kernel.h>
22 #include <linux/types.h>
23 #include <linux/module.h>
24 #include <linux/platform_device.h>
25 #include <linux/spinlock.h>
27 #include <asm/sgi/hpc3.h>
28 #include <asm/sgi/ip22.h>
29 #include <asm/sgi/wd.h>
34 struct ip22_hostdata
{
35 struct WD33C93_hostdata wh
;
41 #define host_to_hostdata(host) ((struct ip22_hostdata *)((host)->hostdata))
44 struct hpc_dma_desc desc
;
45 u32 _padding
; /* align to quadword boundary */
48 /* space for hpc dma descriptors */
49 #define HPC_DMA_SIZE PAGE_SIZE
51 #define DMA_DIR(d) ((d == DATA_OUT_DIR) ? DMA_TO_DEVICE : DMA_FROM_DEVICE)
53 static irqreturn_t
sgiwd93_intr(int irq
, void *dev_id
)
55 struct Scsi_Host
* host
= dev_id
;
58 spin_lock_irqsave(host
->host_lock
, flags
);
60 spin_unlock_irqrestore(host
->host_lock
, flags
);
66 void fill_hpc_entries(struct ip22_hostdata
*hd
, struct scsi_cmnd
*cmd
, int din
)
68 unsigned long len
= cmd
->SCp
.this_residual
;
69 void *addr
= cmd
->SCp
.ptr
;
72 struct hpc_chunk
*hcp
;
74 physaddr
= dma_map_single(hd
->dev
, addr
, len
, DMA_DIR(din
));
75 cmd
->SCp
.dma_handle
= physaddr
;
80 * even cntinfo could be up to 16383, without
81 * magic only 8192 works correctly
83 count
= len
> 8192 ? 8192 : len
;
84 hcp
->desc
.pbuf
= physaddr
;
85 hcp
->desc
.cntinfo
= count
;
92 * To make sure, if we trip an HPC bug, that we transfer every single
93 * byte, we tag on an extra zero length dma descriptor at the end of
97 hcp
->desc
.cntinfo
= HPCDMA_EOX
;
98 dma_cache_sync(hd
->dev
, hd
->cpu
,
99 (unsigned long)(hcp
+ 1) - (unsigned long)hd
->cpu
,
103 static int dma_setup(struct scsi_cmnd
*cmd
, int datainp
)
105 struct ip22_hostdata
*hdata
= host_to_hostdata(cmd
->device
->host
);
106 struct hpc3_scsiregs
*hregs
=
107 (struct hpc3_scsiregs
*) cmd
->device
->host
->base
;
109 pr_debug("dma_setup: datainp<%d> hcp<%p> ", datainp
, hdata
->cpu
);
111 hdata
->wh
.dma_dir
= datainp
;
114 * wd33c93 shouldn't pass us bogus dma_setups, but it does:-( The
115 * other wd33c93 drivers deal with it the same way (which isn't that
116 * obvious). IMHO a better fix would be, not to do these dma setups
117 * in the first place.
119 if (cmd
->SCp
.ptr
== NULL
|| cmd
->SCp
.this_residual
== 0)
122 fill_hpc_entries(hdata
, cmd
, datainp
);
124 pr_debug(" HPCGO\n");
126 /* Start up the HPC. */
127 hregs
->ndptr
= hdata
->dma
;
129 hregs
->ctrl
= HPC3_SCTRL_ACTIVE
;
131 hregs
->ctrl
= HPC3_SCTRL_ACTIVE
| HPC3_SCTRL_DIR
;
136 static void dma_stop(struct Scsi_Host
*instance
, struct scsi_cmnd
*SCpnt
,
139 struct ip22_hostdata
*hdata
= host_to_hostdata(instance
);
140 struct hpc3_scsiregs
*hregs
;
145 if (SCpnt
->SCp
.ptr
== NULL
|| SCpnt
->SCp
.this_residual
== 0)
148 hregs
= (struct hpc3_scsiregs
*) SCpnt
->device
->host
->base
;
150 pr_debug("dma_stop: status<%d> ", status
);
152 /* First stop the HPC and flush it's FIFO. */
153 if (hdata
->wh
.dma_dir
) {
154 hregs
->ctrl
|= HPC3_SCTRL_FLUSH
;
155 while (hregs
->ctrl
& HPC3_SCTRL_ACTIVE
)
159 dma_unmap_single(hdata
->dev
, SCpnt
->SCp
.dma_handle
,
160 SCpnt
->SCp
.this_residual
,
161 DMA_DIR(hdata
->wh
.dma_dir
));
166 void sgiwd93_reset(unsigned long base
)
168 struct hpc3_scsiregs
*hregs
= (struct hpc3_scsiregs
*) base
;
170 hregs
->ctrl
= HPC3_SCTRL_CRESET
;
174 EXPORT_SYMBOL_GPL(sgiwd93_reset
);
176 static inline void init_hpc_chain(struct ip22_hostdata
*hdata
)
178 struct hpc_chunk
*hcp
= (struct hpc_chunk
*)hdata
->cpu
;
179 dma_addr_t dma
= hdata
->dma
;
180 unsigned long start
, end
;
182 start
= (unsigned long) hcp
;
183 end
= start
+ HPC_DMA_SIZE
;
184 while (start
< end
) {
185 hcp
->desc
.pnext
= (u32
) (dma
+ sizeof(struct hpc_chunk
));
186 hcp
->desc
.cntinfo
= HPCDMA_EOX
;
188 dma
+= sizeof(struct hpc_chunk
);
189 start
+= sizeof(struct hpc_chunk
);
192 hcp
->desc
.pnext
= hdata
->dma
;
196 * Kludge alert - the SCSI code calls the abort and reset method with int
197 * arguments not with pointers. So this is going to blow up beautyfully
198 * on 64-bit systems with memory outside the compat address spaces.
200 static struct scsi_host_template sgiwd93_template
= {
201 .module
= THIS_MODULE
,
202 .proc_name
= "SGIWD93",
204 .queuecommand
= wd33c93_queuecommand
,
205 .eh_abort_handler
= wd33c93_abort
,
206 .eh_host_reset_handler
= wd33c93_host_reset
,
209 .sg_tablesize
= SG_ALL
,
211 .use_clustering
= DISABLE_CLUSTERING
,
214 static int sgiwd93_probe(struct platform_device
*pdev
)
216 struct sgiwd93_platform_data
*pd
= pdev
->dev
.platform_data
;
217 unsigned char *wdregs
= pd
->wdregs
;
218 struct hpc3_scsiregs
*hregs
= pd
->hregs
;
219 struct ip22_hostdata
*hdata
;
220 struct Scsi_Host
*host
;
222 unsigned int unit
= pd
->unit
;
223 unsigned int irq
= pd
->irq
;
226 host
= scsi_host_alloc(&sgiwd93_template
, sizeof(struct ip22_hostdata
));
232 host
->base
= (unsigned long) hregs
;
235 hdata
= host_to_hostdata(host
);
236 hdata
->dev
= &pdev
->dev
;
237 hdata
->cpu
= dma_alloc_attrs(&pdev
->dev
, HPC_DMA_SIZE
, &hdata
->dma
,
238 GFP_KERNEL
, DMA_ATTR_NON_CONSISTENT
);
240 printk(KERN_WARNING
"sgiwd93: Could not allocate memory for "
241 "host %d buffer.\n", unit
);
246 init_hpc_chain(hdata
);
248 regs
.SASR
= wdregs
+ 3;
249 regs
.SCMD
= wdregs
+ 7;
251 hdata
->wh
.no_sync
= 0;
253 hdata
->wh
.dma_mode
= CTRL_BURST
;
255 wd33c93_init(host
, regs
, dma_setup
, dma_stop
, WD33C93_FS_MHZ(20));
257 err
= request_irq(irq
, sgiwd93_intr
, 0, "SGI WD93", host
);
259 printk(KERN_WARNING
"sgiwd93: Could not register irq %d "
260 "for host %d.\n", irq
, unit
);
264 platform_set_drvdata(pdev
, host
);
266 err
= scsi_add_host(host
, NULL
);
270 scsi_scan_host(host
);
277 dma_free_attrs(&pdev
->dev
, HPC_DMA_SIZE
, hdata
->cpu
, hdata
->dma
,
278 DMA_ATTR_NON_CONSISTENT
);
286 static int sgiwd93_remove(struct platform_device
*pdev
)
288 struct Scsi_Host
*host
= platform_get_drvdata(pdev
);
289 struct ip22_hostdata
*hdata
= (struct ip22_hostdata
*) host
->hostdata
;
290 struct sgiwd93_platform_data
*pd
= pdev
->dev
.platform_data
;
292 scsi_remove_host(host
);
293 free_irq(pd
->irq
, host
);
294 dma_free_attrs(&pdev
->dev
, HPC_DMA_SIZE
, hdata
->cpu
, hdata
->dma
,
295 DMA_ATTR_NON_CONSISTENT
);
300 static struct platform_driver sgiwd93_driver
= {
301 .probe
= sgiwd93_probe
,
302 .remove
= sgiwd93_remove
,
308 static int __init
sgiwd93_module_init(void)
310 return platform_driver_register(&sgiwd93_driver
);
313 static void __exit
sgiwd93_module_exit(void)
315 return platform_driver_unregister(&sgiwd93_driver
);
318 module_init(sgiwd93_module_init
);
319 module_exit(sgiwd93_module_exit
);
321 MODULE_DESCRIPTION("SGI WD33C93 driver");
322 MODULE_AUTHOR("Ralf Baechle <ralf@linux-mips.org>");
323 MODULE_LICENSE("GPL");
324 MODULE_ALIAS("platform:sgiwd93");