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

Subversion Repositories or1k

[/] [or1k/] [trunk/] [linux/] [linux-2.4/] [drivers/] [scsi/] [sun3_scsi.c] - Blame information for rev 1765

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1275 phoenix
/*
2
 * Sun3 SCSI stuff by Erik Verbruggen (erik@bigmama.xtdnet.nl)
3
 *
4
 * Sun3 DMA routines added by Sam Creasey (sammy@sammy.net)
5
 *
6
 * Adapted from mac_scsinew.c:
7
 */
8
/*
9
 * Generic Macintosh NCR5380 driver
10
 *
11
 * Copyright 1998, Michael Schmitz <mschmitz@lbl.gov>
12
 *
13
 * derived in part from:
14
 */
15
/*
16
 * Generic Generic NCR5380 driver
17
 *
18
 * Copyright 1995, Russell King
19
 *
20
 * ALPHA RELEASE 1.
21
 *
22
 * For more information, please consult
23
 *
24
 * NCR 5380 Family
25
 * SCSI Protocol Controller
26
 * Databook
27
 *
28
 * NCR Microelectronics
29
 * 1635 Aeroplaza Drive
30
 * Colorado Springs, CO 80916
31
 * 1+ (719) 578-3400
32
 * 1+ (800) 334-5454
33
 */
34
 
35
 
36
/*
37
 * This is from mac_scsi.h, but hey, maybe this is useful for Sun3 too! :)
38
 *
39
 * Options :
40
 *
41
 * PARITY - enable parity checking.  Not supported.
42
 *
43
 * SCSI2 - enable support for SCSI-II tagged queueing.  Untested.
44
 *
45
 * USLEEP - enable support for devices that don't disconnect.  Untested.
46
 */
47
 
48
/*
49
 * $Log: not supported by cvs2svn $
50
 */
51
 
52
#define AUTOSENSE
53
 
54
#include <linux/types.h>
55
#include <linux/stddef.h>
56
#include <linux/ctype.h>
57
#include <linux/delay.h>
58
 
59
#include <linux/module.h>
60
#include <linux/signal.h>
61
#include <linux/sched.h>
62
#include <linux/ioport.h>
63
#include <linux/init.h>
64
#include <linux/blk.h>
65
 
66
#include <asm/io.h>
67
#include <asm/system.h>
68
 
69
#include <asm/sun3ints.h>
70
#include <asm/dvma.h>
71
#include <asm/idprom.h>
72
#include <asm/machines.h>
73
 
74
/* dma on! */
75
#define REAL_DMA
76
 
77
#include "scsi.h"
78
#include "hosts.h"
79
#include "sun3_scsi.h"
80
#include "NCR5380.h"
81
#include "constants.h"
82
 
83
/* #define OLDDMA */
84
 
85
#define USE_WRAPPER
86
/*#define RESET_BOOT */
87
#define DRIVER_SETUP
88
 
89
#define NDEBUG 0
90
 
91
/*
92
 * BUG can be used to trigger a strange code-size related hang on 2.1 kernels
93
 */
94
#ifdef BUG
95
#undef RESET_BOOT
96
#undef DRIVER_SETUP
97
#endif
98
 
99
/* #define SUPPORT_TAGS */
100
 
101
#define ENABLE_IRQ()    enable_irq( IRQ_SUN3_SCSI ); 
102
 
103
 
104
static void scsi_sun3_intr(int irq, void *dummy, struct pt_regs *fp);
105
static inline unsigned char sun3scsi_read(int reg);
106
static inline void sun3scsi_write(int reg, int value);
107
 
108
static int setup_can_queue = -1;
109
static int setup_cmd_per_lun = -1;
110
static int setup_sg_tablesize = -1;
111
#ifdef SUPPORT_TAGS
112
static int setup_use_tagged_queuing = -1;
113
#endif
114
static int setup_hostid = -1;
115
 
116
static Scsi_Cmnd *sun3_dma_setup_done = NULL;
117
 
118
#define AFTER_RESET_DELAY       (HZ/2)
119
 
120
/* ms to wait after hitting dma regs */
121
#define SUN3_DMA_DELAY 10
122
 
123
/* dvma buffer to allocate -- 32k should hopefully be more than sufficient */
124
#define SUN3_DVMA_BUFSIZE 0xe000
125
 
126
/* minimum number of bytes to do dma on */
127
#define SUN3_DMA_MINSIZE 128
128
 
