1/* $Id$
2 * 1993/03/31
3 * linux/kernel/aha1740.c
4 *
5 * Based loosely on aha1542.c which is
6 * Copyright (C) 1992 Tommy Thorn and
7 * Modified by Eric Youngdale
8 *
9 * This file is aha1740.c, written and
10 * Copyright (C) 1992,1993 Brad McLean
11 * brad@saturn.gaylord.com or brad@bradpc.gaylord.com.
12 *
13 * Modifications to makecode and queuecommand
14 * for proper handling of multiple devices courteously
15 * provided by Michael Weller, March, 1993
16 *
17 * Multiple adapter support, extended translation detection,
18 * update to current scsi subsystem changes, proc fs support,
19 * working (!) module support based on patches from Andreas Arens,
20 * by Andreas Degert <ad@papyrus.hamburg.com>, 2/1997
21 *
22 * aha1740_makecode may still need even more work
23 * if it doesn't work for your devices, take a look.
24 *
25 * Reworked for new_eh and new locking by Alan Cox <alan@lxorguk.ukuu.org.uk>
26 *
27 * Converted to EISA and generic DMA APIs by Marc Zyngier
28 * <maz@wild-wind.fr.eu.org>, 4/2003.
29 *
30 * Shared interrupt support added by Rask Ingemann Lambertsen
31 * <rask@sygehus.dk>, 10/2003
32 *
33 * For the avoidance of doubt the "preferred form" of this code is one which
34 * is in an open non patent encumbered format. Where cryptographic key signing
35 * forms part of the process of creating an executable the information
36 * including keys needed to generate an equivalently functional executable
37 * are deemed to be part of the source code.
38 */
39
40#include <linux/blkdev.h>
41#include <linux/interrupt.h>
42#include <linux/module.h>
43#include <linux/kernel.h>
44#include <linux/types.h>
45#include <linux/string.h>
46#include <linux/ioport.h>
47#include <linux/proc_fs.h>
48#include <linux/stat.h>
49#include <linux/init.h>
50#include <linux/device.h>
51#include <linux/eisa.h>
52#include <linux/dma-mapping.h>
53#include <linux/gfp.h>
54
55#include <asm/dma.h>
56#include <asm/io.h>
57
58#include <scsi/scsi.h>
59#include <scsi/scsi_cmnd.h>
60#include <scsi/scsi_device.h>
61#include <scsi/scsi_eh.h>
62#include <scsi/scsi_host.h>
63#include <scsi/scsi_tcq.h>
64#include "aha1740.h"
65
66/* IF YOU ARE HAVING PROBLEMS WITH THIS DRIVER, AND WANT TO WATCH
67 IT WORK, THEN:
68#define DEBUG
69*/
70#ifdef DEBUG
71#define DEB(x) x
72#else
73#define DEB(x)
74#endif
75
76struct aha1740_hostdata {
77 struct eisa_device *edev;
78 unsigned int translation;
79 unsigned int last_ecb_used;
80 dma_addr_t ecb_dma_addr;
81 struct ecb ecb[AHA1740_ECBS];
82};
83
84struct aha1740_sg {
85 struct aha1740_chain sg_chain[AHA1740_SCATTER];
86 dma_addr_t sg_dma_addr;
87 dma_addr_t buf_dma_addr;
88};
89
90#define HOSTDATA(host) ((struct aha1740_hostdata *) &host->hostdata)
91
92static inline struct ecb *ecb_dma_to_cpu (struct Scsi_Host *host,
93 dma_addr_t dma)
94{
95 struct aha1740_hostdata *hdata = HOSTDATA (host);
96 dma_addr_t offset;
97
98 offset = dma - hdata->ecb_dma_addr;
99
100 return (struct ecb *)(((char *) hdata->ecb) + (unsigned int) offset);
101}
102
103static inline dma_addr_t ecb_cpu_to_dma (struct Scsi_Host *host, void *cpu)
104{
105 struct aha1740_hostdata *hdata = HOSTDATA (host);
106 dma_addr_t offset;
107
108 offset = (char *) cpu - (char *) hdata->ecb;
109
110 return hdata->ecb_dma_addr + offset;
111}
112
113static int aha1740_show_info(struct seq_file *m, struct Scsi_Host *shpnt)
114{
115 struct aha1740_hostdata *host = HOSTDATA(shpnt);
116 seq_printf(m, fmt: "aha174x at IO:%lx, IRQ %d, SLOT %d.\n"
117 "Extended translation %sabled.\n",
118 shpnt->io_port, shpnt->irq, host->edev->slot,
119 host->translation ? "en" : "dis");
120 return 0;
121}
122
123static int aha1740_makecode(unchar *sense, unchar *status)
124{
125 struct statusword
126 {
127 ushort don:1, /* Command Done - No Error */
128 du:1, /* Data underrun */
129 :1, qf:1, /* Queue full */
130 sc:1, /* Specification Check */
131 dor:1, /* Data overrun */
132 ch:1, /* Chaining Halted */
133 intr:1, /* Interrupt issued */
134 asa:1, /* Additional Status Available */
135 sns:1, /* Sense information Stored */
136 :1, ini:1, /* Initialization Required */
137 me:1, /* Major error or exception */
138 :1, eca:1, /* Extended Contingent alliance */
139 :1;
140 } status_word;
141 int retval = DID_OK;
142
143 status_word = * (struct statusword *) status;
144#ifdef DEBUG
145 printk("makecode from %x,%x,%x,%x %x,%x,%x,%x",
146 status[0], status[1], status[2], status[3],
147 sense[0], sense[1], sense[2], sense[3]);
148#endif
149 if (!status_word.don) { /* Anything abnormal was detected */
150 if ( (status[1]&0x18) || status_word.sc ) {
151 /*Additional info available*/
152 /* Use the supplied info for further diagnostics */
153 switch ( status[2] ) {
154 case 0x12:
155 if ( status_word.dor )
156 retval=DID_ERROR; /* It's an Overrun */
157 /* If not overrun, assume underrun and
158 * ignore it! */
159 break;
160 case 0x00: /* No info, assume no error, should
161 * not occur */
162 break;
163 case 0x11:
164 case 0x21:
165 retval=DID_TIME_OUT;
166 break;
167 case 0x0a:
168 retval=DID_BAD_TARGET;
169 break;
170 case 0x04:
171 case 0x05:
172 retval=DID_ABORT;
173 /* Either by this driver or the
174 * AHA1740 itself */
175 break;
176 default:
177 retval=DID_ERROR; /* No further
178 * diagnostics
179 * possible */
180 }
181 } else {
182 /* Michael suggests, and Brad concurs: */
183 if ( status_word.qf ) {
184 retval = DID_TIME_OUT; /* forces a redo */
185 /* I think this specific one should
186 * not happen -Brad */
187 printk("aha1740.c: WARNING: AHA1740 queue overflow!\n");
188 } else
189 if ( status[0]&0x60 ) {
190 /* Didn't find a better error */
191 retval = DID_ERROR;
192 }
193 /* In any other case return DID_OK so for example
194 CONDITION_CHECKS make it through to the appropriate
195 device driver */
196 }
197 }
198 /* Under all circumstances supply the target status -Michael */
199 return status[3] | retval << 16;
200}
201
202static int aha1740_test_port(unsigned int base)
203{
204 if ( inb(PORTADR(base)) & PORTADDR_ENH )
205 return 1; /* Okay, we're all set */
206
207 printk("aha174x: Board detected, but not in enhanced mode, so disabled it.\n");
208 return 0;
209}
210
211/* A "high" level interrupt handler */
212static irqreturn_t aha1740_intr_handle(int irq, void *dev_id)
213{
214 struct Scsi_Host *host = (struct Scsi_Host *) dev_id;
215 void (*my_done)(struct scsi_cmnd *);
216 int errstatus, adapstat;
217 int number_serviced;
218 struct ecb *ecbptr;
219 struct scsi_cmnd *SCtmp;
220 unsigned int base;
221 unsigned long flags;
222 int handled = 0;
223 struct aha1740_sg *sgptr;
224 struct eisa_device *edev;
225
226 if (!host)
227 panic(fmt: "aha1740.c: Irq from unknown host!\n");
228 spin_lock_irqsave(host->host_lock, flags);
229 base = host->io_port;
230 number_serviced = 0;
231 edev = HOSTDATA(host)->edev;
232
233 while(inb(G2STAT(base)) & G2STAT_INTPEND) {
234 handled = 1;
235 DEB(printk("aha1740_intr top of loop.\n"));
236 adapstat = inb(G2INTST(base));
237 ecbptr = ecb_dma_to_cpu (host, inl(MBOXIN0(base)));
238 outb(G2CNTRL_IRST,G2CNTRL(base)); /* interrupt reset */
239
240 switch ( adapstat & G2INTST_MASK ) {
241 case G2INTST_CCBRETRY:
242 case G2INTST_CCBERROR:
243 case G2INTST_CCBGOOD:
244 /* Host Ready -> Mailbox in complete */
245 outb(G2CNTRL_HRDY,G2CNTRL(base));
246 if (!ecbptr) {
247 printk("Aha1740 null ecbptr in interrupt (%x,%x,%x,%d)\n",
248 inb(G2STAT(base)),adapstat,
249 inb(G2INTST(base)), number_serviced++);
250 continue;
251 }
252 SCtmp = ecbptr->SCpnt;
253 if (!SCtmp) {
254 printk("Aha1740 null SCtmp in interrupt (%x,%x,%x,%d)\n",
255 inb(G2STAT(base)),adapstat,
256 inb(G2INTST(base)), number_serviced++);
257 continue;
258 }
259 sgptr = (struct aha1740_sg *) SCtmp->host_scribble;
260 scsi_dma_unmap(cmd: SCtmp);
261
262 /* Free the sg block */
263 dma_free_coherent (dev: &edev->dev,
264 size: sizeof (struct aha1740_sg),
265 cpu_addr: SCtmp->host_scribble,
266 dma_handle: sgptr->sg_dma_addr);
267
268 /* Fetch the sense data, and tuck it away, in
269 the required slot. The Adaptec
270 automatically fetches it, and there is no
271 guarantee that we will still have it in the
272 cdb when we come back */
273 if ( (adapstat & G2INTST_MASK) == G2INTST_CCBERROR ) {
274 memcpy_and_pad(dest: SCtmp->sense_buffer,
275 SCSI_SENSE_BUFFERSIZE,
276 src: ecbptr->sense,
277 count: sizeof(ecbptr->sense),
278 pad: 0);
279 errstatus = aha1740_makecode(sense: ecbptr->sense,status: ecbptr->status);
280 } else
281 errstatus = 0;
282 DEB(if (errstatus)
283 printk("aha1740_intr_handle: returning %6x\n",
284 errstatus));
285 SCtmp->result = errstatus;
286 my_done = ecbptr->done;
287 memset(ecbptr,0,sizeof(struct ecb));
288 if ( my_done )
289 my_done(SCtmp);
290 break;
291
292 case G2INTST_HARDFAIL:
293 printk(KERN_ALERT "aha1740 hardware failure!\n");
294 panic(fmt: "aha1740.c"); /* Goodbye */
295
296 case G2INTST_ASNEVENT:
297 printk("aha1740 asynchronous event: %02x %02x %02x %02x %02x\n",
298 adapstat,
299 inb(MBOXIN0(base)),
300 inb(MBOXIN1(base)),
301 inb(MBOXIN2(base)),
302 inb(MBOXIN3(base))); /* Say What? */
303 /* Host Ready -> Mailbox in complete */
304 outb(G2CNTRL_HRDY,G2CNTRL(base));
305 break;
306
307 case G2INTST_CMDGOOD:
308 /* set immediate command success flag here: */
309 break;
310
311 case G2INTST_CMDERROR:
312 /* Set immediate command failure flag here: */
313 break;
314 }
315 number_serviced++;
316 }
317
318 spin_unlock_irqrestore(lock: host->host_lock, flags);
319 return IRQ_RETVAL(handled);
320}
321
322static int aha1740_queuecommand_lck(struct scsi_cmnd *SCpnt)
323{
324 void (*done)(struct scsi_cmnd *) = scsi_done;
325 unchar direction;
326 unchar *cmd = (unchar *) SCpnt->cmnd;
327 unchar target = scmd_id(SCpnt);
328 struct aha1740_hostdata *host = HOSTDATA(SCpnt->device->host);
329 unsigned long flags;
330 dma_addr_t sg_dma;
331 struct aha1740_sg *sgptr;
332 int ecbno, nseg;
333 DEB(int i);
334
335 if(*cmd == REQUEST_SENSE) {
336 SCpnt->result = 0;
337 done(SCpnt);
338 return 0;
339 }
340
341#ifdef DEBUG
342 if (*cmd == READ_10 || *cmd == WRITE_10)
343 i = xscsi2int(cmd+2);
344 else if (*cmd == READ_6 || *cmd == WRITE_6)
345 i = scsi2int(cmd+2);
346 else
347 i = -1;
348 printk("aha1740_queuecommand: dev %d cmd %02x pos %d len %d ",
349 target, *cmd, i, bufflen);
350 printk("scsi cmd:");
351 for (i = 0; i < SCpnt->cmd_len; i++) printk("%02x ", cmd[i]);
352 printk("\n");
353#endif
354
355 /* locate an available ecb */
356 spin_lock_irqsave(SCpnt->device->host->host_lock, flags);
357 ecbno = host->last_ecb_used + 1; /* An optimization */
358 if (ecbno >= AHA1740_ECBS)
359 ecbno = 0;
360 do {
361 if (!host->ecb[ecbno].cmdw)
362 break;
363 ecbno++;
364 if (ecbno >= AHA1740_ECBS)
365 ecbno = 0;
366 } while (ecbno != host->last_ecb_used);
367
368 if (host->ecb[ecbno].cmdw)
369 panic(fmt: "Unable to find empty ecb for aha1740.\n");
370
371 host->ecb[ecbno].cmdw = AHA1740CMD_INIT; /* SCSI Initiator Command
372 doubles as reserved flag */
373
374 host->last_ecb_used = ecbno;
375 spin_unlock_irqrestore(lock: SCpnt->device->host->host_lock, flags);
376
377#ifdef DEBUG
378 printk("Sending command (%d %x)...", ecbno, done);
379#endif
380
381 host->ecb[ecbno].cdblen = SCpnt->cmd_len; /* SCSI Command
382 * Descriptor Block
383 * Length */
384
385 direction = 0;
386 if (*cmd == READ_10 || *cmd == READ_6)
387 direction = 1;
388 else if (*cmd == WRITE_10 || *cmd == WRITE_6)
389 direction = 0;
390
391 memcpy(host->ecb[ecbno].cdb, cmd, SCpnt->cmd_len);
392
393 SCpnt->host_scribble = dma_alloc_coherent (dev: &host->edev->dev,
394 size: sizeof (struct aha1740_sg),
395 dma_handle: &sg_dma, GFP_ATOMIC);
396 if(SCpnt->host_scribble == NULL) {
397 printk(KERN_WARNING "aha1740: out of memory in queuecommand!\n");
398 return 1;
399 }
400 sgptr = (struct aha1740_sg *) SCpnt->host_scribble;
401 sgptr->sg_dma_addr = sg_dma;
402
403 nseg = scsi_dma_map(cmd: SCpnt);
404 BUG_ON(nseg < 0);
405 if (nseg) {
406 struct scatterlist *sg;
407 struct aha1740_chain * cptr;
408 int i;
409 DEB(unsigned char * ptr);
410
411 host->ecb[ecbno].sg = 1; /* SCSI Initiator Command
412 * w/scatter-gather*/
413 cptr = sgptr->sg_chain;
414 scsi_for_each_sg(SCpnt, sg, nseg, i) {
415 cptr[i].datalen = sg_dma_len (sg);
416 cptr[i].dataptr = sg_dma_address (sg);
417 }
418 host->ecb[ecbno].datalen = nseg * sizeof(struct aha1740_chain);
419 host->ecb[ecbno].dataptr = sg_dma;
420#ifdef DEBUG
421 printk("cptr %x: ",cptr);
422 ptr = (unsigned char *) cptr;
423 for(i=0;i<24;i++) printk("%02x ", ptr[i]);
424#endif
425 } else {
426 host->ecb[ecbno].datalen = 0;
427 host->ecb[ecbno].dataptr = 0;
428 }
429 host->ecb[ecbno].lun = SCpnt->device->lun;
430 host->ecb[ecbno].ses = 1; /* Suppress underrun errors */
431 host->ecb[ecbno].dir = direction;
432 host->ecb[ecbno].ars = 1; /* Yes, get the sense on an error */
433 host->ecb[ecbno].senselen = 12;
434 host->ecb[ecbno].senseptr = ecb_cpu_to_dma (host: SCpnt->device->host,
435 cpu: host->ecb[ecbno].sense);
436 host->ecb[ecbno].statusptr = ecb_cpu_to_dma (host: SCpnt->device->host,
437 cpu: host->ecb[ecbno].status);
438 host->ecb[ecbno].done = done;
439 host->ecb[ecbno].SCpnt = SCpnt;
440#ifdef DEBUG
441 {
442 int i;
443 printk("aha1740_command: sending.. ");
444 for (i = 0; i < sizeof(host->ecb[ecbno]) - 10; i++)
445 printk("%02x ", ((unchar *)&host->ecb[ecbno])[i]);
446 }
447 printk("\n");
448#endif
449 if (done) {
450 /* The Adaptec Spec says the card is so fast that the loops
451 will only be executed once in the code below. Even if this
452 was true with the fastest processors when the spec was
453 written, it doesn't seem to be true with today's fast
454 processors. We print a warning if the code is executed more
455 often than LOOPCNT_WARN. If this happens, it should be
456 investigated. If the count reaches LOOPCNT_MAX, we assume
457 something is broken; since there is no way to return an
458 error (the return value is ignored by the mid-level scsi
459 layer) we have to panic (and maybe that's the best thing we
460 can do then anyhow). */
461
462#define LOOPCNT_WARN 10 /* excessive mbxout wait -> syslog-msg */
463#define LOOPCNT_MAX 1000000 /* mbxout deadlock -> panic() after ~ 2 sec. */
464 int loopcnt;
465 unsigned int base = SCpnt->device->host->io_port;
466 DEB(printk("aha1740[%d] critical section\n",ecbno));
467
468 spin_lock_irqsave(SCpnt->device->host->host_lock, flags);
469 for (loopcnt = 0; ; loopcnt++) {
470 if (inb(G2STAT(base)) & G2STAT_MBXOUT) break;
471 if (loopcnt == LOOPCNT_WARN) {
472 printk("aha1740[%d]_mbxout wait!\n",ecbno);
473 }
474 if (loopcnt == LOOPCNT_MAX)
475 panic(fmt: "aha1740.c: mbxout busy!\n");
476 }
477 outl (value: ecb_cpu_to_dma (host: SCpnt->device->host, cpu: host->ecb + ecbno),
478 MBOXOUT0(base));
479 for (loopcnt = 0; ; loopcnt++) {
480 if (! (inb(G2STAT(base)) & G2STAT_BUSY)) break;
481 if (loopcnt == LOOPCNT_WARN) {
482 printk("aha1740[%d]_attn wait!\n",ecbno);
483 }
484 if (loopcnt == LOOPCNT_MAX)
485 panic(fmt: "aha1740.c: attn wait failed!\n");
486 }
487 outb(ATTN_START | (target & 7), ATTN(base)); /* Start it up */
488 spin_unlock_irqrestore(lock: SCpnt->device->host->host_lock, flags);
489 DEB(printk("aha1740[%d] request queued.\n",ecbno));
490 } else
491 printk(KERN_ALERT "aha1740_queuecommand: done can't be NULL\n");
492 return 0;
493}
494
495static DEF_SCSI_QCMD(aha1740_queuecommand)
496
497/* Query the board for its irq_level and irq_type. Nothing else matters
498 in enhanced mode on an EISA bus. */
499
500static void aha1740_getconfig(unsigned int base, unsigned int *irq_level,
501 unsigned int *irq_type,
502 unsigned int *translation)
503{
504 static int intab[] = { 9, 10, 11, 12, 0, 14, 15, 0 };
505
506 *irq_level = intab[inb(INTDEF(base)) & 0x7];
507 *irq_type = (inb(INTDEF(base)) & 0x8) >> 3;
508 *translation = inb(RESV1(base)) & 0x1;
509 outb(inb(INTDEF(base)) | 0x10, INTDEF(base));
510}
511
512static int aha1740_biosparam(struct scsi_device *sdev,
513 struct block_device *dev,
514 sector_t capacity, int* ip)
515{
516 int size = capacity;
517 int extended = HOSTDATA(sdev->host)->translation;
518
519 DEB(printk("aha1740_biosparam\n"));
520 if (extended && (ip[2] > 1024)) {
521 ip[0] = 255;
522 ip[1] = 63;
523 ip[2] = size / (255 * 63);
524 } else {
525 ip[0] = 64;
526 ip[1] = 32;
527 ip[2] = size >> 11;
528 }
529 return 0;
530}
531
532static int aha1740_eh_abort_handler (struct scsi_cmnd *dummy)
533{
534/*
535 * From Alan Cox :
536 * The AHA1740 has firmware handled abort/reset handling. The "head in
537 * sand" kernel code is correct for once 8)
538 *
539 * So we define a dummy handler just to keep the kernel SCSI code as
540 * quiet as possible...
541 */
542
543 return SUCCESS;
544}
545
546static const struct scsi_host_template aha1740_template = {
547 .module = THIS_MODULE,
548 .proc_name = "aha1740",
549 .show_info = aha1740_show_info,
550 .name = "Adaptec 174x (EISA)",
551 .queuecommand = aha1740_queuecommand,
552 .bios_param = aha1740_biosparam,
553 .can_queue = AHA1740_ECBS,
554 .this_id = 7,
555 .sg_tablesize = AHA1740_SCATTER,
556 .eh_abort_handler = aha1740_eh_abort_handler,
557};
558
559static int aha1740_probe (struct device *dev)
560{
561 int slotbase, rc;
562 unsigned int irq_level, irq_type, translation;
563 struct Scsi_Host *shpnt;
564 struct aha1740_hostdata *host;
565 struct eisa_device *edev = to_eisa_device (dev);
566
567 DEB(printk("aha1740_probe: \n"));
568
569 slotbase = edev->base_addr + EISA_VENDOR_ID_OFFSET;
570 if (!request_region(slotbase, SLOTSIZE, "aha1740")) /* See if in use */
571 return -EBUSY;
572 if (!aha1740_test_port(base: slotbase))
573 goto err_release_region;
574 aha1740_getconfig(base: slotbase,irq_level: &irq_level,irq_type: &irq_type,translation: &translation);
575 if ((inb(G2STAT(slotbase)) &
576 (G2STAT_MBXOUT|G2STAT_BUSY)) != G2STAT_MBXOUT) {
577 /* If the card isn't ready, hard reset it */
578 outb(G2CNTRL_HRST, G2CNTRL(slotbase));
579 outb(value: 0, G2CNTRL(slotbase));
580 }
581 printk(KERN_INFO "Configuring slot %d at IO:%x, IRQ %u (%s)\n",
582 edev->slot, slotbase, irq_level, irq_type ? "edge" : "level");
583 printk(KERN_INFO "aha174x: Extended translation %sabled.\n",
584 translation ? "en" : "dis");
585 shpnt = scsi_host_alloc(&aha1740_template,
586 sizeof(struct aha1740_hostdata));
587 if(shpnt == NULL)
588 goto err_release_region;
589
590 shpnt->base = 0;
591 shpnt->io_port = slotbase;
592 shpnt->n_io_port = SLOTSIZE;
593 shpnt->irq = irq_level;
594 shpnt->dma_channel = 0xff;
595 host = HOSTDATA(shpnt);
596 host->edev = edev;
597 host->translation = translation;
598 host->ecb_dma_addr = dma_map_single (&edev->dev, host->ecb,
599 sizeof (host->ecb),
600 DMA_BIDIRECTIONAL);
601 if (!host->ecb_dma_addr) {
602 printk (KERN_ERR "aha1740_probe: Couldn't map ECB, giving up\n");
603 goto err_host_put;
604 }
605
606 DEB(printk("aha1740_probe: enable interrupt channel %d\n",irq_level));
607 if (request_irq(irq: irq_level,handler: aha1740_intr_handle,flags: irq_type ? 0 : IRQF_SHARED,
608 name: "aha1740",dev: shpnt)) {
609 printk(KERN_ERR "aha1740_probe: Unable to allocate IRQ %d.\n",
610 irq_level);
611 goto err_unmap;
612 }
613
614 eisa_set_drvdata (edev, data: shpnt);
615
616 rc = scsi_add_host (host: shpnt, dev);
617 if (rc)
618 goto err_irq;
619
620 scsi_scan_host (shpnt);
621 return 0;
622
623 err_irq:
624 free_irq(irq_level, shpnt);
625 err_unmap:
626 dma_unmap_single (&edev->dev, host->ecb_dma_addr,
627 sizeof (host->ecb), DMA_BIDIRECTIONAL);
628 err_host_put:
629 scsi_host_put (t: shpnt);
630 err_release_region:
631 release_region(slotbase, SLOTSIZE);
632
633 return -ENODEV;
634}
635
636static int aha1740_remove (struct device *dev)
637{
638 struct Scsi_Host *shpnt = dev_get_drvdata(dev);
639 struct aha1740_hostdata *host = HOSTDATA (shpnt);
640
641 scsi_remove_host(shpnt);
642
643 free_irq (shpnt->irq, shpnt);
644 dma_unmap_single (dev, host->ecb_dma_addr,
645 sizeof (host->ecb), DMA_BIDIRECTIONAL);
646 release_region (shpnt->io_port, SLOTSIZE);
647
648 scsi_host_put (t: shpnt);
649
650 return 0;
651}
652
653static struct eisa_device_id aha1740_ids[] = {
654 { "ADP0000" }, /* 1740 */
655 { "ADP0001" }, /* 1740A */
656 { "ADP0002" }, /* 1742A */
657 { "ADP0400" }, /* 1744 */
658 { "" }
659};
660MODULE_DEVICE_TABLE(eisa, aha1740_ids);
661
662static struct eisa_driver aha1740_driver = {
663 .id_table = aha1740_ids,
664 .driver = {
665 .name = "aha1740",
666 .probe = aha1740_probe,
667 .remove = aha1740_remove,
668 },
669};
670
671static __init int aha1740_init (void)
672{
673 return eisa_driver_register (edrv: &aha1740_driver);
674}
675
676static __exit void aha1740_exit (void)
677{
678 eisa_driver_unregister (edrv: &aha1740_driver);
679}
680
681module_init (aha1740_init);
682module_exit (aha1740_exit);
683
684MODULE_LICENSE("GPL");
685

source code of linux/drivers/scsi/aha1740.c