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