OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [uclinux/] [uClinux-2.0.x/] [arch/] [armnommu/] [drivers/] [scsi/] [cumana_2.c] - Blame information for rev 1765

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 199 simons
/*
2
 * linux/arch/arm/drivers/scsi/cumana_2.c
3
 *
4
 * Copyright (C) 1997-1998 Russell King
5
 *
6
 * Changelog:
7
 *  30-08-1997  RMK     0.0.0   Created, READONLY version.
8
 *  22-01-1998  RMK     0.0.1   Updated to 2.1.80.
9
 *  15-04-1998  RMK     0.0.1   Only do PIO if FAS216 will allow it.
10
 *  02-05-1998  RMK     0.0.2   Updated & added DMA support.
11
 *  18-08-1998  RMK     0.0.3   Fixed synchronous transfer depth.
12
 */
13
 
14
#include <linux/module.h>
15
#include <linux/blk.h>
16
#include <linux/kernel.h>
17
#include <linux/string.h>
18
#include <linux/ioport.h>
19
#include <linux/sched.h>
20
#include <linux/proc_fs.h>
21
#include <linux/unistd.h>
22
#include <linux/stat.h>
23
 
24
#include <asm/delay.h>
25
#include <asm/dma.h>
26
#include <asm/ecard.h>
27
#include <asm/io.h>
28
#include <asm/irq.h>
29
#include <asm/pgtable.h>
30
 
31
#include "sd.h"
32
#include "hosts.h"
33
#include "cumana_2.h"
34
 
35
/* Configuration */
36
#define CUMANASCSI2_XTALFREQ            40
37
#define CUMANASCSI2_ASYNC_PERIOD        200
38
#define CUMANASCSI2_SYNC_DEPTH          7
39
 
40
/*
41
 * List of devices that the driver will recognise
42
 */
43
#define CUMANASCSI2_LIST                { MANU_CUMANA, PROD_CUMANA_SCSI_2 }
44
 
45
#define CUMANASCSI2_STATUS              (0)
46
#define STATUS_INT                      (1 << 0)
47
#define STATUS_DRQ                      (1 << 1)
48
#define STATUS_LATCHED                  (1 << 3)
49
 
50
#define CUMANASCSI2_ALATCH              (5)
51
#define ALATCH_ENA_INT                  (3)
52
#define ALATCH_DIS_INT                  (2)
53
#define ALATCH_ENA_TERM                 (5)
54
#define ALATCH_DIS_TERM                 (4)
55
#define ALATCH_ENA_BIT32                (11)
56
#define ALATCH_DIS_BIT32                (10)
57
#define ALATCH_ENA_DMA                  (13)
58
#define ALATCH_DIS_DMA                  (12)
59
#define ALATCH_DMA_OUT                  (15)
60
#define ALATCH_DMA_IN                   (14)
61
 
62
#define CUMANASCSI2_PSEUDODMA           (0x80)
63
 
64
#define CUMANASCSI2_FAS216_OFFSET       (0xc0)
65
#define CUMANASCSI2_FAS216_SHIFT        0
66
 
67
/*
68
 * Version
69
 */
70
#define VER_MAJOR       0
71
#define VER_MINOR       0
72
#define VER_PATCH       3
73
 
74
static struct expansion_card *ecs[MAX_ECARDS];
75
 
76
/*
77
 * Use term=0,1,0,0,0 to turn terminators on/off
78
 */
79
int term[MAX_ECARDS] = { 1, 1, 1, 1, 1, 1, 1, 1 };
80
 
81
static struct proc_dir_entry proc_scsi_cumanascsi_2 = {
82
        PROC_SCSI_QLOGICFAS, 6, "cumanascs2",
83
        S_IFDIR | S_IRUGO | S_IXUGO, 2
84
};
85
 
86
/* Prototype: void cumanascsi_2_irqenable(ec, irqnr)
87
 * Purpose  : Enable interrupts on Cumana SCSI 2 card
88
 * Params   : ec    - expansion card structure
89
 *          : irqnr - interrupt number
90
 */
