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 * VME support added by Sam Creasey
   7 *
   8 * TODO: modify this driver to support multiple Sun3 SCSI VME boards
   9 *
  10 * Adapted from mac_scsinew.c:
  11 */
  12/*
  13 * Generic Macintosh NCR5380 driver
  14 *
  15 * Copyright 1998, Michael Schmitz <mschmitz@lbl.gov>
  16 *
  17 * derived in part from:
  18 */
  19/*
  20 * Generic Generic NCR5380 driver
  21 *
  22 * Copyright 1995, Russell King
  23 */
  24
  25#include <linux/types.h>
  26#include <linux/delay.h>
  27#include <linux/module.h>
  28#include <linux/ioport.h>
  29#include <linux/init.h>
  30#include <linux/blkdev.h>
  31#include <linux/platform_device.h>
  32
  33#include <asm/io.h>
  34#include <asm/dvma.h>
  35
  36#include <scsi/scsi_host.h>
  37#include "sun3_scsi.h"
  38
  39/* minimum number of bytes to do dma on */
  40#define DMA_MIN_SIZE                    129
  41
  42/* Definitions for the core NCR5380 driver. */
  43
  44#define NCR5380_implementation_fields   /* none */
  45
  46#define NCR5380_read(reg)               sun3scsi_read(reg)
  47#define NCR5380_write(reg, value)       sun3scsi_write(reg, value)
  48
  49#define NCR5380_queue_command           sun3scsi_queue_command
  50#define NCR5380_bus_reset               sun3scsi_bus_reset
  51#define NCR5380_abort                   sun3scsi_abort
  52#define NCR5380_info                    sun3scsi_info
  53
  54#define NCR5380_dma_recv_setup(instance, data, count) (count)
  55#define NCR5380_dma_send_setup(instance, data, count) (count)
  56#define NCR5380_dma_residual(instance) \
  57        sun3scsi_dma_residual(instance)
  58#define NCR5380_dma_xfer_len(instance, cmd, phase) \
  59        sun3scsi_dma_xfer_len(cmd->SCp.this_residual, cmd)
  60
  61#define NCR5380_acquire_dma_irq(instance)    (1)
  62#define NCR5380_release_dma_irq(instance)
  63
  64#include "NCR5380.h"
  65
  66
  67extern int sun3_map_test(unsigned long, char *);
  68
  69static int setup_can_queue = -1;
  70module_param(setup_can_queue, int, 0);
  71static int setup_cmd_per_lun = -1;
  72module_param(setup_cmd_per_lun, int, 0);
  73static int setup_sg_tablesize = -1;
  74module_param(setup_sg_tablesize, int, 0);
  75static int setup_hostid = -1;
  76module_param(setup_hostid, int, 0);
  77
  78/* ms to wait after hitting dma regs */
  79#define SUN3_DMA_DELAY 10
  80
  81/* dvma buffer to allocate -- 32k should hopefully be more than sufficient */
  82#define SUN3_DVMA_BUFSIZE 0xe000
  83
  84static struct scsi_cmnd *sun3_dma_setup_done;
  85static unsigned char *sun3_scsi_regp;
  86static volatile struct sun3_dma_regs *dregs;
  87static struct sun3_udc_regs *udc_regs;
  88static unsigned char *sun3_dma_orig_addr;
  89static unsigned long sun3_dma_orig_count;
  90static int sun3_dma_active;
  91static unsigned long last_residual;
  92
  93/*
  94 * NCR 5380 register access functions
  95 */
  96
  97static inline unsigned char sun3scsi_read(int reg)
  98{
  99        return in_8(sun3_scsi_regp + reg);
 100}
 101
 102static inline void sun3scsi_write(int reg, int value)
 103{
 104        out_8(sun3_scsi_regp + reg, value);
 105}
 106
 107#ifndef SUN3_SCSI_VME
 108/* dma controller register access functions */
 109
 110static inline unsigned short sun3_udc_read(unsigned char reg)
 111{
 112        unsigned short ret;
 113
 114        dregs->udc_addr = UDC_CSR;
 115        udelay(SUN3_DMA_DELAY);
 116        ret = dregs->udc_data;
 117        udelay(SUN3_DMA_DELAY);
 118        
 119        return ret;
 120}
 121
 122static inline void sun3_udc_write(unsigned short val, unsigned char reg)
 123{
 124        dregs->udc_addr = reg;
 125        udelay(SUN3_DMA_DELAY);
 126        dregs->udc_data = val;
 127        udelay(SUN3_DMA_DELAY);
 128}
 129#endif
 130
 131// safe bits for the CSR
 132#define CSR_GOOD 0x060f
 133
 134static irqreturn_t scsi_sun3_intr(int irq, void *dev)
 135{
 136        struct Scsi_Host *instance = dev;
 137        unsigned short csr = dregs->csr;
 138        int handled = 0;
 139
 140#ifdef SUN3_SCSI_VME
 141        dregs->csr &= ~CSR_DMA_ENABLE;
 142#endif
 143
 144        if(csr & ~CSR_GOOD) {
 145                if (csr & CSR_DMA_BUSERR)
 146                        shost_printk(KERN_ERR, instance, "bus error in DMA\n");
 147                if (csr & CSR_DMA_CONFLICT)
 148                        shost_printk(KERN_ERR, instance, "DMA conflict\n");
 149                handled = 1;
 150        }
 151
 152        if(csr & (CSR_SDB_INT | CSR_DMA_INT)) {
 153                NCR5380_intr(irq, dev);
 154                handled = 1;
 155        }
 156
 157        return IRQ_RETVAL(handled);
 158}
 159
 160/* sun3scsi_dma_setup() -- initialize the dma controller for a read/write */
 161static unsigned long sun3scsi_dma_setup(struct Scsi_Host *instance,
 162                                void *data, unsigned long count, int write_flag)
 163{
 164        void *addr;
 165
 166        if(sun3_dma_orig_addr != NULL)
 167                dvma_unmap(sun3_dma_orig_addr);
 168
 169#ifdef SUN3_SCSI_VME
 170        addr = (void *)dvma_map_vme((unsigned long) data, count);
 171#else
 172        addr = (void *)dvma_map((unsigned long) data, count);
 173#endif
 174                
 175        sun3_dma_orig_addr = addr;
 176        sun3_dma_orig_count = count;
 177
 178#ifndef SUN3_SCSI_VME
 179        dregs->fifo_count = 0;
 180        sun3_udc_write(UDC_RESET, UDC_CSR);
 181        
 182        /* reset fifo */
 183        dregs->csr &= ~CSR_FIFO;
 184        dregs->csr |= CSR_FIFO;
 185#endif
 186        
 187        /* set direction */
 188        if(write_flag)
 189                dregs->csr |= CSR_SEND;
 190        else
 191                dregs->csr &= ~CSR_SEND;
 192        
 193#ifdef SUN3_SCSI_VME
 194        dregs->csr |= CSR_PACK_ENABLE;
 195
 196        dregs->dma_addr_hi = ((unsigned long)addr >> 16);
 197        dregs->dma_addr_lo = ((unsigned long)addr & 0xffff);
 198
 199        dregs->dma_count_hi = 0;
 200        dregs->dma_count_lo = 0;
 201        dregs->fifo_count_hi = 0;
 202        dregs->fifo_count = 0;
 203#else
 204        /* byte count for fifo */
 205        dregs->fifo_count = count;
 206
 207        sun3_udc_write(UDC_RESET, UDC_CSR);
 208        
 209        /* reset fifo */
 210        dregs->csr &= ~CSR_FIFO;
 211        dregs->csr |= CSR_FIFO;
 212        
 213        if(dregs->fifo_count != count) { 
 214                shost_printk(KERN_ERR, instance, "FIFO mismatch %04x not %04x\n",
 215                             dregs->fifo_count, (unsigned int) count);
 216                NCR5380_dprint(NDEBUG_DMA, instance);
 217        }
 218
 219        /* setup udc */
 220        udc_regs->addr_hi = (((unsigned long)(addr) & 0xff0000) >> 8);
 221        udc_regs->addr_lo = ((unsigned long)(addr) & 0xffff);
 222        udc_regs->count = count/2; /* count in words */
 223        udc_regs->mode_hi = UDC_MODE_HIWORD;
 224        if(write_flag) {
 225                if(count & 1)
 226                        udc_regs->count++;
 227                udc_regs->mode_lo = UDC_MODE_LSEND;
 228                udc_regs->rsel = UDC_RSEL_SEND;
 229        } else {
 230                udc_regs->mode_lo = UDC_MODE_LRECV;
 231                udc_regs->rsel = UDC_RSEL_RECV;
 232        }
 233        
 234        /* announce location of regs block */
 235        sun3_udc_write(((dvma_vtob(udc_regs) & 0xff0000) >> 8),
 236                       UDC_CHN_HI); 
 237
 238        sun3_udc_write((dvma_vtob(udc_regs) & 0xffff), UDC_CHN_LO);
 239
 240        /* set dma master on */
 241        sun3_udc_write(0xd, UDC_MODE);
 242
 243        /* interrupt enable */
 244        sun3_udc_write(UDC_INT_ENABLE, UDC_CSR);
 245#endif
 246        
 247        return count;
 248
 249}
 250
 251static inline unsigned long sun3scsi_dma_residual(struct Scsi_Host *instance)
 252{
 253        return last_residual;
 254}
 255
 256static inline unsigned long sun3scsi_dma_xfer_len(unsigned long wanted_len,
 257                                                  struct scsi_cmnd *cmd)
 258{
 259        if (wanted_len < DMA_MIN_SIZE || cmd->request->cmd_type != REQ_TYPE_FS)
 260                return 0;
 261
 262        return wanted_len;
 263}
 264
 265static inline int sun3scsi_dma_start(unsigned long count, unsigned char *data)
 266{
 267#ifdef SUN3_SCSI_VME
 268        unsigned short csr;
 269
 270        csr = dregs->csr;
 271
 272        dregs->dma_count_hi = (sun3_dma_orig_count >> 16);
 273        dregs->dma_count_lo = (sun3_dma_orig_count & 0xffff);
 274
 275        dregs->fifo_count_hi = (sun3_dma_orig_count >> 16);
 276        dregs->fifo_count = (sun3_dma_orig_count & 0xffff);
 277
 278/*      if(!(csr & CSR_DMA_ENABLE))
 279 *              dregs->csr |= CSR_DMA_ENABLE;
 280 */
 281#else
 282    sun3_udc_write(UDC_CHN_START, UDC_CSR);
 283#endif
 284    
 285    return 0;
 286}
 287
 288/* clean up after our dma is done */
 289static int sun3scsi_dma_finish(int write_flag)
 290{
 291        unsigned short __maybe_unused count;
 292        unsigned short fifo;
 293        int ret = 0;
 294        
 295        sun3_dma_active = 0;
 296
 297#ifdef SUN3_SCSI_VME
 298        dregs->csr &= ~CSR_DMA_ENABLE;
 299
 300        fifo = dregs->fifo_count;
 301        if (write_flag) {
 302                if ((fifo > 0) && (fifo < sun3_dma_orig_count))
 303                        fifo++;
 304        }
 305
 306        last_residual = fifo;
 307        /* empty bytes from the fifo which didn't make it */
 308        if ((!write_flag) && (dregs->csr & CSR_LEFT)) {
 309                unsigned char *vaddr;
 310
 311                vaddr = (unsigned char *)dvma_vmetov(sun3_dma_orig_addr);
 312
 313                vaddr += (sun3_dma_orig_count - fifo);
 314                vaddr--;
 315
 316                switch (dregs->csr & CSR_LEFT) {
 317                case CSR_LEFT_3:
 318                        *vaddr = (dregs->bpack_lo & 0xff00) >> 8;
 319                        vaddr--;
 320
 321                case CSR_LEFT_2:
 322                        *vaddr = (dregs->bpack_hi & 0x00ff);
 323                        vaddr--;
 324
 325                case CSR_LEFT_1:
 326                        *vaddr = (dregs->bpack_hi & 0xff00) >> 8;
 327                        break;
 328                }
 329        }
 330#else
 331        // check to empty the fifo on a read
 332        if(!write_flag) {
 333                int tmo = 20000; /* .2 sec */
 334                
 335                while(1) {
 336                        if(dregs->csr & CSR_FIFO_EMPTY)
 337                                break;
 338
 339                        if(--tmo <= 0) {
 340                                printk("sun3scsi: fifo failed to empty!\n");
 341                                return 1;
 342                        }
 343                        udelay(10);
 344                }
 345        }
 346
 347        dregs->udc_addr = 0x32;
 348        udelay(SUN3_DMA_DELAY);
 349        count = 2 * dregs->udc_data;
 350        udelay(SUN3_DMA_DELAY);
 351
 352        fifo = dregs->fifo_count;
 353        last_residual = fifo;
 354
 355        /* empty bytes from the fifo which didn't make it */
 356        if((!write_flag) && (count - fifo) == 2) {
 357                unsigned short data;
 358                unsigned char *vaddr;
 359
 360                data = dregs->fifo_data;
 361                vaddr = (unsigned char *)dvma_btov(sun3_dma_orig_addr);
 362                
 363                vaddr += (sun3_dma_orig_count - fifo);
 364
 365                vaddr[-2] = (data & 0xff00) >> 8;
 366                vaddr[-1] = (data & 0xff);
 367        }
 368#endif
 369
 370        dvma_unmap(sun3_dma_orig_addr);
 371        sun3_dma_orig_addr = NULL;
 372
 373#ifdef SUN3_SCSI_VME
 374        dregs->dma_addr_hi = 0;
 375        dregs->dma_addr_lo = 0;
 376        dregs->dma_count_hi = 0;
 377        dregs->dma_count_lo = 0;
 378
 379        dregs->fifo_count = 0;
 380        dregs->fifo_count_hi = 0;
 381
 382        dregs->csr &= ~CSR_SEND;
 383/*      dregs->csr |= CSR_DMA_ENABLE; */
 384#else
 385        sun3_udc_write(UDC_RESET, UDC_CSR);
 386        dregs->fifo_count = 0;
 387        dregs->csr &= ~CSR_SEND;
 388
 389        /* reset fifo */
 390        dregs->csr &= ~CSR_FIFO;
 391        dregs->csr |= CSR_FIFO;
 392#endif
 393        
 394        sun3_dma_setup_done = NULL;
 395
 396        return ret;
 397
 398}
 399        
 400#include "NCR5380.c"
 401
 402#ifdef SUN3_SCSI_VME
 403#define SUN3_SCSI_NAME          "Sun3 NCR5380 VME SCSI"
 404#define DRV_MODULE_NAME         "sun3_scsi_vme"
 405#else
 406#define SUN3_SCSI_NAME          "Sun3 NCR5380 SCSI"
 407#define DRV_MODULE_NAME         "sun3_scsi"
 408#endif
 409
 410#define PFX                     DRV_MODULE_NAME ": "
 411
 412static struct scsi_host_template sun3_scsi_template = {
 413        .module                 = THIS_MODULE,
 414        .proc_name              = DRV_MODULE_NAME,
 415        .name                   = SUN3_SCSI_NAME,
 416        .info                   = sun3scsi_info,
 417        .queuecommand           = sun3scsi_queue_command,
 418        .eh_abort_handler       = sun3scsi_abort,
 419        .eh_bus_reset_handler   = sun3scsi_bus_reset,
 420        .can_queue              = 16,
 421        .this_id                = 7,
 422        .sg_tablesize           = SG_NONE,
 423        .cmd_per_lun            = 2,
 424        .use_clustering         = DISABLE_CLUSTERING,
 425        .cmd_size               = NCR5380_CMD_SIZE,
 426};
 427
 428static int __init sun3_scsi_probe(struct platform_device *pdev)
 429{
 430        struct Scsi_Host *instance;
 431        int error;
 432        struct resource *irq, *mem;
 433        unsigned char *ioaddr;
 434        int host_flags = 0;
 435#ifdef SUN3_SCSI_VME
 436        int i;
 437#endif
 438
 439        if (setup_can_queue > 0)
 440                sun3_scsi_template.can_queue = setup_can_queue;
 441        if (setup_cmd_per_lun > 0)
 442                sun3_scsi_template.cmd_per_lun = setup_cmd_per_lun;
 443        if (setup_sg_tablesize >= 0)
 444                sun3_scsi_template.sg_tablesize = setup_sg_tablesize;
 445        if (setup_hostid >= 0)
 446                sun3_scsi_template.this_id = setup_hostid & 7;
 447
 448#ifdef SUN3_SCSI_VME
 449        ioaddr = NULL;
 450        for (i = 0; i < 2; i++) {
 451                unsigned char x;
 452
 453                irq = platform_get_resource(pdev, IORESOURCE_IRQ, i);
 454                mem = platform_get_resource(pdev, IORESOURCE_MEM, i);
 455                if (!irq || !mem)
 456                        break;
 457
 458                ioaddr = sun3_ioremap(mem->start, resource_size(mem),
 459                                      SUN3_PAGE_TYPE_VME16);
 460                dregs = (struct sun3_dma_regs *)(ioaddr + 8);
 461
 462                if (sun3_map_test((unsigned long)dregs, &x)) {
 463                        unsigned short oldcsr;
 464
 465                        oldcsr = dregs->csr;
 466                        dregs->csr = 0;
 467                        udelay(SUN3_DMA_DELAY);
 468                        if (dregs->csr == 0x1400)
 469                                break;
 470
 471                        dregs->csr = oldcsr;
 472                }
 473
 474                iounmap(ioaddr);
 475                ioaddr = NULL;
 476        }
 477        if (!ioaddr)
 478                return -ENODEV;
 479#else
 480        irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
 481        mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 482        if (!irq || !mem)
 483                return -ENODEV;
 484
 485        ioaddr = ioremap(mem->start, resource_size(mem));
 486        dregs = (struct sun3_dma_regs *)(ioaddr + 8);
 487
 488        udc_regs = dvma_malloc(sizeof(struct sun3_udc_regs));
 489        if (!udc_regs) {
 490                pr_err(PFX "couldn't allocate DVMA memory!\n");
 491                iounmap(ioaddr);
 492                return -ENOMEM;
 493        }
 494#endif
 495
 496        sun3_scsi_regp = ioaddr;
 497
 498        instance = scsi_host_alloc(&sun3_scsi_template,
 499                                   sizeof(struct NCR5380_hostdata));
 500        if (!instance) {
 501                error = -ENOMEM;
 502                goto fail_alloc;
 503        }
 504
 505        instance->io_port = (unsigned long)ioaddr;
 506        instance->irq = irq->start;
 507
 508        error = NCR5380_init(instance, host_flags);
 509        if (error)
 510                goto fail_init;
 511
 512        error = request_irq(instance->irq, scsi_sun3_intr, 0,
 513                            "NCR5380", instance);
 514        if (error) {
 515                pr_err(PFX "scsi%d: IRQ %d not free, bailing out\n",
 516                       instance->host_no, instance->irq);
 517                goto fail_irq;
 518        }
 519
 520        dregs->csr = 0;
 521        udelay(SUN3_DMA_DELAY);
 522        dregs->csr = CSR_SCSI | CSR_FIFO | CSR_INTR;
 523        udelay(SUN3_DMA_DELAY);
 524        dregs->fifo_count = 0;
 525#ifdef SUN3_SCSI_VME
 526        dregs->fifo_count_hi = 0;
 527        dregs->dma_addr_hi = 0;
 528        dregs->dma_addr_lo = 0;
 529        dregs->dma_count_hi = 0;
 530        dregs->dma_count_lo = 0;
 531
 532        dregs->ivect = VME_DATA24 | (instance->irq & 0xff);
 533#endif
 534
 535        NCR5380_maybe_reset_bus(instance);
 536
 537        error = scsi_add_host(instance, NULL);
 538        if (error)
 539                goto fail_host;
 540
 541        platform_set_drvdata(pdev, instance);
 542
 543        scsi_scan_host(instance);
 544        return 0;
 545
 546fail_host:
 547        free_irq(instance->irq, instance);
 548fail_irq:
 549        NCR5380_exit(instance);
 550fail_init:
 551        scsi_host_put(instance);
 552fail_alloc:
 553        if (udc_regs)
 554                dvma_free(udc_regs);
 555        iounmap(sun3_scsi_regp);
 556        return error;
 557}
 558
 559static int __exit sun3_scsi_remove(struct platform_device *pdev)
 560{
 561        struct Scsi_Host *instance = platform_get_drvdata(pdev);
 562
 563        scsi_remove_host(instance);
 564        free_irq(instance->irq, instance);
 565        NCR5380_exit(instance);
 566        scsi_host_put(instance);
 567        if (udc_regs)
 568                dvma_free(udc_regs);
 569        iounmap(sun3_scsi_regp);
 570        return 0;
 571}
 572
 573static struct platform_driver sun3_scsi_driver = {
 574        .remove = __exit_p(sun3_scsi_remove),
 575        .driver = {
 576                .name   = DRV_MODULE_NAME,
 577        },
 578};
 579
 580module_platform_driver_probe(sun3_scsi_driver, sun3_scsi_probe);
 581
 582MODULE_ALIAS("platform:" DRV_MODULE_NAME);
 583MODULE_LICENSE("GPL");
 584