129
static volatile unsigned char *sun3_scsi_regp;
130
static volatile struct sun3_dma_regs *dregs;
131
#ifdef OLDDMA
132
static unsigned char *dmabuf = NULL; /* dma memory buffer */
133
#endif
134
static struct sun3_udc_regs *udc_regs = NULL;
135
static unsigned char *sun3_dma_orig_addr = NULL;
136
static unsigned long sun3_dma_orig_count = 0;
137
static int sun3_dma_active = 0;
138
static unsigned long last_residual = 0;
139
 
140
/*
141
 * NCR 5380 register access functions
142
 */
143
 
144
static inline unsigned char sun3scsi_read(int reg)
145
{
146
        return( sun3_scsi_regp[reg] );
147
}
148
 
149
static inline void sun3scsi_write(int reg, int value)
150
{
151
        sun3_scsi_regp[reg] = value;
152
}
153
 
154
/* dma controller register access functions */
155
 
156
static inline unsigned short sun3_udc_read(unsigned char reg)
157
{
158
        unsigned short ret;
159
 
160
        dregs->udc_addr = UDC_CSR;
161
        udelay(SUN3_DMA_DELAY);
162
        ret = dregs->udc_data;
163
        udelay(SUN3_DMA_DELAY);
164
 
165
        return ret;
166
}
167
 
168
static inline void sun3_udc_write(unsigned short val, unsigned char reg)
169
{
170
        dregs->udc_addr = reg;
171
        udelay(SUN3_DMA_DELAY);
172
        dregs->udc_data = val;
173
        udelay(SUN3_DMA_DELAY);
174
}
175
 
176
/*
177
 * XXX: status debug
178
 */
179
static struct Scsi_Host *default_instance;
180
 
181
/*
182
 * Function : int sun3scsi_detect(Scsi_Host_Template * tpnt)
183
 *
184
 * Purpose : initializes mac NCR5380 driver based on the
185
 *      command line / compile time port and irq definitions.
186
 *
187
 * Inputs : tpnt - template for this SCSI adapter.
188
 *
189
 * Returns : 1 if a host adapter was found, 0 if not.
190
 *
191
 */
192
 
193
int sun3scsi_detect(Scsi_Host_Template * tpnt)
194
{
195
        unsigned long ioaddr;
196
        static int called = 0;
197
        struct Scsi_Host *instance;
198
 
199
        /* check that this machine has an onboard 5380 */
200
        switch(idprom->id_machtype) {
201
        case SM_SUN3|SM_3_50:
202
        case SM_SUN3|SM_3_60:
203
                break;
204
 
205
        default:
206
                return 0;
207
        }
208
 
209
        if(called)
210
                return 0;
211
 
212
        tpnt->proc_name = "Sun3 5380 SCSI";
213
 
214
        /* setup variables */
215
        tpnt->can_queue =
216
                (setup_can_queue > 0) ? setup_can_queue : CAN_QUEUE;
217
        tpnt->cmd_per_lun =
218
                (setup_cmd_per_lun > 0) ? setup_cmd_per_lun : CMD_PER_LUN;
219
        tpnt->sg_tablesize =
220
                (setup_sg_tablesize >= 0) ? setup_sg_tablesize : SG_TABLESIZE;
221
 
222
        if (setup_hostid >= 0)
223
                tpnt->this_id = setup_hostid;
224
        else {
225
                /* use 7 as default */
226
                tpnt->this_id = 7;
227
        }
228
 
229
        ioaddr = (unsigned long)ioremap(IOBASE_SUN3_SCSI, PAGE_SIZE);
230
        sun3_scsi_regp = (unsigned char *)ioaddr;
231
 
232
        dregs = (struct sun3_dma_regs *)(((unsigned char *)ioaddr) + 8);
233
 
234
        if((udc_regs = dvma_malloc(sizeof(struct sun3_udc_regs)))
235
           == NULL) {
236
             printk("SUN3 Scsi couldn't allocate DVMA memory!\n");
237
             return 0;
238
        }
239
#ifdef OLDDMA
240
        if((dmabuf = dvma_malloc_align(SUN3_DVMA_BUFSIZE, 0x10000)) == NULL) {
241
             printk("SUN3 Scsi couldn't allocate DVMA memory!\n");
242
             return 0;
243
        }
244
#endif
245
#ifdef SUPPORT_TAGS
246
        if (setup_use_tagged_queuing < 0)
247
                setup_use_tagged_queuing = USE_TAGGED_QUEUING;
248
#endif
249
 
250
        instance = scsi_register (tpnt, sizeof(struct NCR5380_hostdata));
251
        if(instance == NULL)
252
                return 0;
253
 
254
        default_instance = instance;
255
 
256
        instance->io_port = (unsigned long) ioaddr;
257
        instance->irq = IRQ_SUN3_SCSI;
258
 
259
        NCR5380_init(instance, 0);
260
 
261
        instance->n_io_port = 32;
262
 
263
        ((struct NCR5380_hostdata *)instance->hostdata)->ctrl = 0;
264
 
265
        if (request_irq(instance->irq, scsi_sun3_intr,
266
                             0, "Sun3SCSI-5380", NULL)) {
267
#ifndef REAL_DMA
268
                printk("scsi%d: IRQ%d not free, interrupts disabled\n",
269
                       instance->host_no, instance->irq);
270
                instance->irq = SCSI_IRQ_NONE;
271
#else
272
                printk("scsi%d: IRQ%d not free, bailing out\n",
273
                       instance->host_no, instance->irq);
274
                return 0;
275
#endif
276
        }
277
 
278
        printk("scsi%d: Sun3 5380 at port %lX irq", instance->host_no, instance->io_port);
279
        if (instance->irq == SCSI_IRQ_NONE)
280
                printk ("s disabled");
281
        else
282
                printk (" %d", instance->irq);
283
        printk(" options CAN_QUEUE=%d CMD_PER_LUN=%d release=%d",
284
               instance->can_queue, instance->cmd_per_lun,
285
               SUN3SCSI_PUBLIC_RELEASE);
286
        printk("\nscsi%d:", instance->host_no);
287
        NCR5380_print_options(instance);
288
        printk("\n");
289
 
290
        dregs->csr = 0;
291
        udelay(SUN3_DMA_DELAY);
292
        dregs->csr = CSR_SCSI | CSR_FIFO | CSR_INTR;
293
        udelay(SUN3_DMA_DELAY);
294
        dregs->fifo_count = 0;
295
 
296
        called = 1;
297
 
298
#ifdef RESET_BOOT
299
        sun3_scsi_reset_boot(instance);
300
#endif
301
 
302
        return 1;
303
}
304
 
