~ubuntu-branches/ubuntu/precise/linux-lowlatency/precise

« back to all changes in this revision

Viewing changes to drivers/scsi/sgiwd93.c

  • Committer: Package Import Robot
  • Author(s): Alessio Igor Bogani
  • Date: 2011-10-26 11:13:05 UTC
  • Revision ID: package-import@ubuntu.com-20111026111305-tz023xykf0i6eosh
Tags: upstream-3.2.0
ImportĀ upstreamĀ versionĀ 3.2.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
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
 
4
 * for more details.
 
5
 *
 
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)
 
10
 * 
 
11
 * (In all truth, Jed Schimmel wrote all this code.)
 
12
 */
 
13
 
 
14
#undef DEBUG
 
15
 
 
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>
 
26
 
 
27
#include <asm/sgi/hpc3.h>
 
28
#include <asm/sgi/ip22.h>
 
29
#include <asm/sgi/wd.h>
 
30
 
 
31
#include "scsi.h"
 
32
#include "wd33c93.h"
 
33
 
 
34
struct ip22_hostdata {
 
35
        struct WD33C93_hostdata wh;
 
36
        dma_addr_t dma;
 
37
        void *cpu;
 
38
        struct device *dev;
 
39
};
 
40
 
 
41
#define host_to_hostdata(host) ((struct ip22_hostdata *)((host)->hostdata))
 
42
 
 
43
struct hpc_chunk {
 
44
        struct hpc_dma_desc desc;
 
45
        u32 _padding;   /* align to quadword boundary */
 
46
};
 
47
 
 
48
/* space for hpc dma descriptors */
 
49
#define HPC_DMA_SIZE   PAGE_SIZE
 
50
 
 
51
#define DMA_DIR(d)   ((d == DATA_OUT_DIR) ? DMA_TO_DEVICE : DMA_FROM_DEVICE)
 
52
 
 
53
static irqreturn_t sgiwd93_intr(int irq, void *dev_id)
 
54
{
 
55
        struct Scsi_Host * host = dev_id;
 
56
        unsigned long flags;
 
57
 
 
58
        spin_lock_irqsave(host->host_lock, flags);
 
59
        wd33c93_intr(host);
 
60
        spin_unlock_irqrestore(host->host_lock, flags);
 
61
 
 
62
        return IRQ_HANDLED;
 
63
}
 
64
 
 
65
static inline
 
66
void fill_hpc_entries(struct ip22_hostdata *hd, struct scsi_cmnd *cmd, int din)
 
67
{
 
68
        unsigned long len = cmd->SCp.this_residual;
 
69
        void *addr = cmd->SCp.ptr;
 
70
        dma_addr_t physaddr;
 
71
        unsigned long count;
 
72
        struct hpc_chunk *hcp;
 
73
 
 
74
        physaddr = dma_map_single(hd->dev, addr, len, DMA_DIR(din));
 
75
        cmd->SCp.dma_handle = physaddr;
 
76
        hcp = hd->cpu;
 
77
 
 
78
        while (len) {
 
79
                /*
 
80
                 * even cntinfo could be up to 16383, without
 
81
                 * magic only 8192 works correctly
 
82
                 */
 
83
                count = len > 8192 ? 8192 : len;
 
84
                hcp->desc.pbuf = physaddr;
 
85
                hcp->desc.cntinfo = count;
 
86
                hcp++;
 
87
                len -= count;
 
88
                physaddr += count;
 
89
        }
 
90
 
 
91
        /*
 
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
 
94
         * the chain.
 
95
         */
 
96
        hcp->desc.pbuf = 0;
 
97
        hcp->desc.cntinfo = HPCDMA_EOX;
 
98
        dma_cache_sync(hd->dev, hd->cpu,
 
99
                       (unsigned long)(hcp + 1) - (unsigned long)hd->cpu,
 
100
                       DMA_TO_DEVICE);
 
101
}
 
102
 
 
103
static int dma_setup(struct scsi_cmnd *cmd, int datainp)
 
104
{
 
105
        struct ip22_hostdata *hdata = host_to_hostdata(cmd->device->host);
 
106
        struct hpc3_scsiregs *hregs =
 
107
                (struct hpc3_scsiregs *) cmd->device->host->base;
 
108
 
 
109
        pr_debug("dma_setup: datainp<%d> hcp<%p> ", datainp, hdata->cpu);
 
110
 
 
111
        hdata->wh.dma_dir = datainp;
 
112
 
 
113
        /*
 
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.
 
118
         */
 
119
        if (cmd->SCp.ptr == NULL || cmd->SCp.this_residual == 0)
 
120
                return 1;
 
121
 
 
122
        fill_hpc_entries(hdata, cmd, datainp);
 
123
 
 
124
        pr_debug(" HPCGO\n");
 
125
 
 
126
        /* Start up the HPC. */
 
127
        hregs->ndptr = hdata->dma;
 
128
        if (datainp)
 
129
                hregs->ctrl = HPC3_SCTRL_ACTIVE;
 
130
        else
 
131
                hregs->ctrl = HPC3_SCTRL_ACTIVE | HPC3_SCTRL_DIR;
 
132
 
 
133
        return 0;
 
134
}
 
