xref: /openbmc/linux/drivers/scsi/aha1740.c (revision 1ac731c529cd4d6adbce134754b51ff7d822b145)
11da177e4SLinus Torvalds /*  $Id$
21da177e4SLinus Torvalds  *  1993/03/31
31da177e4SLinus Torvalds  *  linux/kernel/aha1740.c
41da177e4SLinus Torvalds  *
51da177e4SLinus Torvalds  *  Based loosely on aha1542.c which is
61da177e4SLinus Torvalds  *  Copyright (C) 1992  Tommy Thorn and
71da177e4SLinus Torvalds  *  Modified by Eric Youngdale
81da177e4SLinus Torvalds  *
91da177e4SLinus Torvalds  *  This file is aha1740.c, written and
101da177e4SLinus Torvalds  *  Copyright (C) 1992,1993  Brad McLean
111da177e4SLinus Torvalds  *  brad@saturn.gaylord.com or brad@bradpc.gaylord.com.
121da177e4SLinus Torvalds  *
131da177e4SLinus Torvalds  *  Modifications to makecode and queuecommand
141da177e4SLinus Torvalds  *  for proper handling of multiple devices courteously
151da177e4SLinus Torvalds  *  provided by Michael Weller, March, 1993
161da177e4SLinus Torvalds  *
171da177e4SLinus Torvalds  *  Multiple adapter support, extended translation detection,
181da177e4SLinus Torvalds  *  update to current scsi subsystem changes, proc fs support,
191da177e4SLinus Torvalds  *  working (!) module support based on patches from Andreas Arens,
201da177e4SLinus Torvalds  *  by Andreas Degert <ad@papyrus.hamburg.com>, 2/1997
211da177e4SLinus Torvalds  *
221da177e4SLinus Torvalds  * aha1740_makecode may still need even more work
231da177e4SLinus Torvalds  * if it doesn't work for your devices, take a look.
241da177e4SLinus Torvalds  *
25fa195afeSAlan Cox  * Reworked for new_eh and new locking by Alan Cox <alan@lxorguk.ukuu.org.uk>
261da177e4SLinus Torvalds  *
271da177e4SLinus Torvalds  * Converted to EISA and generic DMA APIs by Marc Zyngier
281da177e4SLinus Torvalds  * <maz@wild-wind.fr.eu.org>, 4/2003.
291da177e4SLinus Torvalds  *
301da177e4SLinus Torvalds  * Shared interrupt support added by Rask Ingemann Lambertsen
311da177e4SLinus Torvalds  * <rask@sygehus.dk>, 10/2003
321da177e4SLinus Torvalds  *
331da177e4SLinus Torvalds  * For the avoidance of doubt the "preferred form" of this code is one which
341da177e4SLinus Torvalds  * is in an open non patent encumbered format. Where cryptographic key signing
351da177e4SLinus Torvalds  * forms part of the process of creating an executable the information
361da177e4SLinus Torvalds  * including keys needed to generate an equivalently functional executable
371da177e4SLinus Torvalds  * are deemed to be part of the source code.
381da177e4SLinus Torvalds  */
391da177e4SLinus Torvalds 
401da177e4SLinus Torvalds #include <linux/blkdev.h>
411da177e4SLinus Torvalds #include <linux/interrupt.h>
421da177e4SLinus Torvalds #include <linux/module.h>
431da177e4SLinus Torvalds #include <linux/kernel.h>
441da177e4SLinus Torvalds #include <linux/types.h>
451da177e4SLinus Torvalds #include <linux/string.h>
461da177e4SLinus Torvalds #include <linux/ioport.h>
471da177e4SLinus Torvalds #include <linux/proc_fs.h>
481da177e4SLinus Torvalds #include <linux/stat.h>
491da177e4SLinus Torvalds #include <linux/init.h>
501da177e4SLinus Torvalds #include <linux/device.h>
511da177e4SLinus Torvalds #include <linux/eisa.h>
521da177e4SLinus Torvalds #include <linux/dma-mapping.h>
535a0e3ad6STejun Heo #include <linux/gfp.h>
541da177e4SLinus Torvalds 
551da177e4SLinus Torvalds #include <asm/dma.h>
561da177e4SLinus Torvalds #include <asm/io.h>
571da177e4SLinus Torvalds 
5853555fb7SBart Van Assche #include <scsi/scsi.h>
5953555fb7SBart Van Assche #include <scsi/scsi_cmnd.h>
6053555fb7SBart Van Assche #include <scsi/scsi_device.h>
6153555fb7SBart Van Assche #include <scsi/scsi_eh.h>
621da177e4SLinus Torvalds #include <scsi/scsi_host.h>
6353555fb7SBart Van Assche #include <scsi/scsi_tcq.h>
641da177e4SLinus Torvalds #include "aha1740.h"
651da177e4SLinus Torvalds 
661da177e4SLinus Torvalds /* IF YOU ARE HAVING PROBLEMS WITH THIS DRIVER, AND WANT TO WATCH
671da177e4SLinus Torvalds    IT WORK, THEN:
681da177e4SLinus Torvalds #define DEBUG
691da177e4SLinus Torvalds */
701da177e4SLinus Torvalds #ifdef DEBUG
711da177e4SLinus Torvalds #define DEB(x) x
721da177e4SLinus Torvalds #else
731da177e4SLinus Torvalds #define DEB(x)
741da177e4SLinus Torvalds #endif
751da177e4SLinus Torvalds 
761da177e4SLinus Torvalds struct aha1740_hostdata {
771da177e4SLinus Torvalds 	struct eisa_device *edev;
781da177e4SLinus Torvalds 	unsigned int translation;
791da177e4SLinus Torvalds 	unsigned int last_ecb_used;
801da177e4SLinus Torvalds 	dma_addr_t ecb_dma_addr;
811da177e4SLinus Torvalds 	struct ecb ecb[AHA1740_ECBS];
821da177e4SLinus Torvalds };
831da177e4SLinus Torvalds 
841da177e4SLinus Torvalds struct aha1740_sg {
851da177e4SLinus Torvalds 	struct aha1740_chain sg_chain[AHA1740_SCATTER];
861da177e4SLinus Torvalds 	dma_addr_t sg_dma_addr;
871da177e4SLinus Torvalds 	dma_addr_t buf_dma_addr;
881da177e4SLinus Torvalds };
891da177e4SLinus Torvalds 
901da177e4SLinus Torvalds #define HOSTDATA(host) ((struct aha1740_hostdata *) &host->hostdata)
911da177e4SLinus Torvalds 
ecb_dma_to_cpu(struct Scsi_Host * host,dma_addr_t dma)921da177e4SLinus Torvalds static inline struct ecb *ecb_dma_to_cpu (struct Scsi_Host *host,
931da177e4SLinus Torvalds 					  dma_addr_t dma)
941da177e4SLinus Torvalds {
951da177e4SLinus Torvalds 	struct aha1740_hostdata *hdata = HOSTDATA (host);
961da177e4SLinus Torvalds 	dma_addr_t offset;
971da177e4SLinus Torvalds 
981da177e4SLinus Torvalds 	offset = dma - hdata->ecb_dma_addr;
991da177e4SLinus Torvalds 
1001da177e4SLinus Torvalds 	return (struct ecb *)(((char *) hdata->ecb) + (unsigned int) offset);
1011da177e4SLinus Torvalds }
1021da177e4SLinus Torvalds 
ecb_cpu_to_dma(struct Scsi_Host * host,void * cpu)1031da177e4SLinus Torvalds static inline dma_addr_t ecb_cpu_to_dma (struct Scsi_Host *host, void *cpu)
1041da177e4SLinus Torvalds {
1051da177e4SLinus Torvalds 	struct aha1740_hostdata *hdata = HOSTDATA (host);
1061da177e4SLinus Torvalds 	dma_addr_t offset;
1071da177e4SLinus Torvalds 
1081da177e4SLinus Torvalds 	offset = (char *) cpu - (char *) hdata->ecb;
1091da177e4SLinus Torvalds 
1101da177e4SLinus Torvalds 	return hdata->ecb_dma_addr + offset;
1111da177e4SLinus Torvalds }
1121da177e4SLinus Torvalds 
aha1740_show_info(struct seq_file * m,struct Scsi_Host * shpnt)113e633c1e5SAl Viro static int aha1740_show_info(struct seq_file *m, struct Scsi_Host *shpnt)
1141da177e4SLinus Torvalds {
115e633c1e5SAl Viro 	struct aha1740_hostdata *host = HOSTDATA(shpnt);
116e633c1e5SAl Viro 	seq_printf(m, "aha174x at IO:%lx, IRQ %d, SLOT %d.\n"
1171da177e4SLinus Torvalds 		      "Extended translation %sabled.\n",
1181da177e4SLinus Torvalds 		      shpnt->io_port, shpnt->irq, host->edev->slot,
1191da177e4SLinus Torvalds 		      host->translation ? "en" : "dis");
1201da177e4SLinus Torvalds 	return 0;
1211da177e4SLinus Torvalds }
1221da177e4SLinus Torvalds 
aha1740_makecode(unchar * sense,unchar * status)1231da177e4SLinus Torvalds static int aha1740_makecode(unchar *sense, unchar *status)
1241da177e4SLinus Torvalds {
1251da177e4SLinus Torvalds 	struct statusword
1261da177e4SLinus Torvalds 	{
1271da177e4SLinus Torvalds 		ushort	don:1,	/* Command Done - No Error */
1281da177e4SLinus Torvalds 			du:1,	/* Data underrun */
1291da177e4SLinus Torvalds 		    :1,	qf:1,	/* Queue full */
1301da177e4SLinus Torvalds 		        sc:1,	/* Specification Check */
1311da177e4SLinus Torvalds 		        dor:1,	/* Data overrun */
1321da177e4SLinus Torvalds 		        ch:1,	/* Chaining Halted */
1331da177e4SLinus Torvalds 		        intr:1,	/* Interrupt issued */
1341da177e4SLinus Torvalds 		        asa:1,	/* Additional Status Available */
1351da177e4SLinus Torvalds 		        sns:1,	/* Sense information Stored */
1361da177e4SLinus Torvalds 		    :1,	ini:1,	/* Initialization Required */
1371da177e4SLinus Torvalds 			me:1,	/* Major error or exception */
1381da177e4SLinus Torvalds 		    :1,	eca:1,  /* Extended Contingent alliance */
1391da177e4SLinus Torvalds 		    :1;
1401da177e4SLinus Torvalds 	} status_word;
1411da177e4SLinus Torvalds 	int retval = DID_OK;
1421da177e4SLinus Torvalds 
1431da177e4SLinus Torvalds 	status_word = * (struct statusword *) status;
1441da177e4SLinus Torvalds #ifdef DEBUG
1451da177e4SLinus Torvalds 	printk("makecode from %x,%x,%x,%x %x,%x,%x,%x",
1461da177e4SLinus Torvalds 	       status[0], status[1], status[2], status[3],
1471da177e4SLinus Torvalds 	       sense[0], sense[1], sense[2], sense[3]);
1481da177e4SLinus Torvalds #endif
1491da177e4SLinus Torvalds 	if (!status_word.don) { /* Anything abnormal was detected */
1501da177e4SLinus Torvalds 		if ( (status[1]&0x18) || status_word.sc ) {
1511da177e4SLinus Torvalds 			/*Additional info available*/
1521da177e4SLinus Torvalds 			/* Use the supplied info for further diagnostics */
1531da177e4SLinus Torvalds 			switch ( status[2] ) {
1541da177e4SLinus Torvalds 			case 0x12:
1551da177e4SLinus Torvalds 				if ( status_word.dor )
1561da177e4SLinus Torvalds 					retval=DID_ERROR; /* It's an Overrun */
1571da177e4SLinus Torvalds 				/* If not overrun, assume underrun and
1581da177e4SLinus Torvalds 				 * ignore it! */
1595133dc47SGustavo A. R. Silva 				break;
1601da177e4SLinus Torvalds 			case 0x00: /* No info, assume no error, should
1611da177e4SLinus Torvalds 				    * not occur */
1621da177e4SLinus Torvalds 				break;
1631da177e4SLinus Torvalds 			case 0x11:
1641da177e4SLinus Torvalds 			case 0x21:
1651da177e4SLinus Torvalds 				retval=DID_TIME_OUT;
1661da177e4SLinus Torvalds 				break;
1671da177e4SLinus Torvalds 			case 0x0a:
1681da177e4SLinus Torvalds 				retval=DID_BAD_TARGET;
1691da177e4SLinus Torvalds 				break;
1701da177e4SLinus Torvalds 			case 0x04:
1711da177e4SLinus Torvalds 			case 0x05:
1721da177e4SLinus Torvalds 				retval=DID_ABORT;
1731da177e4SLinus Torvalds 				/* Either by this driver or the
1741da177e4SLinus Torvalds 				 * AHA1740 itself */
1751da177e4SLinus Torvalds 				break;
1761da177e4SLinus Torvalds 			default:
1771da177e4SLinus Torvalds 				retval=DID_ERROR; /* No further
1781da177e4SLinus Torvalds 						   * diagnostics
1791da177e4SLinus Torvalds 						   * possible */
1801da177e4SLinus Torvalds 			}
1811da177e4SLinus Torvalds 		} else {
1821da177e4SLinus Torvalds 			/* Michael suggests, and Brad concurs: */
1831da177e4SLinus Torvalds 			if ( status_word.qf ) {
1841da177e4SLinus Torvalds 				retval = DID_TIME_OUT; /* forces a redo */
1851da177e4SLinus Torvalds 				/* I think this specific one should
1861da177e4SLinus Torvalds 				 * not happen -Brad */
1871da177e4SLinus Torvalds 				printk("aha1740.c: WARNING: AHA1740 queue overflow!\n");
1881da177e4SLinus Torvalds 			} else
1891da177e4SLinus Torvalds 				if ( status[0]&0x60 ) {
1901da177e4SLinus Torvalds 					 /* Didn't find a better error */
1911da177e4SLinus Torvalds 					retval = DID_ERROR;
1921da177e4SLinus Torvalds 				}
1931da177e4SLinus Torvalds 			/* In any other case return DID_OK so for example
1941da177e4SLinus Torvalds 			   CONDITION_CHECKS make it through to the appropriate
1951da177e4SLinus Torvalds 			   device driver */
1961da177e4SLinus Torvalds 		}
1971da177e4SLinus Torvalds 	}
1981da177e4SLinus Torvalds 	/* Under all circumstances supply the target status -Michael */
1991da177e4SLinus Torvalds 	return status[3] | retval << 16;
2001da177e4SLinus Torvalds }
2011da177e4SLinus Torvalds 
aha1740_test_port(unsigned int base)2021da177e4SLinus Torvalds static int aha1740_test_port(unsigned int base)
2031da177e4SLinus Torvalds {
2041da177e4SLinus Torvalds 	if ( inb(PORTADR(base)) & PORTADDR_ENH )
2051da177e4SLinus Torvalds 		return 1;   /* Okay, we're all set */
2061da177e4SLinus Torvalds 
2071da177e4SLinus Torvalds 	printk("aha174x: Board detected, but not in enhanced mode, so disabled it.\n");
2081da177e4SLinus Torvalds 	return 0;
2091da177e4SLinus Torvalds }
2101da177e4SLinus Torvalds 
2111da177e4SLinus Torvalds /* A "high" level interrupt handler */
aha1740_intr_handle(int irq,void * dev_id)2127d12e780SDavid Howells static irqreturn_t aha1740_intr_handle(int irq, void *dev_id)
2131da177e4SLinus Torvalds {
2141da177e4SLinus Torvalds 	struct Scsi_Host *host = (struct Scsi_Host *) dev_id;
21591ebc1faSJohannes Thumshirn         void (*my_done)(struct scsi_cmnd *);
2161da177e4SLinus Torvalds 	int errstatus, adapstat;
2171da177e4SLinus Torvalds 	int number_serviced;
2181da177e4SLinus Torvalds 	struct ecb *ecbptr;
21991ebc1faSJohannes Thumshirn 	struct scsi_cmnd *SCtmp;
2201da177e4SLinus Torvalds 	unsigned int base;
2211da177e4SLinus Torvalds 	unsigned long flags;
2221da177e4SLinus Torvalds 	int handled = 0;
2231da177e4SLinus Torvalds 	struct aha1740_sg *sgptr;
2241da177e4SLinus Torvalds 	struct eisa_device *edev;
2251da177e4SLinus Torvalds 
2261da177e4SLinus Torvalds 	if (!host)
2271da177e4SLinus Torvalds 		panic("aha1740.c: Irq from unknown host!\n");
2281da177e4SLinus Torvalds 	spin_lock_irqsave(host->host_lock, flags);
2291da177e4SLinus Torvalds 	base = host->io_port;
2301da177e4SLinus Torvalds 	number_serviced = 0;
2311da177e4SLinus Torvalds 	edev = HOSTDATA(host)->edev;
2321da177e4SLinus Torvalds 
2331da177e4SLinus Torvalds 	while(inb(G2STAT(base)) & G2STAT_INTPEND) {
2341da177e4SLinus Torvalds 		handled = 1;
2351da177e4SLinus Torvalds 		DEB(printk("aha1740_intr top of loop.\n"));
2361da177e4SLinus Torvalds 		adapstat = inb(G2INTST(base));
2371da177e4SLinus Torvalds 		ecbptr = ecb_dma_to_cpu (host, inl(MBOXIN0(base)));
2381da177e4SLinus Torvalds 		outb(G2CNTRL_IRST,G2CNTRL(base)); /* interrupt reset */
2391da177e4SLinus Torvalds 
2401da177e4SLinus Torvalds 		switch ( adapstat & G2INTST_MASK ) {
2411da177e4SLinus Torvalds 		case	G2INTST_CCBRETRY:
2421da177e4SLinus Torvalds 		case	G2INTST_CCBERROR:
2431da177e4SLinus Torvalds 		case	G2INTST_CCBGOOD:
2441da177e4SLinus Torvalds 			/* Host Ready -> Mailbox in complete */
2451da177e4SLinus Torvalds 			outb(G2CNTRL_HRDY,G2CNTRL(base));
2461da177e4SLinus Torvalds 			if (!ecbptr) {
2471da177e4SLinus Torvalds 				printk("Aha1740 null ecbptr in interrupt (%x,%x,%x,%d)\n",
2481da177e4SLinus Torvalds 				       inb(G2STAT(base)),adapstat,
2491da177e4SLinus Torvalds 				       inb(G2INTST(base)), number_serviced++);
2501da177e4SLinus Torvalds 				continue;
2511da177e4SLinus Torvalds 			}
2521da177e4SLinus Torvalds 			SCtmp = ecbptr->SCpnt;
2531da177e4SLinus Torvalds 			if (!SCtmp) {
2541da177e4SLinus Torvalds 				printk("Aha1740 null SCtmp in interrupt (%x,%x,%x,%d)\n",
2551da177e4SLinus Torvalds 				       inb(G2STAT(base)),adapstat,
2561da177e4SLinus Torvalds 				       inb(G2INTST(base)), number_serviced++);
2571da177e4SLinus Torvalds 				continue;
2581da177e4SLinus Torvalds 			}
2591da177e4SLinus Torvalds 			sgptr = (struct aha1740_sg *) SCtmp->host_scribble;
260c66cc13cSFUJITA Tomonori 			scsi_dma_unmap(SCtmp);
2611da177e4SLinus Torvalds 
2621da177e4SLinus Torvalds 			/* Free the sg block */
2631da177e4SLinus Torvalds 			dma_free_coherent (&edev->dev,
2641da177e4SLinus Torvalds 					   sizeof (struct aha1740_sg),
2651da177e4SLinus Torvalds 					   SCtmp->host_scribble,
2661da177e4SLinus Torvalds 					   sgptr->sg_dma_addr);
2671da177e4SLinus Torvalds 
2681da177e4SLinus Torvalds 			/* Fetch the sense data, and tuck it away, in
2691da177e4SLinus Torvalds 			   the required slot.  The Adaptec
2701da177e4SLinus Torvalds 			   automatically fetches it, and there is no
2711da177e4SLinus Torvalds 			   guarantee that we will still have it in the
2721da177e4SLinus Torvalds 			   cdb when we come back */
2731da177e4SLinus Torvalds 			if ( (adapstat & G2INTST_MASK) == G2INTST_CCBERROR ) {
274041761f4SKees Cook 				memcpy_and_pad(SCtmp->sense_buffer,
275041761f4SKees Cook 					       SCSI_SENSE_BUFFERSIZE,
276041761f4SKees Cook 					       ecbptr->sense,
277041761f4SKees Cook 					       sizeof(ecbptr->sense),
278041761f4SKees Cook 					       0);
2791da177e4SLinus Torvalds 				errstatus = aha1740_makecode(ecbptr->sense,ecbptr->status);
2801da177e4SLinus Torvalds 			} else
2811da177e4SLinus Torvalds 				errstatus = 0;
2821da177e4SLinus Torvalds 			DEB(if (errstatus)
2831da177e4SLinus Torvalds 			    printk("aha1740_intr_handle: returning %6x\n",
2841da177e4SLinus Torvalds 				   errstatus));
2851da177e4SLinus Torvalds 			SCtmp->result = errstatus;
2861da177e4SLinus Torvalds 			my_done = ecbptr->done;
2871da177e4SLinus Torvalds 			memset(ecbptr,0,sizeof(struct ecb));
2881da177e4SLinus Torvalds 			if ( my_done )
2891da177e4SLinus Torvalds 				my_done(SCtmp);
2901da177e4SLinus Torvalds 			break;
2911da177e4SLinus Torvalds 
2921da177e4SLinus Torvalds 		case	G2INTST_HARDFAIL:
2931da177e4SLinus Torvalds 			printk(KERN_ALERT "aha1740 hardware failure!\n");
2941da177e4SLinus Torvalds 			panic("aha1740.c");	/* Goodbye */
2951da177e4SLinus Torvalds 
2961da177e4SLinus Torvalds 		case	G2INTST_ASNEVENT:
2971da177e4SLinus Torvalds 			printk("aha1740 asynchronous event: %02x %02x %02x %02x %02x\n",
2981da177e4SLinus Torvalds 			       adapstat,
2991da177e4SLinus Torvalds 			       inb(MBOXIN0(base)),
3001da177e4SLinus Torvalds 			       inb(MBOXIN1(base)),
3011da177e4SLinus Torvalds 			       inb(MBOXIN2(base)),
3021da177e4SLinus Torvalds 			       inb(MBOXIN3(base))); /* Say What? */
3031da177e4SLinus Torvalds 			/* Host Ready -> Mailbox in complete */
3041da177e4SLinus Torvalds 			outb(G2CNTRL_HRDY,G2CNTRL(base));
3051da177e4SLinus Torvalds 			break;
3061da177e4SLinus Torvalds 
3071da177e4SLinus Torvalds 		case	G2INTST_CMDGOOD:
3081da177e4SLinus Torvalds 			/* set immediate command success flag here: */
3091da177e4SLinus Torvalds 			break;
3101da177e4SLinus Torvalds 
3111da177e4SLinus Torvalds 		case	G2INTST_CMDERROR:
3121da177e4SLinus Torvalds 			/* Set immediate command failure flag here: */
3131da177e4SLinus Torvalds 			break;
3141da177e4SLinus Torvalds 		}
3151da177e4SLinus Torvalds 		number_serviced++;
3161da177e4SLinus Torvalds 	}
3171da177e4SLinus Torvalds 
3181da177e4SLinus Torvalds 	spin_unlock_irqrestore(host->host_lock, flags);
3191da177e4SLinus Torvalds 	return IRQ_RETVAL(handled);
3201da177e4SLinus Torvalds }
3211da177e4SLinus Torvalds 
aha1740_queuecommand_lck(struct scsi_cmnd * SCpnt)322af049dfdSBart Van Assche static int aha1740_queuecommand_lck(struct scsi_cmnd *SCpnt)
3231da177e4SLinus Torvalds {
324af049dfdSBart Van Assche 	void (*done)(struct scsi_cmnd *) = scsi_done;
3251da177e4SLinus Torvalds 	unchar direction;
3261da177e4SLinus Torvalds 	unchar *cmd = (unchar *) SCpnt->cmnd;
327422c0d61SJeff Garzik 	unchar target = scmd_id(SCpnt);
3281da177e4SLinus Torvalds 	struct aha1740_hostdata *host = HOSTDATA(SCpnt->device->host);
3291da177e4SLinus Torvalds 	unsigned long flags;
3301da177e4SLinus Torvalds 	dma_addr_t sg_dma;
3311da177e4SLinus Torvalds 	struct aha1740_sg *sgptr;
332c66cc13cSFUJITA Tomonori 	int ecbno, nseg;
3331da177e4SLinus Torvalds 	DEB(int i);
3341da177e4SLinus Torvalds 
3351da177e4SLinus Torvalds 	if(*cmd == REQUEST_SENSE) {
3361da177e4SLinus Torvalds 		SCpnt->result = 0;
3371da177e4SLinus Torvalds 		done(SCpnt);
3381da177e4SLinus Torvalds 		return 0;
3391da177e4SLinus Torvalds 	}
3401da177e4SLinus Torvalds 
3411da177e4SLinus Torvalds #ifdef DEBUG
3421da177e4SLinus Torvalds 	if (*cmd == READ_10 || *cmd == WRITE_10)
3431da177e4SLinus Torvalds 		i = xscsi2int(cmd+2);
3441da177e4SLinus Torvalds 	else if (*cmd == READ_6 || *cmd == WRITE_6)
3451da177e4SLinus Torvalds 		i = scsi2int(cmd+2);
3461da177e4SLinus Torvalds 	else
3471da177e4SLinus Torvalds 		i = -1;
3481da177e4SLinus Torvalds 	printk("aha1740_queuecommand: dev %d cmd %02x pos %d len %d ",
3491da177e4SLinus Torvalds 	       target, *cmd, i, bufflen);
3501da177e4SLinus Torvalds 	printk("scsi cmd:");
3511da177e4SLinus Torvalds 	for (i = 0; i < SCpnt->cmd_len; i++) printk("%02x ", cmd[i]);
3521da177e4SLinus Torvalds 	printk("\n");
3531da177e4SLinus Torvalds #endif
3541da177e4SLinus Torvalds 
3551da177e4SLinus Torvalds 	/* locate an available ecb */
3561da177e4SLinus Torvalds 	spin_lock_irqsave(SCpnt->device->host->host_lock, flags);
3571da177e4SLinus Torvalds 	ecbno = host->last_ecb_used + 1; /* An optimization */
3581da177e4SLinus Torvalds 	if (ecbno >= AHA1740_ECBS)
3591da177e4SLinus Torvalds 		ecbno = 0;
3601da177e4SLinus Torvalds 	do {
3611da177e4SLinus Torvalds 		if (!host->ecb[ecbno].cmdw)
3621da177e4SLinus Torvalds 			break;
3631da177e4SLinus Torvalds 		ecbno++;
3641da177e4SLinus Torvalds 		if (ecbno >= AHA1740_ECBS)
3651da177e4SLinus Torvalds 			ecbno = 0;
3661da177e4SLinus Torvalds 	} while (ecbno != host->last_ecb_used);
3671da177e4SLinus Torvalds 
3681da177e4SLinus Torvalds 	if (host->ecb[ecbno].cmdw)
3691da177e4SLinus Torvalds 		panic("Unable to find empty ecb for aha1740.\n");
3701da177e4SLinus Torvalds 
3711da177e4SLinus Torvalds 	host->ecb[ecbno].cmdw = AHA1740CMD_INIT; /* SCSI Initiator Command
3721da177e4SLinus Torvalds 						    doubles as reserved flag */
3731da177e4SLinus Torvalds 
3741da177e4SLinus Torvalds 	host->last_ecb_used = ecbno;
3751da177e4SLinus Torvalds 	spin_unlock_irqrestore(SCpnt->device->host->host_lock, flags);
3761da177e4SLinus Torvalds 
3771da177e4SLinus Torvalds #ifdef DEBUG
3781da177e4SLinus Torvalds 	printk("Sending command (%d %x)...", ecbno, done);
3791da177e4SLinus Torvalds #endif
3801da177e4SLinus Torvalds 
3811da177e4SLinus Torvalds 	host->ecb[ecbno].cdblen = SCpnt->cmd_len; /* SCSI Command
3821da177e4SLinus Torvalds 						   * Descriptor Block
3831da177e4SLinus Torvalds 						   * Length */
3841da177e4SLinus Torvalds 
3851da177e4SLinus Torvalds 	direction = 0;
3861da177e4SLinus Torvalds 	if (*cmd == READ_10 || *cmd == READ_6)
3871da177e4SLinus Torvalds 		direction = 1;
3881da177e4SLinus Torvalds 	else if (*cmd == WRITE_10 || *cmd == WRITE_6)
3891da177e4SLinus Torvalds 		direction = 0;
3901da177e4SLinus Torvalds 
3911da177e4SLinus Torvalds 	memcpy(host->ecb[ecbno].cdb, cmd, SCpnt->cmd_len);
3921da177e4SLinus Torvalds 
3931da177e4SLinus Torvalds 	SCpnt->host_scribble = dma_alloc_coherent (&host->edev->dev,
3941da177e4SLinus Torvalds 						   sizeof (struct aha1740_sg),
3951da177e4SLinus Torvalds 						   &sg_dma, GFP_ATOMIC);
3961da177e4SLinus Torvalds 	if(SCpnt->host_scribble == NULL) {
3971da177e4SLinus Torvalds 		printk(KERN_WARNING "aha1740: out of memory in queuecommand!\n");
3981da177e4SLinus Torvalds 		return 1;
3991da177e4SLinus Torvalds 	}
4001da177e4SLinus Torvalds 	sgptr = (struct aha1740_sg *) SCpnt->host_scribble;
4011da177e4SLinus Torvalds 	sgptr->sg_dma_addr = sg_dma;
4021da177e4SLinus Torvalds 
403c66cc13cSFUJITA Tomonori 	nseg = scsi_dma_map(SCpnt);
404c66cc13cSFUJITA Tomonori 	BUG_ON(nseg < 0);
405c66cc13cSFUJITA Tomonori 	if (nseg) {
406c66cc13cSFUJITA Tomonori 		struct scatterlist *sg;
4071da177e4SLinus Torvalds 		struct aha1740_chain * cptr;
408c66cc13cSFUJITA Tomonori 		int i;
4091da177e4SLinus Torvalds 		DEB(unsigned char * ptr);
4101da177e4SLinus Torvalds 
4111da177e4SLinus Torvalds 		host->ecb[ecbno].sg = 1;  /* SCSI Initiator Command
4121da177e4SLinus Torvalds 					   * w/scatter-gather*/
4131da177e4SLinus Torvalds 		cptr = sgptr->sg_chain;
414c66cc13cSFUJITA Tomonori 		scsi_for_each_sg(SCpnt, sg, nseg, i) {
415c66cc13cSFUJITA Tomonori 			cptr[i].datalen = sg_dma_len (sg);
416c66cc13cSFUJITA Tomonori 			cptr[i].dataptr = sg_dma_address (sg);
4171da177e4SLinus Torvalds 		}
418c66cc13cSFUJITA Tomonori 		host->ecb[ecbno].datalen = nseg * sizeof(struct aha1740_chain);
4191da177e4SLinus Torvalds 		host->ecb[ecbno].dataptr = sg_dma;
4201da177e4SLinus Torvalds #ifdef DEBUG
4211da177e4SLinus Torvalds 		printk("cptr %x: ",cptr);
4221da177e4SLinus Torvalds 		ptr = (unsigned char *) cptr;
4231da177e4SLinus Torvalds 		for(i=0;i<24;i++) printk("%02x ", ptr[i]);
4241da177e4SLinus Torvalds #endif
4251da177e4SLinus Torvalds 	} else {
426c66cc13cSFUJITA Tomonori 		host->ecb[ecbno].datalen = 0;
427c66cc13cSFUJITA Tomonori 		host->ecb[ecbno].dataptr = 0;
4281da177e4SLinus Torvalds 	}
4291da177e4SLinus Torvalds 	host->ecb[ecbno].lun = SCpnt->device->lun;
4301da177e4SLinus Torvalds 	host->ecb[ecbno].ses = 1; /* Suppress underrun errors */
4311da177e4SLinus Torvalds 	host->ecb[ecbno].dir = direction;
4321da177e4SLinus Torvalds 	host->ecb[ecbno].ars = 1; /* Yes, get the sense on an error */
4331da177e4SLinus Torvalds 	host->ecb[ecbno].senselen = 12;
4341da177e4SLinus Torvalds 	host->ecb[ecbno].senseptr = ecb_cpu_to_dma (SCpnt->device->host,
4351da177e4SLinus Torvalds 						    host->ecb[ecbno].sense);
4361da177e4SLinus Torvalds 	host->ecb[ecbno].statusptr = ecb_cpu_to_dma (SCpnt->device->host,
4371da177e4SLinus Torvalds 						     host->ecb[ecbno].status);
4381da177e4SLinus Torvalds 	host->ecb[ecbno].done = done;
4391da177e4SLinus Torvalds 	host->ecb[ecbno].SCpnt = SCpnt;
4401da177e4SLinus Torvalds #ifdef DEBUG
4411da177e4SLinus Torvalds 	{
4421da177e4SLinus Torvalds 		int i;
4431da177e4SLinus Torvalds 		printk("aha1740_command: sending.. ");
4441da177e4SLinus Torvalds 		for (i = 0; i < sizeof(host->ecb[ecbno]) - 10; i++)
4451da177e4SLinus Torvalds 			printk("%02x ", ((unchar *)&host->ecb[ecbno])[i]);
4461da177e4SLinus Torvalds 	}
4471da177e4SLinus Torvalds 	printk("\n");
4481da177e4SLinus Torvalds #endif
4491da177e4SLinus Torvalds 	if (done) {
4501da177e4SLinus Torvalds 	/* The Adaptec Spec says the card is so fast that the loops
4511da177e4SLinus Torvalds            will only be executed once in the code below. Even if this
4521da177e4SLinus Torvalds            was true with the fastest processors when the spec was
45325985edcSLucas De Marchi            written, it doesn't seem to be true with today's fast
4541da177e4SLinus Torvalds            processors. We print a warning if the code is executed more
4551da177e4SLinus Torvalds            often than LOOPCNT_WARN. If this happens, it should be
4561da177e4SLinus Torvalds            investigated. If the count reaches LOOPCNT_MAX, we assume
4571da177e4SLinus Torvalds            something is broken; since there is no way to return an
4581da177e4SLinus Torvalds            error (the return value is ignored by the mid-level scsi
4591da177e4SLinus Torvalds            layer) we have to panic (and maybe that's the best thing we
4601da177e4SLinus Torvalds            can do then anyhow). */
4611da177e4SLinus Torvalds 
4621da177e4SLinus Torvalds #define LOOPCNT_WARN 10		/* excessive mbxout wait -> syslog-msg */
4631da177e4SLinus Torvalds #define LOOPCNT_MAX 1000000	/* mbxout deadlock -> panic() after ~ 2 sec. */
4641da177e4SLinus Torvalds 		int loopcnt;
4651da177e4SLinus Torvalds 		unsigned int base = SCpnt->device->host->io_port;
4661da177e4SLinus Torvalds 		DEB(printk("aha1740[%d] critical section\n",ecbno));
4671da177e4SLinus Torvalds 
4681da177e4SLinus Torvalds 		spin_lock_irqsave(SCpnt->device->host->host_lock, flags);
4691da177e4SLinus Torvalds 		for (loopcnt = 0; ; loopcnt++) {
4701da177e4SLinus Torvalds 			if (inb(G2STAT(base)) & G2STAT_MBXOUT) break;
4711da177e4SLinus Torvalds 			if (loopcnt == LOOPCNT_WARN) {
4721da177e4SLinus Torvalds 				printk("aha1740[%d]_mbxout wait!\n",ecbno);
4731da177e4SLinus Torvalds 			}
4741da177e4SLinus Torvalds 			if (loopcnt == LOOPCNT_MAX)
4751da177e4SLinus Torvalds 				panic("aha1740.c: mbxout busy!\n");
4761da177e4SLinus Torvalds 		}
4771da177e4SLinus Torvalds 		outl (ecb_cpu_to_dma (SCpnt->device->host, host->ecb + ecbno),
4781da177e4SLinus Torvalds 		      MBOXOUT0(base));
4791da177e4SLinus Torvalds 		for (loopcnt = 0; ; loopcnt++) {
4801da177e4SLinus Torvalds 			if (! (inb(G2STAT(base)) & G2STAT_BUSY)) break;
4811da177e4SLinus Torvalds 			if (loopcnt == LOOPCNT_WARN) {
4821da177e4SLinus Torvalds 				printk("aha1740[%d]_attn wait!\n",ecbno);
4831da177e4SLinus Torvalds 			}
4841da177e4SLinus Torvalds 			if (loopcnt == LOOPCNT_MAX)
4851da177e4SLinus Torvalds 				panic("aha1740.c: attn wait failed!\n");
4861da177e4SLinus Torvalds 		}
4871da177e4SLinus Torvalds 		outb(ATTN_START | (target & 7), ATTN(base)); /* Start it up */
4881da177e4SLinus Torvalds 		spin_unlock_irqrestore(SCpnt->device->host->host_lock, flags);
4891da177e4SLinus Torvalds 		DEB(printk("aha1740[%d] request queued.\n",ecbno));
4901da177e4SLinus Torvalds 	} else
4911da177e4SLinus Torvalds 		printk(KERN_ALERT "aha1740_queuecommand: done can't be NULL\n");
4921da177e4SLinus Torvalds 	return 0;
4931da177e4SLinus Torvalds }
4941da177e4SLinus Torvalds 
DEF_SCSI_QCMD(aha1740_queuecommand)495f281233dSJeff Garzik static DEF_SCSI_QCMD(aha1740_queuecommand)
496f281233dSJeff Garzik 
4971da177e4SLinus Torvalds /* Query the board for its irq_level and irq_type.  Nothing else matters
4981da177e4SLinus Torvalds    in enhanced mode on an EISA bus. */
4991da177e4SLinus Torvalds 
5001da177e4SLinus Torvalds static void aha1740_getconfig(unsigned int base, unsigned int *irq_level,
5011da177e4SLinus Torvalds 			      unsigned int *irq_type,
5021da177e4SLinus Torvalds 			      unsigned int *translation)
5031da177e4SLinus Torvalds {
5041da177e4SLinus Torvalds 	static int intab[] = { 9, 10, 11, 12, 0, 14, 15, 0 };
5051da177e4SLinus Torvalds 
5061da177e4SLinus Torvalds 	*irq_level = intab[inb(INTDEF(base)) & 0x7];
5071da177e4SLinus Torvalds 	*irq_type  = (inb(INTDEF(base)) & 0x8) >> 3;
5081da177e4SLinus Torvalds 	*translation = inb(RESV1(base)) & 0x1;
5091da177e4SLinus Torvalds 	outb(inb(INTDEF(base)) | 0x10, INTDEF(base));
5101da177e4SLinus Torvalds }
5111da177e4SLinus Torvalds 
aha1740_biosparam(struct scsi_device * sdev,struct block_device * dev,sector_t capacity,int * ip)5121da177e4SLinus Torvalds static int aha1740_biosparam(struct scsi_device *sdev,
5131da177e4SLinus Torvalds 			     struct block_device *dev,
5141da177e4SLinus Torvalds 			     sector_t capacity, int* ip)
5151da177e4SLinus Torvalds {
5161da177e4SLinus Torvalds 	int size = capacity;
5171da177e4SLinus Torvalds 	int extended = HOSTDATA(sdev->host)->translation;
5181da177e4SLinus Torvalds 
5191da177e4SLinus Torvalds 	DEB(printk("aha1740_biosparam\n"));
5201da177e4SLinus Torvalds 	if (extended && (ip[2] > 1024))	{
5211da177e4SLinus Torvalds 		ip[0] = 255;
5221da177e4SLinus Torvalds 		ip[1] = 63;
5231da177e4SLinus Torvalds 		ip[2] = size / (255 * 63);
5241da177e4SLinus Torvalds 	} else {
5251da177e4SLinus Torvalds 		ip[0] = 64;
5261da177e4SLinus Torvalds 		ip[1] = 32;
5271da177e4SLinus Torvalds 		ip[2] = size >> 11;
5281da177e4SLinus Torvalds 	}
5291da177e4SLinus Torvalds 	return 0;
5301da177e4SLinus Torvalds }
5311da177e4SLinus Torvalds 
aha1740_eh_abort_handler(struct scsi_cmnd * dummy)53291ebc1faSJohannes Thumshirn static int aha1740_eh_abort_handler (struct scsi_cmnd *dummy)
5331da177e4SLinus Torvalds {
5341da177e4SLinus Torvalds /*
5351da177e4SLinus Torvalds  * From Alan Cox :
5361da177e4SLinus Torvalds  * The AHA1740 has firmware handled abort/reset handling. The "head in
5371da177e4SLinus Torvalds  * sand" kernel code is correct for once 8)
5381da177e4SLinus Torvalds  *
5391da177e4SLinus Torvalds  * So we define a dummy handler just to keep the kernel SCSI code as
5401da177e4SLinus Torvalds  * quiet as possible...
5411da177e4SLinus Torvalds  */
5421da177e4SLinus Torvalds 
543b6c92b7eSHannes Reinecke 	return SUCCESS;
5441da177e4SLinus Torvalds }
5451da177e4SLinus Torvalds 
546*4df23b30SBart Van Assche static const struct scsi_host_template aha1740_template = {
5471da177e4SLinus Torvalds 	.module           = THIS_MODULE,
5481da177e4SLinus Torvalds 	.proc_name        = "aha1740",
549e633c1e5SAl Viro 	.show_info        = aha1740_show_info,
5501da177e4SLinus Torvalds 	.name             = "Adaptec 174x (EISA)",
5511da177e4SLinus Torvalds 	.queuecommand     = aha1740_queuecommand,
5521da177e4SLinus Torvalds 	.bios_param       = aha1740_biosparam,
5531da177e4SLinus Torvalds 	.can_queue        = AHA1740_ECBS,
5541da177e4SLinus Torvalds 	.this_id          = 7,
5551da177e4SLinus Torvalds 	.sg_tablesize     = AHA1740_SCATTER,
5561da177e4SLinus Torvalds 	.eh_abort_handler = aha1740_eh_abort_handler,
5571da177e4SLinus Torvalds };
5581da177e4SLinus Torvalds 
aha1740_probe(struct device * dev)5591da177e4SLinus Torvalds static int aha1740_probe (struct device *dev)
5601da177e4SLinus Torvalds {
56108157cd0SJeff Garzik 	int slotbase, rc;
5621da177e4SLinus Torvalds 	unsigned int irq_level, irq_type, translation;
5631da177e4SLinus Torvalds 	struct Scsi_Host *shpnt;
5641da177e4SLinus Torvalds 	struct aha1740_hostdata *host;
5651da177e4SLinus Torvalds 	struct eisa_device *edev = to_eisa_device (dev);
5661da177e4SLinus Torvalds 
5671da177e4SLinus Torvalds 	DEB(printk("aha1740_probe: \n"));
5681da177e4SLinus Torvalds 
5691da177e4SLinus Torvalds 	slotbase = edev->base_addr + EISA_VENDOR_ID_OFFSET;
5701da177e4SLinus Torvalds 	if (!request_region(slotbase, SLOTSIZE, "aha1740")) /* See if in use */
5711da177e4SLinus Torvalds 		return -EBUSY;
5721da177e4SLinus Torvalds 	if (!aha1740_test_port(slotbase))
5731da177e4SLinus Torvalds 		goto err_release_region;
5741da177e4SLinus Torvalds 	aha1740_getconfig(slotbase,&irq_level,&irq_type,&translation);
5751da177e4SLinus Torvalds 	if ((inb(G2STAT(slotbase)) &
5761da177e4SLinus Torvalds 	     (G2STAT_MBXOUT|G2STAT_BUSY)) != G2STAT_MBXOUT) {
5771da177e4SLinus Torvalds 		/* If the card isn't ready, hard reset it */
5781da177e4SLinus Torvalds 		outb(G2CNTRL_HRST, G2CNTRL(slotbase));
5791da177e4SLinus Torvalds 		outb(0, G2CNTRL(slotbase));
5801da177e4SLinus Torvalds 	}
5811da177e4SLinus Torvalds 	printk(KERN_INFO "Configuring slot %d at IO:%x, IRQ %u (%s)\n",
5821da177e4SLinus Torvalds 	       edev->slot, slotbase, irq_level, irq_type ? "edge" : "level");
5831da177e4SLinus Torvalds 	printk(KERN_INFO "aha174x: Extended translation %sabled.\n",
5841da177e4SLinus Torvalds 	       translation ? "en" : "dis");
5851da177e4SLinus Torvalds 	shpnt = scsi_host_alloc(&aha1740_template,
5861da177e4SLinus Torvalds 			      sizeof(struct aha1740_hostdata));
5871da177e4SLinus Torvalds 	if(shpnt == NULL)
5881da177e4SLinus Torvalds 		goto err_release_region;
5891da177e4SLinus Torvalds 
5901da177e4SLinus Torvalds 	shpnt->base = 0;
5911da177e4SLinus Torvalds 	shpnt->io_port = slotbase;
5921da177e4SLinus Torvalds 	shpnt->n_io_port = SLOTSIZE;
5931da177e4SLinus Torvalds 	shpnt->irq = irq_level;
5941da177e4SLinus Torvalds 	shpnt->dma_channel = 0xff;
5951da177e4SLinus Torvalds 	host = HOSTDATA(shpnt);
5961da177e4SLinus Torvalds 	host->edev = edev;
5971da177e4SLinus Torvalds 	host->translation = translation;
5981da177e4SLinus Torvalds 	host->ecb_dma_addr = dma_map_single (&edev->dev, host->ecb,
5991da177e4SLinus Torvalds 					     sizeof (host->ecb),
6001da177e4SLinus Torvalds 					     DMA_BIDIRECTIONAL);
6011da177e4SLinus Torvalds 	if (!host->ecb_dma_addr) {
6021da177e4SLinus Torvalds 		printk (KERN_ERR "aha1740_probe: Couldn't map ECB, giving up\n");
6031da177e4SLinus Torvalds 		goto err_host_put;
6041da177e4SLinus Torvalds 	}
6051da177e4SLinus Torvalds 
6061da177e4SLinus Torvalds 	DEB(printk("aha1740_probe: enable interrupt channel %d\n",irq_level));
6071d6f359aSThomas Gleixner 	if (request_irq(irq_level,aha1740_intr_handle,irq_type ? 0 : IRQF_SHARED,
6081da177e4SLinus Torvalds 			"aha1740",shpnt)) {
6091da177e4SLinus Torvalds 		printk(KERN_ERR "aha1740_probe: Unable to allocate IRQ %d.\n",
6101da177e4SLinus Torvalds 		       irq_level);
6111da177e4SLinus Torvalds 		goto err_unmap;
6121da177e4SLinus Torvalds 	}
6131da177e4SLinus Torvalds 
6141da177e4SLinus Torvalds 	eisa_set_drvdata (edev, shpnt);
61508157cd0SJeff Garzik 
61608157cd0SJeff Garzik 	rc = scsi_add_host (shpnt, dev);
61708157cd0SJeff Garzik 	if (rc)
61808157cd0SJeff Garzik 		goto err_irq;
61908157cd0SJeff Garzik 
6201da177e4SLinus Torvalds 	scsi_scan_host (shpnt);
6211da177e4SLinus Torvalds 	return 0;
6221da177e4SLinus Torvalds 
62308157cd0SJeff Garzik  err_irq:
62408157cd0SJeff Garzik  	free_irq(irq_level, shpnt);
6251da177e4SLinus Torvalds  err_unmap:
6261da177e4SLinus Torvalds 	dma_unmap_single (&edev->dev, host->ecb_dma_addr,
6271da177e4SLinus Torvalds 			  sizeof (host->ecb), DMA_BIDIRECTIONAL);
6281da177e4SLinus Torvalds  err_host_put:
6291da177e4SLinus Torvalds 	scsi_host_put (shpnt);
6301da177e4SLinus Torvalds  err_release_region:
6311da177e4SLinus Torvalds 	release_region(slotbase, SLOTSIZE);
6321da177e4SLinus Torvalds 
6331da177e4SLinus Torvalds 	return -ENODEV;
6341da177e4SLinus Torvalds }
6351da177e4SLinus Torvalds 
aha1740_remove(struct device * dev)6366f039790SGreg Kroah-Hartman static int aha1740_remove (struct device *dev)
6371da177e4SLinus Torvalds {
63878c55d76SGreg Kroah-Hartman 	struct Scsi_Host *shpnt = dev_get_drvdata(dev);
6391da177e4SLinus Torvalds 	struct aha1740_hostdata *host = HOSTDATA (shpnt);
6401da177e4SLinus Torvalds 
6411da177e4SLinus Torvalds 	scsi_remove_host(shpnt);
6421da177e4SLinus Torvalds 
6431da177e4SLinus Torvalds 	free_irq (shpnt->irq, shpnt);
6441da177e4SLinus Torvalds 	dma_unmap_single (dev, host->ecb_dma_addr,
6451da177e4SLinus Torvalds 			  sizeof (host->ecb), DMA_BIDIRECTIONAL);
6461da177e4SLinus Torvalds 	release_region (shpnt->io_port, SLOTSIZE);
6471da177e4SLinus Torvalds 
6481da177e4SLinus Torvalds 	scsi_host_put (shpnt);
6491da177e4SLinus Torvalds 
6501da177e4SLinus Torvalds 	return 0;
6511da177e4SLinus Torvalds }
6521da177e4SLinus Torvalds 
6531da177e4SLinus Torvalds static struct eisa_device_id aha1740_ids[] = {
6541da177e4SLinus Torvalds 	{ "ADP0000" },		/* 1740  */
6551da177e4SLinus Torvalds 	{ "ADP0001" },		/* 1740A */
6561da177e4SLinus Torvalds 	{ "ADP0002" },		/* 1742A */
6571da177e4SLinus Torvalds 	{ "ADP0400" },		/* 1744  */
6581da177e4SLinus Torvalds 	{ "" }
6591da177e4SLinus Torvalds };
66007563c71SMichael Tokarev MODULE_DEVICE_TABLE(eisa, aha1740_ids);
6611da177e4SLinus Torvalds 
6621da177e4SLinus Torvalds static struct eisa_driver aha1740_driver = {
6631da177e4SLinus Torvalds 	.id_table = aha1740_ids,
6641da177e4SLinus Torvalds 	.driver   = {
6651da177e4SLinus Torvalds 		.name    = "aha1740",
6661da177e4SLinus Torvalds 		.probe   = aha1740_probe,
6676f039790SGreg Kroah-Hartman 		.remove  = aha1740_remove,
6681da177e4SLinus Torvalds 	},
6691da177e4SLinus Torvalds };
6701da177e4SLinus Torvalds 
aha1740_init(void)6711da177e4SLinus Torvalds static __init int aha1740_init (void)
6721da177e4SLinus Torvalds {
6731da177e4SLinus Torvalds 	return eisa_driver_register (&aha1740_driver);
6741da177e4SLinus Torvalds }
6751da177e4SLinus Torvalds 
aha1740_exit(void)6761da177e4SLinus Torvalds static __exit void aha1740_exit (void)
6771da177e4SLinus Torvalds {
6781da177e4SLinus Torvalds 	eisa_driver_unregister (&aha1740_driver);
6791da177e4SLinus Torvalds }
6801da177e4SLinus Torvalds 
6811da177e4SLinus Torvalds module_init (aha1740_init);
6821da177e4SLinus Torvalds module_exit (aha1740_exit);
6831da177e4SLinus Torvalds 
6841da177e4SLinus Torvalds MODULE_LICENSE("GPL");
685