305
#ifdef MODULE
306
int sun3scsi_release (struct Scsi_Host *shpnt)
307
{
308
        if (shpnt->irq != SCSI_IRQ_NONE)
309
                free_irq (shpnt->irq, NULL);
310
 
311
        iounmap((void *)sun3_scsi_regp);
312
 
313
        return 0;
314
}
315
#endif
316
 
317
#ifdef RESET_BOOT
318
/*
319
 * Our 'bus reset on boot' function
320
 */
321
 
322
static void sun3_scsi_reset_boot(struct Scsi_Host *instance)
323
{
324
        unsigned long end;
325
 
326
        NCR5380_local_declare();
327
        NCR5380_setup(instance);
328
 
329
        /*
330
         * Do a SCSI reset to clean up the bus during initialization. No
331
         * messing with the queues, interrupts, or locks necessary here.
332
         */
333
 
334
        printk( "Sun3 SCSI: resetting the SCSI bus..." );
335
 
336
        /* switch off SCSI IRQ - catch an interrupt without IRQ bit set else */
337
//              sun3_disable_irq( IRQ_SUN3_SCSI );
338
 
339
        /* get in phase */
340
        NCR5380_write( TARGET_COMMAND_REG,
341
                      PHASE_SR_TO_TCR( NCR5380_read(STATUS_REG) ));
342
 
343
        /* assert RST */
344
        NCR5380_write( INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_RST );
345
 
346
        /* The min. reset hold time is 25us, so 40us should be enough */
347
        udelay( 50 );
348
 
349
        /* reset RST and interrupt */
350
        NCR5380_write( INITIATOR_COMMAND_REG, ICR_BASE );
351
        NCR5380_read( RESET_PARITY_INTERRUPT_REG );
352
 
353
        for( end = jiffies + AFTER_RESET_DELAY; time_before(jiffies, end); )
354
                barrier();
355
 
356
        /* switch on SCSI IRQ again */
357
//              sun3_enable_irq( IRQ_SUN3_SCSI );
358
 
359
        printk( " done\n" );
360
}
361
#endif
362
 
363
const char * sun3scsi_info (struct Scsi_Host *spnt) {
364
    return "";
365
}
366
 
367
// safe bits for the CSR
368
#define CSR_GOOD 0x060f
369
 
