1 /*
2  *  linux/drivers/acorn/scsi/eesox.c
3  *
4  *  Copyright (C) 1997-2003 Russell King
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License version 2 as
8  * published by the Free Software Foundation.
9  *
10  *  This driver is based on experimentation.  Hence, it may have made
11  *  assumptions about the particular card that I have available, and
12  *  may not be reliable!
13  *
14  *  Changelog:
15  *   01-10-1997	RMK		Created, READONLY version
16  *   15-02-1998	RMK		READ/WRITE version
17  *				added DMA support and hardware definitions
18  *   14-03-1998	RMK		Updated DMA support
19  *				Added terminator control
20  *   15-04-1998	RMK		Only do PIO if FAS216 will allow it.
21  *   27-06-1998	RMK		Changed asm/delay.h to linux/delay.h
22  *   02-04-2000	RMK	0.0.3	Fixed NO_IRQ/NO_DMA problem, updated for new
23  *				error handling code.
24  */
25 #include <linux/module.h>
26 #include <linux/blk.h>
27 #include <linux/kernel.h>
28 #include <linux/string.h>
29 #include <linux/ioport.h>
30 #include <linux/sched.h>
31 #include <linux/proc_fs.h>
32 #include <linux/delay.h>
33 #include <linux/pci.h>
34 #include <linux/init.h>
35 
36 #include <asm/io.h>
37 #include <asm/irq.h>
38 #include <asm/dma.h>
39 #include <asm/ecard.h>
40 #include <asm/pgtable.h>
41 
42 #include "../../scsi/sd.h"
43 #include "../../scsi/hosts.h"
44 #include "fas216.h"
45 #include "scsi.h"
46 
47 #include <scsi/scsicam.h>
48 
49 /*
50  * List of devices that the driver will recognise
51  */
52 #define EESOXSCSI_LIST	{ MANU_EESOX, PROD_EESOX_SCSI2 }
53 
54 #define EESOX_FAS216_OFFSET	0xc00
55 #define EESOX_FAS216_SHIFT	3
56 
57 #define EESOX_DMASTAT		0xa00
58 #define EESOX_STAT_INTR		0x01
59 #define EESOX_STAT_DMA		0x02
60 
61 #define EESOX_CONTROL		0xa00
62 #define EESOX_INTR_ENABLE	0x04
63 #define EESOX_TERM_ENABLE	0x02
64 #define EESOX_RESET		0x01
65 
66 #define EESOX_DMADATA		0xe00
67 
68 /*
69  * Version
70  */
71 #define VERSION "1.10 (22/01/2003 2.4.19-rmk5)"
72 
73 /*
74  * Use term=0,1,0,0,0 to turn terminators on/off
75  */
76 static int term[MAX_ECARDS] = { 1, 1, 1, 1, 1, 1, 1, 1 };
77 
78 #define NR_SG	256
79 
80 struct eesoxscsi_info {
81 	FAS216_Info		info;
82 	struct expansion_card	*ec;
83 
84 	unsigned int		ctl_port;
85 	unsigned int		control;
86 	struct scatterlist	sg[NR_SG];	/* Scatter DMA list	*/
87 };
88 
89 /* Prototype: void eesoxscsi_irqenable(ec, irqnr)
90  * Purpose  : Enable interrupts on EESOX SCSI card
91  * Params   : ec    - expansion card structure
92  *          : irqnr - interrupt number
93  */
94 static void
eesoxscsi_irqenable(struct expansion_card * ec,int irqnr)95 eesoxscsi_irqenable(struct expansion_card *ec, int irqnr)
96 {
97 	struct eesoxscsi_info *info = (struct eesoxscsi_info *)ec->irq_data;
98 
99 	info->control |= EESOX_INTR_ENABLE;
100 
101 	outb(info->control, info->ctl_port);
102 }
103 
104 /* Prototype: void eesoxscsi_irqdisable(ec, irqnr)
105  * Purpose  : Disable interrupts on EESOX SCSI card
106  * Params   : ec    - expansion card structure
107  *          : irqnr - interrupt number
108  */
109 static void
eesoxscsi_irqdisable(struct expansion_card * ec,int irqnr)110 eesoxscsi_irqdisable(struct expansion_card *ec, int irqnr)
111 {
112 	struct eesoxscsi_info *info = (struct eesoxscsi_info *)ec->irq_data;
113 
114 	info->control &= ~EESOX_INTR_ENABLE;
115 
116 	outb(info->control, info->ctl_port);
117 }
118 
119 static const expansioncard_ops_t eesoxscsi_ops = {
120 	.irqenable	= eesoxscsi_irqenable,
121 	.irqdisable	= eesoxscsi_irqdisable,
122 };
123 
124 /* Prototype: void eesoxscsi_terminator_ctl(*host, on_off)
125  * Purpose  : Turn the EESOX SCSI terminators on or off
126  * Params   : host   - card to turn on/off
127  *          : on_off - !0 to turn on, 0 to turn off
128  */
129 static void
eesoxscsi_terminator_ctl(struct Scsi_Host * host,int on_off)130 eesoxscsi_terminator_ctl(struct Scsi_Host *host, int on_off)
131 {
132 	struct eesoxscsi_info *info = (struct eesoxscsi_info *)host->hostdata;
133 	unsigned long flags;
134 
135 	save_flags_cli(flags);
136 	if (on_off)
137 		info->control |= EESOX_TERM_ENABLE;
138 	else
139 		info->control &= ~EESOX_TERM_ENABLE;
140 
141 	outb(info->control, info->ctl_port);
142 	restore_flags(flags);
143 }
144 
145 /* Prototype: void eesoxscsi_intr(irq, *dev_id, *regs)
146  * Purpose  : handle interrupts from EESOX SCSI card
147  * Params   : irq    - interrupt number
148  *	      dev_id - user-defined (Scsi_Host structure)
149  *	      regs   - processor registers at interrupt
150  */
151 static void
eesoxscsi_intr(int irq,void * dev_id,struct pt_regs * regs)152 eesoxscsi_intr(int irq, void *dev_id, struct pt_regs *regs)
153 {
154 	fas216_intr(dev_id);
155 }
156 
157 /* Prototype: fasdmatype_t eesoxscsi_dma_setup(host, SCpnt, direction, min_type)
158  * Purpose  : initialises DMA/PIO
159  * Params   : host      - host
160  *	      SCpnt     - command
161  *	      direction - DMA on to/off of card
162  *	      min_type  - minimum DMA support that we must have for this transfer
163  * Returns  : type of transfer to be performed
164  */
165 static fasdmatype_t
eesoxscsi_dma_setup(struct Scsi_Host * host,Scsi_Pointer * SCp,fasdmadir_t direction,fasdmatype_t min_type)166 eesoxscsi_dma_setup(struct Scsi_Host *host, Scsi_Pointer *SCp,
167 		       fasdmadir_t direction, fasdmatype_t min_type)
168 {
169 	struct eesoxscsi_info *info = (struct eesoxscsi_info *)host->hostdata;
170 	int dmach = host->dma_channel;
171 
172 	if (dmach != NO_DMA &&
173 	    (min_type == fasdma_real_all || SCp->this_residual >= 512)) {
174 		int bufs, map_dir, dma_dir;
175 
176 		bufs = copy_SCp_to_sg(&info->sg[0], SCp, NR_SG);
177 
178 		if (direction == DMA_OUT)
179 			map_dir = PCI_DMA_TODEVICE,
180 			dma_dir = DMA_MODE_WRITE;
181 		else
182 			map_dir = PCI_DMA_FROMDEVICE,
183 			dma_dir = DMA_MODE_READ;
184 
185 		pci_map_sg(NULL, info->sg, bufs, map_dir);
186 
187 		disable_dma(dmach);
188 		set_dma_sg(dmach, info->sg, bufs);
189 		set_dma_mode(dmach, dma_dir);
190 		enable_dma(dmach);
191 		return fasdma_real_all;
192 	}
193 	/*
194 	 * We don't do DMA, we only do slow PIO
195 	 *
196 	 * Some day, we will do Pseudo DMA
197 	 */
198 	return fasdma_pseudo;
199 }
200 
eesoxscsi_buffer_in(void * buf,int length,unsigned long base)201 static void eesoxscsi_buffer_in(void *buf, int length, unsigned long base)
202 {
203 	const unsigned long reg_fas = base + EESOX_FAS216_OFFSET;
204 	const unsigned long reg_dmastat = base + EESOX_DMASTAT;
205 	const unsigned long reg_dmadata = base + EESOX_DMADATA;
206 
207 	do {
208 		unsigned int status;
209 
210 		/*
211 		 * Interrupt request?
212 		 */
213 		status = inb(reg_fas + (REG_STAT << EESOX_FAS216_SHIFT));
214 		if (status & STAT_INT)
215 			break;
216 
217 		/*
218 		 * DMA request active?
219 		 */
220 		status = inb(reg_dmastat);
221 		if (!(status & EESOX_STAT_DMA))
222 			continue;
223 
224 		/*
225 		 * Get number of bytes in FIFO
226 		 */
227 		status = inb(reg_fas + (REG_CFIS << EESOX_FAS216_SHIFT)) & CFIS_CF;
228 		if (status > 16)
229 			status = 16;
230 		if (status > length)
231 			status = length;
232 
233 		/*
234 		 * Align buffer.
235 		 */
236 		if (((u32)buf) & 2 && status >= 2) {
237 			*((u16 *)buf)++ = inw(reg_dmadata);
238 			status -= 2;
239 			length -= 2;
240 		}
241 
242 		if (status >= 8) {
243 			unsigned long l1, l2;
244 
245 			l1 = inw(reg_dmadata);
246 			l1 |= inw(reg_dmadata) << 16;
247 			l2 = inw(reg_dmadata);
248 			l2 |= inw(reg_dmadata) << 16;
249 			*((u32 *)buf)++ = l1;
250 			*((u32 *)buf)++ = l2;
251 			length -= 8;
252 			continue;
253 		}
254 
255 		if (status >= 4) {
256 			unsigned long l1;
257 
258 			l1 = inw(reg_dmadata);
259 			l1 |= inw(reg_dmadata) << 16;
260 			*((u32 *)buf)++ = l1;
261 			length -= 4;
262 			continue;
263 		}
264 
265 		if (status >= 2) {
266 			*((u16 *)buf)++ = inw(reg_dmadata);
267 			length -= 2;
268 		}
269 	} while (length);
270 }
271 
eesoxscsi_buffer_out(void * buf,int length,unsigned long base)272 static void eesoxscsi_buffer_out(void *buf, int length, unsigned long base)
273 {
274 	const unsigned long reg_fas = base + EESOX_FAS216_OFFSET;
275 	const unsigned long reg_dmastat = base + EESOX_DMASTAT;
276 	const unsigned long reg_dmadata = base + EESOX_DMADATA;
277 
278 	do {
279 		unsigned int status;
280 
281 		/*
282 		 * Interrupt request?
283 		 */
284 		status = inb(reg_fas + (REG_STAT << EESOX_FAS216_SHIFT));
285 		if (status & STAT_INT)
286 			break;
287 
288 		/*
289 		 * DMA request active?
290 		 */
291 		status = inb(reg_dmastat);
292 		if (!(status & EESOX_STAT_DMA))
293 			continue;
294 
295 		/*
296 		 * Get number of bytes in FIFO
297 		 */
298 		status = inb(reg_fas + (REG_CFIS << EESOX_FAS216_SHIFT)) & CFIS_CF;
299 		if (status > 16)
300 			status = 16;
301 		status = 16 - status;
302 		if (status > length)
303 			status = length;
304 
305 		/*
306 		 * Align buffer.
307 		 */
308 		if (((u32)buf) & 2 && status >= 2) {
309 			outw(*((u16 *)buf)++, reg_dmadata);
310 			status -= 2;
311 			length -= 2;
312 		}
313 
314 		if (status >= 8) {
315 			unsigned long l1, l2;
316 
317 			l1 = *((u32 *)buf)++;
318 			l2 = *((u32 *)buf)++;
319 
320 			outw(l1, reg_dmadata);
321 			outw(l1 >> 16, reg_dmadata);
322 			outw(l2, reg_dmadata);
323 			outw(l2 >> 16, reg_dmadata);
324 			status -= 8;
325 			length -= 8;
326 			continue;
327 		}
328 
329 		if (status >= 4) {
330 			unsigned long l1;
331 
332 			l1 = *((u32 *)buf)++;
333 			outw(l1, reg_dmadata);
334 			outw(l1 >> 16, reg_dmadata);
335 			status -= 4;
336 			length -= 4;
337 			continue;
338 		}
339 
340 		if (status >= 2) {
341 			outw(*((u16 *)buf)++, reg_dmadata);
342 			length -= 2;
343 		}
344 	} while (length);
345 }
346 
347 static void
eesoxscsi_dma_pseudo(struct Scsi_Host * host,Scsi_Pointer * SCp,fasdmadir_t dir,int transfer_size)348 eesoxscsi_dma_pseudo(struct Scsi_Host *host, Scsi_Pointer *SCp,
349 		     fasdmadir_t dir, int transfer_size)
350 {
351 	unsigned int base = host->io_port;
352 	if (dir == DMA_IN) {
353 		eesoxscsi_buffer_in(SCp->ptr, SCp->this_residual, base);
354 	} else {
355 		eesoxscsi_buffer_out(SCp->ptr, SCp->this_residual, base);
356 	}
357 }
358 
359 /* Prototype: int eesoxscsi_dma_stop(host, SCpnt)
360  * Purpose  : stops DMA/PIO
361  * Params   : host  - host
362  *	      SCpnt - command
363  */
364 static void
eesoxscsi_dma_stop(struct Scsi_Host * host,Scsi_Pointer * SCp)365 eesoxscsi_dma_stop(struct Scsi_Host *host, Scsi_Pointer *SCp)
366 {
367 	if (host->dma_channel != NO_DMA)
368 		disable_dma(host->dma_channel);
369 }
370 
371 /* Prototype: const char *eesoxscsi_info(struct Scsi_Host * host)
372  * Purpose  : returns a descriptive string about this interface,
373  * Params   : host - driver host structure to return info for.
374  * Returns  : pointer to a static buffer containing null terminated string.
375  */
eesoxscsi_info(struct Scsi_Host * host)376 const char *eesoxscsi_info(struct Scsi_Host *host)
377 {
378 	struct eesoxscsi_info *info = (struct eesoxscsi_info *)host->hostdata;
379 	static char string[150];
380 
381 	sprintf(string, "%s (%s) in slot %d v%s terminators o%s",
382 		host->hostt->name, info->info.scsi.type, info->ec->slot_no,
383 		VERSION, info->control & EESOX_TERM_ENABLE ? "n" : "ff");
384 
385 	return string;
386 }
387 
388 /* Prototype: int eesoxscsi_set_proc_info(struct Scsi_Host *host, char *buffer, int length)
389  * Purpose  : Set a driver specific function
390  * Params   : host   - host to setup
391  *          : buffer - buffer containing string describing operation
392  *          : length - length of string
393  * Returns  : -EINVAL, or 0
394  */
395 static int
eesoxscsi_set_proc_info(struct Scsi_Host * host,char * buffer,int length)396 eesoxscsi_set_proc_info(struct Scsi_Host *host, char *buffer, int length)
397 {
398 	int ret = length;
399 
400 	if (length >= 9 && strncmp(buffer, "EESOXSCSI", 9) == 0) {
401 		buffer += 9;
402 		length -= 9;
403 
404 		if (length >= 5 && strncmp(buffer, "term=", 5) == 0) {
405 			if (buffer[5] == '1')
406 				eesoxscsi_terminator_ctl(host, 1);
407 			else if (buffer[5] == '0')
408 				eesoxscsi_terminator_ctl(host, 0);
409 			else
410 				ret = -EINVAL;
411 		} else
412 			ret = -EINVAL;
413 	} else
414 		ret = -EINVAL;
415 
416 	return ret;
417 }
418 
419 /* Prototype: int eesoxscsi_proc_info(char *buffer, char **start, off_t offset,
420  *				      int length, int host_no, int inout)
421  * Purpose  : Return information about the driver to a user process accessing
422  *	      the /proc filesystem.
423  * Params   : buffer - a buffer to write information to
424  *	      start  - a pointer into this buffer set by this routine to the start
425  *		       of the required information.
426  *	      offset - offset into information that we have read upto.
427  *	      length - length of buffer
428  *	      host_no - host number to return information for
429  *	      inout  - 0 for reading, 1 for writing.
430  * Returns  : length of data written to buffer.
431  */
eesoxscsi_proc_info(char * buffer,char ** start,off_t offset,int length,int host_no,int inout)432 int eesoxscsi_proc_info(char *buffer, char **start, off_t offset,
433 			    int length, int host_no, int inout)
434 {
435 	int pos, begin;
436 	struct Scsi_Host *host;
437 	struct eesoxscsi_info *info;
438 	Scsi_Device *scd;
439 
440 	host = scsi_host_hn_get(host_no);
441 	if (!host)
442 		return 0;
443 
444 	if (inout == 1)
445 		return eesoxscsi_set_proc_info(host, buffer, length);
446 
447 	info = (struct eesoxscsi_info *)host->hostdata;
448 
449 	begin = 0;
450 	pos = sprintf(buffer, "EESOX SCSI driver v%s\n", VERSION);
451 	pos += fas216_print_host(&info->info, buffer + pos);
452 	pos += sprintf(buffer + pos, "Term    : o%s\n",
453 			info->control & EESOX_TERM_ENABLE ? "n" : "ff");
454 
455 	pos += fas216_print_stats(&info->info, buffer + pos);
456 
457 	pos += sprintf(buffer+pos, "\nAttached devices:\n");
458 
459 	for (scd = host->host_queue; scd; scd = scd->next) {
460 		int len;
461 
462 		proc_print_scsidevice(scd, buffer, &len, pos);
463 		pos += len;
464 		pos += sprintf(buffer+pos, "Extensions: ");
465 		if (scd->tagged_supported)
466 			pos += sprintf(buffer+pos, "TAG %sabled [%d] ",
467 					scd->tagged_queue ? "en" : "dis",
468 					scd->current_tag);
469 		pos += sprintf (buffer+pos, "\n");
470 
471 		if (pos + begin < offset) {
472 			begin += pos;
473 			pos = 0;
474 		}
475 	}
476 	*start = buffer + (offset - begin);
477 	pos -= offset - begin;
478 	if (pos > length)
479 		pos = length;
480 
481 	return pos;
482 }
483 
484 static int eesoxscsi_probe(struct expansion_card *ec);
485 
486 /* Prototype: int eesoxscsi_detect(Scsi_Host_Template * tpnt)
487  * Purpose  : initialises EESOX SCSI driver
488  * Params   : tpnt - template for this SCSI adapter
489  * Returns  : >0 if host found, 0 otherwise.
490  */
eesoxscsi_detect(Scsi_Host_Template * tpnt)491 static int eesoxscsi_detect(Scsi_Host_Template *tpnt)
492 {
493 	static const card_ids eesoxscsi_cids[] =
494 			{ EESOXSCSI_LIST, { 0xffff, 0xffff} };
495 	struct expansion_card *ec;
496 	int count = 0, ret;
497 
498 	ecard_startfind();
499 
500 	while(1) {
501 		ec = ecard_find(0, eesoxscsi_cids);
502 		if (!ec)
503 			break;
504 
505 		ecard_claim(ec);
506 
507 		ret = eesoxscsi_probe(ec);
508 		if (ret) {
509 			ecard_release(ec);
510 			break;
511 		}
512 		++count;
513 	}
514 	return count;
515 }
516 
517 static void eesoxscsi_remove(struct Scsi_Host *host);
518 
519 /* Prototype: int eesoxscsi_release(struct Scsi_Host * host)
520  * Purpose  : releases all resources used by this adapter
521  * Params   : host - driver host structure to return info for.
522  */
eesoxscsi_release(struct Scsi_Host * host)523 static int eesoxscsi_release(struct Scsi_Host *host)
524 {
525 	eesoxscsi_remove(host);
526 	return 0;
527 }
528 
529 static Scsi_Host_Template eesox_template = {
530 	.module				= THIS_MODULE,
531 	.proc_info			= eesoxscsi_proc_info,
532 	.name				= "EESOX SCSI",
533 	.detect				= eesoxscsi_detect,
534 	.release			= eesoxscsi_release,
535 	.info				= eesoxscsi_info,
536 	.bios_param			= scsicam_bios_param,
537 	.command			= fas216_command,
538 	.queuecommand			= fas216_queue_command,
539 	.eh_host_reset_handler		= fas216_eh_host_reset,
540 	.eh_bus_reset_handler		= fas216_eh_bus_reset,
541 	.eh_device_reset_handler	= fas216_eh_device_reset,
542 	.eh_abort_handler		= fas216_eh_abort,
543 	.use_new_eh_code		= 1,
544 
545 	.can_queue			= 1,
546 	.this_id			= 7,
547 	.sg_tablesize			= SG_ALL,
548 	.cmd_per_lun			= 1,
549 	.use_clustering			= DISABLE_CLUSTERING,
550 	.proc_name			= "eesox",
551 };
552 
553 static int
eesoxscsi_probe(struct expansion_card * ec)554 eesoxscsi_probe(struct expansion_card *ec)
555 {
556 	struct Scsi_Host *host;
557 	struct eesoxscsi_info *info;
558 	unsigned long base;
559 	int ret;
560 
561 	base = ecard_address(ec, ECARD_IOC, ECARD_FAST);
562 
563 	if (!request_region(base + EESOX_FAS216_OFFSET,
564 			    16 << EESOX_FAS216_SHIFT, "eesox2-fas")) {
565 		ret = -EBUSY;
566 		goto out;
567 	}
568 
569 	host = scsi_register(&eesox_template,
570 			     sizeof(struct eesoxscsi_info));
571 	if (!host) {
572 		ret = -ENOMEM;
573 		goto out_region;
574 	}
575 
576 	host->io_port	  = base;
577 	host->irq	  = ec->irq;
578 	host->dma_channel = ec->dma;
579 
580 	info = (struct eesoxscsi_info *)host->hostdata;
581 	info->ec	= ec;
582 	info->ctl_port	= base + EESOX_CONTROL;
583 	info->control	= term[ec->slot_no] ? EESOX_TERM_ENABLE : 0;
584 	outb(info->control, info->ctl_port);
585 
586 	ec->irqaddr	= (unsigned char *)ioaddr(base + EESOX_DMASTAT);
587 	ec->irqmask	= EESOX_STAT_INTR;
588 	ec->irq_data	= info;
589 	ec->ops		= (expansioncard_ops_t *)&eesoxscsi_ops;
590 
591 	info->info.scsi.io_port		= base + EESOX_FAS216_OFFSET;
592 	info->info.scsi.io_shift	= EESOX_FAS216_SHIFT;
593 	info->info.scsi.irq		= host->irq;
594 	info->info.ifcfg.clockrate	= 40; /* MHz */
595 	info->info.ifcfg.select_timeout	= 255;
596 	info->info.ifcfg.asyncperiod	= 200; /* ns */
597 	info->info.ifcfg.sync_max_depth	= 7;
598 	info->info.ifcfg.cntl3		= CNTL3_FASTSCSI | CNTL3_FASTCLK;
599 	info->info.ifcfg.disconnect_ok	= 1;
600 	info->info.ifcfg.wide_max_size	= 0;
601 	info->info.ifcfg.capabilities	= FASCAP_PSEUDODMA;
602 	info->info.dma.setup		= eesoxscsi_dma_setup;
603 	info->info.dma.pseudo		= eesoxscsi_dma_pseudo;
604 	info->info.dma.stop		= eesoxscsi_dma_stop;
605 
606 	ret = fas216_init(host);
607 	if (ret)
608 		goto out_free;
609 
610 	ret = request_irq(host->irq, eesoxscsi_intr, 0, "eesox", &info->info);
611 	if (ret) {
612 		printk("scsi%d: IRQ%d not free: %d\n",
613 		       host->host_no, host->irq, ret);
614 		goto out_remove;
615 	}
616 
617 	if (host->dma_channel != NO_DMA) {
618 		if (request_dma(host->dma_channel, "eesox")) {
619 			printk("scsi%d: DMA%d not free, DMA disabled\n",
620 			       host->host_no, host->dma_channel);
621 			host->dma_channel = NO_DMA;
622 		} else {
623 			set_dma_speed(host->dma_channel, 180);
624 			info->info.ifcfg.capabilities |= FASCAP_DMA;
625 			info->info.ifcfg.cntl3 |= CNTL3_BS8;
626 		}
627 	}
628 
629 	ret = fas216_add(host);
630 	if (ret == 0)
631 		goto out;
632 
633 	if (host->dma_channel != NO_DMA)
634 		free_dma(host->dma_channel);
635 	free_irq(host->irq, host);
636 
637  out_remove:
638 	fas216_remove(host);
639 
640  out_free:
641 	scsi_unregister(host);
642 
643  out_region:
644 	release_region(base + EESOX_FAS216_OFFSET, 16 << EESOX_FAS216_SHIFT);
645 
646  out:
647 	return ret;
648 }
649 
eesoxscsi_remove(struct Scsi_Host * host)650 static void eesoxscsi_remove(struct Scsi_Host *host)
651 {
652 	struct eesoxscsi_info *info = (struct eesoxscsi_info *)host->hostdata;
653 
654 	fas216_remove(host);
655 
656 	if (host->dma_channel != NO_DMA)
657 		free_dma(host->dma_channel);
658 	free_irq(host->irq, host);
659 
660 	release_region(host->io_port + EESOX_FAS216_OFFSET, 16 << EESOX_FAS216_SHIFT);
661 
662 	fas216_release(host);
663 	ecard_release(info->ec);
664 }
665 
eesox_init(void)666 static int __init eesox_init(void)
667 {
668 	scsi_register_module(MODULE_SCSI_HA, &eesox_template);
669 	if (eesox_template.present)
670 		return 0;
671 
672 	scsi_unregister_module(MODULE_SCSI_HA, &eesox_template);
673 	return -ENODEV;
674 }
675 
eesox_exit(void)676 static void __exit eesox_exit(void)
677 {
678 	scsi_unregister_module(MODULE_SCSI_HA, &eesox_template);
679 }
680 
681 module_init(eesox_init);
682 module_exit(eesox_exit);
683 
684 MODULE_AUTHOR("Russell King");
685 MODULE_DESCRIPTION("EESOX 'Fast' SCSI driver for Acorn machines");
686 MODULE_PARM(term, "1-8i");
687 MODULE_PARM_DESC(term, "SCSI bus termination");
688 MODULE_LICENSE("GPL");
689 EXPORT_NO_SYMBOLS;
690