linux/drivers/scsi/sun3_scsi_vme.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 * VME support added by Sam Creasey
   7 *
   8 * Adapted from sun3_scsi.c -- see there for other headers
   9 *
  10 * TODO: modify this driver to support multiple Sun3 SCSI VME boards
  11 *
  12 */
  13
  14#define AUTOSENSE
  15
  16#include <linux/types.h>
  17#include <linux/stddef.h>
  18#include <linux/ctype.h>
  19#include <linux/delay.h>
  20
  21#include <linux/module.h>
  22#include <linux/signal.h>
  23#include <linux/ioport.h>
  24#include <linux/init.h>
  25#include <linux/blkdev.h>
  26
  27#include <asm/io.h>
  28
  29#include <asm/sun3ints.h>
  30#include <asm/dvma.h>
  31#include <asm/idprom.h>
  32#include <asm/machines.h>
  33
  34#define SUN3_SCSI_VME
  35
  36#undef SUN3_SCSI_DEBUG
  37
  38/* dma on! */
  39#define REAL_DMA
  40
  41#define NDEBUG 0
  42
  43#define NDEBUG_ABORT            0x00100000
  44#define NDEBUG_TAGS             0x00200000
  45#define NDEBUG_MERGING          0x00400000
  46
  47#include "scsi.h"
  48#include "initio.h"
  49#include <scsi/scsi_host.h>
  50#include "sun3_scsi.h"
  51
  52extern int sun3_map_test(unsigned long, char *);
  53
  54#define USE_WRAPPER
  55/*#define RESET_BOOT */
  56#define DRIVER_SETUP
  57
  58/*
  59 * BUG can be used to trigger a strange code-size related hang on 2.1 kernels
  60 */
  61#ifdef BUG
  62#undef RESET_BOOT
  63#undef DRIVER_SETUP
  64#endif
  65
  66/* #define SUPPORT_TAGS */
  67
  68//#define       ENABLE_IRQ()    enable_irq( SUN3_VEC_VMESCSI0 ); 
  69#define ENABLE_IRQ()
  70
  71
  72static irqreturn_t scsi_sun3_intr(int irq, void *dummy);
  73static inline unsigned char sun3scsi_read(int reg);
  74static inline void sun3scsi_write(int reg, int value);
  75
  76static int setup_can_queue = -1;
  77module_param(setup_can_queue, int, 0);
  78static int setup_cmd_per_lun = -1;
  79module_param(setup_cmd_per_lun, int, 0);
  80static int setup_sg_tablesize = -1;
  81module_param(setup_sg_tablesize, int, 0);
  82#ifdef SUPPORT_TAGS
  83static int setup_use_tagged_queuing = -1;
  84module_param(setup_use_tagged_queuing, int, 0);
  85#endif
  86static int setup_hostid = -1;
  87module_param(setup_hostid, int, 0);
  88
  89static struct scsi_cmnd *sun3_dma_setup_done = NULL;
  90
  91#define AFTER_RESET_DELAY       (HZ/2)
  92
  93/* ms to wait after hitting dma regs */
  94#define SUN3_DMA_DELAY 10
  95
  96/* dvma buffer to allocate -- 32k should hopefully be more than sufficient */
  97#define SUN3_DVMA_BUFSIZE 0xe000
  98
  99/* minimum number of bytes to do dma on */
 100#define SUN3_DMA_MINSIZE 128
 101
 102static volatile unsigned char *sun3_scsi_regp;
 103static volatile struct sun3_dma_regs *dregs;
 104#ifdef OLDDMA
 105static unsigned char *dmabuf = NULL; /* dma memory buffer */
 106#endif
 107static unsigned char *sun3_dma_orig_addr = NULL;
 108static unsigned long sun3_dma_orig_count = 0;
 109static int sun3_dma_active = 0;
 110static unsigned long last_residual = 0;
 111
 112/*
 113 * NCR 5380 register access functions
 114 */
 115
 116static inline unsigned char sun3scsi_read(int reg)
 117{
 118        return( sun3_scsi_regp[reg] );
 119}
 120
 121static inline void sun3scsi_write(int reg, int value)
 122{
 123        sun3_scsi_regp[reg] = value;
 124}
 125
 126/*
 127 * XXX: status debug
 128 */
 129static struct Scsi_Host *default_instance;
 130
 131/*
 132 * Function : int sun3scsi_detect(struct scsi_host_template * tpnt)
 133 *
 134 * Purpose : initializes mac NCR5380 driver based on the
 135 *      command line / compile time port and irq definitions.
 136 *
 137 * Inputs : tpnt - template for this SCSI adapter.
 138 *
 139 * Returns : 1 if a host adapter was found, 0 if not.
 140 *
 141 */
 142 
 143static int __init sun3scsi_detect(struct scsi_host_template * tpnt)
 144{
 145        unsigned long ioaddr, irq = 0;
 146        static int called = 0;
 147        struct Scsi_Host *instance;
 148        int i;
 149        unsigned long addrs[3] = { IOBASE_SUN3_VMESCSI, 
 150                                   IOBASE_SUN3_VMESCSI + 0x4000,
 151                                   0 };
 152        unsigned long vecs[3] = { SUN3_VEC_VMESCSI0,
 153                                  SUN3_VEC_VMESCSI1,
 154                                  0 };
 155        /* check that this machine has an onboard 5380 */
 156        switch(idprom->id_machtype) {
 157        case SM_SUN3|SM_3_160:
 158        case SM_SUN3|SM_3_260:
 159                break;
 160
 161        default:
 162                return 0;
 163        }
 164
 165        if(called)
 166                return 0;
 167
 168        tpnt->proc_name = "Sun3 5380 VME SCSI";
 169
 170        /* setup variables */
 171        tpnt->can_queue =
 172                (setup_can_queue > 0) ? setup_can_queue : CAN_QUEUE;
 173        tpnt->cmd_per_lun =
 174                (setup_cmd_per_lun > 0) ? setup_cmd_per_lun : CMD_PER_LUN;
 175        tpnt->sg_tablesize = 
 176                (setup_sg_tablesize >= 0) ? setup_sg_tablesize : SG_TABLESIZE;
 177        
 178        if (setup_hostid >= 0)
 179                tpnt->this_id = setup_hostid;
 180        else {
 181                /* use 7 as default */
 182                tpnt->this_id = 7;
 183        }
 184        
 185        ioaddr = 0;
 186        for(i = 0; addrs[i] != 0; i++) {
 187                unsigned char x;
 188                
 189                ioaddr = (unsigned long)sun3_ioremap(addrs[i], PAGE_SIZE,
 190                                                     SUN3_PAGE_TYPE_VME16);
 191                irq = vecs[i];
 192                sun3_scsi_regp = (unsigned char *)ioaddr;
 193                
 194                dregs = (struct sun3_dma_regs *)(((unsigned char *)ioaddr) + 8);
 195                
 196                if(sun3_map_test((unsigned long)dregs, &x)) {
 197                        unsigned short oldcsr;
 198
 199                        oldcsr = dregs->csr;
 200                        dregs->csr = 0;
 201                        udelay(SUN3_DMA_DELAY);
 202                        if(dregs->csr == 0x1400)
 203                                break;
 204                        
 205                        dregs->csr = oldcsr;
 206                }
 207
 208                iounmap((void *)ioaddr);
 209                ioaddr = 0;
 210        }
 211
 212        if(!ioaddr)
 213                return 0;
 214        
 215#ifdef SUPPORT_TAGS
 216        if (setup_use_tagged_queuing < 0)
 217                setup_use_tagged_queuing = USE_TAGGED_QUEUING;
 218#endif
 219
 220        instance = scsi_register (tpnt, sizeof(struct NCR5380_hostdata));
 221        if(instance == NULL)
 222                return 0;
 223                
 224        default_instance = instance;
 225
 226        instance->io_port = (unsigned long) ioaddr;
 227        instance->irq = irq;
 228
 229        NCR5380_init(instance, 0);
 230
 231        instance->n_io_port = 32;
 232
 233        ((struct NCR5380_hostdata *)instance->hostdata)->ctrl = 0;
 234
 235        if (request_irq(instance->irq, scsi_sun3_intr,
 236                        0, "Sun3SCSI-5380VME", instance)) {
 237#ifndef REAL_DMA
 238                printk("scsi%d: IRQ%d not free, interrupts disabled\n",
 239                       instance->host_no, instance->irq);
 240                instance->irq = SCSI_IRQ_NONE;
 241#else
 242                printk("scsi%d: IRQ%d not free, bailing out\n",
 243                       instance->host_no, instance->irq);
 244                return 0;
 245#endif
 246        }
 247
 248        printk("scsi%d: Sun3 5380 VME at port %lX irq", instance->host_no, instance->io_port);
 249        if (instance->irq == SCSI_IRQ_NONE)
 250                printk ("s disabled");
 251        else
 252                printk (" %d", instance->irq);
 253        printk(" options CAN_QUEUE=%d CMD_PER_LUN=%d release=%d",
 254               instance->can_queue, instance->cmd_per_lun,
 255               SUN3SCSI_PUBLIC_RELEASE);
 256        printk("\nscsi%d:", instance->host_no);
 257        NCR5380_print_options(instance);
 258        printk("\n");
 259
 260        dregs->csr = 0;
 261        udelay(SUN3_DMA_DELAY);
 262        dregs->csr = CSR_SCSI | CSR_FIFO | CSR_INTR;
 263        udelay(SUN3_DMA_DELAY);
 264        dregs->fifo_count = 0;
 265        dregs->fifo_count_hi = 0;
 266        dregs->dma_addr_hi = 0;
 267        dregs->dma_addr_lo = 0;
 268        dregs->dma_count_hi = 0;
 269        dregs->dma_count_lo = 0;
 270
 271        dregs->ivect = VME_DATA24 | (instance->irq & 0xff);
 272
 273        called = 1;
 274
 275#ifdef RESET_BOOT
 276        sun3_scsi_reset_boot(instance);
 277#endif
 278
 279        return 1;
 280}
 281
 282int sun3scsi_release (struct Scsi_Host *shpnt)
 283{
 284        if (shpnt->irq != SCSI_IRQ_NONE)
 285                free_irq(shpnt->irq, shpnt);
 286
 287        iounmap((void *)sun3_scsi_regp);
 288
 289        NCR5380_exit(shpnt);
 290        return 0;
 291}
 292
 293#ifdef RESET_BOOT
 294/*
 295 * Our 'bus reset on boot' function
 296 */
 297
 298static void sun3_scsi_reset_boot(struct Scsi_Host *instance)
 299{
 300        unsigned long end;
 301
 302        NCR5380_local_declare();
 303        NCR5380_setup(instance);
 304        
 305        /*
 306         * Do a SCSI reset to clean up the bus during initialization. No
 307         * messing with the queues, interrupts, or locks necessary here.
 308         */
 309
 310        printk( "Sun3 SCSI: resetting the SCSI bus..." );
 311
 312        /* switch off SCSI IRQ - catch an interrupt without IRQ bit set else */
 313//              sun3_disable_irq( IRQ_SUN3_SCSI );
 314
 315        /* get in phase */
 316        NCR5380_write( TARGET_COMMAND_REG,
 317                      PHASE_SR_TO_TCR( NCR5380_read(STATUS_REG) ));
 318
 319        /* assert RST */
 320        NCR5380_write( INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_RST );
 321
 322        /* The min. reset hold time is 25us, so 40us should be enough */
 323        udelay( 50 );
 324
 325        /* reset RST and interrupt */
 326        NCR5380_write( INITIATOR_COMMAND_REG, ICR_BASE );
 327        NCR5380_read( RESET_PARITY_INTERRUPT_REG );
 328
 329        for( end = jiffies + AFTER_RESET_DELAY; time_before(jiffies, end); )
 330                barrier();
 331
 332        /* switch on SCSI IRQ again */
 333//              sun3_enable_irq( IRQ_SUN3_SCSI );
 334
 335        printk( " done\n" );
 336}
 337#endif
 338
 339static const char * sun3scsi_info (struct Scsi_Host *spnt) {
 340    return "";
 341}
 342
 343// safe bits for the CSR
 344#define CSR_GOOD 0x060f
 345
 346static irqreturn_t scsi_sun3_intr(int irq, void *dummy)
 347{
 348        unsigned short csr = dregs->csr;
 349        int handled = 0;
 350
 351        dregs->csr &= ~CSR_DMA_ENABLE;
 352
 353
 354#ifdef SUN3_SCSI_DEBUG
 355        printk("scsi_intr csr %x\n", csr);
 356#endif
 357
 358        if(csr & ~CSR_GOOD) {
 359                if(csr & CSR_DMA_BUSERR) {
 360                        printk("scsi%d: bus error in dma\n", default_instance->host_no);
 361#ifdef SUN3_SCSI_DEBUG
 362                        printk("scsi: residual %x count %x addr %p dmaaddr %x\n", 
 363                               dregs->fifo_count,
 364                               dregs->dma_count_lo | (dregs->dma_count_hi << 16),
 365                               sun3_dma_orig_addr,
 366                               dregs->dma_addr_lo | (dregs->dma_addr_hi << 16));
 367#endif
 368                }
 369
 370                if(csr & CSR_DMA_CONFLICT) {
 371                        printk("scsi%d: dma conflict\n", default_instance->host_no);
 372                }
 373                handled = 1;
 374        }
 375
 376        if(csr & (CSR_SDB_INT | CSR_DMA_INT)) {
 377                NCR5380_intr(irq, dummy);
 378                handled = 1;
 379        }
 380
 381        return IRQ_RETVAL(handled);
 382}
 383
 384/*
 385 * Debug stuff - to be called on NMI, or sysrq key. Use at your own risk; 
 386 * reentering NCR5380_print_status seems to have ugly side effects
 387 */
 388
 389/* this doesn't seem to get used at all -- sam */
 390#if 0
 391void sun3_sun3_debug (void)
 392{
 393        unsigned long flags;
 394        NCR5380_local_declare();
 395
 396        if (default_instance) {
 397                        local_irq_save(flags);
 398                        NCR5380_print_status(default_instance);
 399                        local_irq_restore(flags);
 400        }
 401}
 402#endif
 403
 404
 405/* sun3scsi_dma_setup() -- initialize the dma controller for a read/write */
 406static unsigned long sun3scsi_dma_setup(void *data, unsigned long count, int write_flag)
 407{
 408        void *addr;
 409
 410        if(sun3_dma_orig_addr != NULL)
 411                dvma_unmap(sun3_dma_orig_addr);
 412
 413//      addr = sun3_dvma_page((unsigned long)data, (unsigned long)dmabuf);
 414        addr = (void *)dvma_map_vme((unsigned long) data, count);
 415                
 416        sun3_dma_orig_addr = addr;
 417        sun3_dma_orig_count = count;
 418        
 419#ifdef SUN3_SCSI_DEBUG
 420        printk("scsi: dma_setup addr %p count %x\n", addr, count);
 421#endif
 422
 423//      dregs->fifo_count = 0;
 424#if 0   
 425        /* reset fifo */
 426        dregs->csr &= ~CSR_FIFO;
 427        dregs->csr |= CSR_FIFO;
 428#endif  
 429        /* set direction */
 430        if(write_flag)
 431                dregs->csr |= CSR_SEND;
 432        else
 433                dregs->csr &= ~CSR_SEND;
 434        
 435        /* reset fifo */
 436//      dregs->csr &= ~CSR_FIFO;
 437//      dregs->csr |= CSR_FIFO;
 438
 439        dregs->csr |= CSR_PACK_ENABLE;
 440
 441        dregs->dma_addr_hi = ((unsigned long)addr >> 16);
 442        dregs->dma_addr_lo = ((unsigned long)addr & 0xffff);
 443        
 444        dregs->dma_count_hi = 0;
 445        dregs->dma_count_lo = 0;
 446        dregs->fifo_count_hi = 0;
 447        dregs->fifo_count = 0;
 448                
 449#ifdef SUN3_SCSI_DEBUG
 450        printk("scsi: dma_setup done csr %x\n", dregs->csr);
 451#endif
 452        return count;
 453
 454}
 455
 456static inline unsigned long sun3scsi_dma_residual(struct Scsi_Host *instance)
 457{
 458        return last_residual;
 459}
 460
 461static inline unsigned long sun3scsi_dma_xfer_len(unsigned long wanted,
 462                                                  struct scsi_cmnd *cmd,
 463                                                  int write_flag)
 464{
 465        if (cmd->request->cmd_type == REQ_TYPE_FS)
 466                return wanted;
 467        else
 468                return 0;
 469}
 470
 471static int sun3scsi_dma_start(unsigned long count, char *data)
 472{
 473        
 474        unsigned short csr;
 475
 476        csr = dregs->csr;
 477#ifdef SUN3_SCSI_DEBUG
 478        printk("scsi: dma_start data %p count %x csr %x fifo %x\n", data, count, csr, dregs->fifo_count);
 479#endif
 480        
 481        dregs->dma_count_hi = (sun3_dma_orig_count >> 16);
 482        dregs->dma_count_lo = (sun3_dma_orig_count & 0xffff);
 483
 484        dregs->fifo_count_hi = (sun3_dma_orig_count >> 16);
 485        dregs->fifo_count = (sun3_dma_orig_count & 0xffff);
 486
 487//      if(!(csr & CSR_DMA_ENABLE))
 488//              dregs->csr |= CSR_DMA_ENABLE;
 489
 490        return 0;
 491}
 492
 493/* clean up after our dma is done */
 494static int sun3scsi_dma_finish(int write_flag)
 495{
 496        unsigned short fifo;
 497        int ret = 0;
 498        
 499        sun3_dma_active = 0;
 500
 501        dregs->csr &= ~CSR_DMA_ENABLE;
 502        
 503        fifo = dregs->fifo_count;
 504        if(write_flag) {
 505                if((fifo > 0) && (fifo < sun3_dma_orig_count))
 506                        fifo++;
 507        }
 508
 509        last_residual = fifo;
 510#ifdef SUN3_SCSI_DEBUG
 511        printk("scsi: residual %x total %x\n", fifo, sun3_dma_orig_count);
 512#endif
 513        /* empty bytes from the fifo which didn't make it */
 514        if((!write_flag) && (dregs->csr & CSR_LEFT)) {
 515                unsigned char *vaddr;
 516
 517#ifdef SUN3_SCSI_DEBUG
 518                printk("scsi: got left over bytes\n");
 519#endif
 520
 521                vaddr = (unsigned char *)dvma_vmetov(sun3_dma_orig_addr);
 522                
 523                vaddr += (sun3_dma_orig_count - fifo);
 524                vaddr--;
 525                
 526                switch(dregs->csr & CSR_LEFT) {
 527                case CSR_LEFT_3:
 528                        *vaddr = (dregs->bpack_lo & 0xff00) >> 8;
 529                        vaddr--;
 530                        
 531                case CSR_LEFT_2:
 532                        *vaddr = (dregs->bpack_hi & 0x00ff);
 533                        vaddr--;
 534                        
 535                case CSR_LEFT_1:
 536                        *vaddr = (dregs->bpack_hi & 0xff00) >> 8;
 537                        break;
 538                }
 539                
 540                
 541        }
 542
 543        dvma_unmap(sun3_dma_orig_addr);
 544        sun3_dma_orig_addr = NULL;
 545
 546        dregs->dma_addr_hi = 0;
 547        dregs->dma_addr_lo = 0;
 548        dregs->dma_count_hi = 0;
 549        dregs->dma_count_lo = 0;
 550
 551        dregs->fifo_count = 0;
 552        dregs->fifo_count_hi = 0;
 553
 554        dregs->csr &= ~CSR_SEND;
 555        
 556//      dregs->csr |= CSR_DMA_ENABLE;
 557        
 558#if 0
 559        /* reset fifo */
 560        dregs->csr &= ~CSR_FIFO;
 561        dregs->csr |= CSR_FIFO;
 562#endif  
 563        sun3_dma_setup_done = NULL;
 564
 565        return ret;
 566
 567}
 568
 569#include "sun3_NCR5380.c"
 570
 571static struct scsi_host_template driver_template = {
 572        .name                   = SUN3_SCSI_NAME,
 573        .detect                 = sun3scsi_detect,
 574        .release                = sun3scsi_release,
 575        .info                   = sun3scsi_info,
 576        .queuecommand           = sun3scsi_queue_command,
 577        .eh_abort_handler       = sun3scsi_abort,
 578        .eh_bus_reset_handler   = sun3scsi_bus_reset,
 579        .can_queue              = CAN_QUEUE,
 580        .this_id                = 7,
 581        .sg_tablesize           = SG_TABLESIZE,
 582        .cmd_per_lun            = CMD_PER_LUN,
 583        .use_clustering         = DISABLE_CLUSTERING
 584};
 585
 586
 587#include "scsi_module.c"
 588
 589MODULE_LICENSE("GPL");
 590