91
static void
92
cumanascsi_2_irqenable(struct expansion_card *ec, int irqnr)
93
{
94
        unsigned int port = (unsigned int)ec->irq_data;
95
        outb(ALATCH_ENA_INT, port);
96
}
97
 
98
/* Prototype: void cumanascsi_2_irqdisable(ec, irqnr)
99
 * Purpose  : Disable interrupts on Cumana SCSI 2 card
100
 * Params   : ec    - expansion card structure
101
 *          : irqnr - interrupt number
102
 */
103
static void
104
cumanascsi_2_irqdisable(struct expansion_card *ec, int irqnr)
105
{
106
        unsigned int port = (unsigned int)ec->irq_data;
107
        outb(ALATCH_DIS_INT, port);
108
}
109
 
110
static const expansioncard_ops_t cumanascsi_2_ops = {
111
        cumanascsi_2_irqenable,
112
        cumanascsi_2_irqdisable,
113
        NULL,
114
        NULL,
115
        NULL,
116
        NULL
117
};
118
 
119
/* Prototype: void cumanascsi_2_terminator_ctl(host, on_off)
120
 * Purpose  : Turn the Cumana SCSI 2 terminators on or off
121
 * Params   : host   - card to turn on/off
122
 *          : on_off - !0 to turn on, 0 to turn off
123
 */
124
static void
125
cumanascsi_2_terminator_ctl(struct Scsi_Host *host, int on_off)
126
{
127
        CumanaScsi2_Info *info = (CumanaScsi2_Info *)host->hostdata;
128
 
129
        if (on_off) {
130
                info->terms = 1;
131
                outb (ALATCH_ENA_TERM, info->alatch);
132
        } else {
133
                info->terms = 0;
134
                outb (ALATCH_DIS_TERM, info->alatch);
135
        }
136
}
137
 
138
/* Prototype: void cumanascsi_2_intr(irq, *dev_id, *regs)
139
 * Purpose  : handle interrupts from Cumana SCSI 2 card
140
 * Params   : irq    - interrupt number
141
 *            dev_id - user-defined (Scsi_Host structure)
142
 *            regs   - processor registers at interrupt
143
 */
144
static void
145
cumanascsi_2_intr(int irq, void *dev_id, struct pt_regs *regs)
146
{
147
        struct Scsi_Host *host = (struct Scsi_Host *)dev_id;
148
 
149
        fas216_intr(host);
150
}
151
 
152
static void
153
cumanascsi_2_invalidate(char *addr, long len, fasdmadir_t direction)
154
{
155
        unsigned int page;
156
 
157
        if (direction == DMA_OUT) {
158
                for (page = (unsigned int) addr; len > 0;
159
                     page += PAGE_SIZE, len -= PAGE_SIZE)
160
                        flush_page_to_ram(page);
161
        } else
162
                flush_cache_range(current->mm, (unsigned long)addr,
163
                                  (unsigned long)addr + len);
164
}
165
 
166
/* Prototype: fasdmatype_t cumanascsi_2_dma_setup(host, SCpnt, direction, min_type)
167
 * Purpose  : initialises DMA/PIO
168
 * Params   : host      - host
169
 *            SCpnt     - command
170
 *            direction - DMA on to/off of card
171
 *            min_type  - minimum DMA support that we must have for this transfer
172
 * Returns  : type of transfer to be performed
173
 */
174
static fasdmatype_t
175
cumanascsi_2_dma_setup(struct Scsi_Host *host, Scsi_Pointer *SCp,
176
                       fasdmadir_t direction, fasdmatype_t min_type)