370
static void scsi_sun3_intr(int irq, void *dummy, struct pt_regs *fp)
371
{
372
        unsigned short csr = dregs->csr;
373
 
374
        if(csr & ~CSR_GOOD) {
375
                if(csr & CSR_DMA_BUSERR) {
376
                        printk("scsi%d: bus error in dma\n", default_instance->host_no);
377
                }
378
 
379
                if(csr & CSR_DMA_CONFLICT) {
380
                        printk("scsi%d: dma conflict\n", default_instance->host_no);
381
                }
382
        }
383
 
384
        if(csr & (CSR_SDB_INT | CSR_DMA_INT))
385
                NCR5380_intr(irq, dummy, fp);
386
}
387
 
388
/*
389
 * Debug stuff - to be called on NMI, or sysrq key. Use at your own risk;
390
 * reentering NCR5380_print_status seems to have ugly side effects
391
 */
392
 
393
/* this doesn't seem to get used at all -- sam */
394
#if 0
395
void sun3_sun3_debug (void)
396
{
397
        unsigned long flags;
398
        NCR5380_local_declare();
399
 
400
        if (default_instance) {
401
                        save_flags(flags);
402
                        cli();
403
                        NCR5380_print_status(default_instance);
404
                        restore_flags(flags);
405
        }
406
}
407
#endif
408
 
409
 
410
/* sun3scsi_dma_setup() -- initialize the dma controller for a read/write */
411
static unsigned long sun3scsi_dma_setup(void *data, unsigned long count, int write_flag)
412
{
413
#ifdef OLDDMA
414
        if(write_flag)
415
                memcpy(dmabuf, data, count);
416
        else {
417
                sun3_dma_orig_addr = data;
418
                sun3_dma_orig_count = count;
419
        }
420
#else
421
        void *addr;
422
 
423
        if(sun3_dma_orig_addr != NULL)
424
                dvma_unmap(sun3_dma_orig_addr);
425
 
426
//      addr = sun3_dvma_page((unsigned long)data, (unsigned long)dmabuf);
427
        addr = (void *)dvma_map((unsigned long) data, count);
428
 
429
        sun3_dma_orig_addr = addr;
430
        sun3_dma_orig_count = count;
431
#endif
432
        dregs->fifo_count = 0;
433
        sun3_udc_write(UDC_RESET, UDC_CSR);
434
 
435
        /* reset fifo */
436
        dregs->csr &= ~CSR_FIFO;
437
        dregs->csr |= CSR_FIFO;
438
 
439
        /* set direction */
440
        if(write_flag)
441
                dregs->csr |= CSR_SEND;
442
        else
443
                dregs->csr &= ~CSR_SEND;
444
 
445
        /* byte count for fifo */
446
        dregs->fifo_count = count;
447
 
448
        sun3_udc_write(UDC_RESET, UDC_CSR);
449
 
450
        /* reset fifo */
451
        dregs->csr &= ~CSR_FIFO;
452
        dregs->csr |= CSR_FIFO;
453
 
454
        if(dregs->fifo_count != count) {
455
                printk("scsi%d: fifo_mismatch %04x not %04x\n",
456
                       default_instance->host_no, dregs->fifo_count,
457
                       (unsigned int) count);
458
                NCR5380_print(default_instance);
459
        }
460
 
461
        /* setup udc */
462
#ifdef OLDDMA
463
        udc_regs->addr_hi = ((dvma_vtob(dmabuf) & 0xff0000) >> 8);
464
        udc_regs->addr_lo = (dvma_vtob(dmabuf) & 0xffff);
465
#else
466
        udc_regs->addr_hi = (((unsigned long)(addr) & 0xff0000) >> 8);
467
        udc_regs->addr_lo = ((unsigned long)(addr) & 0xffff);
468
#endif
469
        udc_regs->count = count/2; /* count in words */
470
        udc_regs->mode_hi = UDC_MODE_HIWORD;
471
        if(write_flag) {
472
                if(count & 1)
473
                        udc_regs->count++;
474
                udc_regs->mode_lo = UDC_MODE_LSEND;
475
                udc_regs->rsel = UDC_RSEL_SEND;
476
        } else {
477
                udc_regs->mode_lo = UDC_MODE_LRECV;
478
                udc_regs->rsel = UDC_RSEL_RECV;
479
        }
480
 
481
        /* announce location of regs block */
482
        sun3_udc_write(((dvma_vtob(udc_regs) & 0xff0000) >> 8),
483
                       UDC_CHN_HI);
484
 
485
        sun3_udc_write((dvma_vtob(udc_regs) & 0xffff), UDC_CHN_LO);
486
 
487
        /* set dma master on */
488
        sun3_udc_write(0xd, UDC_MODE);
489
 
490
        /* interrupt enable */
491
        sun3_udc_write(UDC_INT_ENABLE, UDC_CSR);
492
 
493
        return count;
494
 
495
}
496
 