135
 
 
136
static void dma_stop(struct Scsi_Host *instance, struct scsi_cmnd *SCpnt,
 
137
                     int status)
 
138
{
 
139
        struct ip22_hostdata *hdata = host_to_hostdata(instance);
 
140
        struct hpc3_scsiregs *hregs;
 
141
 
 
142
        if (!SCpnt)
 
143
                return;
 
144
 
 
145
        if (SCpnt->SCp.ptr == NULL || SCpnt->SCp.this_residual == 0)
 
146
                return;
 
147
 
 
148
        hregs = (struct hpc3_scsiregs *) SCpnt->device->host->base;
 
149
 
 
150
        pr_debug("dma_stop: status<%d> ", status);
 
151
 
 
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)
 
156
                        barrier();
 
157
        }
 
158
        hregs->ctrl = 0;
 
159
        dma_unmap_single(hdata->dev, SCpnt->SCp.dma_handle,
 
160
                         SCpnt->SCp.this_residual,
 
161
                         DMA_DIR(hdata->wh.dma_dir));
 
162
 
 
163
        pr_debug("\n");
 
164
}
 
165
 
 
166
void sgiwd93_reset(unsigned long base)
 
167
{
 
168
        struct hpc3_scsiregs *hregs = (struct hpc3_scsiregs *) base;
 
169
 
 
170
        hregs->ctrl = HPC3_SCTRL_CRESET;
 
171
        udelay(50);
 
172
        hregs->ctrl = 0;
 
173
}
 
174
EXPORT_SYMBOL_GPL(sgiwd93_reset);
 
175
 
 
176
static inline void init_hpc_chain(struct ip22_hostdata *hdata)
 
177
{
 
178
        struct hpc_chunk *hcp = (struct hpc_chunk *)hdata->cpu;
 
179
        dma_addr_t dma = hdata->dma;
 
180
        unsigned long start, end;
 
181
 
 
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;
 
187
                hcp++;
 
188
                dma += sizeof(struct hpc_chunk);
 
189
                start += sizeof(struct hpc_chunk);
 
190
        };
 
191
        hcp--;
 
192
        hcp->desc.pnext = hdata->dma;
 
193
}
 
194
 
 
195
static int sgiwd93_bus_reset(struct scsi_cmnd *cmd)
 
196
{
 
197
        /* FIXME perform bus-specific reset */
 
198
 
 
199
        /* FIXME 2: kill this function, and let midlayer fallback
 
200
           to the same result, calling wd33c93_host_reset() */
 
201
 
 
202
        spin_lock_irq(cmd->device->host->host_lock);
 
203
        wd33c93_host_reset(cmd);
 
204
        spin_unlock_irq(cmd->device->host->host_lock);
 
205
 
 
206
        return SUCCESS;
 
207
}
 
208
 
 
209
/*
 
210
 * Kludge alert - the SCSI code calls the abort and reset method with int
 
211
 * arguments not with pointers.  So this is going to blow up beautyfully
 
212
 * on 64-bit systems with memory outside the compat address spaces.
 
213
 */
 
214
static struct scsi_host_template sgiwd93_template = {
 
215
        .module                 = THIS_MODULE,
 
216
        .proc_name              = "SGIWD93",
 
217
        .name                   = "SGI WD93",
 
218
        .queuecommand           = wd33c93_queuecommand,
 
219
        .eh_abort_handler       = wd33c93_abort,
 
220
        .eh_bus_reset_handler   = sgiwd93_bus_reset,
 
221
        .eh_host_reset_handler  = wd33c93_host_reset,
 
222
        .can_queue              = 16,
 
223
        .this_id                = 7,
 
224
        .sg_tablesize           = SG_ALL,
 
225
        .cmd_per_lun            = 8,
 
226
        .use_clustering         = DISABLE_CLUSTERING,
 
227
};
 
228
 
 
229
static int __devinit sgiwd93_probe(struct platform_device *pdev)
 
