18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Sun3 SCSI stuff by Erik Verbruggen (erik@bigmama.xtdnet.nl)
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Sun3 DMA routines added by Sam Creasey (sammy@sammy.net)
68c2ecf20Sopenharmony_ci *
78c2ecf20Sopenharmony_ci * VME support added by Sam Creasey
88c2ecf20Sopenharmony_ci *
98c2ecf20Sopenharmony_ci * TODO: modify this driver to support multiple Sun3 SCSI VME boards
108c2ecf20Sopenharmony_ci *
118c2ecf20Sopenharmony_ci * Adapted from mac_scsinew.c:
128c2ecf20Sopenharmony_ci */
138c2ecf20Sopenharmony_ci/*
148c2ecf20Sopenharmony_ci * Generic Macintosh NCR5380 driver
158c2ecf20Sopenharmony_ci *
168c2ecf20Sopenharmony_ci * Copyright 1998, Michael Schmitz <mschmitz@lbl.gov>
178c2ecf20Sopenharmony_ci *
188c2ecf20Sopenharmony_ci * derived in part from:
198c2ecf20Sopenharmony_ci */
208c2ecf20Sopenharmony_ci/*
218c2ecf20Sopenharmony_ci * Generic Generic NCR5380 driver
228c2ecf20Sopenharmony_ci *
238c2ecf20Sopenharmony_ci * Copyright 1995, Russell King
248c2ecf20Sopenharmony_ci */
258c2ecf20Sopenharmony_ci
268c2ecf20Sopenharmony_ci#include <linux/types.h>
278c2ecf20Sopenharmony_ci#include <linux/delay.h>
288c2ecf20Sopenharmony_ci#include <linux/module.h>
298c2ecf20Sopenharmony_ci#include <linux/ioport.h>
308c2ecf20Sopenharmony_ci#include <linux/init.h>
318c2ecf20Sopenharmony_ci#include <linux/blkdev.h>
328c2ecf20Sopenharmony_ci#include <linux/platform_device.h>
338c2ecf20Sopenharmony_ci
348c2ecf20Sopenharmony_ci#include <asm/io.h>
358c2ecf20Sopenharmony_ci#include <asm/dvma.h>
368c2ecf20Sopenharmony_ci
378c2ecf20Sopenharmony_ci#include <scsi/scsi_host.h>
388c2ecf20Sopenharmony_ci
398c2ecf20Sopenharmony_ci/* minimum number of bytes to do dma on */
408c2ecf20Sopenharmony_ci#define DMA_MIN_SIZE                    129
418c2ecf20Sopenharmony_ci
428c2ecf20Sopenharmony_ci/* Definitions for the core NCR5380 driver. */
438c2ecf20Sopenharmony_ci
448c2ecf20Sopenharmony_ci#define NCR5380_implementation_fields   /* none */
458c2ecf20Sopenharmony_ci
468c2ecf20Sopenharmony_ci#define NCR5380_read(reg)               in_8(hostdata->io + (reg))
478c2ecf20Sopenharmony_ci#define NCR5380_write(reg, value)       out_8(hostdata->io + (reg), value)
488c2ecf20Sopenharmony_ci
498c2ecf20Sopenharmony_ci#define NCR5380_queue_command           sun3scsi_queue_command
508c2ecf20Sopenharmony_ci#define NCR5380_host_reset              sun3scsi_host_reset
518c2ecf20Sopenharmony_ci#define NCR5380_abort                   sun3scsi_abort
528c2ecf20Sopenharmony_ci#define NCR5380_info                    sun3scsi_info
538c2ecf20Sopenharmony_ci
548c2ecf20Sopenharmony_ci#define NCR5380_dma_xfer_len            sun3scsi_dma_xfer_len
558c2ecf20Sopenharmony_ci#define NCR5380_dma_recv_setup          sun3scsi_dma_count
568c2ecf20Sopenharmony_ci#define NCR5380_dma_send_setup          sun3scsi_dma_count
578c2ecf20Sopenharmony_ci#define NCR5380_dma_residual            sun3scsi_dma_residual
588c2ecf20Sopenharmony_ci
598c2ecf20Sopenharmony_ci#include "NCR5380.h"
608c2ecf20Sopenharmony_ci
618c2ecf20Sopenharmony_ci/* dma regs start at regbase + 8, directly after the NCR regs */
628c2ecf20Sopenharmony_cistruct sun3_dma_regs {
638c2ecf20Sopenharmony_ci	unsigned short dma_addr_hi; /* vme only */
648c2ecf20Sopenharmony_ci	unsigned short dma_addr_lo; /* vme only */
658c2ecf20Sopenharmony_ci	unsigned short dma_count_hi; /* vme only */
668c2ecf20Sopenharmony_ci	unsigned short dma_count_lo; /* vme only */
678c2ecf20Sopenharmony_ci	unsigned short udc_data; /* udc dma data reg (obio only) */
688c2ecf20Sopenharmony_ci	unsigned short udc_addr; /* uda dma addr reg (obio only) */
698c2ecf20Sopenharmony_ci	unsigned short fifo_data; /* fifo data reg,
708c2ecf20Sopenharmony_ci	                           * holds extra byte on odd dma reads
718c2ecf20Sopenharmony_ci	                           */
728c2ecf20Sopenharmony_ci	unsigned short fifo_count;
738c2ecf20Sopenharmony_ci	unsigned short csr; /* control/status reg */
748c2ecf20Sopenharmony_ci	unsigned short bpack_hi; /* vme only */
758c2ecf20Sopenharmony_ci	unsigned short bpack_lo; /* vme only */
768c2ecf20Sopenharmony_ci	unsigned short ivect; /* vme only */
778c2ecf20Sopenharmony_ci	unsigned short fifo_count_hi; /* vme only */
788c2ecf20Sopenharmony_ci};
798c2ecf20Sopenharmony_ci
808c2ecf20Sopenharmony_ci/* ucd chip specific regs - live in dvma space */
818c2ecf20Sopenharmony_cistruct sun3_udc_regs {
828c2ecf20Sopenharmony_ci	unsigned short rsel; /* select regs to load */
838c2ecf20Sopenharmony_ci	unsigned short addr_hi; /* high word of addr */
848c2ecf20Sopenharmony_ci	unsigned short addr_lo; /* low word */
858c2ecf20Sopenharmony_ci	unsigned short count; /* words to be xfer'd */
868c2ecf20Sopenharmony_ci	unsigned short mode_hi; /* high word of channel mode */
878c2ecf20Sopenharmony_ci	unsigned short mode_lo; /* low word of channel mode */
888c2ecf20Sopenharmony_ci};
898c2ecf20Sopenharmony_ci
908c2ecf20Sopenharmony_ci/* addresses of the udc registers */
918c2ecf20Sopenharmony_ci#define UDC_MODE 0x38
928c2ecf20Sopenharmony_ci#define UDC_CSR 0x2e /* command/status */
938c2ecf20Sopenharmony_ci#define UDC_CHN_HI 0x26 /* chain high word */
948c2ecf20Sopenharmony_ci#define UDC_CHN_LO 0x22 /* chain lo word */
958c2ecf20Sopenharmony_ci#define UDC_CURA_HI 0x1a /* cur reg A high */
968c2ecf20Sopenharmony_ci#define UDC_CURA_LO 0x0a /* cur reg A low */
978c2ecf20Sopenharmony_ci#define UDC_CURB_HI 0x12 /* cur reg B high */
988c2ecf20Sopenharmony_ci#define UDC_CURB_LO 0x02 /* cur reg B low */
998c2ecf20Sopenharmony_ci#define UDC_MODE_HI 0x56 /* mode reg high */
1008c2ecf20Sopenharmony_ci#define UDC_MODE_LO 0x52 /* mode reg low */
1018c2ecf20Sopenharmony_ci#define UDC_COUNT 0x32 /* words to xfer */
1028c2ecf20Sopenharmony_ci
1038c2ecf20Sopenharmony_ci/* some udc commands */
1048c2ecf20Sopenharmony_ci#define UDC_RESET 0
1058c2ecf20Sopenharmony_ci#define UDC_CHN_START 0xa0 /* start chain */
1068c2ecf20Sopenharmony_ci#define UDC_INT_ENABLE 0x32 /* channel 1 int on */
1078c2ecf20Sopenharmony_ci
1088c2ecf20Sopenharmony_ci/* udc mode words */
1098c2ecf20Sopenharmony_ci#define UDC_MODE_HIWORD 0x40
1108c2ecf20Sopenharmony_ci#define UDC_MODE_LSEND 0xc2
1118c2ecf20Sopenharmony_ci#define UDC_MODE_LRECV 0xd2
1128c2ecf20Sopenharmony_ci
1138c2ecf20Sopenharmony_ci/* udc reg selections */
1148c2ecf20Sopenharmony_ci#define UDC_RSEL_SEND 0x282
1158c2ecf20Sopenharmony_ci#define UDC_RSEL_RECV 0x182
1168c2ecf20Sopenharmony_ci
1178c2ecf20Sopenharmony_ci/* bits in csr reg */
1188c2ecf20Sopenharmony_ci#define CSR_DMA_ACTIVE 0x8000
1198c2ecf20Sopenharmony_ci#define CSR_DMA_CONFLICT 0x4000
1208c2ecf20Sopenharmony_ci#define CSR_DMA_BUSERR 0x2000
1218c2ecf20Sopenharmony_ci
1228c2ecf20Sopenharmony_ci#define CSR_FIFO_EMPTY 0x400 /* fifo flushed? */
1238c2ecf20Sopenharmony_ci#define CSR_SDB_INT 0x200 /* sbc interrupt pending */
1248c2ecf20Sopenharmony_ci#define CSR_DMA_INT 0x100 /* dma interrupt pending */
1258c2ecf20Sopenharmony_ci
1268c2ecf20Sopenharmony_ci#define CSR_LEFT 0xc0
1278c2ecf20Sopenharmony_ci#define CSR_LEFT_3 0xc0
1288c2ecf20Sopenharmony_ci#define CSR_LEFT_2 0x80
1298c2ecf20Sopenharmony_ci#define CSR_LEFT_1 0x40
1308c2ecf20Sopenharmony_ci#define CSR_PACK_ENABLE 0x20
1318c2ecf20Sopenharmony_ci
1328c2ecf20Sopenharmony_ci#define CSR_DMA_ENABLE 0x10
1338c2ecf20Sopenharmony_ci
1348c2ecf20Sopenharmony_ci#define CSR_SEND 0x8 /* 1 = send  0 = recv */
1358c2ecf20Sopenharmony_ci#define CSR_FIFO 0x2 /* reset fifo */
1368c2ecf20Sopenharmony_ci#define CSR_INTR 0x4 /* interrupt enable */
1378c2ecf20Sopenharmony_ci#define CSR_SCSI 0x1
1388c2ecf20Sopenharmony_ci
1398c2ecf20Sopenharmony_ci#define VME_DATA24 0x3d00
1408c2ecf20Sopenharmony_ci
1418c2ecf20Sopenharmony_ciextern int sun3_map_test(unsigned long, char *);
1428c2ecf20Sopenharmony_ci
1438c2ecf20Sopenharmony_cistatic int setup_can_queue = -1;
1448c2ecf20Sopenharmony_cimodule_param(setup_can_queue, int, 0);
1458c2ecf20Sopenharmony_cistatic int setup_cmd_per_lun = -1;
1468c2ecf20Sopenharmony_cimodule_param(setup_cmd_per_lun, int, 0);
1478c2ecf20Sopenharmony_cistatic int setup_sg_tablesize = -1;
1488c2ecf20Sopenharmony_cimodule_param(setup_sg_tablesize, int, 0);
1498c2ecf20Sopenharmony_cistatic int setup_hostid = -1;
1508c2ecf20Sopenharmony_cimodule_param(setup_hostid, int, 0);
1518c2ecf20Sopenharmony_ci
1528c2ecf20Sopenharmony_ci/* ms to wait after hitting dma regs */
1538c2ecf20Sopenharmony_ci#define SUN3_DMA_DELAY 10
1548c2ecf20Sopenharmony_ci
1558c2ecf20Sopenharmony_ci/* dvma buffer to allocate -- 32k should hopefully be more than sufficient */
1568c2ecf20Sopenharmony_ci#define SUN3_DVMA_BUFSIZE 0xe000
1578c2ecf20Sopenharmony_ci
1588c2ecf20Sopenharmony_cistatic struct scsi_cmnd *sun3_dma_setup_done;
1598c2ecf20Sopenharmony_cistatic volatile struct sun3_dma_regs *dregs;
1608c2ecf20Sopenharmony_cistatic struct sun3_udc_regs *udc_regs;
1618c2ecf20Sopenharmony_cistatic unsigned char *sun3_dma_orig_addr;
1628c2ecf20Sopenharmony_cistatic unsigned long sun3_dma_orig_count;
1638c2ecf20Sopenharmony_cistatic int sun3_dma_active;
1648c2ecf20Sopenharmony_cistatic unsigned long last_residual;
1658c2ecf20Sopenharmony_ci
1668c2ecf20Sopenharmony_ci#ifndef SUN3_SCSI_VME
1678c2ecf20Sopenharmony_ci/* dma controller register access functions */
1688c2ecf20Sopenharmony_ci
1698c2ecf20Sopenharmony_cistatic inline unsigned short sun3_udc_read(unsigned char reg)
1708c2ecf20Sopenharmony_ci{
1718c2ecf20Sopenharmony_ci	unsigned short ret;
1728c2ecf20Sopenharmony_ci
1738c2ecf20Sopenharmony_ci	dregs->udc_addr = UDC_CSR;
1748c2ecf20Sopenharmony_ci	udelay(SUN3_DMA_DELAY);
1758c2ecf20Sopenharmony_ci	ret = dregs->udc_data;
1768c2ecf20Sopenharmony_ci	udelay(SUN3_DMA_DELAY);
1778c2ecf20Sopenharmony_ci
1788c2ecf20Sopenharmony_ci	return ret;
1798c2ecf20Sopenharmony_ci}
1808c2ecf20Sopenharmony_ci
1818c2ecf20Sopenharmony_cistatic inline void sun3_udc_write(unsigned short val, unsigned char reg)
1828c2ecf20Sopenharmony_ci{
1838c2ecf20Sopenharmony_ci	dregs->udc_addr = reg;
1848c2ecf20Sopenharmony_ci	udelay(SUN3_DMA_DELAY);
1858c2ecf20Sopenharmony_ci	dregs->udc_data = val;
1868c2ecf20Sopenharmony_ci	udelay(SUN3_DMA_DELAY);
1878c2ecf20Sopenharmony_ci}
1888c2ecf20Sopenharmony_ci#endif
1898c2ecf20Sopenharmony_ci
1908c2ecf20Sopenharmony_ci// safe bits for the CSR
1918c2ecf20Sopenharmony_ci#define CSR_GOOD 0x060f
1928c2ecf20Sopenharmony_ci
1938c2ecf20Sopenharmony_cistatic irqreturn_t scsi_sun3_intr(int irq, void *dev)
1948c2ecf20Sopenharmony_ci{
1958c2ecf20Sopenharmony_ci	struct Scsi_Host *instance = dev;
1968c2ecf20Sopenharmony_ci	unsigned short csr = dregs->csr;
1978c2ecf20Sopenharmony_ci	int handled = 0;
1988c2ecf20Sopenharmony_ci
1998c2ecf20Sopenharmony_ci#ifdef SUN3_SCSI_VME
2008c2ecf20Sopenharmony_ci	dregs->csr &= ~CSR_DMA_ENABLE;
2018c2ecf20Sopenharmony_ci#endif
2028c2ecf20Sopenharmony_ci
2038c2ecf20Sopenharmony_ci	if(csr & ~CSR_GOOD) {
2048c2ecf20Sopenharmony_ci		if (csr & CSR_DMA_BUSERR)
2058c2ecf20Sopenharmony_ci			shost_printk(KERN_ERR, instance, "bus error in DMA\n");
2068c2ecf20Sopenharmony_ci		if (csr & CSR_DMA_CONFLICT)
2078c2ecf20Sopenharmony_ci			shost_printk(KERN_ERR, instance, "DMA conflict\n");
2088c2ecf20Sopenharmony_ci		handled = 1;
2098c2ecf20Sopenharmony_ci	}
2108c2ecf20Sopenharmony_ci
2118c2ecf20Sopenharmony_ci	if(csr & (CSR_SDB_INT | CSR_DMA_INT)) {
2128c2ecf20Sopenharmony_ci		NCR5380_intr(irq, dev);
2138c2ecf20Sopenharmony_ci		handled = 1;
2148c2ecf20Sopenharmony_ci	}
2158c2ecf20Sopenharmony_ci
2168c2ecf20Sopenharmony_ci	return IRQ_RETVAL(handled);
2178c2ecf20Sopenharmony_ci}
2188c2ecf20Sopenharmony_ci
2198c2ecf20Sopenharmony_ci/* sun3scsi_dma_setup() -- initialize the dma controller for a read/write */
2208c2ecf20Sopenharmony_cistatic int sun3scsi_dma_setup(struct NCR5380_hostdata *hostdata,
2218c2ecf20Sopenharmony_ci                              unsigned char *data, int count, int write_flag)
2228c2ecf20Sopenharmony_ci{
2238c2ecf20Sopenharmony_ci	void *addr;
2248c2ecf20Sopenharmony_ci
2258c2ecf20Sopenharmony_ci	if(sun3_dma_orig_addr != NULL)
2268c2ecf20Sopenharmony_ci		dvma_unmap(sun3_dma_orig_addr);
2278c2ecf20Sopenharmony_ci
2288c2ecf20Sopenharmony_ci#ifdef SUN3_SCSI_VME
2298c2ecf20Sopenharmony_ci	addr = (void *)dvma_map_vme((unsigned long) data, count);
2308c2ecf20Sopenharmony_ci#else
2318c2ecf20Sopenharmony_ci	addr = (void *)dvma_map((unsigned long) data, count);
2328c2ecf20Sopenharmony_ci#endif
2338c2ecf20Sopenharmony_ci
2348c2ecf20Sopenharmony_ci	sun3_dma_orig_addr = addr;
2358c2ecf20Sopenharmony_ci	sun3_dma_orig_count = count;
2368c2ecf20Sopenharmony_ci
2378c2ecf20Sopenharmony_ci#ifndef SUN3_SCSI_VME
2388c2ecf20Sopenharmony_ci	dregs->fifo_count = 0;
2398c2ecf20Sopenharmony_ci	sun3_udc_write(UDC_RESET, UDC_CSR);
2408c2ecf20Sopenharmony_ci
2418c2ecf20Sopenharmony_ci	/* reset fifo */
2428c2ecf20Sopenharmony_ci	dregs->csr &= ~CSR_FIFO;
2438c2ecf20Sopenharmony_ci	dregs->csr |= CSR_FIFO;
2448c2ecf20Sopenharmony_ci#endif
2458c2ecf20Sopenharmony_ci
2468c2ecf20Sopenharmony_ci	/* set direction */
2478c2ecf20Sopenharmony_ci	if(write_flag)
2488c2ecf20Sopenharmony_ci		dregs->csr |= CSR_SEND;
2498c2ecf20Sopenharmony_ci	else
2508c2ecf20Sopenharmony_ci		dregs->csr &= ~CSR_SEND;
2518c2ecf20Sopenharmony_ci
2528c2ecf20Sopenharmony_ci#ifdef SUN3_SCSI_VME
2538c2ecf20Sopenharmony_ci	dregs->csr |= CSR_PACK_ENABLE;
2548c2ecf20Sopenharmony_ci
2558c2ecf20Sopenharmony_ci	dregs->dma_addr_hi = ((unsigned long)addr >> 16);
2568c2ecf20Sopenharmony_ci	dregs->dma_addr_lo = ((unsigned long)addr & 0xffff);
2578c2ecf20Sopenharmony_ci
2588c2ecf20Sopenharmony_ci	dregs->dma_count_hi = 0;
2598c2ecf20Sopenharmony_ci	dregs->dma_count_lo = 0;
2608c2ecf20Sopenharmony_ci	dregs->fifo_count_hi = 0;
2618c2ecf20Sopenharmony_ci	dregs->fifo_count = 0;
2628c2ecf20Sopenharmony_ci#else
2638c2ecf20Sopenharmony_ci	/* byte count for fifo */
2648c2ecf20Sopenharmony_ci	dregs->fifo_count = count;
2658c2ecf20Sopenharmony_ci
2668c2ecf20Sopenharmony_ci	sun3_udc_write(UDC_RESET, UDC_CSR);
2678c2ecf20Sopenharmony_ci
2688c2ecf20Sopenharmony_ci	/* reset fifo */
2698c2ecf20Sopenharmony_ci	dregs->csr &= ~CSR_FIFO;
2708c2ecf20Sopenharmony_ci	dregs->csr |= CSR_FIFO;
2718c2ecf20Sopenharmony_ci
2728c2ecf20Sopenharmony_ci	if(dregs->fifo_count != count) {
2738c2ecf20Sopenharmony_ci		shost_printk(KERN_ERR, hostdata->host,
2748c2ecf20Sopenharmony_ci		             "FIFO mismatch %04x not %04x\n",
2758c2ecf20Sopenharmony_ci		             dregs->fifo_count, (unsigned int) count);
2768c2ecf20Sopenharmony_ci		NCR5380_dprint(NDEBUG_DMA, hostdata->host);
2778c2ecf20Sopenharmony_ci	}
2788c2ecf20Sopenharmony_ci
2798c2ecf20Sopenharmony_ci	/* setup udc */
2808c2ecf20Sopenharmony_ci	udc_regs->addr_hi = (((unsigned long)(addr) & 0xff0000) >> 8);
2818c2ecf20Sopenharmony_ci	udc_regs->addr_lo = ((unsigned long)(addr) & 0xffff);
2828c2ecf20Sopenharmony_ci	udc_regs->count = count/2; /* count in words */
2838c2ecf20Sopenharmony_ci	udc_regs->mode_hi = UDC_MODE_HIWORD;
2848c2ecf20Sopenharmony_ci	if(write_flag) {
2858c2ecf20Sopenharmony_ci		if(count & 1)
2868c2ecf20Sopenharmony_ci			udc_regs->count++;
2878c2ecf20Sopenharmony_ci		udc_regs->mode_lo = UDC_MODE_LSEND;
2888c2ecf20Sopenharmony_ci		udc_regs->rsel = UDC_RSEL_SEND;
2898c2ecf20Sopenharmony_ci	} else {
2908c2ecf20Sopenharmony_ci		udc_regs->mode_lo = UDC_MODE_LRECV;
2918c2ecf20Sopenharmony_ci		udc_regs->rsel = UDC_RSEL_RECV;
2928c2ecf20Sopenharmony_ci	}
2938c2ecf20Sopenharmony_ci
2948c2ecf20Sopenharmony_ci	/* announce location of regs block */
2958c2ecf20Sopenharmony_ci	sun3_udc_write(((dvma_vtob(udc_regs) & 0xff0000) >> 8),
2968c2ecf20Sopenharmony_ci		       UDC_CHN_HI);
2978c2ecf20Sopenharmony_ci
2988c2ecf20Sopenharmony_ci	sun3_udc_write((dvma_vtob(udc_regs) & 0xffff), UDC_CHN_LO);
2998c2ecf20Sopenharmony_ci
3008c2ecf20Sopenharmony_ci	/* set dma master on */
3018c2ecf20Sopenharmony_ci	sun3_udc_write(0xd, UDC_MODE);
3028c2ecf20Sopenharmony_ci
3038c2ecf20Sopenharmony_ci	/* interrupt enable */
3048c2ecf20Sopenharmony_ci	sun3_udc_write(UDC_INT_ENABLE, UDC_CSR);
3058c2ecf20Sopenharmony_ci#endif
3068c2ecf20Sopenharmony_ci
3078c2ecf20Sopenharmony_ci       	return count;
3088c2ecf20Sopenharmony_ci
3098c2ecf20Sopenharmony_ci}
3108c2ecf20Sopenharmony_ci
3118c2ecf20Sopenharmony_cistatic int sun3scsi_dma_count(struct NCR5380_hostdata *hostdata,
3128c2ecf20Sopenharmony_ci                              unsigned char *data, int count)
3138c2ecf20Sopenharmony_ci{
3148c2ecf20Sopenharmony_ci	return count;
3158c2ecf20Sopenharmony_ci}
3168c2ecf20Sopenharmony_ci
3178c2ecf20Sopenharmony_cistatic inline int sun3scsi_dma_recv_setup(struct NCR5380_hostdata *hostdata,
3188c2ecf20Sopenharmony_ci                                          unsigned char *data, int count)
3198c2ecf20Sopenharmony_ci{
3208c2ecf20Sopenharmony_ci	return sun3scsi_dma_setup(hostdata, data, count, 0);
3218c2ecf20Sopenharmony_ci}
3228c2ecf20Sopenharmony_ci
3238c2ecf20Sopenharmony_cistatic inline int sun3scsi_dma_send_setup(struct NCR5380_hostdata *hostdata,
3248c2ecf20Sopenharmony_ci                                          unsigned char *data, int count)
3258c2ecf20Sopenharmony_ci{
3268c2ecf20Sopenharmony_ci	return sun3scsi_dma_setup(hostdata, data, count, 1);
3278c2ecf20Sopenharmony_ci}
3288c2ecf20Sopenharmony_ci
3298c2ecf20Sopenharmony_cistatic int sun3scsi_dma_residual(struct NCR5380_hostdata *hostdata)
3308c2ecf20Sopenharmony_ci{
3318c2ecf20Sopenharmony_ci	return last_residual;
3328c2ecf20Sopenharmony_ci}
3338c2ecf20Sopenharmony_ci
3348c2ecf20Sopenharmony_cistatic int sun3scsi_dma_xfer_len(struct NCR5380_hostdata *hostdata,
3358c2ecf20Sopenharmony_ci                                 struct scsi_cmnd *cmd)
3368c2ecf20Sopenharmony_ci{
3378c2ecf20Sopenharmony_ci	int wanted_len = cmd->SCp.this_residual;
3388c2ecf20Sopenharmony_ci
3398c2ecf20Sopenharmony_ci	if (wanted_len < DMA_MIN_SIZE || blk_rq_is_passthrough(cmd->request))
3408c2ecf20Sopenharmony_ci		return 0;
3418c2ecf20Sopenharmony_ci
3428c2ecf20Sopenharmony_ci	return wanted_len;
3438c2ecf20Sopenharmony_ci}
3448c2ecf20Sopenharmony_ci
3458c2ecf20Sopenharmony_cistatic inline int sun3scsi_dma_start(unsigned long count, unsigned char *data)
3468c2ecf20Sopenharmony_ci{
3478c2ecf20Sopenharmony_ci#ifdef SUN3_SCSI_VME
3488c2ecf20Sopenharmony_ci	unsigned short csr;
3498c2ecf20Sopenharmony_ci
3508c2ecf20Sopenharmony_ci	csr = dregs->csr;
3518c2ecf20Sopenharmony_ci
3528c2ecf20Sopenharmony_ci	dregs->dma_count_hi = (sun3_dma_orig_count >> 16);
3538c2ecf20Sopenharmony_ci	dregs->dma_count_lo = (sun3_dma_orig_count & 0xffff);
3548c2ecf20Sopenharmony_ci
3558c2ecf20Sopenharmony_ci	dregs->fifo_count_hi = (sun3_dma_orig_count >> 16);
3568c2ecf20Sopenharmony_ci	dregs->fifo_count = (sun3_dma_orig_count & 0xffff);
3578c2ecf20Sopenharmony_ci
3588c2ecf20Sopenharmony_ci/*	if(!(csr & CSR_DMA_ENABLE))
3598c2ecf20Sopenharmony_ci *		dregs->csr |= CSR_DMA_ENABLE;
3608c2ecf20Sopenharmony_ci */
3618c2ecf20Sopenharmony_ci#else
3628c2ecf20Sopenharmony_ci    sun3_udc_write(UDC_CHN_START, UDC_CSR);
3638c2ecf20Sopenharmony_ci#endif
3648c2ecf20Sopenharmony_ci
3658c2ecf20Sopenharmony_ci    return 0;
3668c2ecf20Sopenharmony_ci}
3678c2ecf20Sopenharmony_ci
3688c2ecf20Sopenharmony_ci/* clean up after our dma is done */
3698c2ecf20Sopenharmony_cistatic int sun3scsi_dma_finish(int write_flag)
3708c2ecf20Sopenharmony_ci{
3718c2ecf20Sopenharmony_ci	unsigned short __maybe_unused count;
3728c2ecf20Sopenharmony_ci	unsigned short fifo;
3738c2ecf20Sopenharmony_ci	int ret = 0;
3748c2ecf20Sopenharmony_ci
3758c2ecf20Sopenharmony_ci	sun3_dma_active = 0;
3768c2ecf20Sopenharmony_ci
3778c2ecf20Sopenharmony_ci#ifdef SUN3_SCSI_VME
3788c2ecf20Sopenharmony_ci	dregs->csr &= ~CSR_DMA_ENABLE;
3798c2ecf20Sopenharmony_ci
3808c2ecf20Sopenharmony_ci	fifo = dregs->fifo_count;
3818c2ecf20Sopenharmony_ci	if (write_flag) {
3828c2ecf20Sopenharmony_ci		if ((fifo > 0) && (fifo < sun3_dma_orig_count))
3838c2ecf20Sopenharmony_ci			fifo++;
3848c2ecf20Sopenharmony_ci	}
3858c2ecf20Sopenharmony_ci
3868c2ecf20Sopenharmony_ci	last_residual = fifo;
3878c2ecf20Sopenharmony_ci	/* empty bytes from the fifo which didn't make it */
3888c2ecf20Sopenharmony_ci	if ((!write_flag) && (dregs->csr & CSR_LEFT)) {
3898c2ecf20Sopenharmony_ci		unsigned char *vaddr;
3908c2ecf20Sopenharmony_ci
3918c2ecf20Sopenharmony_ci		vaddr = (unsigned char *)dvma_vmetov(sun3_dma_orig_addr);
3928c2ecf20Sopenharmony_ci
3938c2ecf20Sopenharmony_ci		vaddr += (sun3_dma_orig_count - fifo);
3948c2ecf20Sopenharmony_ci		vaddr--;
3958c2ecf20Sopenharmony_ci
3968c2ecf20Sopenharmony_ci		switch (dregs->csr & CSR_LEFT) {
3978c2ecf20Sopenharmony_ci		case CSR_LEFT_3:
3988c2ecf20Sopenharmony_ci			*vaddr = (dregs->bpack_lo & 0xff00) >> 8;
3998c2ecf20Sopenharmony_ci			vaddr--;
4008c2ecf20Sopenharmony_ci			fallthrough;
4018c2ecf20Sopenharmony_ci
4028c2ecf20Sopenharmony_ci		case CSR_LEFT_2:
4038c2ecf20Sopenharmony_ci			*vaddr = (dregs->bpack_hi & 0x00ff);
4048c2ecf20Sopenharmony_ci			vaddr--;
4058c2ecf20Sopenharmony_ci			fallthrough;
4068c2ecf20Sopenharmony_ci
4078c2ecf20Sopenharmony_ci		case CSR_LEFT_1:
4088c2ecf20Sopenharmony_ci			*vaddr = (dregs->bpack_hi & 0xff00) >> 8;
4098c2ecf20Sopenharmony_ci			break;
4108c2ecf20Sopenharmony_ci		}
4118c2ecf20Sopenharmony_ci	}
4128c2ecf20Sopenharmony_ci#else
4138c2ecf20Sopenharmony_ci	// check to empty the fifo on a read
4148c2ecf20Sopenharmony_ci	if(!write_flag) {
4158c2ecf20Sopenharmony_ci		int tmo = 20000; /* .2 sec */
4168c2ecf20Sopenharmony_ci
4178c2ecf20Sopenharmony_ci		while(1) {
4188c2ecf20Sopenharmony_ci			if(dregs->csr & CSR_FIFO_EMPTY)
4198c2ecf20Sopenharmony_ci				break;
4208c2ecf20Sopenharmony_ci
4218c2ecf20Sopenharmony_ci			if(--tmo <= 0) {
4228c2ecf20Sopenharmony_ci				printk("sun3scsi: fifo failed to empty!\n");
4238c2ecf20Sopenharmony_ci				return 1;
4248c2ecf20Sopenharmony_ci			}
4258c2ecf20Sopenharmony_ci			udelay(10);
4268c2ecf20Sopenharmony_ci		}
4278c2ecf20Sopenharmony_ci	}
4288c2ecf20Sopenharmony_ci
4298c2ecf20Sopenharmony_ci	dregs->udc_addr = 0x32;
4308c2ecf20Sopenharmony_ci	udelay(SUN3_DMA_DELAY);
4318c2ecf20Sopenharmony_ci	count = 2 * dregs->udc_data;
4328c2ecf20Sopenharmony_ci	udelay(SUN3_DMA_DELAY);
4338c2ecf20Sopenharmony_ci
4348c2ecf20Sopenharmony_ci	fifo = dregs->fifo_count;
4358c2ecf20Sopenharmony_ci	last_residual = fifo;
4368c2ecf20Sopenharmony_ci
4378c2ecf20Sopenharmony_ci	/* empty bytes from the fifo which didn't make it */
4388c2ecf20Sopenharmony_ci	if((!write_flag) && (count - fifo) == 2) {
4398c2ecf20Sopenharmony_ci		unsigned short data;
4408c2ecf20Sopenharmony_ci		unsigned char *vaddr;
4418c2ecf20Sopenharmony_ci
4428c2ecf20Sopenharmony_ci		data = dregs->fifo_data;
4438c2ecf20Sopenharmony_ci		vaddr = (unsigned char *)dvma_btov(sun3_dma_orig_addr);
4448c2ecf20Sopenharmony_ci
4458c2ecf20Sopenharmony_ci		vaddr += (sun3_dma_orig_count - fifo);
4468c2ecf20Sopenharmony_ci
4478c2ecf20Sopenharmony_ci		vaddr[-2] = (data & 0xff00) >> 8;
4488c2ecf20Sopenharmony_ci		vaddr[-1] = (data & 0xff);
4498c2ecf20Sopenharmony_ci	}
4508c2ecf20Sopenharmony_ci#endif
4518c2ecf20Sopenharmony_ci
4528c2ecf20Sopenharmony_ci	dvma_unmap(sun3_dma_orig_addr);
4538c2ecf20Sopenharmony_ci	sun3_dma_orig_addr = NULL;
4548c2ecf20Sopenharmony_ci
4558c2ecf20Sopenharmony_ci#ifdef SUN3_SCSI_VME
4568c2ecf20Sopenharmony_ci	dregs->dma_addr_hi = 0;
4578c2ecf20Sopenharmony_ci	dregs->dma_addr_lo = 0;
4588c2ecf20Sopenharmony_ci	dregs->dma_count_hi = 0;
4598c2ecf20Sopenharmony_ci	dregs->dma_count_lo = 0;
4608c2ecf20Sopenharmony_ci
4618c2ecf20Sopenharmony_ci	dregs->fifo_count = 0;
4628c2ecf20Sopenharmony_ci	dregs->fifo_count_hi = 0;
4638c2ecf20Sopenharmony_ci
4648c2ecf20Sopenharmony_ci	dregs->csr &= ~CSR_SEND;
4658c2ecf20Sopenharmony_ci/*	dregs->csr |= CSR_DMA_ENABLE; */
4668c2ecf20Sopenharmony_ci#else
4678c2ecf20Sopenharmony_ci	sun3_udc_write(UDC_RESET, UDC_CSR);
4688c2ecf20Sopenharmony_ci	dregs->fifo_count = 0;
4698c2ecf20Sopenharmony_ci	dregs->csr &= ~CSR_SEND;
4708c2ecf20Sopenharmony_ci
4718c2ecf20Sopenharmony_ci	/* reset fifo */
4728c2ecf20Sopenharmony_ci	dregs->csr &= ~CSR_FIFO;
4738c2ecf20Sopenharmony_ci	dregs->csr |= CSR_FIFO;
4748c2ecf20Sopenharmony_ci#endif
4758c2ecf20Sopenharmony_ci
4768c2ecf20Sopenharmony_ci	sun3_dma_setup_done = NULL;
4778c2ecf20Sopenharmony_ci
4788c2ecf20Sopenharmony_ci	return ret;
4798c2ecf20Sopenharmony_ci
4808c2ecf20Sopenharmony_ci}
4818c2ecf20Sopenharmony_ci
4828c2ecf20Sopenharmony_ci#include "NCR5380.c"
4838c2ecf20Sopenharmony_ci
4848c2ecf20Sopenharmony_ci#ifdef SUN3_SCSI_VME
4858c2ecf20Sopenharmony_ci#define SUN3_SCSI_NAME          "Sun3 NCR5380 VME SCSI"
4868c2ecf20Sopenharmony_ci#define DRV_MODULE_NAME         "sun3_scsi_vme"
4878c2ecf20Sopenharmony_ci#else
4888c2ecf20Sopenharmony_ci#define SUN3_SCSI_NAME          "Sun3 NCR5380 SCSI"
4898c2ecf20Sopenharmony_ci#define DRV_MODULE_NAME         "sun3_scsi"
4908c2ecf20Sopenharmony_ci#endif
4918c2ecf20Sopenharmony_ci
4928c2ecf20Sopenharmony_ci#define PFX                     DRV_MODULE_NAME ": "
4938c2ecf20Sopenharmony_ci
4948c2ecf20Sopenharmony_cistatic struct scsi_host_template sun3_scsi_template = {
4958c2ecf20Sopenharmony_ci	.module			= THIS_MODULE,
4968c2ecf20Sopenharmony_ci	.proc_name		= DRV_MODULE_NAME,
4978c2ecf20Sopenharmony_ci	.name			= SUN3_SCSI_NAME,
4988c2ecf20Sopenharmony_ci	.info			= sun3scsi_info,
4998c2ecf20Sopenharmony_ci	.queuecommand		= sun3scsi_queue_command,
5008c2ecf20Sopenharmony_ci	.eh_abort_handler	= sun3scsi_abort,
5018c2ecf20Sopenharmony_ci	.eh_host_reset_handler	= sun3scsi_host_reset,
5028c2ecf20Sopenharmony_ci	.can_queue		= 16,
5038c2ecf20Sopenharmony_ci	.this_id		= 7,
5048c2ecf20Sopenharmony_ci	.sg_tablesize		= 1,
5058c2ecf20Sopenharmony_ci	.cmd_per_lun		= 2,
5068c2ecf20Sopenharmony_ci	.dma_boundary		= PAGE_SIZE - 1,
5078c2ecf20Sopenharmony_ci	.cmd_size		= NCR5380_CMD_SIZE,
5088c2ecf20Sopenharmony_ci};
5098c2ecf20Sopenharmony_ci
5108c2ecf20Sopenharmony_cistatic int __init sun3_scsi_probe(struct platform_device *pdev)
5118c2ecf20Sopenharmony_ci{
5128c2ecf20Sopenharmony_ci	struct Scsi_Host *instance;
5138c2ecf20Sopenharmony_ci	struct NCR5380_hostdata *hostdata;
5148c2ecf20Sopenharmony_ci	int error;
5158c2ecf20Sopenharmony_ci	struct resource *irq, *mem;
5168c2ecf20Sopenharmony_ci	void __iomem *ioaddr;
5178c2ecf20Sopenharmony_ci	int host_flags = 0;
5188c2ecf20Sopenharmony_ci#ifdef SUN3_SCSI_VME
5198c2ecf20Sopenharmony_ci	int i;
5208c2ecf20Sopenharmony_ci#endif
5218c2ecf20Sopenharmony_ci
5228c2ecf20Sopenharmony_ci	if (setup_can_queue > 0)
5238c2ecf20Sopenharmony_ci		sun3_scsi_template.can_queue = setup_can_queue;
5248c2ecf20Sopenharmony_ci	if (setup_cmd_per_lun > 0)
5258c2ecf20Sopenharmony_ci		sun3_scsi_template.cmd_per_lun = setup_cmd_per_lun;
5268c2ecf20Sopenharmony_ci	if (setup_sg_tablesize > 0)
5278c2ecf20Sopenharmony_ci		sun3_scsi_template.sg_tablesize = setup_sg_tablesize;
5288c2ecf20Sopenharmony_ci	if (setup_hostid >= 0)
5298c2ecf20Sopenharmony_ci		sun3_scsi_template.this_id = setup_hostid & 7;
5308c2ecf20Sopenharmony_ci
5318c2ecf20Sopenharmony_ci#ifdef SUN3_SCSI_VME
5328c2ecf20Sopenharmony_ci	ioaddr = NULL;
5338c2ecf20Sopenharmony_ci	for (i = 0; i < 2; i++) {
5348c2ecf20Sopenharmony_ci		unsigned char x;
5358c2ecf20Sopenharmony_ci
5368c2ecf20Sopenharmony_ci		irq = platform_get_resource(pdev, IORESOURCE_IRQ, i);
5378c2ecf20Sopenharmony_ci		mem = platform_get_resource(pdev, IORESOURCE_MEM, i);
5388c2ecf20Sopenharmony_ci		if (!irq || !mem)
5398c2ecf20Sopenharmony_ci			break;
5408c2ecf20Sopenharmony_ci
5418c2ecf20Sopenharmony_ci		ioaddr = sun3_ioremap(mem->start, resource_size(mem),
5428c2ecf20Sopenharmony_ci		                      SUN3_PAGE_TYPE_VME16);
5438c2ecf20Sopenharmony_ci		dregs = (struct sun3_dma_regs *)(ioaddr + 8);
5448c2ecf20Sopenharmony_ci
5458c2ecf20Sopenharmony_ci		if (sun3_map_test((unsigned long)dregs, &x)) {
5468c2ecf20Sopenharmony_ci			unsigned short oldcsr;
5478c2ecf20Sopenharmony_ci
5488c2ecf20Sopenharmony_ci			oldcsr = dregs->csr;
5498c2ecf20Sopenharmony_ci			dregs->csr = 0;
5508c2ecf20Sopenharmony_ci			udelay(SUN3_DMA_DELAY);
5518c2ecf20Sopenharmony_ci			if (dregs->csr == 0x1400)
5528c2ecf20Sopenharmony_ci				break;
5538c2ecf20Sopenharmony_ci
5548c2ecf20Sopenharmony_ci			dregs->csr = oldcsr;
5558c2ecf20Sopenharmony_ci		}
5568c2ecf20Sopenharmony_ci
5578c2ecf20Sopenharmony_ci		iounmap(ioaddr);
5588c2ecf20Sopenharmony_ci		ioaddr = NULL;
5598c2ecf20Sopenharmony_ci	}
5608c2ecf20Sopenharmony_ci	if (!ioaddr)
5618c2ecf20Sopenharmony_ci		return -ENODEV;
5628c2ecf20Sopenharmony_ci#else
5638c2ecf20Sopenharmony_ci	irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
5648c2ecf20Sopenharmony_ci	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
5658c2ecf20Sopenharmony_ci	if (!irq || !mem)
5668c2ecf20Sopenharmony_ci		return -ENODEV;
5678c2ecf20Sopenharmony_ci
5688c2ecf20Sopenharmony_ci	ioaddr = ioremap(mem->start, resource_size(mem));
5698c2ecf20Sopenharmony_ci	dregs = (struct sun3_dma_regs *)(ioaddr + 8);
5708c2ecf20Sopenharmony_ci
5718c2ecf20Sopenharmony_ci	udc_regs = dvma_malloc(sizeof(struct sun3_udc_regs));
5728c2ecf20Sopenharmony_ci	if (!udc_regs) {
5738c2ecf20Sopenharmony_ci		pr_err(PFX "couldn't allocate DVMA memory!\n");
5748c2ecf20Sopenharmony_ci		iounmap(ioaddr);
5758c2ecf20Sopenharmony_ci		return -ENOMEM;
5768c2ecf20Sopenharmony_ci	}
5778c2ecf20Sopenharmony_ci#endif
5788c2ecf20Sopenharmony_ci
5798c2ecf20Sopenharmony_ci	instance = scsi_host_alloc(&sun3_scsi_template,
5808c2ecf20Sopenharmony_ci	                           sizeof(struct NCR5380_hostdata));
5818c2ecf20Sopenharmony_ci	if (!instance) {
5828c2ecf20Sopenharmony_ci		error = -ENOMEM;
5838c2ecf20Sopenharmony_ci		goto fail_alloc;
5848c2ecf20Sopenharmony_ci	}
5858c2ecf20Sopenharmony_ci
5868c2ecf20Sopenharmony_ci	instance->irq = irq->start;
5878c2ecf20Sopenharmony_ci
5888c2ecf20Sopenharmony_ci	hostdata = shost_priv(instance);
5898c2ecf20Sopenharmony_ci	hostdata->base = mem->start;
5908c2ecf20Sopenharmony_ci	hostdata->io = ioaddr;
5918c2ecf20Sopenharmony_ci
5928c2ecf20Sopenharmony_ci	error = NCR5380_init(instance, host_flags);
5938c2ecf20Sopenharmony_ci	if (error)
5948c2ecf20Sopenharmony_ci		goto fail_init;
5958c2ecf20Sopenharmony_ci
5968c2ecf20Sopenharmony_ci	error = request_irq(instance->irq, scsi_sun3_intr, 0,
5978c2ecf20Sopenharmony_ci	                    "NCR5380", instance);
5988c2ecf20Sopenharmony_ci	if (error) {
5998c2ecf20Sopenharmony_ci		pr_err(PFX "scsi%d: IRQ %d not free, bailing out\n",
6008c2ecf20Sopenharmony_ci		       instance->host_no, instance->irq);
6018c2ecf20Sopenharmony_ci		goto fail_irq;
6028c2ecf20Sopenharmony_ci	}
6038c2ecf20Sopenharmony_ci
6048c2ecf20Sopenharmony_ci	dregs->csr = 0;
6058c2ecf20Sopenharmony_ci	udelay(SUN3_DMA_DELAY);
6068c2ecf20Sopenharmony_ci	dregs->csr = CSR_SCSI | CSR_FIFO | CSR_INTR;
6078c2ecf20Sopenharmony_ci	udelay(SUN3_DMA_DELAY);
6088c2ecf20Sopenharmony_ci	dregs->fifo_count = 0;
6098c2ecf20Sopenharmony_ci#ifdef SUN3_SCSI_VME
6108c2ecf20Sopenharmony_ci	dregs->fifo_count_hi = 0;
6118c2ecf20Sopenharmony_ci	dregs->dma_addr_hi = 0;
6128c2ecf20Sopenharmony_ci	dregs->dma_addr_lo = 0;
6138c2ecf20Sopenharmony_ci	dregs->dma_count_hi = 0;
6148c2ecf20Sopenharmony_ci	dregs->dma_count_lo = 0;
6158c2ecf20Sopenharmony_ci
6168c2ecf20Sopenharmony_ci	dregs->ivect = VME_DATA24 | (instance->irq & 0xff);
6178c2ecf20Sopenharmony_ci#endif
6188c2ecf20Sopenharmony_ci
6198c2ecf20Sopenharmony_ci	NCR5380_maybe_reset_bus(instance);
6208c2ecf20Sopenharmony_ci
6218c2ecf20Sopenharmony_ci	error = scsi_add_host(instance, NULL);
6228c2ecf20Sopenharmony_ci	if (error)
6238c2ecf20Sopenharmony_ci		goto fail_host;
6248c2ecf20Sopenharmony_ci
6258c2ecf20Sopenharmony_ci	platform_set_drvdata(pdev, instance);
6268c2ecf20Sopenharmony_ci
6278c2ecf20Sopenharmony_ci	scsi_scan_host(instance);
6288c2ecf20Sopenharmony_ci	return 0;
6298c2ecf20Sopenharmony_ci
6308c2ecf20Sopenharmony_cifail_host:
6318c2ecf20Sopenharmony_ci	free_irq(instance->irq, instance);
6328c2ecf20Sopenharmony_cifail_irq:
6338c2ecf20Sopenharmony_ci	NCR5380_exit(instance);
6348c2ecf20Sopenharmony_cifail_init:
6358c2ecf20Sopenharmony_ci	scsi_host_put(instance);
6368c2ecf20Sopenharmony_cifail_alloc:
6378c2ecf20Sopenharmony_ci	if (udc_regs)
6388c2ecf20Sopenharmony_ci		dvma_free(udc_regs);
6398c2ecf20Sopenharmony_ci	iounmap(ioaddr);
6408c2ecf20Sopenharmony_ci	return error;
6418c2ecf20Sopenharmony_ci}
6428c2ecf20Sopenharmony_ci
6438c2ecf20Sopenharmony_cistatic int __exit sun3_scsi_remove(struct platform_device *pdev)
6448c2ecf20Sopenharmony_ci{
6458c2ecf20Sopenharmony_ci	struct Scsi_Host *instance = platform_get_drvdata(pdev);
6468c2ecf20Sopenharmony_ci	struct NCR5380_hostdata *hostdata = shost_priv(instance);
6478c2ecf20Sopenharmony_ci	void __iomem *ioaddr = hostdata->io;
6488c2ecf20Sopenharmony_ci
6498c2ecf20Sopenharmony_ci	scsi_remove_host(instance);
6508c2ecf20Sopenharmony_ci	free_irq(instance->irq, instance);
6518c2ecf20Sopenharmony_ci	NCR5380_exit(instance);
6528c2ecf20Sopenharmony_ci	scsi_host_put(instance);
6538c2ecf20Sopenharmony_ci	if (udc_regs)
6548c2ecf20Sopenharmony_ci		dvma_free(udc_regs);
6558c2ecf20Sopenharmony_ci	iounmap(ioaddr);
6568c2ecf20Sopenharmony_ci	return 0;
6578c2ecf20Sopenharmony_ci}
6588c2ecf20Sopenharmony_ci
6598c2ecf20Sopenharmony_cistatic struct platform_driver sun3_scsi_driver = {
6608c2ecf20Sopenharmony_ci	.remove = __exit_p(sun3_scsi_remove),
6618c2ecf20Sopenharmony_ci	.driver = {
6628c2ecf20Sopenharmony_ci		.name	= DRV_MODULE_NAME,
6638c2ecf20Sopenharmony_ci	},
6648c2ecf20Sopenharmony_ci};
6658c2ecf20Sopenharmony_ci
6668c2ecf20Sopenharmony_cimodule_platform_driver_probe(sun3_scsi_driver, sun3_scsi_probe);
6678c2ecf20Sopenharmony_ci
6688c2ecf20Sopenharmony_ciMODULE_ALIAS("platform:" DRV_MODULE_NAME);
6698c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
670