177
{
178
        CumanaScsi2_Info *info = (CumanaScsi2_Info *)host->hostdata;
179
        int dmach = host->dma_channel;
180
 
181
        outb(ALATCH_DIS_DMA, info->alatch);
182
 
183
        if (dmach != NO_DMA &&
184
            (min_type == fasdma_real_all || SCp->this_residual >= 512)) {
185
                int buf;
186
 
187
                for (buf = 1; buf <= SCp->buffers_residual &&
188
                              buf < NR_SG; buf++) {
189
                        info->dmasg[buf].address = __virt_to_bus(
190
                                (unsigned long)SCp->buffer[buf].address);
191
                        info->dmasg[buf].length = SCp->buffer[buf].length;
192
 
193
                        cumanascsi_2_invalidate(SCp->buffer[buf].address,
194
                                                SCp->buffer[buf].length,
195
                                                direction);
196
                }
197
 
198
                info->dmasg[0].address = __virt_to_phys((unsigned long)SCp->ptr);
199
                info->dmasg[0].length = SCp->this_residual;
200
                cumanascsi_2_invalidate(SCp->ptr,
201
                                        SCp->this_residual, direction);
202
 
203
                disable_dma(dmach);
204
                set_dma_sg(dmach, info->dmasg, buf);
205
                if (direction == DMA_OUT) {
206
                        outb(ALATCH_DMA_OUT, info->alatch);
207
                        set_dma_mode(dmach, DMA_MODE_WRITE);
208
                } else {
209
                        outb(ALATCH_DMA_IN, info->alatch);
210
                        set_dma_mode(dmach, DMA_MODE_READ);
211
                }
212
                enable_dma(dmach);
213
                outb(ALATCH_ENA_DMA, info->alatch);
214
                outb(ALATCH_DIS_BIT32, info->alatch);
215
                return fasdma_real_all;
216
        }
217
 
218
        /*
219
         * If we're not doing DMA,
220
         *  we'll do pseudo DMA
221
         */
222
        return fasdma_pio;
223
}
224
 
225
/*
226
 * Prototype: void cumanascsi_2_dma_pseudo(host, SCpnt, direction, transfer)
227
 * Purpose  : handles pseudo DMA
228
 * Params   : host      - host
229
 *            SCpnt     - command
230
 *            direction - DMA on to/off of card
231
 *            transfer  - minimum number of bytes we expect to transfer
232
 */
233
static void
234
cumanascsi_2_dma_pseudo(struct Scsi_Host *host, Scsi_Pointer *SCp,
235
                        fasdmadir_t direction, int transfer)
236
{
237
        CumanaScsi2_Info *info = (CumanaScsi2_Info *)host->hostdata;
238
        unsigned int length;
239
        unsigned char *addr;
240
 
241
        length = SCp->this_residual;
242
        addr = SCp->ptr;
243
 
244
        if (direction == DMA_OUT)
245
#if 0
246
                while (length > 1) {
247
                        unsigned long word;
248
                        unsigned int status = inb(info->status);
249
 
250
                        if (status & STATUS_INT)
251
                                goto end;
252
 
253
                        if (!(status & STATUS_DRQ))
254
                                continue;
255
 
256
                        word = *addr | *(addr + 1) << 8;
257
                        outw (info->dmaarea);
258
                        addr += 2;
259
                        length -= 2;
260
                }
261
#else
262
                printk ("PSEUDO_OUT???\n");
263
#endif
264
        else {
265
                if (transfer && (transfer & 255)) {
266
                        while (length >= 256) {
267
                                unsigned int status = inb(info->status);
268
 
269
                                if (status & STATUS_INT)
270
                                        goto end;
271
 
272
                                if (!(status & STATUS_DRQ))
273
                                        continue;
274
 
275
                                insw(info->dmaarea, addr, 256 >> 1);
276
                                addr += 256;
277
                                length -= 256;
278
                        }
279
                }
280
 
281
                while (length > 0) {
282
                        unsigned long word;
283
                        unsigned int status = inb(info->status);
284
 
285
                        if (status & STATUS_INT)
286
                                goto end;
287
 
288
                        if (!(status & STATUS_DRQ))
289
                                continue;
290
 
291
                        word = inw (info->dmaarea);
292
                        *addr++ = word;
293
                        if (--length > 0) {
294
                                *addr++ = word >> 8;
295
                                length --;
296
                        }
297
                }
298
        }
299
 
300
end:
301
}
302
 
303
/* Prototype: int cumanascsi_2_dma_stop(host, SCpnt)
304
 * Purpose  : stops DMA/PIO
305
 * Params   : host  - host
306
 *            SCpnt - command
307
 */
