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
  38/* minimum number of bytes to do dma on */
  39#define DMA_MIN_SIZE                    129
  40
  41/* Definitions for the core NCR5380 driver. */
  42
  43#define NCR5380_implementation_fields   /* none */
  44
  45#define NCR5380_read(reg)               in_8(hostdata->io + (reg))
  46#define NCR5380_write(reg, value)       out_8(hostdata->io + (reg), value)
  47
  48#define NCR5380_queue_command           sun3scsi_queue_command
  49#define NCR5380_host_reset              sun3scsi_host_reset
  50#define NCR5380_abort                   sun3scsi_abort
  51#define NCR5380_info                    sun3scsi_info
  52
  53#define NCR5380_dma_xfer_len            sun3scsi_dma_xfer_len
  54#define NCR5380_dma_recv_setup          sun3scsi_dma_count
  55#define NCR5380_dma_send_setup          sun3scsi_dma_count
  56#define NCR5380_dma_residual            sun3scsi_dma_residual
  57
  58#include "NCR5380.h"
  59
  60/* dma regs start at regbase + 8, directly after the NCR regs */
  61struct sun3_dma_regs {
  62        unsigned short dma_addr_hi; /* vme only */
  63        unsigned short dma_addr_lo; /* vme only */
  64        unsigned short dma_count_hi; /* vme only */
  65        unsigned short dma_count_lo; /* vme only */
  66        unsigned short udc_data; /* udc dma data reg (obio only) */
  67        unsigned short udc_addr; /* uda dma addr reg (obio only) */
  68        unsigned short fifo_data; /* fifo data reg,
  69                                   * holds extra byte on odd dma reads
  70                                   */
  71        unsigned short fifo_count;
  72        unsigned short csr; /* control/status reg */
  73        unsigned short bpack_hi; /* vme only */
  74        unsigned short bpack_lo; /* vme only */
  75        unsigned short ivect; /* vme only */
  76        unsigned short fifo_count_hi; /* vme only */
  77};
  78
  79/* ucd chip specific regs - live in dvma space */
  80struct sun3_udc_regs {
  81        unsigned short rsel; /* select regs to load */
  82        unsigned short addr_hi; /* high word of addr */
  83        unsigned short addr_lo; /* low word */
  84        unsigned short count; /* words to be xfer'd */
  85        unsigned short mode_hi; /* high word of channel mode */
  86        unsigned short mode_lo; /* low word of channel mode */
  87};
  88
  89/* addresses of the udc registers */
  90#define UDC_MODE 0x38
  91#define UDC_CSR 0x2e /* command/status */
  92#define UDC_CHN_HI 0x26 /* chain high word */
  93#define UDC_CHN_LO 0x22 /* chain lo word */
  94#define UDC_CURA_HI 0x1a /* cur reg A high */
  95#define UDC_CURA_LO 0x0a /* cur reg A low */
  96#define UDC_CURB_HI 0x12 /* cur reg B high */
  97#define UDC_CURB_LO 0x02 /* cur reg B low */
  98#define UDC_MODE_HI 0x56 /* mode reg high */
  99#define UDC_MODE_LO 0x52 /* mode reg low */
 100#define UDC_COUNT 0x32 /* words to xfer */
 101
 102/* some udc commands */
 103#define UDC_RESET 0
 104#define UDC_CHN_START 0xa0 /* start chain */
 105#define UDC_INT_ENABLE 0x32 /* channel 1 int on */
 106
 107/* udc mode words */
 108#define UDC_MODE_HIWORD 0x40
 109#define UDC_MODE_LSEND 0xc2
 110#define UDC_MODE_LRECV 0xd2
 111
 112/* udc reg selections */
 113#define UDC_RSEL_SEND 0x282
 114#define UDC_RSEL_RECV 0x182
 115
 116/* bits in csr reg */
 117#define CSR_DMA_ACTIVE 0x8000
 118#define CSR_DMA_CONFLICT 0x4000
 119#define CSR_DMA_BUSERR 0x2000
 120
 121#define CSR_FIFO_EMPTY 0x400 /* fifo flushed? */
 122#define CSR_SDB_INT 0x200 /* sbc interrupt pending */
 123#define CSR_DMA_INT 0x100 /* dma interrupt pending */
 124
 125#define CSR_LEFT 0xc0
 126#define CSR_LEFT_3 0xc0
 127#define CSR_LEFT_2 0x80
 128#define CSR_LEFT_1 0x40
 129#define CSR_PACK_ENABLE 0x20
 130
 131#define CSR_DMA_ENABLE 0x10
 132
 133#define CSR_SEND 0x8 /* 1 = send  0 = recv */
 134#define CSR_FIFO 0x2 /* reset fifo */
 135#define CSR_INTR 0x4 /* interrupt enable */
 136#define CSR_SCSI 0x1
 137
 138#define VME_DATA24 0x3d00
 139
 140extern int sun3_map_test(unsigned long, char *);
 141
 142static int setup_can_queue = -1;
 143module_param(setup_can_queue, int, 0);
 144static int setup_cmd_per_lun = -1;
 145module_param(setup_cmd_per_lun, int, 0);
 146static int setup_sg_tablesize = -1;
 147module_param(setup_sg_tablesize, int, 0);
 148static int setup_hostid = -1;
 149module_param(setup_hostid, int, 0);
 150
 151/* ms to wait after hitting dma regs */
 152#define SUN3_DMA_DELAY 10
 153
 154/* dvma buffer to allocate -- 32k should hopefully be more than sufficient */
 155#define SUN3_DVMA_BUFSIZE 0xe000
 156
 157static struct scsi_cmnd *sun3_dma_setup_done;
 158static volatile struct sun3_dma_regs *dregs;
 159static struct sun3_udc_regs *udc_regs;
 160static unsigned char *sun3_dma_orig_addr;
 161static unsigned long sun3_dma_orig_count;
 162static int sun3_dma_active;
 163static unsigned long last_residual;
 164
 165#ifndef SUN3_SCSI_VME
 166/* dma controller register access functions */
 167
 168static inline unsigned short sun3_udc_read(unsigned char reg)
 169{
 170        unsigned short ret;
 171
 172        dregs->udc_addr = UDC_CSR;
 173        udelay(SUN3_DMA_DELAY);
 174        ret = dregs->udc_data;
 175        udelay(SUN3_DMA_DELAY);
 176        
 177        return ret;
 178}
 179
 180static inline void sun3_udc_write(unsigned short val, unsigned char reg)
 181{
 182        dregs->udc_addr = reg;
 183        udelay(SUN3_DMA_DELAY);
 184        dregs->udc_data = val;
 185        udelay(SUN3_DMA_DELAY);
 186}
 187#endif
 188
 189// safe bits for the CSR
 190#define CSR_GOOD 0x060f
 191
 192static irqreturn_t scsi_sun3_intr(int irq, void *dev)
 193{
 194        struct Scsi_Host *instance = dev;
 195        unsigned short csr = dregs->csr;
 196        int handled = 0;
 197
 198#ifdef SUN3_SCSI_VME
 199        dregs->csr &= ~CSR_DMA_ENABLE;
 200#endif
 201
 202        if(csr & ~CSR_GOOD) {
 203                if (csr & CSR_DMA_BUSERR)
 204                        shost_printk(KERN_ERR, instance, "bus error in DMA\n");
 205                if (csr & CSR_DMA_CONFLICT)
 206                        shost_printk(KERN_ERR, instance, "DMA conflict\n");
 207                handled = 1;
 208        }
 209
 210        if(csr & (CSR_SDB_INT | CSR_DMA_INT)) {
 211                NCR5380_intr(irq, dev);
 212                handled = 1;
 213        }
 214
 215        return IRQ_RETVAL(handled);
 216}
 217
 218/* sun3scsi_dma_setup() -- initialize the dma controller for a read/write */
 219static int sun3scsi_dma_setup(struct NCR5380_hostdata *hostdata,
 220                              unsigned char *data, int count, int write_flag)
 221{
 222        void *addr;
 223
 224        if(sun3_dma_orig_addr != NULL)
 225                dvma_unmap(sun3_dma_orig_addr);
 226
 227#ifdef SUN3_SCSI_VME
 228        addr = (void *)dvma_map_vme((unsigned long) data, count);
 229#else
 230        addr = (void *)dvma_map((unsigned long) data, count);
 231#endif
 232                
 233        sun3_dma_orig_addr = addr;
 234        sun3_dma_orig_count = count;
 235
 236#ifndef SUN3_SCSI_VME
 237        dregs->fifo_count = 0;
 238        sun3_udc_write(UDC_RESET, UDC_CSR);
 239        
 240        /* reset fifo */
 241        dregs->csr &= ~CSR_FIFO;
 242        dregs->csr |= CSR_FIFO;
 243#endif
 244        
 245        /* set direction */
 246        if(write_flag)
 247                dregs->csr |= CSR_SEND;
 248        else
 249                dregs->csr &= ~CSR_SEND;
 250        
 251#ifdef SUN3_SCSI_VME
 252        dregs->csr |= CSR_PACK_ENABLE;
 253
 254        dregs->dma_addr_hi = ((unsigned long)addr >> 16);
 255        dregs->dma_addr_lo = ((unsigned long)addr & 0xffff);
 256
 257        dregs->dma_count_hi = 0;
 258        dregs->dma_count_lo = 0;
 259        dregs->fifo_count_hi = 0;
 260        dregs->fifo_count = 0;
 261#else
 262        /* byte count for fifo */
 263        dregs->fifo_count = count;
 264
 265        sun3_udc_write(UDC_RESET, UDC_CSR);
 266        
 267        /* reset fifo */
 268        dregs->csr &= ~CSR_FIFO;
 269        dregs->csr |= CSR_FIFO;
 270        
 271        if(dregs->fifo_count != count) { 
 272                shost_printk(KERN_ERR, hostdata->host,
 273                             "FIFO mismatch %04x not %04x\n",
 274                             dregs->fifo_count, (unsigned int) count);
 275                NCR5380_dprint(NDEBUG_DMA, hostdata->host);
 276        }
 277
 278        /* setup udc */
 279        udc_regs->addr_hi = (((unsigned long)(addr) & 0xff0000) >> 8);
 280        udc_regs->addr_lo = ((unsigned long)(addr) & 0xffff);
 281        udc_regs->count = count/2; /* count in words */
 282        udc_regs->mode_hi = UDC_MODE_HIWORD;
 283        if(write_flag) {
 284                if(count & 1)
 285                        udc_regs->count++;
 286                udc_regs->mode_lo = UDC_MODE_LSEND;
 287                udc_regs->rsel = UDC_RSEL_SEND;
 288        } else {
 289                udc_regs->mode_lo = UDC_MODE_LRECV;
 290                udc_regs->rsel = UDC_RSEL_RECV;
 291        }
 292        
 293        /* announce location of regs block */
 294        sun3_udc_write(((dvma_vtob(udc_regs) & 0xff0000) >> 8),
 295                       UDC_CHN_HI); 
 296
 297        sun3_udc_write((dvma_vtob(udc_regs) & 0xffff), UDC_CHN_LO);
 298
 299        /* set dma master on */
 300        sun3_udc_write(0xd, UDC_MODE);
 301
 302        /* interrupt enable */
 303        sun3_udc_write(UDC_INT_ENABLE, UDC_CSR);
 304#endif
 305        
 306        return count;
 307
 308}
 309
 310static int sun3scsi_dma_count(struct NCR5380_hostdata *hostdata,
 311                              unsigned char *data, int count)
 312{
 313        return count;
 314}
 315
 316static inline int sun3scsi_dma_recv_setup(struct NCR5380_hostdata *hostdata,
 317                                          unsigned char *data, int count)
 318{
 319        return sun3scsi_dma_setup(hostdata, data, count, 0);
 320}
 321
 322static inline int sun3scsi_dma_send_setup(struct NCR5380_hostdata *hostdata,
 323                                          unsigned char *data, int count)
 324{
 325        return sun3scsi_dma_setup(hostdata, data, count, 1);
 326}
 327
 328static int sun3scsi_dma_residual(struct NCR5380_hostdata *hostdata)
 329{
 330        return last_residual;
 331}
 332
 333static int sun3scsi_dma_xfer_len(struct NCR5380_hostdata *hostdata,
 334                                 struct scsi_cmnd *cmd)
 335{
 336        int wanted_len = cmd->SCp.this_residual;
 337
 338        if (wanted_len < DMA_MIN_SIZE || blk_rq_is_passthrough(cmd->request))
 339                return 0;
 340
 341        return wanted_len;
 342}
 343
 344static inline int sun3scsi_dma_start(unsigned long count, unsigned char *data)
 345{
 346#ifdef SUN3_SCSI_VME
 347        unsigned short csr;
 348
 349        csr = dregs->csr;
 350
 351        dregs->dma_count_hi = (sun3_dma_orig_count >> 16);
 352        dregs->dma_count_lo = (sun3_dma_orig_count & 0xffff);
 353
 354        dregs->fifo_count_hi = (sun3_dma_orig_count >> 16);
 355        dregs->fifo_count = (sun3_dma_orig_count & 0xffff);
 356
 357/*      if(!(csr & CSR_DMA_ENABLE))
 358 *              dregs->csr |= CSR_DMA_ENABLE;
 359 */
 360#else
 361    sun3_udc_write(UDC_CHN_START, UDC_CSR);
 362#endif
 363    
 364    return 0;
 365}
 366
 367/* clean up after our dma is done */
 368static int sun3scsi_dma_finish(int write_flag)
 369{
 370        unsigned short __maybe_unused count;
 371        unsigned short fifo;
 372        int ret = 0;
 373        
 374        sun3_dma_active = 0;
 375
 376#ifdef SUN3_SCSI_VME
 377        dregs->csr &= ~CSR_DMA_ENABLE;
 378
 379        fifo = dregs->fifo_count;
 380        if (write_flag) {
 381                if ((fifo > 0) && (fifo < sun3_dma_orig_count))
 382                        fifo++;
 383        }
 384
 385        last_residual = fifo;
 386        /* empty bytes from the fifo which didn't make it */
 387        if ((!write_flag) && (dregs->csr & CSR_LEFT)) {
 388                unsigned char *vaddr;
 389
 390                vaddr = (unsigned char *)dvma_vmetov(sun3_dma_orig_addr);
 391
 392                vaddr += (sun3_dma_orig_count - fifo);
 393                vaddr--;
 394
 395                switch (dregs->csr & CSR_LEFT) {
 396                case CSR_LEFT_3:
 397                        *vaddr = (dregs->bpack_lo & 0xff00) >> 8;
 398                        vaddr--;
 399
 400                case CSR_LEFT_2:
 401                        *vaddr = (dregs->bpack_hi & 0x00ff);
 402                        vaddr--;
 403
 404                case CSR_LEFT_1:
 405                        *vaddr = (dregs->bpack_hi & 0xff00) >> 8;
 406                        break;
 407                }
 408        }
 409#else
 410        // check to empty the fifo on a read
 411        if(!write_flag) {
 412                int tmo = 20000; /* .2 sec */
 413                
 414                while(1) {
 415                        if(dregs->csr & CSR_FIFO_EMPTY)
 416                                break;
 417
 418                        if(--tmo <= 0) {
 419                                printk("sun3scsi: fifo failed to empty!\n");
 420                                return 1;
 421                        }
 422                        udelay(10);
 423                }
 424        }
 425
 426        dregs->udc_addr = 0x32;
 427        udelay(SUN3_DMA_DELAY);
 428        count = 2 * dregs->udc_data;
 429        udelay(SUN3_DMA_DELAY);
 430
 431        fifo = dregs->fifo_count;
 432        last_residual = fifo;
 433
 434        /* empty bytes from the fifo which didn't make it */
 435        if((!write_flag) && (count - fifo) == 2) {
 436                unsigned short data;
 437                unsigned char *vaddr;
 438
 439                data = dregs->fifo_data;
 440                vaddr = (unsigned char *)dvma_btov(sun3_dma_orig_addr);
 441                
 442                vaddr += (sun3_dma_orig_count - fifo);
 443
 444                vaddr[-2] = (data & 0xff00) >> 8;
 445                vaddr[-1] = (data & 0xff);
 446        }
 447#endif
 448
 449        dvma_unmap(sun3_dma_orig_addr);
 450        sun3_dma_orig_addr = NULL;
 451
 452#ifdef SUN3_SCSI_VME
 453        dregs->dma_addr_hi = 0;
 454        dregs->dma_addr_lo = 0;
 455        dregs->dma_count_hi = 0;
 456        dregs->dma_count_lo = 0;
 457
 458        dregs->fifo_count = 0;
 459        dregs->fifo_count_hi = 0;
 460
 461        dregs->csr &= ~CSR_SEND;
 462/*      dregs->csr |= CSR_DMA_ENABLE; */
 463#else
 464        sun3_udc_write(UDC_RESET, UDC_CSR);
 465        dregs->fifo_count = 0;
 466        dregs->csr &= ~CSR_SEND;
 467
 468        /* reset fifo */
 469        dregs->csr &= ~CSR_FIFO;
 470        dregs->csr |= CSR_FIFO;
 471#endif
 472        
 473        sun3_dma_setup_done = NULL;
 474
 475        return ret;
 476
 477}
 478        
 479#include "NCR5380.c"
 480
 481#ifdef SUN3_SCSI_VME
 482#define SUN3_SCSI_NAME          "Sun3 NCR5380 VME SCSI"
 483#define DRV_MODULE_NAME         "sun3_scsi_vme"
 484#else
 485#define SUN3_SCSI_NAME          "Sun3 NCR5380 SCSI"
 486#define DRV_MODULE_NAME         "sun3_scsi"
 487#endif
 488
 489#define PFX                     DRV_MODULE_NAME ": "
 490
 491static struct scsi_host_template sun3_scsi_template = {
 492        .module                 = THIS_MODULE,
 493        .proc_name              = DRV_MODULE_NAME,
 494        .name                   = SUN3_SCSI_NAME,
 495        .info                   = sun3scsi_info,
 496        .queuecommand           = sun3scsi_queue_command,
 497        .eh_abort_handler       = sun3scsi_abort,
 498        .eh_host_reset_handler  = sun3scsi_host_reset,
 499        .can_queue              = 16,
 500        .this_id                = 7,
 501        .sg_tablesize           = SG_NONE,
 502        .cmd_per_lun            = 2,
 503        .use_clustering         = DISABLE_CLUSTERING,
 504        .cmd_size               = NCR5380_CMD_SIZE,
 505};
 506
 507static int __init sun3_scsi_probe(struct platform_device *pdev)
 508{
 509        struct Scsi_Host *instance;
 510        struct NCR5380_hostdata *hostdata;
 511        int error;
 512        struct resource *irq, *mem;
 513        void __iomem *ioaddr;
 514        int host_flags = 0;
 515#ifdef SUN3_SCSI_VME
 516        int i;
 517#endif
 518
 519        if (setup_can_queue > 0)
 520                sun3_scsi_template.can_queue = setup_can_queue;
 521        if (setup_cmd_per_lun > 0)
 522                sun3_scsi_template.cmd_per_lun = setup_cmd_per_lun;
 523        if (setup_sg_tablesize >= 0)
 524                sun3_scsi_template.sg_tablesize = setup_sg_tablesize;
 525        if (setup_hostid >= 0)
 526                sun3_scsi_template.this_id = setup_hostid & 7;
 527
 528#ifdef SUN3_SCSI_VME
 529        ioaddr = NULL;
 530        for (i = 0; i < 2; i++) {
 531                unsigned char x;
 532
 533                irq = platform_get_resource(pdev, IORESOURCE_IRQ, i);
 534                mem = platform_get_resource(pdev, IORESOURCE_MEM, i);
 535                if (!irq || !mem)
 536                        break;
 537
 538                ioaddr = sun3_ioremap(mem->start, resource_size(mem),
 539                                      SUN3_PAGE_TYPE_VME16);
 540                dregs = (struct sun3_dma_regs *)(ioaddr + 8);
 541
 542                if (sun3_map_test((unsigned long)dregs, &x)) {
 543                        unsigned short oldcsr;
 544
 545                        oldcsr = dregs->csr;
 546                        dregs->csr = 0;
 547                        udelay(SUN3_DMA_DELAY);
 548                        if (dregs->csr == 0x1400)
 549                                break;
 550
 551                        dregs->csr = oldcsr;
 552                }
 553
 554                iounmap(ioaddr);
 555                ioaddr = NULL;
 556        }
 557        if (!ioaddr)
 558                return -ENODEV;
 559#else
 560        irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
 561        mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 562        if (!irq || !mem)
 563                return -ENODEV;
 564
 565        ioaddr = ioremap(mem->start, resource_size(mem));
 566        dregs = (struct sun3_dma_regs *)(ioaddr + 8);
 567
 568        udc_regs = dvma_malloc(sizeof(struct sun3_udc_regs));
 569        if (!udc_regs) {
 570                pr_err(PFX "couldn't allocate DVMA memory!\n");
 571                iounmap(ioaddr);
 572                return -ENOMEM;
 573        }
 574#endif
 575
 576        instance = scsi_host_alloc(&sun3_scsi_template,
 577                                   sizeof(struct NCR5380_hostdata));
 578        if (!instance) {
 579                error = -ENOMEM;
 580                goto fail_alloc;
 581        }
 582
 583        instance->irq = irq->start;
 584
 585        hostdata = shost_priv(instance);
 586        hostdata->base = mem->start;
 587        hostdata->io = ioaddr;
 588
 589        error = NCR5380_init(instance, host_flags);
 590        if (error)
 591                goto fail_init;
 592
 593        error = request_irq(instance->irq, scsi_sun3_intr, 0,
 594                            "NCR5380", instance);
 595        if (error) {
 596                pr_err(PFX "scsi%d: IRQ %d not free, bailing out\n",
 597                       instance->host_no, instance->irq);
 598                goto fail_irq;
 599        }
 600
 601        dregs->csr = 0;
 602        udelay(SUN3_DMA_DELAY);
 603        dregs->csr = CSR_SCSI | CSR_FIFO | CSR_INTR;
 604        udelay(SUN3_DMA_DELAY);
 605        dregs->fifo_count = 0;
 606#ifdef SUN3_SCSI_VME
 607        dregs->fifo_count_hi = 0;
 608        dregs->dma_addr_hi = 0;
 609        dregs->dma_addr_lo = 0;
 610        dregs->dma_count_hi = 0;
 611        dregs->dma_count_lo = 0;
 612
 613        dregs->ivect = VME_DATA24 | (instance->irq & 0xff);
 614#endif
 615
 616        NCR5380_maybe_reset_bus(instance);
 617
 618        error = scsi_add_host(instance, NULL);
 619        if (error)
 620                goto fail_host;
 621
 622        platform_set_drvdata(pdev, instance);
 623
 624        scsi_scan_host(instance);
 625        return 0;
 626
 627fail_host:
 628        free_irq(instance->irq, instance);
 629fail_irq:
 630        NCR5380_exit(instance);
 631fail_init:
 632        scsi_host_put(instance);
 633fail_alloc:
 634        if (udc_regs)
 635                dvma_free(udc_regs);
 636        iounmap(ioaddr);
 637        return error;
 638}
 639
 640static int __exit sun3_scsi_remove(struct platform_device *pdev)
 641{
 642        struct Scsi_Host *instance = platform_get_drvdata(pdev);
 643        struct NCR5380_hostdata *hostdata = shost_priv(instance);
 644        void __iomem *ioaddr = hostdata->io;
 645
 646        scsi_remove_host(instance);
 647        free_irq(instance->irq, instance);
 648        NCR5380_exit(instance);
 649        scsi_host_put(instance);
 650        if (udc_regs)
 651                dvma_free(udc_regs);
 652        iounmap(ioaddr);
 653        return 0;
 654}
 655
 656static struct platform_driver sun3_scsi_driver = {
 657        .remove = __exit_p(sun3_scsi_remove),
 658        .driver = {
 659                .name   = DRV_MODULE_NAME,
 660        },
 661};
 662
 663module_platform_driver_probe(sun3_scsi_driver, sun3_scsi_probe);
 664
 665MODULE_ALIAS("platform:" DRV_MODULE_NAME);
 666MODULE_LICENSE("GPL");
 667