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