308
static void
309
cumanascsi_2_dma_stop(struct Scsi_Host *host, Scsi_Pointer *SCp)
310
{
311
        CumanaScsi2_Info *info = (CumanaScsi2_Info *)host->hostdata;
312
        if (host->dma_channel != NO_DMA) {
313
                outb(ALATCH_DIS_DMA, info->alatch);
314
                disable_dma(host->dma_channel);
315
        }
316
}
317
 
318
/* Prototype: int cumanascsi_2_detect(Scsi_Host_Template * tpnt)
319
 * Purpose  : initialises Cumana SCSI 2 driver
320
 * Params   : tpnt - template for this SCSI adapter
321
 * Returns  : >0 if host found, 0 otherwise.
322
 */
323
int
324
cumanascsi_2_detect(Scsi_Host_Template *tpnt)
325
{
326
        static const card_ids cumanascsi_2_cids[] =
327
                        { CUMANASCSI2_LIST, { 0xffff, 0xffff} };
328
        int count = 0;
329
        struct Scsi_Host *host;
330
 
331
        tpnt->proc_dir = &proc_scsi_cumanascsi_2;
332
        memset(ecs, 0, sizeof (ecs));
333
 
334
        ecard_startfind();
335
 
336
        while (1) {
337
                CumanaScsi2_Info *info;
338
 
339
                ecs[count] = ecard_find(0, cumanascsi_2_cids);
340
                if (!ecs[count])
341
                        break;
342
 
343
                ecard_claim(ecs[count]);
344
 
345
                host = scsi_register(tpnt, sizeof (CumanaScsi2_Info));
346
                if (!host) {
347
                        ecard_release(ecs[count]);
348
                        break;
349
                }
350
 
351
                host->io_port = ecard_address(ecs[count], ECARD_MEMC, 0);
352
                host->irq = ecs[count]->irq;
353
                host->dma_channel = ecs[count]->dma;
354
                info = (CumanaScsi2_Info *)host->hostdata;
355
 
356
                info->terms                     = term[count] ? 1 : 0;
357
                cumanascsi_2_terminator_ctl(host, info->terms);
358
 
359
                info->info.scsi.io_port         = host->io_port + CUMANASCSI2_FAS216_OFFSET;
360
                info->info.scsi.io_shift        = CUMANASCSI2_FAS216_SHIFT;
361
                info->info.scsi.irq             = host->irq;
362
                info->info.ifcfg.clockrate      = CUMANASCSI2_XTALFREQ;
363
                info->info.ifcfg.select_timeout = 255;
364
                info->info.ifcfg.asyncperiod    = CUMANASCSI2_ASYNC_PERIOD;
365
                info->info.ifcfg.sync_max_depth = CUMANASCSI2_SYNC_DEPTH;
366
                info->info.ifcfg.cntl3          = CNTL3_BS8 | CNTL3_FASTSCSI | CNTL3_FASTCLK;
367
                info->info.ifcfg.disconnect_ok  = 1;
368
                info->info.ifcfg.wide_max_size  = 0;
369
                info->info.dma.setup            = cumanascsi_2_dma_setup;
370
                info->info.dma.pseudo           = cumanascsi_2_dma_pseudo;
371
                info->info.dma.stop             = cumanascsi_2_dma_stop;
372
                info->dmaarea                   = host->io_port + CUMANASCSI2_PSEUDODMA;
373
                info->status                    = host->io_port + CUMANASCSI2_STATUS;
374
                info->alatch                    = host->io_port + CUMANASCSI2_ALATCH;
375
 
376
                ecs[count]->irqaddr     = (unsigned char *)ioaddr(info->status);
377
                ecs[count]->irqmask     = STATUS_INT;
378
                ecs[count]->irq_data    = (void *)info->alatch;
379
                ecs[count]->ops         = (expansioncard_ops_t *)&cumanascsi_2_ops;
380
 
381
                request_region(host->io_port + CUMANASCSI2_FAS216_OFFSET,
382
                               16 << CUMANASCSI2_FAS216_SHIFT, "cumanascsi2-fas");
383
 
384
                if (host->irq != NO_IRQ &&
385
                    request_irq(host->irq, cumanascsi_2_intr,
386
                                SA_INTERRUPT, "cumanascsi2", host)) {
387
                        printk("scsi%d: IRQ%d not free, interrupts disabled\n",
388
                               host->host_no, host->irq);
389
                        host->irq = NO_IRQ;
390
                        info->info.scsi.irq = NO_IRQ;
391
                }
392
 
393
                if (host->dma_channel != NO_DMA &&
394
                    request_dma(host->dma_channel, "cumanascsi2")) {
395
                        printk("scsi%d: DMA%d not free, DMA disabled\n",
396
                               host->host_no, host->dma_channel);
397
                        host->dma_channel = NO_DMA;
398
                }
399
 
400
                fas216_init(host);
401
                ++count;
402
        }
403
        return count;
404
}
405
 
