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