xref: /openbmc/linux/drivers/scsi/arm/arxescsi.c (revision 1ac731c529cd4d6adbce134754b51ff7d822b145)
109c434b8SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
21da177e4SLinus Torvalds /*
3f30c2269SUwe Zeisberger  * linux/drivers/scsi/arm/arxescsi.c
41da177e4SLinus Torvalds  *
51da177e4SLinus Torvalds  * Copyright (C) 1997-2000 Russell King, Stefan Hanske
61da177e4SLinus Torvalds  *
71da177e4SLinus Torvalds  * This driver is based on experimentation.  Hence, it may have made
81da177e4SLinus Torvalds  * assumptions about the particular card that I have available, and
91da177e4SLinus Torvalds  * may not be reliable!
101da177e4SLinus Torvalds  *
111da177e4SLinus Torvalds  * Changelog:
121da177e4SLinus Torvalds  *  30-08-1997	RMK	0.0.0	Created, READONLY version as cumana_2.c
131da177e4SLinus Torvalds  *  22-01-1998	RMK	0.0.1	Updated to 2.1.80
141da177e4SLinus Torvalds  *  15-04-1998	RMK	0.0.1	Only do PIO if FAS216 will allow it.
151da177e4SLinus Torvalds  *  11-06-1998 	SH	0.0.2   Changed to support ARXE 16-bit SCSI card
161da177e4SLinus Torvalds  *				enabled writing
171da177e4SLinus Torvalds  *  01-01-2000	SH	0.1.0   Added *real* pseudo dma writing
181da177e4SLinus Torvalds  *				(arxescsi_pseudo_dma_write)
191da177e4SLinus Torvalds  *  02-04-2000	RMK	0.1.1	Updated for new error handling code.
201da177e4SLinus Torvalds  *  22-10-2000  SH		Updated for new registering scheme.
211da177e4SLinus Torvalds  */
221da177e4SLinus Torvalds #include <linux/module.h>
231da177e4SLinus Torvalds #include <linux/blkdev.h>
241da177e4SLinus Torvalds #include <linux/kernel.h>
251da177e4SLinus Torvalds #include <linux/string.h>
261da177e4SLinus Torvalds #include <linux/ioport.h>
271da177e4SLinus Torvalds #include <linux/proc_fs.h>
281da177e4SLinus Torvalds #include <linux/unistd.h>
291da177e4SLinus Torvalds #include <linux/stat.h>
301da177e4SLinus Torvalds #include <linux/delay.h>
311da177e4SLinus Torvalds #include <linux/init.h>
321da177e4SLinus Torvalds #include <linux/interrupt.h>
331da177e4SLinus Torvalds 
341da177e4SLinus Torvalds #include <asm/dma.h>
351da177e4SLinus Torvalds #include <asm/io.h>
361da177e4SLinus Torvalds #include <asm/ecard.h>
371da177e4SLinus Torvalds 
3853555fb7SBart Van Assche #include <scsi/scsi.h>
3953555fb7SBart Van Assche #include <scsi/scsi_cmnd.h>
4053555fb7SBart Van Assche #include <scsi/scsi_device.h>
4153555fb7SBart Van Assche #include <scsi/scsi_eh.h>
421da177e4SLinus Torvalds #include <scsi/scsi_host.h>
4353555fb7SBart Van Assche #include <scsi/scsi_tcq.h>
441da177e4SLinus Torvalds #include "fas216.h"
451da177e4SLinus Torvalds 
461da177e4SLinus Torvalds struct arxescsi_info {
471da177e4SLinus Torvalds 	FAS216_Info		info;
481da177e4SLinus Torvalds 	struct expansion_card	*ec;
491da177e4SLinus Torvalds 	void __iomem		*base;
501da177e4SLinus Torvalds };
511da177e4SLinus Torvalds 
521da177e4SLinus Torvalds #define DMADATA_OFFSET	(0x200)
531da177e4SLinus Torvalds 
541da177e4SLinus Torvalds #define DMASTAT_OFFSET	(0x600)
551da177e4SLinus Torvalds #define DMASTAT_DRQ	(1 << 0)
561da177e4SLinus Torvalds 
571da177e4SLinus Torvalds #define CSTATUS_IRQ	(1 << 0)
581da177e4SLinus Torvalds 
591da177e4SLinus Torvalds #define VERSION "1.10 (23/01/2003 2.5.57)"
601da177e4SLinus Torvalds 
611da177e4SLinus Torvalds /*
621da177e4SLinus Torvalds  * Function: int arxescsi_dma_setup(host, SCpnt, direction, min_type)
631da177e4SLinus Torvalds  * Purpose : initialises DMA/PIO
641da177e4SLinus Torvalds  * Params  : host      - host
651da177e4SLinus Torvalds  *	     SCpnt     - command
661da177e4SLinus Torvalds  *	     direction - DMA on to/off of card
671da177e4SLinus Torvalds  *	     min_type  - minimum DMA support that we must have for this transfer
681da177e4SLinus Torvalds  * Returns : 0 if we should not set CMD_WITHDMA for transfer info command
691da177e4SLinus Torvalds  */
701da177e4SLinus Torvalds static fasdmatype_t
arxescsi_dma_setup(struct Scsi_Host * host,struct scsi_pointer * SCp,fasdmadir_t direction,fasdmatype_t min_type)710a04137eSChristoph Hellwig arxescsi_dma_setup(struct Scsi_Host *host, struct scsi_pointer *SCp,
721da177e4SLinus Torvalds 		       fasdmadir_t direction, fasdmatype_t min_type)
731da177e4SLinus Torvalds {
741da177e4SLinus Torvalds 	/*
751da177e4SLinus Torvalds 	 * We don't do real DMA
761da177e4SLinus Torvalds 	 */
771da177e4SLinus Torvalds 	return fasdma_pseudo;
781da177e4SLinus Torvalds }
791da177e4SLinus Torvalds 
arxescsi_pseudo_dma_write(unsigned char * addr,void __iomem * base)801da177e4SLinus Torvalds static void arxescsi_pseudo_dma_write(unsigned char *addr, void __iomem *base)
811da177e4SLinus Torvalds {
821da177e4SLinus Torvalds        __asm__ __volatile__(
831da177e4SLinus Torvalds        "               stmdb   sp!, {r0-r12}\n"
841da177e4SLinus Torvalds        "               mov     r3, %0\n"
851da177e4SLinus Torvalds        "               mov     r1, %1\n"
861da177e4SLinus Torvalds        "               add     r2, r1, #512\n"
871da177e4SLinus Torvalds        "               mov     r4, #256\n"
881da177e4SLinus Torvalds        ".loop_1:       ldmia   r3!, {r6, r8, r10, r12}\n"
891da177e4SLinus Torvalds        "               mov     r5, r6, lsl #16\n"
901da177e4SLinus Torvalds        "               mov     r7, r8, lsl #16\n"
911da177e4SLinus Torvalds        ".loop_2:       ldrb    r0, [r1, #1536]\n"
921da177e4SLinus Torvalds        "               tst     r0, #1\n"
931da177e4SLinus Torvalds        "               beq     .loop_2\n"
941da177e4SLinus Torvalds        "               stmia   r2, {r5-r8}\n\t"
951da177e4SLinus Torvalds        "               mov     r9, r10, lsl #16\n"
961da177e4SLinus Torvalds        "               mov     r11, r12, lsl #16\n"
971da177e4SLinus Torvalds        ".loop_3:       ldrb    r0, [r1, #1536]\n"
981da177e4SLinus Torvalds        "               tst     r0, #1\n"
991da177e4SLinus Torvalds        "               beq     .loop_3\n"
1001da177e4SLinus Torvalds        "               stmia   r2, {r9-r12}\n"
1011da177e4SLinus Torvalds        "               subs    r4, r4, #16\n"
1021da177e4SLinus Torvalds        "               bne     .loop_1\n"
1031da177e4SLinus Torvalds        "               ldmia   sp!, {r0-r12}\n"
1041da177e4SLinus Torvalds        :
1051da177e4SLinus Torvalds        : "r" (addr), "r" (base));
1061da177e4SLinus Torvalds }
1071da177e4SLinus Torvalds 
1081da177e4SLinus Torvalds /*
1091da177e4SLinus Torvalds  * Function: int arxescsi_dma_pseudo(host, SCpnt, direction, transfer)
1101da177e4SLinus Torvalds  * Purpose : handles pseudo DMA
1111da177e4SLinus Torvalds  * Params  : host      - host
1121da177e4SLinus Torvalds  *	     SCpnt     - command
1131da177e4SLinus Torvalds  *	     direction - DMA on to/off of card
1141da177e4SLinus Torvalds  *	     transfer  - minimum number of bytes we expect to transfer
1151da177e4SLinus Torvalds  */
1161da177e4SLinus Torvalds static void
arxescsi_dma_pseudo(struct Scsi_Host * host,struct scsi_pointer * SCp,fasdmadir_t direction,int transfer)1170a04137eSChristoph Hellwig arxescsi_dma_pseudo(struct Scsi_Host *host, struct scsi_pointer *SCp,
1181da177e4SLinus Torvalds 		    fasdmadir_t direction, int transfer)
1191da177e4SLinus Torvalds {
1201da177e4SLinus Torvalds 	struct arxescsi_info *info = (struct arxescsi_info *)host->hostdata;
1211da177e4SLinus Torvalds 	unsigned int length, error = 0;
1221da177e4SLinus Torvalds 	void __iomem *base = info->info.scsi.io_base;
1231da177e4SLinus Torvalds 	unsigned char *addr;
1241da177e4SLinus Torvalds 
1251da177e4SLinus Torvalds 	length = SCp->this_residual;
1261da177e4SLinus Torvalds 	addr = SCp->ptr;
1271da177e4SLinus Torvalds 
1281da177e4SLinus Torvalds 	if (direction == DMA_OUT) {
1291da177e4SLinus Torvalds 		unsigned int word;
1301da177e4SLinus Torvalds 		while (length > 256) {
1311da177e4SLinus Torvalds 			if (readb(base + 0x80) & STAT_INT) {
1321da177e4SLinus Torvalds 				error = 1;
1331da177e4SLinus Torvalds 				break;
1341da177e4SLinus Torvalds 			}
1351da177e4SLinus Torvalds 			arxescsi_pseudo_dma_write(addr, base);
1361da177e4SLinus Torvalds 			addr += 256;
1371da177e4SLinus Torvalds 			length -= 256;
1381da177e4SLinus Torvalds 		}
1391da177e4SLinus Torvalds 
1401da177e4SLinus Torvalds 		if (!error)
1411da177e4SLinus Torvalds 			while (length > 0) {
1421da177e4SLinus Torvalds 				if (readb(base + 0x80) & STAT_INT)
1431da177e4SLinus Torvalds 					break;
1441da177e4SLinus Torvalds 
1451da177e4SLinus Torvalds 				if (!(readb(base + DMASTAT_OFFSET) & DMASTAT_DRQ))
1461da177e4SLinus Torvalds 					continue;
1471da177e4SLinus Torvalds 
1481da177e4SLinus Torvalds 				word = *addr | *(addr + 1) << 8;
1491da177e4SLinus Torvalds 
1501da177e4SLinus Torvalds 				writew(word, base + DMADATA_OFFSET);
1511da177e4SLinus Torvalds 				if (length > 1) {
1521da177e4SLinus Torvalds 					addr += 2;
1531da177e4SLinus Torvalds 					length -= 2;
1541da177e4SLinus Torvalds 				} else {
1551da177e4SLinus Torvalds 					addr += 1;
1561da177e4SLinus Torvalds 					length -= 1;
1571da177e4SLinus Torvalds 				}
1581da177e4SLinus Torvalds 			}
1591da177e4SLinus Torvalds 	}
1601da177e4SLinus Torvalds 	else {
1611da177e4SLinus Torvalds 		if (transfer && (transfer & 255)) {
1621da177e4SLinus Torvalds 			while (length >= 256) {
1631da177e4SLinus Torvalds 				if (readb(base + 0x80) & STAT_INT) {
1641da177e4SLinus Torvalds 					error = 1;
1651da177e4SLinus Torvalds 					break;
1661da177e4SLinus Torvalds 				}
1671da177e4SLinus Torvalds 
1681da177e4SLinus Torvalds 				if (!(readb(base + DMASTAT_OFFSET) & DMASTAT_DRQ))
1691da177e4SLinus Torvalds 					continue;
1701da177e4SLinus Torvalds 
1711da177e4SLinus Torvalds 				readsw(base + DMADATA_OFFSET, addr, 256 >> 1);
1721da177e4SLinus Torvalds 				addr += 256;
1731da177e4SLinus Torvalds 				length -= 256;
1741da177e4SLinus Torvalds 			}
1751da177e4SLinus Torvalds 		}
1761da177e4SLinus Torvalds 
1771da177e4SLinus Torvalds 		if (!(error))
1781da177e4SLinus Torvalds 			while (length > 0) {
1791da177e4SLinus Torvalds 				unsigned long word;
1801da177e4SLinus Torvalds 
1811da177e4SLinus Torvalds 				if (readb(base + 0x80) & STAT_INT)
1821da177e4SLinus Torvalds 					break;
1831da177e4SLinus Torvalds 
1841da177e4SLinus Torvalds 				if (!(readb(base + DMASTAT_OFFSET) & DMASTAT_DRQ))
1851da177e4SLinus Torvalds 					continue;
1861da177e4SLinus Torvalds 
1871da177e4SLinus Torvalds 				word = readw(base + DMADATA_OFFSET);
1881da177e4SLinus Torvalds 				*addr++ = word;
1891da177e4SLinus Torvalds 				if (--length > 0) {
1901da177e4SLinus Torvalds 					*addr++ = word >> 8;
1911da177e4SLinus Torvalds 					length --;
1921da177e4SLinus Torvalds 				}
1931da177e4SLinus Torvalds 			}
1941da177e4SLinus Torvalds 	}
1951da177e4SLinus Torvalds }
1961da177e4SLinus Torvalds 
1971da177e4SLinus Torvalds /*
1981da177e4SLinus Torvalds  * Function: int arxescsi_dma_stop(host, SCpnt)
1991da177e4SLinus Torvalds  * Purpose : stops DMA/PIO
2001da177e4SLinus Torvalds  * Params  : host  - host
2011da177e4SLinus Torvalds  *	     SCpnt - command
2021da177e4SLinus Torvalds  */
arxescsi_dma_stop(struct Scsi_Host * host,struct scsi_pointer * SCp)2030a04137eSChristoph Hellwig static void arxescsi_dma_stop(struct Scsi_Host *host, struct scsi_pointer *SCp)
2041da177e4SLinus Torvalds {
2051da177e4SLinus Torvalds 	/*
2061da177e4SLinus Torvalds 	 * no DMA to stop
2071da177e4SLinus Torvalds 	 */
2081da177e4SLinus Torvalds }
2091da177e4SLinus Torvalds 
2101da177e4SLinus Torvalds /*
2111da177e4SLinus Torvalds  * Function: const char *arxescsi_info(struct Scsi_Host * host)
2121da177e4SLinus Torvalds  * Purpose : returns a descriptive string about this interface,
2131da177e4SLinus Torvalds  * Params  : host - driver host structure to return info for.
2141da177e4SLinus Torvalds  * Returns : pointer to a static buffer containing null terminated string.
2151da177e4SLinus Torvalds  */
arxescsi_info(struct Scsi_Host * host)2161da177e4SLinus Torvalds static const char *arxescsi_info(struct Scsi_Host *host)
2171da177e4SLinus Torvalds {
2181da177e4SLinus Torvalds 	struct arxescsi_info *info = (struct arxescsi_info *)host->hostdata;
2191da177e4SLinus Torvalds 	static char string[150];
2201da177e4SLinus Torvalds 
2211da177e4SLinus Torvalds 	sprintf(string, "%s (%s) in slot %d v%s",
2221da177e4SLinus Torvalds 		host->hostt->name, info->info.scsi.type, info->ec->slot_no,
2231da177e4SLinus Torvalds 		VERSION);
2241da177e4SLinus Torvalds 
2251da177e4SLinus Torvalds 	return string;
2261da177e4SLinus Torvalds }
2271da177e4SLinus Torvalds 
2281da177e4SLinus Torvalds static int
arxescsi_show_info(struct seq_file * m,struct Scsi_Host * host)2299d4e5c54SAl Viro arxescsi_show_info(struct seq_file *m, struct Scsi_Host *host)
2301da177e4SLinus Torvalds {
2311da177e4SLinus Torvalds 	struct arxescsi_info *info;
2321da177e4SLinus Torvalds 	info = (struct arxescsi_info *)host->hostdata;
2331da177e4SLinus Torvalds 
2349d4e5c54SAl Viro 	seq_printf(m, "ARXE 16-bit SCSI driver v%s\n", VERSION);
2359d4e5c54SAl Viro 	fas216_print_host(&info->info, m);
2369d4e5c54SAl Viro 	fas216_print_stats(&info->info, m);
2379d4e5c54SAl Viro 	fas216_print_devices(&info->info, m);
2389d4e5c54SAl Viro 	return 0;
2391da177e4SLinus Torvalds }
2401da177e4SLinus Torvalds 
241*116e5de7SBart Van Assche static const struct scsi_host_template arxescsi_template = {
2429d4e5c54SAl Viro 	.show_info			= arxescsi_show_info,
2431da177e4SLinus Torvalds 	.name				= "ARXE SCSI card",
2441da177e4SLinus Torvalds 	.info				= arxescsi_info,
2451da177e4SLinus Torvalds 	.queuecommand			= fas216_noqueue_command,
2461da177e4SLinus Torvalds 	.eh_host_reset_handler		= fas216_eh_host_reset,
2471da177e4SLinus Torvalds 	.eh_bus_reset_handler		= fas216_eh_bus_reset,
2481da177e4SLinus Torvalds 	.eh_device_reset_handler	= fas216_eh_device_reset,
2491da177e4SLinus Torvalds 	.eh_abort_handler		= fas216_eh_abort,
250caffd3adSBart Van Assche 	.cmd_size			= sizeof(struct fas216_cmd_priv),
2511da177e4SLinus Torvalds 	.can_queue			= 0,
2521da177e4SLinus Torvalds 	.this_id			= 7,
2531da177e4SLinus Torvalds 	.sg_tablesize			= SG_ALL,
2544af14d11SChristoph Hellwig 	.dma_boundary			= PAGE_SIZE - 1,
2551da177e4SLinus Torvalds 	.proc_name			= "arxescsi",
2561da177e4SLinus Torvalds };
2571da177e4SLinus Torvalds 
arxescsi_probe(struct expansion_card * ec,const struct ecard_id * id)2586f039790SGreg Kroah-Hartman static int arxescsi_probe(struct expansion_card *ec, const struct ecard_id *id)
2591da177e4SLinus Torvalds {
2601da177e4SLinus Torvalds 	struct Scsi_Host *host;
2611da177e4SLinus Torvalds 	struct arxescsi_info *info;
2621da177e4SLinus Torvalds 	void __iomem *base;
2631da177e4SLinus Torvalds 	int ret;
2641da177e4SLinus Torvalds 
2651da177e4SLinus Torvalds 	ret = ecard_request_resources(ec);
2661da177e4SLinus Torvalds 	if (ret)
2671da177e4SLinus Torvalds 		goto out;
2681da177e4SLinus Torvalds 
26910bdaaa0SRussell King 	base = ecardm_iomap(ec, ECARD_RES_MEMC, 0, 0);
2701da177e4SLinus Torvalds 	if (!base) {
2711da177e4SLinus Torvalds 		ret = -ENOMEM;
2721da177e4SLinus Torvalds 		goto out_region;
2731da177e4SLinus Torvalds 	}
2741da177e4SLinus Torvalds 
2751da177e4SLinus Torvalds 	host = scsi_host_alloc(&arxescsi_template, sizeof(struct arxescsi_info));
2761da177e4SLinus Torvalds 	if (!host) {
2771da177e4SLinus Torvalds 		ret = -ENOMEM;
27810bdaaa0SRussell King 		goto out_region;
2791da177e4SLinus Torvalds 	}
2801da177e4SLinus Torvalds 
2811da177e4SLinus Torvalds 	info = (struct arxescsi_info *)host->hostdata;
2821da177e4SLinus Torvalds 	info->ec = ec;
2831da177e4SLinus Torvalds 	info->base = base;
2841da177e4SLinus Torvalds 
2851da177e4SLinus Torvalds 	info->info.scsi.io_base		= base + 0x2000;
28641569e37SRussell King 	info->info.scsi.irq		= 0;
2871da177e4SLinus Torvalds 	info->info.scsi.dma		= NO_DMA;
2881da177e4SLinus Torvalds 	info->info.scsi.io_shift	= 5;
2891da177e4SLinus Torvalds 	info->info.ifcfg.clockrate	= 24; /* MHz */
2901da177e4SLinus Torvalds 	info->info.ifcfg.select_timeout = 255;
2911da177e4SLinus Torvalds 	info->info.ifcfg.asyncperiod	= 200; /* ns */
2921da177e4SLinus Torvalds 	info->info.ifcfg.sync_max_depth	= 0;
2931da177e4SLinus Torvalds 	info->info.ifcfg.cntl3		= CNTL3_FASTSCSI | CNTL3_FASTCLK;
2941da177e4SLinus Torvalds 	info->info.ifcfg.disconnect_ok	= 0;
2951da177e4SLinus Torvalds 	info->info.ifcfg.wide_max_size	= 0;
2961da177e4SLinus Torvalds 	info->info.ifcfg.capabilities	= FASCAP_PSEUDODMA;
2971da177e4SLinus Torvalds 	info->info.dma.setup		= arxescsi_dma_setup;
2981da177e4SLinus Torvalds 	info->info.dma.pseudo		= arxescsi_dma_pseudo;
2991da177e4SLinus Torvalds 	info->info.dma.stop		= arxescsi_dma_stop;
3001da177e4SLinus Torvalds 
3011da177e4SLinus Torvalds 	ec->irqaddr = base;
3021da177e4SLinus Torvalds 	ec->irqmask = CSTATUS_IRQ;
3031da177e4SLinus Torvalds 
3041da177e4SLinus Torvalds 	ret = fas216_init(host);
3051da177e4SLinus Torvalds 	if (ret)
3061da177e4SLinus Torvalds 		goto out_unregister;
3071da177e4SLinus Torvalds 
3081da177e4SLinus Torvalds 	ret = fas216_add(host, &ec->dev);
3091da177e4SLinus Torvalds 	if (ret == 0)
3101da177e4SLinus Torvalds 		goto out;
3111da177e4SLinus Torvalds 
3121da177e4SLinus Torvalds 	fas216_release(host);
3131da177e4SLinus Torvalds  out_unregister:
3141da177e4SLinus Torvalds 	scsi_host_put(host);
3151da177e4SLinus Torvalds  out_region:
3161da177e4SLinus Torvalds 	ecard_release_resources(ec);
3171da177e4SLinus Torvalds  out:
3181da177e4SLinus Torvalds 	return ret;
3191da177e4SLinus Torvalds }
3201da177e4SLinus Torvalds 
arxescsi_remove(struct expansion_card * ec)3216f039790SGreg Kroah-Hartman static void arxescsi_remove(struct expansion_card *ec)
3221da177e4SLinus Torvalds {
3231da177e4SLinus Torvalds 	struct Scsi_Host *host = ecard_get_drvdata(ec);
3241da177e4SLinus Torvalds 
3251da177e4SLinus Torvalds 	ecard_set_drvdata(ec, NULL);
3261da177e4SLinus Torvalds 	fas216_remove(host);
3271da177e4SLinus Torvalds 
3281da177e4SLinus Torvalds 	fas216_release(host);
3291da177e4SLinus Torvalds 	scsi_host_put(host);
3301da177e4SLinus Torvalds 	ecard_release_resources(ec);
3311da177e4SLinus Torvalds }
3321da177e4SLinus Torvalds 
3331da177e4SLinus Torvalds static const struct ecard_id arxescsi_cids[] = {
3341da177e4SLinus Torvalds 	{ MANU_ARXE, PROD_ARXE_SCSI },
3351da177e4SLinus Torvalds 	{ 0xffff, 0xffff },
3361da177e4SLinus Torvalds };
3371da177e4SLinus Torvalds 
3381da177e4SLinus Torvalds static struct ecard_driver arxescsi_driver = {
3391da177e4SLinus Torvalds 	.probe		= arxescsi_probe,
3406f039790SGreg Kroah-Hartman 	.remove		= arxescsi_remove,
3411da177e4SLinus Torvalds 	.id_table	= arxescsi_cids,
3421da177e4SLinus Torvalds 	.drv = {
3431da177e4SLinus Torvalds 		.name		= "arxescsi",
3441da177e4SLinus Torvalds 	},
3451da177e4SLinus Torvalds };
3461da177e4SLinus Torvalds 
init_arxe_scsi_driver(void)3471da177e4SLinus Torvalds static int __init init_arxe_scsi_driver(void)
3481da177e4SLinus Torvalds {
3491da177e4SLinus Torvalds 	return ecard_register_driver(&arxescsi_driver);
3501da177e4SLinus Torvalds }
3511da177e4SLinus Torvalds 
exit_arxe_scsi_driver(void)3521da177e4SLinus Torvalds static void __exit exit_arxe_scsi_driver(void)
3531da177e4SLinus Torvalds {
3541da177e4SLinus Torvalds 	ecard_remove_driver(&arxescsi_driver);
3551da177e4SLinus Torvalds }
3561da177e4SLinus Torvalds 
3571da177e4SLinus Torvalds module_init(init_arxe_scsi_driver);
3581da177e4SLinus Torvalds module_exit(exit_arxe_scsi_driver);
3591da177e4SLinus Torvalds 
3601da177e4SLinus Torvalds MODULE_AUTHOR("Stefan Hanske");
3611da177e4SLinus Torvalds MODULE_DESCRIPTION("ARXESCSI driver for Acorn machines");
3621da177e4SLinus Torvalds MODULE_LICENSE("GPL");
3631da177e4SLinus Torvalds 
364