406
/* Prototype: int cumanascsi_2_release(struct Scsi_Host * host)
407
 * Purpose  : releases all resources used by this adapter
408
 * Params   : host - driver host structure to return info for.
409
 */
410
int cumanascsi_2_release(struct Scsi_Host *host)
411
{
412
        int i;
413
 
414
        fas216_release(host);
415
 
416
        if (host->irq != NO_IRQ)
417
                free_irq(host->irq, host);
418
        if (host->dma_channel != NO_DMA)
419
                free_dma(host->dma_channel);
420
        release_region(host->io_port + CUMANASCSI2_FAS216_OFFSET,
421
                       16 << CUMANASCSI2_FAS216_SHIFT);
422
 
423
        for (i = 0; i < MAX_ECARDS; i++)
424
                if (ecs[i] && host->io_port == ecard_address (ecs[i], ECARD_MEMC, 0))
425
                        ecard_release (ecs[i]);
426
        return 0;
427
}
428
 
429
/* Prototype: const char *cumanascsi_2_info(struct Scsi_Host * host)
430
 * Purpose  : returns a descriptive string about this interface,
431
 * Params   : host - driver host structure to return info for.
432
 * Returns  : pointer to a static buffer containing null terminated string.
433
 */
434
const char *cumanascsi_2_info(struct Scsi_Host *host)
435
{
436
        CumanaScsi2_Info *info = (CumanaScsi2_Info *)host->hostdata;
437
        static char string[100], *p;
438
 
439
        p = string;
440
        p += sprintf(string, "%s at port %X ",
441
                     host->hostt->name, host->io_port);
442
 
443
        if (host->irq != NO_IRQ)
444
                p += sprintf(p, "irq %d ", host->irq);
445
        else
446
                p += sprintf(p, "NO IRQ ");
447
 
448
        if (host->dma_channel != NO_DMA)
449
                p += sprintf(p, "dma %d ", host->dma_channel);
450
        else
451
                p += sprintf(p, "NO DMA ");
452
 
453
        p += sprintf(p, "v%d.%d.%d scsi %s",
454
                     VER_MAJOR, VER_MINOR, VER_PATCH,
455
                     info->info.scsi.type);
456
 
457
        p += sprintf(p, " terminators %s",
458
                     info->terms ? "on" : "off");
459
 
460
        return string;
461
}
462
 
463
/* Prototype: int cumanascsi_2_set_proc_info(struct Scsi_Host *host, char *buffer, int length)
464
 * Purpose  : Set a driver specific function
465
 * Params   : host   - host to setup
466
 *          : buffer - buffer containing string describing operation
467
 *          : length - length of string
468
 * Returns  : -EINVAL, or 0
469
 */
470
static int
471
cumanascsi_2_set_proc_info(struct Scsi_Host *host, char *buffer, int length)
472
{
473
        int ret = length;
474
 
475
        if (length >= 11 && strcmp(buffer, "CUMANASCSI2") == 0) {
476
                buffer += 11;
477
                length -= 11;
478
 
479
                if (length >= 5 && strncmp(buffer, "term=", 5) == 0) {
480
                        if (buffer[5] == '1')
481
                                cumanascsi_2_terminator_ctl(host, 1);
482
                        else if (buffer[5] == '0')
483
                                cumanascsi_2_terminator_ctl(host, 0);
484
                        else
485
                                ret = -EINVAL;
486
                } else
487
                        ret = -EINVAL;
488
        } else
489
                ret = -EINVAL;
490
 
491
        return ret;
492
}
493
 