230
{
 
231
        struct sgiwd93_platform_data *pd = pdev->dev.platform_data;
 
232
        unsigned char *wdregs = pd->wdregs;
 
233
        struct hpc3_scsiregs *hregs = pd->hregs;
 
234
        struct ip22_hostdata *hdata;
 
235
        struct Scsi_Host *host;
 
236
        wd33c93_regs regs;
 
237
        unsigned int unit = pd->unit;
 
238
        unsigned int irq = pd->irq;
 
239
        int err;
 
240
 
 
241
        host = scsi_host_alloc(&sgiwd93_template, sizeof(struct ip22_hostdata));
 
242
        if (!host) {
 
243
                err = -ENOMEM;
 
244
                goto out;
 
245
        }
 
246
 
 
247
        host->base = (unsigned long) hregs;
 
248
        host->irq = irq;
 
249
 
 
250
        hdata = host_to_hostdata(host);
 
251
        hdata->dev = &pdev->dev;
 
252
        hdata->cpu = dma_alloc_noncoherent(&pdev->dev, HPC_DMA_SIZE,
 
253
                                           &hdata->dma, GFP_KERNEL);
 
254
        if (!hdata->cpu) {
 
255
                printk(KERN_WARNING "sgiwd93: Could not allocate memory for "
 
256
                       "host %d buffer.\n", unit);
 
257
                err = -ENOMEM;
 
258
                goto out_put;
 
259
        }
 
260
 
 
261
        init_hpc_chain(hdata);
 
262
 
 
263
        regs.SASR = wdregs + 3;
 
264
        regs.SCMD = wdregs + 7;
 
265
 
 
266
        hdata->wh.no_sync = 0;
 
267
        hdata->wh.fast = 1;
 
268
        hdata->wh.dma_mode = CTRL_BURST;
 
269
 
 
270
        wd33c93_init(host, regs, dma_setup, dma_stop, WD33C93_FS_MHZ(20));
 
271
 
 
272
        err = request_irq(irq, sgiwd93_intr, 0, "SGI WD93", host);
 
273
        if (err) {
 
274
                printk(KERN_WARNING "sgiwd93: Could not register irq %d "
 
275
                       "for host %d.\n", irq, unit);
 
276
                goto out_free;
 
277
        }
 
278
 
 
279
        platform_set_drvdata(pdev, host);
 
280
 
 
281
        err = scsi_add_host(host, NULL);
 
282
        if (err)
 
283
                goto out_irq;
 
284
 
 
285
        scsi_scan_host(host);
 
286
 
 
287
        return 0;
 
288
 
 
289
out_irq:
 
290
        free_irq(irq, host);
 
291
out_free:
 
292
        dma_free_noncoherent(&pdev->dev, HPC_DMA_SIZE, hdata->cpu, hdata->dma);
 
293
out_put:
 
294
        scsi_host_put(host);
 
295
out:
 
296
 
 
297
        return err;
 
298
}
 
299
 
 
300
static int __exit sgiwd93_remove(struct platform_device *pdev)
 
301
{
 
302
        struct Scsi_Host *host = platform_get_drvdata(pdev);
 
303
        struct ip22_hostdata *hdata = (struct ip22_hostdata *) host->hostdata;
 
304
        struct sgiwd93_platform_data *pd = pdev->dev.platform_data;
 
305
 
 
306
        scsi_remove_host(host);
 
307
        free_irq(pd->irq, host);
 
308
        dma_free_noncoherent(&pdev->dev, HPC_DMA_SIZE, hdata->cpu, hdata->dma);
 
309
        scsi_host_put(host);
 
310
        return 0;
 
311
}
 
312
 
 
313
static struct platform_driver sgiwd93_driver = {
 
314
        .probe  = sgiwd93_probe,
 
315
        .remove = __devexit_p(sgiwd93_remove),
 
316
        .driver = {
 
317
                .name   = "sgiwd93",
 
318
                .owner  = THIS_MODULE,
 
319
        }
 
320
};
 
321
 
 
322
static int __init sgiwd93_module_init(void)
 
323
{
 
324
        return platform_driver_register(&sgiwd93_driver);
 
325
}
 
326
 
 
327
static void __exit sgiwd93_module_exit(void)
 
328
{
 
329
        return platform_driver_unregister(&sgiwd93_driver);
 
330
}
 
331
 
 
332
module_init(sgiwd93_module_init);
 
333
module_exit(sgiwd93_module_exit);
 
334
 
 
335
MODULE_DESCRIPTION("SGI WD33C93 driver");
 
336
MODULE_AUTHOR("Ralf Baechle <ralf@linux-mips.org>");
 
337
MODULE_LICENSE("GPL");
 
338
MODULE_ALIAS("platform:sgiwd93");