linux/drivers/scsi/sun3_scsi.c
<<
>>
Prefs
   1/*
   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: sun3_NCR5380.c,v $
  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/ioport.h>
  62#include <linux/init.h>
  63#include <linux/blkdev.h>
  64
  65#include <asm/io.h>
  66#include <asm/system.h>
  67
  68#include <asm/sun3ints.h>
  69#include <asm/dvma.h>
  70#include <asm/idprom.h>
  71#include <asm/machines.h>
  72
  73/* dma on! */
  74#define REAL_DMA
  75
  76#include "scsi.h"
  77#include "initio.h"
  78#include <scsi/scsi_host.h>
  79#include "sun3_scsi.h"
  80
  81static void NCR5380_print(struct Scsi_Host *instance);
  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
 104static irqreturn_t scsi_sun3_intr(int irq, void *dummy);
 105static inline unsigned char sun3scsi_read(int reg);
 106static inline void sun3scsi_write(int reg, int value);
 107
 108static int setup_can_queue = -1;
 109module_param(setup_can_queue, int, 0);
 110static int setup_cmd_per_lun = -1;
 111module_param(setup_cmd_per_lun, int, 0);
 112static int setup_sg_tablesize = -1;
 113module_param(setup_sg_tablesize, int, 0);
 114#ifdef SUPPORT_TAGS
 115static int setup_use_tagged_queuing = -1;
 116module_param(setup_use_tagged_queuing, int, 0);
 117#endif
 118static int setup_hostid = -1;
 119module_param(setup_hostid, int, 0);
 120
 121static struct scsi_cmnd *sun3_dma_setup_done = NULL;
 122
 123#define AFTER_RESET_DELAY       (HZ/2)
 124
 125/* ms to wait after hitting dma regs */
 126#define SUN3_DMA_DELAY 10
 127
 128/* dvma buffer to allocate -- 32k should hopefully be more than sufficient */
 129#define SUN3_DVMA_BUFSIZE 0xe000
 130
 131/* minimum number of bytes to do dma on */
 132#define SUN3_DMA_MINSIZE 128
 133
 134static volatile unsigned char *sun3_scsi_regp;
 135static volatile struct sun3_dma_regs *dregs;
 136#ifdef OLDDMA
 137static unsigned char *dmabuf = NULL; /* dma memory buffer */
 138#endif
 139static struct sun3_udc_regs *udc_regs = NULL;
 140static unsigned char *sun3_dma_orig_addr = NULL;
 141static unsigned long sun3_dma_orig_count = 0;
 142static int sun3_dma_active = 0;
 143static unsigned long last_residual = 0;
 144
 145/*
 146 * NCR 5380 register access functions
 147 */
 148
 149static inline unsigned char sun3scsi_read(int reg)
 150{
 151        return( sun3_scsi_regp[reg] );
 152}
 153
 154static inline void sun3scsi_write(int reg, int value)
 155{
 156        sun3_scsi_regp[reg] = value;
 157}
 158
 159/* dma controller register access functions */
 160
 161static inline unsigned short sun3_udc_read(unsigned char reg)
 162{
 163        unsigned short ret;
 164
 165        dregs->udc_addr = UDC_CSR;
 166        udelay(SUN3_DMA_DELAY);
 167        ret = dregs->udc_data;
 168        udelay(SUN3_DMA_DELAY);
 169        
 170        return ret;
 171}
 172
 173static inline void sun3_udc_write(unsigned short val, unsigned char reg)
 174{
 175        dregs->udc_addr = reg;
 176        udelay(SUN3_DMA_DELAY);
 177        dregs->udc_data = val;
 178        udelay(SUN3_DMA_DELAY);
 179}
 180
 181/*
 182 * XXX: status debug
 183 */
 184static struct Scsi_Host *default_instance;
 185
 186/*
 187 * Function : int sun3scsi_detect(struct scsi_host_template * tpnt)
 188 *
 189 * Purpose : initializes mac NCR5380 driver based on the
 190 *      command line / compile time port and irq definitions.
 191 *
 192 * Inputs : tpnt - template for this SCSI adapter.
 193 *
 194 * Returns : 1 if a host adapter was found, 0 if not.
 195 *
 196 */
 197 
 198int sun3scsi_detect(struct scsi_host_template * tpnt)
 199{
 200        unsigned long ioaddr;
 201        static int called = 0;
 202        struct Scsi_Host *instance;
 203
 204        /* check that this machine has an onboard 5380 */
 205        switch(idprom->id_machtype) {
 206        case SM_SUN3|SM_3_50:
 207        case SM_SUN3|SM_3_60:
 208                break;
 209
 210        default:
 211                return 0;
 212        }
 213
 214        if(called)
 215                return 0;
 216
 217        tpnt->proc_name = "Sun3 5380 SCSI";
 218
 219        /* setup variables */
 220        tpnt->can_queue =
 221                (setup_can_queue > 0) ? setup_can_queue : CAN_QUEUE;
 222        tpnt->cmd_per_lun =
 223                (setup_cmd_per_lun > 0) ? setup_cmd_per_lun : CMD_PER_LUN;
 224        tpnt->sg_tablesize = 
 225                (setup_sg_tablesize >= 0) ? setup_sg_tablesize : SG_TABLESIZE;
 226
 227        if (setup_hostid >= 0)
 228                tpnt->this_id = setup_hostid;
 229        else {
 230                /* use 7 as default */
 231                tpnt->this_id = 7;
 232        }
 233
 234        ioaddr = (unsigned long)ioremap(IOBASE_SUN3_SCSI, PAGE_SIZE);
 235        sun3_scsi_regp = (unsigned char *)ioaddr;
 236
 237        dregs = (struct sun3_dma_regs *)(((unsigned char *)ioaddr) + 8);
 238
 239        if((udc_regs = dvma_malloc(sizeof(struct sun3_udc_regs)))
 240           == NULL) {
 241             printk("SUN3 Scsi couldn't allocate DVMA memory!\n");
 242             return 0;
 243        }
 244#ifdef OLDDMA
 245        if((dmabuf = dvma_malloc_align(SUN3_DVMA_BUFSIZE, 0x10000)) == NULL) {
 246             printk("SUN3 Scsi couldn't allocate DVMA memory!\n");
 247             return 0;
 248        }
 249#endif
 250#ifdef SUPPORT_TAGS
 251        if (setup_use_tagged_queuing < 0)
 252                setup_use_tagged_queuing = USE_TAGGED_QUEUING;
 253#endif
 254
 255        instance = scsi_register (tpnt, sizeof(struct NCR5380_hostdata));
 256        if(instance == NULL)
 257                return 0;
 258                
 259        default_instance = instance;
 260
 261        instance->io_port = (unsigned long) ioaddr;
 262        instance->irq = IRQ_SUN3_SCSI;
 263
 264        NCR5380_init(instance, 0);
 265
 266        instance->n_io_port = 32;
 267
 268        ((struct NCR5380_hostdata *)instance->hostdata)->ctrl = 0;
 269
 270        if (request_irq(instance->irq, scsi_sun3_intr,
 271                             0, "Sun3SCSI-5380", instance)) {
 272#ifndef REAL_DMA
 273                printk("scsi%d: IRQ%d not free, interrupts disabled\n",
 274                       instance->host_no, instance->irq);
 275                instance->irq = SCSI_IRQ_NONE;
 276#else
 277                printk("scsi%d: IRQ%d not free, bailing out\n",
 278                       instance->host_no, instance->irq);
 279                return 0;
 280#endif
 281        }
 282        
 283        printk("scsi%d: Sun3 5380 at port %lX irq", instance->host_no, instance->io_port);
 284        if (instance->irq == SCSI_IRQ_NONE)
 285                printk ("s disabled");
 286        else
 287                printk (" %d", instance->irq);
 288        printk(" options CAN_QUEUE=%d CMD_PER_LUN=%d release=%d",
 289               instance->can_queue, instance->cmd_per_lun,
 290               SUN3SCSI_PUBLIC_RELEASE);
 291        printk("\nscsi%d:", instance->host_no);
 292        NCR5380_print_options(instance);
 293        printk("\n");
 294
 295        dregs->csr = 0;
 296        udelay(SUN3_DMA_DELAY);
 297        dregs->csr = CSR_SCSI | CSR_FIFO | CSR_INTR;
 298        udelay(SUN3_DMA_DELAY);
 299        dregs->fifo_count = 0;
 300
 301        called = 1;
 302
 303#ifdef RESET_BOOT
 304        sun3_scsi_reset_boot(instance);
 305#endif
 306
 307        return 1;
 308}
 309
 310int sun3scsi_release (struct Scsi_Host *shpnt)
 311{
 312        if (shpnt->irq != SCSI_IRQ_NONE)
 313                free_irq(shpnt->irq, shpnt);
 314
 315        iounmap((void *)sun3_scsi_regp);
 316
 317        return 0;
 318}
 319
 320#ifdef RESET_BOOT
 321/*
 322 * Our 'bus reset on boot' function
 323 */
 324
 325static void sun3_scsi_reset_boot(struct Scsi_Host *instance)
 326{
 327        unsigned long end;
 328
 329        NCR5380_local_declare();
 330        NCR5380_setup(instance);
 331        
 332        /*
 333         * Do a SCSI reset to clean up the bus during initialization. No
 334         * messing with the queues, interrupts, or locks necessary here.
 335         */
 336
 337        printk( "Sun3 SCSI: resetting the SCSI bus..." );
 338
 339        /* switch off SCSI IRQ - catch an interrupt without IRQ bit set else */
 340//              sun3_disable_irq( IRQ_SUN3_SCSI );
 341
 342        /* get in phase */
 343        NCR5380_write( TARGET_COMMAND_REG,
 344                      PHASE_SR_TO_TCR( NCR5380_read(STATUS_REG) ));
 345
 346        /* assert RST */
 347        NCR5380_write( INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_RST );
 348
 349        /* The min. reset hold time is 25us, so 40us should be enough */
 350        udelay( 50 );
 351
 352        /* reset RST and interrupt */
 353        NCR5380_write( INITIATOR_COMMAND_REG, ICR_BASE );
 354        NCR5380_read( RESET_PARITY_INTERRUPT_REG );
 355
 356        for( end = jiffies + AFTER_RESET_DELAY; time_before(jiffies, end); )
 357                barrier();
 358
 359        /* switch on SCSI IRQ again */
 360//              sun3_enable_irq( IRQ_SUN3_SCSI );
 361
 362        printk( " done\n" );
 363}
 364#endif
 365
 366const char * sun3scsi_info (struct Scsi_Host *spnt) {
 367    return "";
 368}
 369
 370// safe bits for the CSR
 371#define CSR_GOOD 0x060f
 372
 373static irqreturn_t scsi_sun3_intr(int irq, void *dummy)
 374{
 375        unsigned short csr = dregs->csr;
 376        int handled = 0;
 377
 378        if(csr & ~CSR_GOOD) {
 379                if(csr & CSR_DMA_BUSERR) {
 380                        printk("scsi%d: bus error in dma\n", default_instance->host_no);
 381                }
 382
 383                if(csr & CSR_DMA_CONFLICT) {
 384                        printk("scsi%d: dma conflict\n", default_instance->host_no);
 385                }
 386                handled = 1;
 387        }
 388
 389        if(csr & (CSR_SDB_INT | CSR_DMA_INT)) {
 390                NCR5380_intr(irq, dummy);
 391                handled = 1;
 392        }
 393
 394        return IRQ_RETVAL(handled);
 395}
 396
 397/*
 398 * Debug stuff - to be called on NMI, or sysrq key. Use at your own risk; 
 399 * reentering NCR5380_print_status seems to have ugly side effects
 400 */
 401
 402/* this doesn't seem to get used at all -- sam */
 403#if 0
 404void sun3_sun3_debug (void)
 405{
 406        unsigned long flags;
 407        NCR5380_local_declare();
 408
 409        if (default_instance) {
 410                        local_irq_save(flags);
 411                        NCR5380_print_status(default_instance);
 412                        local_irq_restore(flags);
 413        }
 414}
 415#endif
 416
 417
 418/* sun3scsi_dma_setup() -- initialize the dma controller for a read/write */
 419static unsigned long sun3scsi_dma_setup(void *data, unsigned long count, int write_flag)
 420{
 421#ifdef OLDDMA
 422        if(write_flag) 
 423                memcpy(dmabuf, data, count);
 424        else {
 425                sun3_dma_orig_addr = data;
 426                sun3_dma_orig_count = count;
 427        }
 428#else
 429        void *addr;
 430
 431        if(sun3_dma_orig_addr != NULL)
 432                dvma_unmap(sun3_dma_orig_addr);
 433
 434//      addr = sun3_dvma_page((unsigned long)data, (unsigned long)dmabuf);
 435        addr = (void *)dvma_map((unsigned long) data, count);
 436                
 437        sun3_dma_orig_addr = addr;
 438        sun3_dma_orig_count = count;
 439#endif
 440        dregs->fifo_count = 0;
 441        sun3_udc_write(UDC_RESET, UDC_CSR);
 442        
 443        /* reset fifo */
 444        dregs->csr &= ~CSR_FIFO;
 445        dregs->csr |= CSR_FIFO;
 446        
 447        /* set direction */
 448        if(write_flag)
 449                dregs->csr |= CSR_SEND;
 450        else
 451                dregs->csr &= ~CSR_SEND;
 452        
 453        /* byte count for fifo */
 454        dregs->fifo_count = count;
 455
 456        sun3_udc_write(UDC_RESET, UDC_CSR);
 457        
 458        /* reset fifo */
 459        dregs->csr &= ~CSR_FIFO;
 460        dregs->csr |= CSR_FIFO;
 461        
 462        if(dregs->fifo_count != count) { 
 463                printk("scsi%d: fifo_mismatch %04x not %04x\n",
 464                       default_instance->host_no, dregs->fifo_count,
 465                       (unsigned int) count);
 466                NCR5380_print(default_instance);
 467        }
 468
 469        /* setup udc */
 470#ifdef OLDDMA
 471        udc_regs->addr_hi = ((dvma_vtob(dmabuf) & 0xff0000) >> 8);
 472        udc_regs->addr_lo = (dvma_vtob(dmabuf) & 0xffff);
 473#else
 474        udc_regs->addr_hi = (((unsigned long)(addr) & 0xff0000) >> 8);
 475        udc_regs->addr_lo = ((unsigned long)(addr) & 0xffff);
 476#endif
 477        udc_regs->count = count/2; /* count in words */
 478        udc_regs->mode_hi = UDC_MODE_HIWORD;
 479        if(write_flag) {
 480                if(count & 1)
 481                        udc_regs->count++;
 482                udc_regs->mode_lo = UDC_MODE_LSEND;
 483                udc_regs->rsel = UDC_RSEL_SEND;
 484        } else {
 485                udc_regs->mode_lo = UDC_MODE_LRECV;
 486                udc_regs->rsel = UDC_RSEL_RECV;
 487        }
 488        
 489        /* announce location of regs block */
 490        sun3_udc_write(((dvma_vtob(udc_regs) & 0xff0000) >> 8),
 491                       UDC_CHN_HI); 
 492
 493        sun3_udc_write((dvma_vtob(udc_regs) & 0xffff), UDC_CHN_LO);
 494
 495        /* set dma master on */
 496        sun3_udc_write(0xd, UDC_MODE);
 497
 498        /* interrupt enable */
 499        sun3_udc_write(UDC_INT_ENABLE, UDC_CSR);
 500        
 501        return count;
 502
 503}
 504
 505static inline unsigned long sun3scsi_dma_count(struct Scsi_Host *instance)
 506{
 507        unsigned short resid;
 508
 509        dregs->udc_addr = 0x32; 
 510        udelay(SUN3_DMA_DELAY);
 511        resid = dregs->udc_data;
 512        udelay(SUN3_DMA_DELAY);
 513        resid *= 2;
 514
 515        return (unsigned long) resid;
 516}
 517
 518static inline unsigned long sun3scsi_dma_residual(struct Scsi_Host *instance)
 519{
 520        return last_residual;
 521}
 522
 523static inline unsigned long sun3scsi_dma_xfer_len(unsigned long wanted,
 524                                                  struct scsi_cmnd *cmd,
 525                                                  int write_flag)
 526{
 527        if(blk_fs_request(cmd->request))
 528                return wanted;
 529        else
 530                return 0;
 531}
 532
 533static inline int sun3scsi_dma_start(unsigned long count, unsigned char *data)
 534{
 535
 536    sun3_udc_write(UDC_CHN_START, UDC_CSR);
 537    
 538    return 0;
 539}
 540
 541/* clean up after our dma is done */
 542static int sun3scsi_dma_finish(int write_flag)
 543{
 544        unsigned short count;
 545        unsigned short fifo;
 546        int ret = 0;
 547        
 548        sun3_dma_active = 0;
 549#if 1
 550        // check to empty the fifo on a read
 551        if(!write_flag) {
 552                int tmo = 20000; /* .2 sec */
 553                
 554                while(1) {
 555                        if(dregs->csr & CSR_FIFO_EMPTY)
 556                                break;
 557
 558                        if(--tmo <= 0) {
 559                                printk("sun3scsi: fifo failed to empty!\n");
 560                                return 1;
 561                        }
 562                        udelay(10);
 563                }
 564        }
 565                
 566#endif
 567
 568        count = sun3scsi_dma_count(default_instance);
 569#ifdef OLDDMA
 570
 571        /* if we've finished a read, copy out the data we read */
 572        if(sun3_dma_orig_addr) {
 573                /* check for residual bytes after dma end */
 574                if(count && (NCR5380_read(BUS_AND_STATUS_REG) &
 575                             (BASR_PHASE_MATCH | BASR_ACK))) {
 576                        printk("scsi%d: sun3_scsi_finish: read overrun baby... ", default_instance->host_no);
 577                        printk("basr now %02x\n", NCR5380_read(BUS_AND_STATUS_REG));
 578                        ret = count;
 579                }
 580                
 581                /* copy in what we dma'd no matter what */
 582                memcpy(sun3_dma_orig_addr, dmabuf, sun3_dma_orig_count);
 583                sun3_dma_orig_addr = NULL;
 584
 585        }
 586#else
 587
 588        fifo = dregs->fifo_count;
 589        last_residual = fifo;
 590
 591        /* empty bytes from the fifo which didn't make it */
 592        if((!write_flag) && (count - fifo) == 2) {
 593                unsigned short data;
 594                unsigned char *vaddr;
 595
 596                data = dregs->fifo_data;
 597                vaddr = (unsigned char *)dvma_btov(sun3_dma_orig_addr);
 598                
 599                vaddr += (sun3_dma_orig_count - fifo);
 600
 601                vaddr[-2] = (data & 0xff00) >> 8;
 602                vaddr[-1] = (data & 0xff);
 603        }
 604
 605        dvma_unmap(sun3_dma_orig_addr);
 606        sun3_dma_orig_addr = NULL;
 607#endif
 608        sun3_udc_write(UDC_RESET, UDC_CSR);
 609        dregs->fifo_count = 0;
 610        dregs->csr &= ~CSR_SEND;
 611
 612        /* reset fifo */
 613        dregs->csr &= ~CSR_FIFO;
 614        dregs->csr |= CSR_FIFO;
 615        
 616        sun3_dma_setup_done = NULL;
 617
 618        return ret;
 619
 620}
 621        
 622#include "sun3_NCR5380.c"
 623
 624static struct scsi_host_template driver_template = {
 625        .name                   = SUN3_SCSI_NAME,
 626        .detect                 = sun3scsi_detect,
 627        .release                = sun3scsi_release,
 628        .info                   = sun3scsi_info,
 629        .queuecommand           = sun3scsi_queue_command,
 630        .eh_abort_handler       = sun3scsi_abort,
 631        .eh_bus_reset_handler   = sun3scsi_bus_reset,
 632        .can_queue              = CAN_QUEUE,
 633        .this_id                = 7,
 634        .sg_tablesize           = SG_TABLESIZE,
 635        .cmd_per_lun            = CMD_PER_LUN,
 636        .use_clustering         = DISABLE_CLUSTERING
 637};
 638
 639
 640#include "scsi_module.c"
 641
 642MODULE_LICENSE("GPL");
 643