494
/* Prototype: int cumanascsi_2_proc_info(char *buffer, char **start, off_t offset,
495
 *                                       int length, int host_no, int inout)
496
 * Purpose  : Return information about the driver to a user process accessing
497
 *            the /proc filesystem.
498
 * Params   : buffer - a buffer to write information to
499
 *            start  - a pointer into this buffer set by this routine to the start
500
 *                     of the required information.
501
 *            offset - offset into information that we have read upto.
502
 *            length - length of buffer
503
 *            host_no - host number to return information for
504
 *            inout  - 0 for reading, 1 for writing.
505
 * Returns  : length of data written to buffer.
506
 */
507
int cumanascsi_2_proc_info (char *buffer, char **start, off_t offset,
508
                            int length, int host_no, int inout)
509
{
510
        int pos, begin, first;
511
        struct Scsi_Host *host = scsi_hostlist;
512
        CumanaScsi2_Info *info;
513
        Scsi_Device *scd;
514
 
515
        while (host) {
516
                if (host->host_no == host_no)
517
                        break;
518
                host = host->next;
519
        }
520
        if (!host)
521
                return 0;
522
 
523
        if (inout == 1)
524
                return cumanascsi_2_set_proc_info(host, buffer, length);
525
 
526
        info = (CumanaScsi2_Info *)host->hostdata;
527
 
528
        begin = 0;
529
        pos = sprintf(buffer,
530
                        "Cumana SCSI II driver version %d.%d.%d\n",
531
                        VER_MAJOR, VER_MINOR, VER_PATCH);
532
        pos += sprintf(buffer + pos,
533
                        "Address: %08X    IRQ : %d     DMA : %d\n"
534
                        "FAS    : %-10s  TERM: %-3s\n\n"
535
                        "Statistics:\n",
536
                        host->io_port, host->irq, host->dma_channel,
537
                        info->info.scsi.type, info->terms ? "on" : "off");
538
 
539
        pos += sprintf(buffer+pos,
540
                        "Queued commands: %-10u   Issued commands: %-10u\n"
541
                        "Done commands  : %-10u   Reads          : %-10u\n"
542
                        "Writes         : %-10u   Others         : %-10u\n"
543
                        "Disconnects    : %-10u   Aborts         : %-10u\n"
544
                        "Resets         : %-10u\n",
545
                        info->info.stats.queues,      info->info.stats.removes,
546
                        info->info.stats.fins,        info->info.stats.reads,
547
                        info->info.stats.writes,      info->info.stats.miscs,
548
                        info->info.stats.disconnects, info->info.stats.aborts,
549
                        info->info.stats.resets);
550
 
551
        first = 1;
552
        for (scd = scsi_devices; scd; scd = scd->next) {
553
                if (scd->host == host) {
554
                        int len;
555
 
556
                        if (first) {
557
                                pos += sprintf(buffer+pos,
558
                                               "\nAttached devices:\n");
559
                                first = 0;
560
                        }
561
 
562
                        proc_print_scsidevice(scd, buffer, &len, pos);
563
                        pos += len;
564
                        pos += sprintf(buffer+pos, "Extensions: ");
565
                        if (scd->tagged_supported)
566
                                pos += sprintf(buffer+pos, "TAG %sabled [%d] ",
567
                                               scd->tagged_queue ? "en" : "dis",
568
                                               scd->current_tag);
569
                        pos += sprintf(buffer+pos, "\n");
570
 
571
                        if (pos + begin < offset) {
572
                                begin += pos;
573
                                pos = 0;
574
                        }
575
                        if (pos + begin > offset + length)
576
                                break;
577
                }
578
        }
579
 
580
        *start = buffer + (offset - begin);
581
        pos -= offset - begin;
582
        if (pos > length)
583
                pos = length;
584
 
585
        return pos;
586
}
587
 
588
#ifdef MODULE
589
Scsi_Host_Template driver_template = CUMANASCSI_2;
590
 
591
#include "scsi_module.c"
592
#endif

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.