497
static inline unsigned long sun3scsi_dma_count(struct Scsi_Host *instance)
498
{
499
        unsigned short resid;
500
 
501
        dregs->udc_addr = 0x32;
502
        udelay(SUN3_DMA_DELAY);
503
        resid = dregs->udc_data;
504
        udelay(SUN3_DMA_DELAY);
505
        resid *= 2;
506
 
507
        return (unsigned long) resid;
508
}
509
 
510
static inline unsigned long sun3scsi_dma_residual(struct Scsi_Host *instance)
511
{
512
        return last_residual;
513
}
514
 
515
static inline unsigned long sun3scsi_dma_xfer_len(unsigned long wanted, Scsi_Cmnd *cmd,
516
                                    int write_flag)
517
{
518
        if((cmd->request.cmd == 0) || (cmd->request.cmd == 1))
519
                return wanted;
520
        else
521
                return 0;
522
}
523
 
524
static inline int sun3scsi_dma_start(unsigned long count, unsigned char *data)
525
{
526
 
527
    sun3_udc_write(UDC_CHN_START, UDC_CSR);
528
 
529
    return 0;
530
}
531
 
532
/* clean up after our dma is done */
533
static int sun3scsi_dma_finish(int write_flag)
534
{
535
        unsigned short count;
536
        unsigned short fifo;
537
        int ret = 0;
538
 
539
        sun3_dma_active = 0;
540
#if 1
541
        // check to empty the fifo on a read
542
        if(!write_flag) {
543
                int tmo = 20000; /* .2 sec */
544
 
545
                while(1) {
546
                        if(dregs->csr & CSR_FIFO_EMPTY)
547
                                break;
548
 
549
                        if(--tmo <= 0)
550
                                return 1;
551
 
552
                        udelay(10);
553
                }
554
        }
555
 
556
#endif
557
 
558
        count = sun3scsi_dma_count(default_instance);
559
#ifdef OLDDMA
560
 
561
        /* if we've finished a read, copy out the data we read */
562
        if(sun3_dma_orig_addr) {
563
                /* check for residual bytes after dma end */
564
                if(count && (NCR5380_read(BUS_AND_STATUS_REG) &
565
                             (BASR_PHASE_MATCH | BASR_ACK))) {
566
                        printk("scsi%d: sun3_scsi_finish: read overrun baby... ", default_instance->host_no);
567
                        printk("basr now %02x\n", NCR5380_read(BUS_AND_STATUS_REG));
568
                        ret = count;
569
                }
570
 
571
                /* copy in what we dma'd no matter what */
572
                memcpy(sun3_dma_orig_addr, dmabuf, sun3_dma_orig_count);
573
                sun3_dma_orig_addr = NULL;
574
 
575
        }
576
#else
577
 
578
        fifo = dregs->fifo_count;
579
        last_residual = fifo;
580
 
581
        /* empty bytes from the fifo which didn't make it */
582
        if((!write_flag) && (count - fifo) == 2) {
583
                unsigned short data;
584
                unsigned char *vaddr;
585
 
586
                data = dregs->fifo_data;
587
                vaddr = (unsigned char *)dvma_btov(sun3_dma_orig_addr);
588
 
589
                vaddr += (sun3_dma_orig_count - fifo);
590
 
591
                vaddr[-2] = (data & 0xff00) >> 8;
592
                vaddr[-1] = (data & 0xff);
593
        }
594
 
595
        dvma_unmap(sun3_dma_orig_addr);
596
        sun3_dma_orig_addr = NULL;
597
#endif
598
        sun3_udc_write(UDC_RESET, UDC_CSR);
599
        dregs->fifo_count = 0;
600
        dregs->csr &= ~CSR_SEND;
601
 
602
        /* reset fifo */
603
        dregs->csr &= ~CSR_FIFO;
604
        dregs->csr |= CSR_FIFO;
605
 
606
        sun3_dma_setup_done = NULL;
607
 
608
        return ret;
609
 
610
}
611
 
612
#include "sun3_NCR5380.c"
613
 
614
static Scsi_Host_Template driver_template = SUN3_NCR5380;
615
 
616
#include "scsi_module.c"
617
 
618
MODULE_LICENSE("GPL");

powered by: WebSVN 2.1.0

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