aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/scsi')
-rw-r--r--drivers/scsi/sgiwd93.c264
1 files changed, 120 insertions, 144 deletions
diff --git a/drivers/scsi/sgiwd93.c b/drivers/scsi/sgiwd93.c
index a15752b37990..eef82758d047 100644
--- a/drivers/scsi/sgiwd93.c
+++ b/drivers/scsi/sgiwd93.c
@@ -6,87 +6,49 @@
6 * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) 6 * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
7 * Copyright (C) 1999 Andrew R. Baker (andrewb@uab.edu) 7 * Copyright (C) 1999 Andrew R. Baker (andrewb@uab.edu)
8 * Copyright (C) 2001 Florian Lohoff (flo@rfc822.org) 8 * Copyright (C) 2001 Florian Lohoff (flo@rfc822.org)
9 * Copyright (C) 2003 Ralf Baechle (ralf@linux-mips.org) 9 * Copyright (C) 2003, 07 Ralf Baechle (ralf@linux-mips.org)
10 * 10 *
11 * (In all truth, Jed Schimmel wrote all this code.) 11 * (In all truth, Jed Schimmel wrote all this code.)
12 */ 12 */
13#include <linux/init.h> 13
14#include <linux/interrupt.h> 14#undef DEBUG
15#include <linux/types.h> 15
16#include <linux/mm.h>
17#include <linux/blkdev.h>
18#include <linux/delay.h> 16#include <linux/delay.h>
19#include <linux/dma-mapping.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>
20#include <linux/spinlock.h> 25#include <linux/spinlock.h>
21 26
22#include <asm/page.h>
23#include <asm/pgtable.h>
24#include <asm/sgialib.h>
25#include <asm/sgi/sgi.h>
26#include <asm/sgi/mc.h>
27#include <asm/sgi/hpc3.h> 27#include <asm/sgi/hpc3.h>
28#include <asm/sgi/ip22.h> 28#include <asm/sgi/ip22.h>
29#include <asm/irq.h> 29#include <asm/sgi/wd.h>
30#include <asm/io.h>
31 30
32#include "scsi.h" 31#include "scsi.h"
33#include <scsi/scsi_host.h>
34#include "wd33c93.h" 32#include "wd33c93.h"
35 33
36#include <linux/stat.h>
37
38#if 0
39#define DPRINTK(args...) printk(args)
40#else
41#define DPRINTK(args...)
42#endif
43
44#define HDATA(ptr) ((struct ip22_hostdata *)((ptr)->hostdata))
45
46struct ip22_hostdata { 34struct ip22_hostdata {
47 struct WD33C93_hostdata wh; 35 struct WD33C93_hostdata wh;
48 struct hpc_data { 36 struct hpc_data {
49 dma_addr_t dma; 37 dma_addr_t dma;
50 void * cpu; 38 void *cpu;
51 } hd; 39 } hd;
52}; 40};
53 41
42#define host_to_hostdata(host) ((struct ip22_hostdata *)((host)->hostdata))
43
54struct hpc_chunk { 44struct hpc_chunk {
55 struct hpc_dma_desc desc; 45 struct hpc_dma_desc desc;
56 u32 _padding; /* align to quadword boundary */ 46 u32 _padding; /* align to quadword boundary */
57}; 47};
58 48
59struct Scsi_Host *sgiwd93_host;
60struct Scsi_Host *sgiwd93_host1;
61
62/* Wuff wuff, wuff, wd33c93.c, wuff wuff, object oriented, bow wow. */
63static inline void write_wd33c93_count(const wd33c93_regs regs,
64 unsigned long value)
65{
66 *regs.SASR = WD_TRANSFER_COUNT_MSB;
67 mb();
68 *regs.SCMD = ((value >> 16) & 0xff);
69 *regs.SCMD = ((value >> 8) & 0xff);
70 *regs.SCMD = ((value >> 0) & 0xff);
71 mb();
72}
73
74static inline unsigned long read_wd33c93_count(const wd33c93_regs regs)
75{
76 unsigned long value;
77
78 *regs.SASR = WD_TRANSFER_COUNT_MSB;
79 mb();
80 value = ((*regs.SCMD & 0xff) << 16);
81 value |= ((*regs.SCMD & 0xff) << 8);
82 value |= ((*regs.SCMD & 0xff) << 0);
83 mb();
84 return value;
85}
86
87static irqreturn_t sgiwd93_intr(int irq, void *dev_id) 49static irqreturn_t sgiwd93_intr(int irq, void *dev_id)
88{ 50{
89 struct Scsi_Host * host = (struct Scsi_Host *) dev_id; 51 struct Scsi_Host * host = dev_id;
90 unsigned long flags; 52 unsigned long flags;
91 53
92 spin_lock_irqsave(host->host_lock, flags); 54 spin_lock_irqsave(host->host_lock, flags);
@@ -131,12 +93,12 @@ void fill_hpc_entries(struct hpc_chunk *hcp, struct scsi_cmnd *cmd, int datainp)
131 93
132static int dma_setup(struct scsi_cmnd *cmd, int datainp) 94static int dma_setup(struct scsi_cmnd *cmd, int datainp)
133{ 95{
134 struct ip22_hostdata *hdata = HDATA(cmd->device->host); 96 struct ip22_hostdata *hdata = host_to_hostdata(cmd->device->host);
135 struct hpc3_scsiregs *hregs = 97 struct hpc3_scsiregs *hregs =
136 (struct hpc3_scsiregs *) cmd->device->host->base; 98 (struct hpc3_scsiregs *) cmd->device->host->base;
137 struct hpc_chunk *hcp = (struct hpc_chunk *) hdata->hd.cpu; 99 struct hpc_chunk *hcp = (struct hpc_chunk *) hdata->hd.cpu;
138 100
139 DPRINTK("dma_setup: datainp<%d> hcp<%p> ", datainp, hcp); 101 pr_debug("dma_setup: datainp<%d> hcp<%p> ", datainp, hcp);
140 102
141 hdata->wh.dma_dir = datainp; 103 hdata->wh.dma_dir = datainp;
142 104
@@ -151,7 +113,7 @@ static int dma_setup(struct scsi_cmnd *cmd, int datainp)
151 113
152 fill_hpc_entries(hcp, cmd, datainp); 114 fill_hpc_entries(hcp, cmd, datainp);
153 115
154 DPRINTK(" HPCGO\n"); 116 pr_debug(" HPCGO\n");
155 117
156 /* Start up the HPC. */ 118 /* Start up the HPC. */
157 hregs->ndptr = hdata->hd.dma; 119 hregs->ndptr = hdata->hd.dma;
@@ -166,7 +128,7 @@ static int dma_setup(struct scsi_cmnd *cmd, int datainp)
166static void dma_stop(struct Scsi_Host *instance, struct scsi_cmnd *SCpnt, 128static void dma_stop(struct Scsi_Host *instance, struct scsi_cmnd *SCpnt,
167 int status) 129 int status)
168{ 130{
169 struct ip22_hostdata *hdata = HDATA(instance); 131 struct ip22_hostdata *hdata = host_to_hostdata(instance);
170 struct hpc3_scsiregs *hregs; 132 struct hpc3_scsiregs *hregs;
171 133
172 if (!SCpnt) 134 if (!SCpnt)
@@ -174,7 +136,7 @@ static void dma_stop(struct Scsi_Host *instance, struct scsi_cmnd *SCpnt,
174 136
175 hregs = (struct hpc3_scsiregs *) SCpnt->device->host->base; 137 hregs = (struct hpc3_scsiregs *) SCpnt->device->host->base;
176 138
177 DPRINTK("dma_stop: status<%d> ", status); 139 pr_debug("dma_stop: status<%d> ", status);
178 140
179 /* First stop the HPC and flush it's FIFO. */ 141 /* First stop the HPC and flush it's FIFO. */
180 if (hdata->wh.dma_dir) { 142 if (hdata->wh.dma_dir) {
@@ -186,7 +148,7 @@ static void dma_stop(struct Scsi_Host *instance, struct scsi_cmnd *SCpnt,
186 dma_unmap_single(NULL, SCpnt->SCp.dma_handle, SCpnt->SCp.this_residual, 148 dma_unmap_single(NULL, SCpnt->SCp.dma_handle, SCpnt->SCp.this_residual,
187 SCpnt->sc_data_direction); 149 SCpnt->sc_data_direction);
188 150
189 DPRINTK("\n"); 151 pr_debug("\n");
190} 152}
191 153
192void sgiwd93_reset(unsigned long base) 154void sgiwd93_reset(unsigned long base)
@@ -216,29 +178,71 @@ static inline void init_hpc_chain(struct hpc_data *hd)
216 hcp->desc.pnext = hd->dma; 178 hcp->desc.pnext = hd->dma;
217} 179}
218 180
219static struct Scsi_Host * __init sgiwd93_setup_scsi( 181static int sgiwd93_bus_reset(struct scsi_cmnd *cmd)
220 struct scsi_host_template *SGIblows, int unit, int irq, 182{
221 struct hpc3_scsiregs *hregs, unsigned char *wdregs) 183 /* FIXME perform bus-specific reset */
184
185 /* FIXME 2: kill this function, and let midlayer fallback
186 to the same result, calling wd33c93_host_reset() */
187
188 spin_lock_irq(cmd->device->host->host_lock);
189 wd33c93_host_reset(cmd);
190 spin_unlock_irq(cmd->device->host->host_lock);
191
192 return SUCCESS;
193}
194
195/*
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.
199 */
200static struct scsi_host_template sgiwd93_template = {
201 .module = THIS_MODULE,
202 .proc_name = "SGIWD93",
203 .name = "SGI WD93",
204 .queuecommand = wd33c93_queuecommand,
205 .eh_abort_handler = wd33c93_abort,
206 .eh_bus_reset_handler = sgiwd93_bus_reset,
207 .eh_host_reset_handler = wd33c93_host_reset,
208 .can_queue = 16,
209 .this_id = 7,
210 .sg_tablesize = SG_ALL,
211 .cmd_per_lun = 8,
212 .use_clustering = DISABLE_CLUSTERING,
213};
214
215static int __init sgiwd93_probe(struct platform_device *pdev)
222{ 216{
217 struct sgiwd93_platform_data *pd = pdev->dev.platform_data;
218 unsigned char *wdregs = pd->wdregs;
219 struct hpc3_scsiregs *hregs = pd->hregs;
223 struct ip22_hostdata *hdata; 220 struct ip22_hostdata *hdata;
224 struct Scsi_Host *host; 221 struct Scsi_Host *host;
225 wd33c93_regs regs; 222 wd33c93_regs regs;
226 223 unsigned int unit = pd->unit;
227 host = scsi_register(SGIblows, sizeof(struct ip22_hostdata)); 224 unsigned int irq = pd->irq;
228 if (!host) 225 int err;
229 return NULL; 226
227 host = scsi_host_alloc(&sgiwd93_template, sizeof(struct ip22_hostdata));
228 if (!host) {
229 err = -ENOMEM;
230 goto out;
231 }
230 232
231 host->base = (unsigned long) hregs; 233 host->base = (unsigned long) hregs;
232 host->irq = irq; 234 host->irq = irq;
233 235
234 hdata = HDATA(host); 236 hdata = host_to_hostdata(host);
235 hdata->hd.cpu = dma_alloc_coherent(NULL, PAGE_SIZE, &hdata->hd.dma, 237 hdata->hd.cpu = dma_alloc_coherent(&pdev->dev, PAGE_SIZE,
236 GFP_KERNEL); 238 &hdata->hd.dma, GFP_KERNEL);
237 if (!hdata->hd.cpu) { 239 if (!hdata->hd.cpu) {
238 printk(KERN_WARNING "sgiwd93: Could not allocate memory for " 240 printk(KERN_WARNING "sgiwd93: Could not allocate memory for "
239 "host %d buffer.\n", unit); 241 "host %d buffer.\n", unit);
240 goto out_unregister; 242 err = -ENOMEM;
243 goto out_put;
241 } 244 }
245
242 init_hpc_chain(&hdata->hd); 246 init_hpc_chain(&hdata->hd);
243 247
244 regs.SASR = wdregs + 3; 248 regs.SASR = wdregs + 3;
@@ -249,95 +253,67 @@ static struct Scsi_Host * __init sgiwd93_setup_scsi(
249 if (hdata->wh.no_sync == 0xff) 253 if (hdata->wh.no_sync == 0xff)
250 hdata->wh.no_sync = 0; 254 hdata->wh.no_sync = 0;
251 255
252 if (request_irq(irq, sgiwd93_intr, 0, "SGI WD93", (void *) host)) { 256 err = request_irq(irq, sgiwd93_intr, 0, "SGI WD93", host);
257 if (err) {
253 printk(KERN_WARNING "sgiwd93: Could not register irq %d " 258 printk(KERN_WARNING "sgiwd93: Could not register irq %d "
254 "for host %d.\n", irq, unit); 259 "for host %d.\n", irq, unit);
255 goto out_free; 260 goto out_free;
256 } 261 }
257 return host;
258 262
259out_free: 263 platform_set_drvdata(pdev, host);
260 dma_free_coherent(NULL, PAGE_SIZE, hdata->hd.cpu, hdata->hd.dma);
261 wd33c93_release();
262 264
263out_unregister: 265 err = scsi_add_host(host, NULL);
264 scsi_unregister(host); 266 if (err)
267 goto out_irq;
265 268
266 return NULL; 269 scsi_scan_host(host);
267}
268
269static int __init sgiwd93_detect(struct scsi_host_template *SGIblows)
270{
271 int found = 0;
272
273 SGIblows->proc_name = "SGIWD93";
274 sgiwd93_host = sgiwd93_setup_scsi(SGIblows, 0, SGI_WD93_0_IRQ,
275 &hpc3c0->scsi_chan0,
276 (unsigned char *)hpc3c0->scsi0_ext);
277 if (sgiwd93_host)
278 found++;
279
280 /* Set up second controller on the Indigo2 */
281 if (ip22_is_fullhouse()) {
282 sgiwd93_host1 = sgiwd93_setup_scsi(SGIblows, 1, SGI_WD93_1_IRQ,
283 &hpc3c0->scsi_chan1,
284 (unsigned char *)hpc3c0->scsi1_ext);
285 if (sgiwd93_host1)
286 found++;
287 }
288
289 return found;
290}
291 270
292static int sgiwd93_release(struct Scsi_Host *instance) 271 return 0;
293{
294 struct ip22_hostdata *hdata = HDATA(instance);
295 int irq = 0;
296
297 if (sgiwd93_host && sgiwd93_host == instance)
298 irq = SGI_WD93_0_IRQ;
299 else if (sgiwd93_host1 && sgiwd93_host1 == instance)
300 irq = SGI_WD93_1_IRQ;
301 272
302 free_irq(irq, sgiwd93_intr); 273out_irq:
274 free_irq(irq, host);
275out_free:
303 dma_free_coherent(NULL, PAGE_SIZE, hdata->hd.cpu, hdata->hd.dma); 276 dma_free_coherent(NULL, PAGE_SIZE, hdata->hd.cpu, hdata->hd.dma);
304 wd33c93_release(); 277out_put:
278 scsi_host_put(host);
279out:
305 280
306 return 1; 281 return err;
307} 282}
308 283
309static int sgiwd93_bus_reset(struct scsi_cmnd *cmd) 284static void __exit sgiwd93_remove(struct platform_device *pdev)
310{ 285{
311 /* FIXME perform bus-specific reset */ 286 struct Scsi_Host *host = platform_get_drvdata(pdev);
287 struct ip22_hostdata *hdata = (struct ip22_hostdata *) host->hostdata;
288 struct sgiwd93_platform_data *pd = pdev->dev.platform_data;
289
290 scsi_remove_host(host);
291 free_irq(pd->irq, host);
292 dma_free_coherent(&pdev->dev, PAGE_SIZE, hdata->hd.cpu, hdata->hd.dma);
293 scsi_host_put(host);
294}
312 295
313 /* FIXME 2: kill this function, and let midlayer fallback 296static struct platform_driver sgiwd93_driver = {
314 to the same result, calling wd33c93_host_reset() */ 297 .probe = sgiwd93_probe,
298 .remove = __devexit_p(sgiwd93_remove),
299 .driver = {
300 .name = "sgiwd93"
301 }
302};
315 303
316 spin_lock_irq(cmd->device->host->host_lock); 304static int __init sgiwd93_module_init(void)
317 wd33c93_host_reset(cmd); 305{
318 spin_unlock_irq(cmd->device->host->host_lock); 306 return platform_driver_register(&sgiwd93_driver);
307}
319 308
320 return SUCCESS; 309static void __exit sgiwd93_module_exit(void)
310{
311 return platform_driver_unregister(&sgiwd93_driver);
321} 312}
322 313
323/* 314module_init(sgiwd93_module_init);
324 * Kludge alert - the SCSI code calls the abort and reset method with int 315module_exit(sgiwd93_module_exit);
325 * arguments not with pointers. So this is going to blow up beautyfully 316
326 * on 64-bit systems with memory outside the compat address spaces. 317MODULE_DESCRIPTION("SGI WD33C93 driver");
327 */ 318MODULE_AUTHOR("Ralf Baechle <ralf@linux-mips.org>");
328static struct scsi_host_template driver_template = { 319MODULE_LICENSE("GPL");
329 .proc_name = "SGIWD93",
330 .name = "SGI WD93",
331 .detect = sgiwd93_detect,
332 .release = sgiwd93_release,
333 .queuecommand = wd33c93_queuecommand,
334 .eh_abort_handler = wd33c93_abort,
335 .eh_bus_reset_handler = sgiwd93_bus_reset,
336 .eh_host_reset_handler = wd33c93_host_reset,
337 .can_queue = 16,
338 .this_id = 7,
339 .sg_tablesize = SG_ALL,
340 .cmd_per_lun = 8,
341 .use_clustering = DISABLE_CLUSTERING,
342};
343#include "scsi_module.c"