blob: a19fcb02ff20c581a250947e5b01659209a49b92 [file] [log] [blame]
Ondrej Zary1d084d22015-02-06 23:11:47 +01001/*
2 * Driver for Adaptec AHA-1542 SCSI host adapters
Linus Torvalds1da177e2005-04-16 15:20:36 -07003 *
4 * Copyright (C) 1992 Tommy Thorn
5 * Copyright (C) 1993, 1994, 1995 Eric Youngdale
Ondrej Zary1d084d22015-02-06 23:11:47 +01006 * Copyright (C) 2015 Ondrej Zary
Linus Torvalds1da177e2005-04-16 15:20:36 -07007 */
8
Linus Torvalds1da177e2005-04-16 15:20:36 -07009#include <linux/module.h>
10#include <linux/interrupt.h>
11#include <linux/kernel.h>
12#include <linux/types.h>
13#include <linux/string.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070014#include <linux/delay.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070015#include <linux/init.h>
16#include <linux/spinlock.h>
Ondrej Zary643a7c42015-02-06 23:11:22 +010017#include <linux/isa.h>
18#include <linux/pnp.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090019#include <linux/slab.h>
Ondrej Zary954a9fd2015-02-06 23:11:48 +010020#include <linux/io.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070021#include <asm/dma.h>
Ondrej Zary954a9fd2015-02-06 23:11:48 +010022#include <scsi/scsi_cmnd.h>
23#include <scsi/scsi_device.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070024#include <scsi/scsi_host.h>
25#include "aha1542.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070026
Ondrej Zaryf71429a2015-02-06 23:11:41 +010027#define MAXBOARDS 4
Linus Torvalds1da177e2005-04-16 15:20:36 -070028
Ondrej Zaryf71429a2015-02-06 23:11:41 +010029static bool isapnp = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -070030module_param(isapnp, bool, 0);
Ondrej Zaryf71429a2015-02-06 23:11:41 +010031MODULE_PARM_DESC(isapnp, "enable PnP support (default=1)");
32
33static int io[MAXBOARDS] = { 0x330, 0x334, 0, 0 };
34module_param_array(io, int, NULL, 0);
35MODULE_PARM_DESC(io, "base IO address of controller (0x130,0x134,0x230,0x234,0x330,0x334, default=0x330,0x334)");
36
37/* time AHA spends on the AT-bus during data transfer */
38static int bus_on[MAXBOARDS] = { -1, -1, -1, -1 }; /* power-on default: 11us */
39module_param_array(bus_on, int, NULL, 0);
40MODULE_PARM_DESC(bus_on, "bus on time [us] (2-15, default=-1 [HW default: 11])");
41
42/* time AHA spends off the bus (not to monopolize it) during data transfer */
43static int bus_off[MAXBOARDS] = { -1, -1, -1, -1 }; /* power-on default: 4us */
44module_param_array(bus_off, int, NULL, 0);
45MODULE_PARM_DESC(bus_off, "bus off time [us] (1-64, default=-1 [HW default: 4])");
46
47/* default is jumper selected (J1 on 1542A), factory default = 5 MB/s */
48static int dma_speed[MAXBOARDS] = { -1, -1, -1, -1 };
49module_param_array(dma_speed, int, NULL, 0);
50MODULE_PARM_DESC(dma_speed, "DMA speed [MB/s] (5,6,7,8,10, default=-1 [by jumper])");
Linus Torvalds1da177e2005-04-16 15:20:36 -070051
Linus Torvalds1da177e2005-04-16 15:20:36 -070052#define BIOS_TRANSLATION_6432 1 /* Default case these days */
53#define BIOS_TRANSLATION_25563 2 /* Big disk case */
54
55struct aha1542_hostdata {
56 /* This will effectively start both of them at the first mailbox */
57 int bios_translation; /* Mapping bios uses - for compatibility */
58 int aha1542_last_mbi_used;
59 int aha1542_last_mbo_used;
Ondrej Zary55b28f92015-02-06 23:11:44 +010060 struct scsi_cmnd *int_cmds[AHA1542_MAILBOXES];
Linus Torvalds1da177e2005-04-16 15:20:36 -070061 struct mailbox mb[2 * AHA1542_MAILBOXES];
62 struct ccb ccb[AHA1542_MAILBOXES];
63};
64
Linus Torvalds1da177e2005-04-16 15:20:36 -070065static DEFINE_SPINLOCK(aha1542_lock);
66
Ondrej Zaryf1bbef62015-02-06 23:11:26 +010067static inline void aha1542_intr_reset(u16 base)
68{
69 outb(IRST, CONTROL(base));
70}
Linus Torvalds1da177e2005-04-16 15:20:36 -070071
Ondrej Zary2093bfa2015-02-06 23:11:31 +010072static inline bool wait_mask(u16 port, u8 mask, u8 allof, u8 noneof, int timeout)
73{
74 bool delayed = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -070075
Ondrej Zary2093bfa2015-02-06 23:11:31 +010076 if (timeout == 0) {
77 timeout = 3000000;
78 delayed = false;
79 }
80
81 while (1) {
82 u8 bits = inb(port) & mask;
83 if ((bits & allof) == allof && ((bits & noneof) == 0))
84 break;
85 if (delayed)
86 mdelay(1);
87 if (--timeout == 0)
88 return false;
89 }
90
91 return true;
92}
Linus Torvalds1da177e2005-04-16 15:20:36 -070093
Linus Torvalds1da177e2005-04-16 15:20:36 -070094/* This is a bit complicated, but we need to make sure that an interrupt
95 routine does not send something out while we are in the middle of this.
96 Fortunately, it is only at boot time that multi-byte messages
97 are ever sent. */
Ondrej Zarycad2fc72015-02-06 23:11:43 +010098static int aha1542_outb(unsigned int base, u8 val)
Ondrej Zary0c2b6482015-02-06 23:11:33 +010099{
100 unsigned long flags;
101
102 while (1) {
Ondrej Zary2906b3c2015-02-06 23:11:51 +0100103 if (!wait_mask(STATUS(base), CDF, 0, CDF, 0))
Ondrej Zary0c2b6482015-02-06 23:11:33 +0100104 return 1;
Ondrej Zary0c2b6482015-02-06 23:11:33 +0100105 spin_lock_irqsave(&aha1542_lock, flags);
106 if (inb(STATUS(base)) & CDF) {
107 spin_unlock_irqrestore(&aha1542_lock, flags);
108 continue;
109 }
Ondrej Zarycad2fc72015-02-06 23:11:43 +0100110 outb(val, DATA(base));
Ondrej Zary0c2b6482015-02-06 23:11:33 +0100111 spin_unlock_irqrestore(&aha1542_lock, flags);
112 return 0;
113 }
114}
115
Ondrej Zarycad2fc72015-02-06 23:11:43 +0100116static int aha1542_out(unsigned int base, u8 *buf, int len)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700117{
Ondrej Zary0c2b6482015-02-06 23:11:33 +0100118 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700119
Ondrej Zary0c2b6482015-02-06 23:11:33 +0100120 spin_lock_irqsave(&aha1542_lock, flags);
121 while (len--) {
122 if (!wait_mask(STATUS(base), CDF, 0, CDF, 0)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700123 spin_unlock_irqrestore(&aha1542_lock, flags);
Ondrej Zary0c2b6482015-02-06 23:11:33 +0100124 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700125 }
Ondrej Zarycad2fc72015-02-06 23:11:43 +0100126 outb(*buf++, DATA(base));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700127 }
Ondrej Zary0c2b6482015-02-06 23:11:33 +0100128 spin_unlock_irqrestore(&aha1542_lock, flags);
Ondrej Zary23e69402015-02-06 23:11:39 +0100129 if (!wait_mask(INTRFLAGS(base), INTRMASK, HACC, 0, 0))
130 return 1;
Ondrej Zary0c2b6482015-02-06 23:11:33 +0100131
Linus Torvalds1da177e2005-04-16 15:20:36 -0700132 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700133}
134
135/* Only used at boot time, so we do not need to worry about latency as much
136 here */
137
Ondrej Zarycad2fc72015-02-06 23:11:43 +0100138static int aha1542_in(unsigned int base, u8 *buf, int len, int timeout)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700139{
140 unsigned long flags;
141
142 spin_lock_irqsave(&aha1542_lock, flags);
143 while (len--) {
Ondrej Zarya13b3722015-02-06 23:11:34 +0100144 if (!wait_mask(STATUS(base), DF, DF, 0, timeout)) {
145 spin_unlock_irqrestore(&aha1542_lock, flags);
Ondrej Zarya13b3722015-02-06 23:11:34 +0100146 return 1;
147 }
Ondrej Zarycad2fc72015-02-06 23:11:43 +0100148 *buf++ = inb(DATA(base));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700149 }
150 spin_unlock_irqrestore(&aha1542_lock, flags);
151 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700152}
153
154static int makecode(unsigned hosterr, unsigned scsierr)
155{
156 switch (hosterr) {
157 case 0x0:
158 case 0xa: /* Linked command complete without error and linked normally */
159 case 0xb: /* Linked command complete without error, interrupt generated */
160 hosterr = 0;
161 break;
162
163 case 0x11: /* Selection time out-The initiator selection or target
164 reselection was not complete within the SCSI Time out period */
165 hosterr = DID_TIME_OUT;
166 break;
167
168 case 0x12: /* Data overrun/underrun-The target attempted to transfer more data
169 than was allocated by the Data Length field or the sum of the
170 Scatter / Gather Data Length fields. */
171
172 case 0x13: /* Unexpected bus free-The target dropped the SCSI BSY at an unexpected time. */
173
174 case 0x15: /* MBO command was not 00, 01 or 02-The first byte of the CB was
175 invalid. This usually indicates a software failure. */
176
177 case 0x16: /* Invalid CCB Operation Code-The first byte of the CCB was invalid.
178 This usually indicates a software failure. */
179
180 case 0x17: /* Linked CCB does not have the same LUN-A subsequent CCB of a set
181 of linked CCB's does not specify the same logical unit number as
182 the first. */
183 case 0x18: /* Invalid Target Direction received from Host-The direction of a
184 Target Mode CCB was invalid. */
185
186 case 0x19: /* Duplicate CCB Received in Target Mode-More than once CCB was
187 received to service data transfer between the same target LUN
188 and initiator SCSI ID in the same direction. */
189
190 case 0x1a: /* Invalid CCB or Segment List Parameter-A segment list with a zero
191 length segment or invalid segment list boundaries was received.
192 A CCB parameter was invalid. */
Ondrej Zaryfde1fb82015-02-06 23:11:52 +0100193#ifdef DEBUG
194 printk("Aha1542: %x %x\n", hosterr, scsierr);
195#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700196 hosterr = DID_ERROR; /* Couldn't find any better */
197 break;
198
199 case 0x14: /* Target bus phase sequence failure-An invalid bus phase or bus
200 phase sequence was requested by the target. The host adapter
201 will generate a SCSI Reset Condition, notifying the host with
202 a SCRD interrupt */
203 hosterr = DID_RESET;
204 break;
205 default:
206 printk(KERN_ERR "aha1542: makecode: unknown hoststatus %x\n", hosterr);
207 break;
208 }
209 return scsierr | (hosterr << 16);
210}
211
Ondrej Zary68ea9de2015-02-06 23:11:49 +0100212static int aha1542_test_port(struct Scsi_Host *sh)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700213{
Ondrej Zarycb5b5702015-02-06 23:11:27 +0100214 u8 inquiry_result[4];
Ondrej Zarycad2fc72015-02-06 23:11:43 +0100215 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700216
217 /* Quick and dirty test for presence of the card. */
Ondrej Zary68ea9de2015-02-06 23:11:49 +0100218 if (inb(STATUS(sh->io_port)) == 0xff)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700219 return 0;
220
221 /* Reset the adapter. I ought to make a hard reset, but it's not really necessary */
222
Linus Torvalds1da177e2005-04-16 15:20:36 -0700223 /* In case some other card was probing here, reset interrupts */
Ondrej Zary68ea9de2015-02-06 23:11:49 +0100224 aha1542_intr_reset(sh->io_port); /* reset interrupts, so they don't block */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700225
Ondrej Zary68ea9de2015-02-06 23:11:49 +0100226 outb(SRST | IRST /*|SCRST */ , CONTROL(sh->io_port));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700227
228 mdelay(20); /* Wait a little bit for things to settle down. */
229
Linus Torvalds1da177e2005-04-16 15:20:36 -0700230 /* Expect INIT and IDLE, any of the others are bad */
Ondrej Zary68ea9de2015-02-06 23:11:49 +0100231 if (!wait_mask(STATUS(sh->io_port), STATMASK, INIT | IDLE, STST | DIAGF | INVDCMD | DF | CDF, 0))
Ondrej Zarya13b3722015-02-06 23:11:34 +0100232 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700233
Linus Torvalds1da177e2005-04-16 15:20:36 -0700234 /* Shouldn't have generated any interrupts during reset */
Ondrej Zary68ea9de2015-02-06 23:11:49 +0100235 if (inb(INTRFLAGS(sh->io_port)) & INTRMASK)
Ondrej Zarya13b3722015-02-06 23:11:34 +0100236 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700237
Linus Torvalds1da177e2005-04-16 15:20:36 -0700238 /* Perform a host adapter inquiry instead so we do not need to set
239 up the mailboxes ahead of time */
240
Ondrej Zary68ea9de2015-02-06 23:11:49 +0100241 aha1542_outb(sh->io_port, CMD_INQUIRY);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700242
Ondrej Zarycad2fc72015-02-06 23:11:43 +0100243 for (i = 0; i < 4; i++) {
Ondrej Zary68ea9de2015-02-06 23:11:49 +0100244 if (!wait_mask(STATUS(sh->io_port), DF, DF, 0, 0))
Ondrej Zarya13b3722015-02-06 23:11:34 +0100245 return 0;
Ondrej Zary68ea9de2015-02-06 23:11:49 +0100246 inquiry_result[i] = inb(DATA(sh->io_port));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700247 }
248
Linus Torvalds1da177e2005-04-16 15:20:36 -0700249 /* Reading port should reset DF */
Ondrej Zary68ea9de2015-02-06 23:11:49 +0100250 if (inb(STATUS(sh->io_port)) & DF)
Ondrej Zarya13b3722015-02-06 23:11:34 +0100251 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700252
Linus Torvalds1da177e2005-04-16 15:20:36 -0700253 /* When HACC, command is completed, and we're though testing */
Ondrej Zary68ea9de2015-02-06 23:11:49 +0100254 if (!wait_mask(INTRFLAGS(sh->io_port), HACC, HACC, 0, 0))
Ondrej Zarya13b3722015-02-06 23:11:34 +0100255 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700256
Linus Torvalds1da177e2005-04-16 15:20:36 -0700257 /* Clear interrupts */
Ondrej Zary68ea9de2015-02-06 23:11:49 +0100258 outb(IRST, CONTROL(sh->io_port));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700259
Ondrej Zarybdebe222015-02-06 23:11:35 +0100260 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700261}
262
Linus Torvalds1da177e2005-04-16 15:20:36 -0700263/* A "high" level interrupt handler */
Ondrej Zaryc2532f62015-02-06 23:11:45 +0100264static void aha1542_intr_handle(struct Scsi_Host *sh)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700265{
Ondrej Zaryc2532f62015-02-06 23:11:45 +0100266 struct aha1542_hostdata *aha1542 = shost_priv(sh);
Ondrej Zary55b28f92015-02-06 23:11:44 +0100267 void (*my_done)(struct scsi_cmnd *) = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700268 int errstatus, mbi, mbo, mbistatus;
269 int number_serviced;
270 unsigned long flags;
Ondrej Zary55b28f92015-02-06 23:11:44 +0100271 struct scsi_cmnd *tmp_cmd;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700272 int flag;
Ondrej Zarye98878f2015-02-06 23:11:25 +0100273 struct mailbox *mb = aha1542->mb;
274 struct ccb *ccb = aha1542->ccb;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700275
276#ifdef DEBUG
277 {
Ondrej Zaryc2532f62015-02-06 23:11:45 +0100278 flag = inb(INTRFLAGS(sh->io_port));
Ondrej Zary2906b3c2015-02-06 23:11:51 +0100279 shost_printk(KERN_DEBUG, sh, "aha1542_intr_handle: ");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700280 if (!(flag & ANYINTR))
281 printk("no interrupt?");
282 if (flag & MBIF)
283 printk("MBIF ");
284 if (flag & MBOA)
285 printk("MBOF ");
286 if (flag & HACC)
287 printk("HACC ");
288 if (flag & SCRD)
289 printk("SCRD ");
Ondrej Zaryc2532f62015-02-06 23:11:45 +0100290 printk("status %02x\n", inb(STATUS(sh->io_port)));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700291 };
292#endif
293 number_serviced = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700294
295 while (1 == 1) {
Ondrej Zaryc2532f62015-02-06 23:11:45 +0100296 flag = inb(INTRFLAGS(sh->io_port));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700297
298 /* Check for unusual interrupts. If any of these happen, we should
299 probably do something special, but for now just printing a message
300 is sufficient. A SCSI reset detected is something that we really
301 need to deal with in some way. */
302 if (flag & ~MBIF) {
303 if (flag & MBOA)
304 printk("MBOF ");
305 if (flag & HACC)
306 printk("HACC ");
Ondrej Zarydfd7c992015-02-06 23:11:36 +0100307 if (flag & SCRD)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700308 printk("SCRD ");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700309 }
Ondrej Zaryc2532f62015-02-06 23:11:45 +0100310 aha1542_intr_reset(sh->io_port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700311
312 spin_lock_irqsave(&aha1542_lock, flags);
Ondrej Zarye98878f2015-02-06 23:11:25 +0100313 mbi = aha1542->aha1542_last_mbi_used + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700314 if (mbi >= 2 * AHA1542_MAILBOXES)
315 mbi = AHA1542_MAILBOXES;
316
317 do {
318 if (mb[mbi].status != 0)
319 break;
320 mbi++;
321 if (mbi >= 2 * AHA1542_MAILBOXES)
322 mbi = AHA1542_MAILBOXES;
Ondrej Zarye98878f2015-02-06 23:11:25 +0100323 } while (mbi != aha1542->aha1542_last_mbi_used);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700324
325 if (mb[mbi].status == 0) {
326 spin_unlock_irqrestore(&aha1542_lock, flags);
327 /* Hmm, no mail. Must have read it the last time around */
Ondrej Zarydfd7c992015-02-06 23:11:36 +0100328 if (!number_serviced)
Ondrej Zary2906b3c2015-02-06 23:11:51 +0100329 shost_printk(KERN_WARNING, sh, "interrupt received, but no mail.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700330 return;
331 };
332
Ondrej Zary10be6252015-02-06 23:11:24 +0100333 mbo = (scsi2int(mb[mbi].ccbptr) - (isa_virt_to_bus(&ccb[0]))) / sizeof(struct ccb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700334 mbistatus = mb[mbi].status;
335 mb[mbi].status = 0;
Ondrej Zarye98878f2015-02-06 23:11:25 +0100336 aha1542->aha1542_last_mbi_used = mbi;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700337 spin_unlock_irqrestore(&aha1542_lock, flags);
338
339#ifdef DEBUG
Ondrej Zaryfde1fb82015-02-06 23:11:52 +0100340 if (ccb[mbo].tarstat | ccb[mbo].hastat)
341 shost_printk(KERN_DEBUG, sh, "aha1542_command: returning %x (status %d)\n",
342 ccb[mbo].tarstat + ((int) ccb[mbo].hastat << 16), mb[mbi].status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700343#endif
344
345 if (mbistatus == 3)
346 continue; /* Aborted command not found */
347
348#ifdef DEBUG
Ondrej Zary2906b3c2015-02-06 23:11:51 +0100349 shost_printk(KERN_DEBUG, sh, "...done %d %d\n", mbo, mbi);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700350#endif
351
Ondrej Zary55b28f92015-02-06 23:11:44 +0100352 tmp_cmd = aha1542->int_cmds[mbo];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700353
Ondrej Zary55b28f92015-02-06 23:11:44 +0100354 if (!tmp_cmd || !tmp_cmd->scsi_done) {
Ondrej Zary2906b3c2015-02-06 23:11:51 +0100355 shost_printk(KERN_WARNING, sh, "Unexpected interrupt\n");
356 shost_printk(KERN_WARNING, sh, "tarstat=%x, hastat=%x idlun=%x ccb#=%d\n", ccb[mbo].tarstat,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700357 ccb[mbo].hastat, ccb[mbo].idlun, mbo);
358 return;
359 }
Ondrej Zary55b28f92015-02-06 23:11:44 +0100360 my_done = tmp_cmd->scsi_done;
361 kfree(tmp_cmd->host_scribble);
362 tmp_cmd->host_scribble = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700363 /* Fetch the sense data, and tuck it away, in the required slot. The
364 Adaptec automatically fetches it, and there is no guarantee that
365 we will still have it in the cdb when we come back */
366 if (ccb[mbo].tarstat == 2)
Ondrej Zary55b28f92015-02-06 23:11:44 +0100367 memcpy(tmp_cmd->sense_buffer, &ccb[mbo].cdb[ccb[mbo].cdblen],
FUJITA Tomonorib80ca4f2008-01-13 15:46:13 +0900368 SCSI_SENSE_BUFFERSIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700369
370
371 /* is there mail :-) */
372
373 /* more error checking left out here */
374 if (mbistatus != 1)
375 /* This is surely wrong, but I don't know what's right */
376 errstatus = makecode(ccb[mbo].hastat, ccb[mbo].tarstat);
377 else
378 errstatus = 0;
379
380#ifdef DEBUG
381 if (errstatus)
Ondrej Zary2906b3c2015-02-06 23:11:51 +0100382 shost_printk(KERN_DEBUG, sh, "(aha1542 error:%x %x %x) ", errstatus,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700383 ccb[mbo].hastat, ccb[mbo].tarstat);
Ondrej Zary6ddc8cf2015-02-06 23:11:53 +0100384 if (ccb[mbo].tarstat == 2)
385 print_hex_dump_bytes("sense: ", DUMP_PREFIX_NONE, &ccb[mbo].cdb[ccb[mbo].cdblen], 12);
Ondrej Zaryfde1fb82015-02-06 23:11:52 +0100386 if (errstatus)
387 printk("aha1542_intr_handle: returning %6x\n", errstatus);
388#endif
Ondrej Zary55b28f92015-02-06 23:11:44 +0100389 tmp_cmd->result = errstatus;
390 aha1542->int_cmds[mbo] = NULL; /* This effectively frees up the mailbox slot, as
Ondrej Zarye98878f2015-02-06 23:11:25 +0100391 far as queuecommand is concerned */
Ondrej Zary55b28f92015-02-06 23:11:44 +0100392 my_done(tmp_cmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700393 number_serviced++;
394 };
395}
396
Ondrej Zary09a44832015-02-06 23:11:28 +0100397/* A quick wrapper for do_aha1542_intr_handle to grab the spin lock */
398static irqreturn_t do_aha1542_intr_handle(int dummy, void *dev_id)
399{
400 unsigned long flags;
Ondrej Zaryc2532f62015-02-06 23:11:45 +0100401 struct Scsi_Host *sh = dev_id;
Ondrej Zary09a44832015-02-06 23:11:28 +0100402
Ondrej Zaryc2532f62015-02-06 23:11:45 +0100403 spin_lock_irqsave(sh->host_lock, flags);
404 aha1542_intr_handle(sh);
405 spin_unlock_irqrestore(sh->host_lock, flags);
Ondrej Zary09a44832015-02-06 23:11:28 +0100406 return IRQ_HANDLED;
407}
408
Ondrej Zary55b28f92015-02-06 23:11:44 +0100409static int aha1542_queuecommand_lck(struct scsi_cmnd *cmd, void (*done) (struct scsi_cmnd *))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700410{
Ondrej Zary2906b3c2015-02-06 23:11:51 +0100411 struct Scsi_Host *sh = cmd->device->host;
412 struct aha1542_hostdata *aha1542 = shost_priv(sh);
Ondrej Zarycb5b5702015-02-06 23:11:27 +0100413 u8 direction;
Ondrej Zary55b28f92015-02-06 23:11:44 +0100414 u8 target = cmd->device->id;
415 u8 lun = cmd->device->lun;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700416 unsigned long flags;
Ondrej Zary55b28f92015-02-06 23:11:44 +0100417 int bufflen = scsi_bufflen(cmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700418 int mbo;
Ondrej Zarye98878f2015-02-06 23:11:25 +0100419 struct mailbox *mb = aha1542->mb;
420 struct ccb *ccb = aha1542->ccb;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700421
Ondrej Zary55b28f92015-02-06 23:11:44 +0100422 if (*cmd->cmnd == REQUEST_SENSE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700423 /* Don't do the command - we have the sense data already */
Ondrej Zary55b28f92015-02-06 23:11:44 +0100424 cmd->result = 0;
425 done(cmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700426 return 0;
427 }
428#ifdef DEBUG
Ondrej Zary764a0c72015-02-06 23:11:54 +0100429 {
430 int i = -1;
431 if (*cmd->cmnd == READ_10 || *cmd->cmnd == WRITE_10)
432 i = xscsi2int(cmd->cmnd + 2);
433 else if (*cmd->cmnd == READ_6 || *cmd->cmnd == WRITE_6)
434 i = scsi2int(cmd->cmnd + 2);
435 shost_printk(KERN_DEBUG, sh, "aha1542_queuecommand: dev %d cmd %02x pos %d len %d",
436 target, *cmd->cmnd, i, bufflen);
437 print_hex_dump_bytes("command: ", DUMP_PREFIX_NONE, cmd->cmnd, cmd->cmd_len);
438 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700439#endif
440 /* Use the outgoing mailboxes in a round-robin fashion, because this
441 is how the host adapter will scan for them */
442
443 spin_lock_irqsave(&aha1542_lock, flags);
Ondrej Zarye98878f2015-02-06 23:11:25 +0100444 mbo = aha1542->aha1542_last_mbo_used + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700445 if (mbo >= AHA1542_MAILBOXES)
446 mbo = 0;
447
448 do {
Ondrej Zary55b28f92015-02-06 23:11:44 +0100449 if (mb[mbo].status == 0 && aha1542->int_cmds[mbo] == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700450 break;
451 mbo++;
452 if (mbo >= AHA1542_MAILBOXES)
453 mbo = 0;
Ondrej Zarye98878f2015-02-06 23:11:25 +0100454 } while (mbo != aha1542->aha1542_last_mbo_used);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700455
Ondrej Zary55b28f92015-02-06 23:11:44 +0100456 if (mb[mbo].status || aha1542->int_cmds[mbo])
Linus Torvalds1da177e2005-04-16 15:20:36 -0700457 panic("Unable to find empty mailbox for aha1542.\n");
458
Ondrej Zary55b28f92015-02-06 23:11:44 +0100459 aha1542->int_cmds[mbo] = cmd; /* This will effectively prevent someone else from
Ondrej Zarye98878f2015-02-06 23:11:25 +0100460 screwing with this cdb. */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700461
Ondrej Zarye98878f2015-02-06 23:11:25 +0100462 aha1542->aha1542_last_mbo_used = mbo;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700463 spin_unlock_irqrestore(&aha1542_lock, flags);
464
465#ifdef DEBUG
Ondrej Zary6ddc8cf2015-02-06 23:11:53 +0100466 shost_printk(KERN_DEBUG, sh, "Sending command (%d %p)...", mbo, done);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700467#endif
468
Ondrej Zary10be6252015-02-06 23:11:24 +0100469 any2scsi(mb[mbo].ccbptr, isa_virt_to_bus(&ccb[mbo])); /* This gets trashed for some reason */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700470
471 memset(&ccb[mbo], 0, sizeof(struct ccb));
472
Ondrej Zary55b28f92015-02-06 23:11:44 +0100473 ccb[mbo].cdblen = cmd->cmd_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700474
475 direction = 0;
Ondrej Zary55b28f92015-02-06 23:11:44 +0100476 if (*cmd->cmnd == READ_10 || *cmd->cmnd == READ_6)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700477 direction = 8;
Ondrej Zary55b28f92015-02-06 23:11:44 +0100478 else if (*cmd->cmnd == WRITE_10 || *cmd->cmnd == WRITE_6)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700479 direction = 16;
480
Ondrej Zary55b28f92015-02-06 23:11:44 +0100481 memcpy(ccb[mbo].cdb, cmd->cmnd, ccb[mbo].cdblen);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700482
Boaz Harroshfc3fdfc2007-09-09 21:02:45 +0300483 if (bufflen) {
Jens Axboe51cf2242007-07-16 10:00:31 +0200484 struct scatterlist *sg;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700485 struct chain *cptr;
Ondrej Zary55b28f92015-02-06 23:11:44 +0100486 int i, sg_count = scsi_sg_count(cmd);
Ondrej Zary6ddc8cf2015-02-06 23:11:53 +0100487
Linus Torvalds1da177e2005-04-16 15:20:36 -0700488 ccb[mbo].op = 2; /* SCSI Initiator Command w/scatter-gather */
Ondrej Zary55b28f92015-02-06 23:11:44 +0100489 cmd->host_scribble = kmalloc(sizeof(*cptr)*sg_count,
Boaz Harroshfc3fdfc2007-09-09 21:02:45 +0300490 GFP_KERNEL | GFP_DMA);
Ondrej Zary55b28f92015-02-06 23:11:44 +0100491 cptr = (struct chain *) cmd->host_scribble;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700492 if (cptr == NULL) {
493 /* free the claimed mailbox slot */
Ondrej Zary55b28f92015-02-06 23:11:44 +0100494 aha1542->int_cmds[mbo] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700495 return SCSI_MLQUEUE_HOST_BUSY;
496 }
Ondrej Zary55b28f92015-02-06 23:11:44 +0100497 scsi_for_each_sg(cmd, sg, sg_count, i) {
Ondrej Zary10be6252015-02-06 23:11:24 +0100498 any2scsi(cptr[i].dataptr, isa_page_to_bus(sg_page(sg))
499 + sg->offset);
Jens Axboe51cf2242007-07-16 10:00:31 +0200500 any2scsi(cptr[i].datalen, sg->length);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700501 };
Boaz Harroshfc3fdfc2007-09-09 21:02:45 +0300502 any2scsi(ccb[mbo].datalen, sg_count * sizeof(struct chain));
Ondrej Zary10be6252015-02-06 23:11:24 +0100503 any2scsi(ccb[mbo].dataptr, isa_virt_to_bus(cptr));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700504#ifdef DEBUG
Ondrej Zary6ddc8cf2015-02-06 23:11:53 +0100505 shost_printk(KERN_DEBUG, sh, "cptr %p: ", cptr);
506 print_hex_dump_bytes("cptr: ", DUMP_PREFIX_NONE, cptr, 18);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700507#endif
508 } else {
509 ccb[mbo].op = 0; /* SCSI Initiator Command */
Ondrej Zary55b28f92015-02-06 23:11:44 +0100510 cmd->host_scribble = NULL;
Boaz Harroshfc3fdfc2007-09-09 21:02:45 +0300511 any2scsi(ccb[mbo].datalen, 0);
512 any2scsi(ccb[mbo].dataptr, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700513 };
514 ccb[mbo].idlun = (target & 7) << 5 | direction | (lun & 7); /*SCSI Target Id */
515 ccb[mbo].rsalen = 16;
516 ccb[mbo].linkptr[0] = ccb[mbo].linkptr[1] = ccb[mbo].linkptr[2] = 0;
517 ccb[mbo].commlinkid = 0;
518
519#ifdef DEBUG
Ondrej Zary6ddc8cf2015-02-06 23:11:53 +0100520 print_hex_dump_bytes("sending: ", DUMP_PREFIX_NONE, &ccb[mbo], sizeof(ccb[mbo]) - 10);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700521#endif
522
523 if (done) {
Ondrej Zaryfde1fb82015-02-06 23:11:52 +0100524#ifdef DEBUG
525 printk("aha1542_queuecommand: now waiting for interrupt ");
526#endif
Ondrej Zary55b28f92015-02-06 23:11:44 +0100527 cmd->scsi_done = done;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700528 mb[mbo].status = 1;
Ondrej Zary55b28f92015-02-06 23:11:44 +0100529 aha1542_outb(cmd->device->host->io_port, CMD_START_SCSI);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700530 } else
531 printk("aha1542_queuecommand: done can't be NULL\n");
532
533 return 0;
534}
535
Jeff Garzikf2812332010-11-16 02:10:29 -0500536static DEF_SCSI_QCMD(aha1542_queuecommand)
537
Linus Torvalds1da177e2005-04-16 15:20:36 -0700538/* Initialize mailboxes */
Ondrej Zary68ea9de2015-02-06 23:11:49 +0100539static void setup_mailboxes(struct Scsi_Host *sh)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700540{
Ondrej Zaryc2532f62015-02-06 23:11:45 +0100541 struct aha1542_hostdata *aha1542 = shost_priv(sh);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700542 int i;
Ondrej Zarye98878f2015-02-06 23:11:25 +0100543 struct mailbox *mb = aha1542->mb;
544 struct ccb *ccb = aha1542->ccb;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700545
Ondrej Zarycad2fc72015-02-06 23:11:43 +0100546 u8 mb_cmd[5] = { CMD_MBINIT, AHA1542_MAILBOXES, 0, 0, 0};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700547
Linus Torvalds1da177e2005-04-16 15:20:36 -0700548 for (i = 0; i < AHA1542_MAILBOXES; i++) {
549 mb[i].status = mb[AHA1542_MAILBOXES + i].status = 0;
Ondrej Zary10be6252015-02-06 23:11:24 +0100550 any2scsi(mb[i].ccbptr, isa_virt_to_bus(&ccb[i]));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700551 };
Ondrej Zary68ea9de2015-02-06 23:11:49 +0100552 aha1542_intr_reset(sh->io_port); /* reset interrupts, so they don't block */
Ondrej Zarycad2fc72015-02-06 23:11:43 +0100553 any2scsi((mb_cmd + 2), isa_virt_to_bus(mb));
Ondrej Zary68ea9de2015-02-06 23:11:49 +0100554 if (aha1542_out(sh->io_port, mb_cmd, 5))
Ondrej Zary2906b3c2015-02-06 23:11:51 +0100555 shost_printk(KERN_ERR, sh, "failed setting up mailboxes\n");
Ondrej Zary68ea9de2015-02-06 23:11:49 +0100556 aha1542_intr_reset(sh->io_port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700557}
558
Ondrej Zary68ea9de2015-02-06 23:11:49 +0100559static int aha1542_getconfig(struct Scsi_Host *sh)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700560{
Ondrej Zarycb5b5702015-02-06 23:11:27 +0100561 u8 inquiry_result[3];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700562 int i;
Ondrej Zary68ea9de2015-02-06 23:11:49 +0100563 i = inb(STATUS(sh->io_port));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700564 if (i & DF) {
Ondrej Zary68ea9de2015-02-06 23:11:49 +0100565 i = inb(DATA(sh->io_port));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700566 };
Ondrej Zary68ea9de2015-02-06 23:11:49 +0100567 aha1542_outb(sh->io_port, CMD_RETCONF);
568 aha1542_in(sh->io_port, inquiry_result, 3, 0);
569 if (!wait_mask(INTRFLAGS(sh->io_port), INTRMASK, HACC, 0, 0))
Ondrej Zary2906b3c2015-02-06 23:11:51 +0100570 shost_printk(KERN_ERR, sh, "error querying board settings\n");
Ondrej Zary68ea9de2015-02-06 23:11:49 +0100571 aha1542_intr_reset(sh->io_port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700572 switch (inquiry_result[0]) {
573 case 0x80:
Ondrej Zary68ea9de2015-02-06 23:11:49 +0100574 sh->dma_channel = 7;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700575 break;
576 case 0x40:
Ondrej Zary68ea9de2015-02-06 23:11:49 +0100577 sh->dma_channel = 6;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700578 break;
579 case 0x20:
Ondrej Zary68ea9de2015-02-06 23:11:49 +0100580 sh->dma_channel = 5;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700581 break;
582 case 0x01:
Ondrej Zary68ea9de2015-02-06 23:11:49 +0100583 sh->dma_channel = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700584 break;
585 case 0:
586 /* This means that the adapter, although Adaptec 1542 compatible, doesn't use a DMA channel.
587 Currently only aware of the BusLogic BT-445S VL-Bus adapter which needs this. */
Ondrej Zary68ea9de2015-02-06 23:11:49 +0100588 sh->dma_channel = 0xFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700589 break;
590 default:
Ondrej Zary2906b3c2015-02-06 23:11:51 +0100591 shost_printk(KERN_ERR, sh, "Unable to determine DMA channel.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700592 return -1;
593 };
594 switch (inquiry_result[1]) {
595 case 0x40:
Ondrej Zary68ea9de2015-02-06 23:11:49 +0100596 sh->irq = 15;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700597 break;
598 case 0x20:
Ondrej Zary68ea9de2015-02-06 23:11:49 +0100599 sh->irq = 14;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700600 break;
601 case 0x8:
Ondrej Zary68ea9de2015-02-06 23:11:49 +0100602 sh->irq = 12;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700603 break;
604 case 0x4:
Ondrej Zary68ea9de2015-02-06 23:11:49 +0100605 sh->irq = 11;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700606 break;
607 case 0x2:
Ondrej Zary68ea9de2015-02-06 23:11:49 +0100608 sh->irq = 10;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700609 break;
610 case 0x1:
Ondrej Zary68ea9de2015-02-06 23:11:49 +0100611 sh->irq = 9;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700612 break;
613 default:
Ondrej Zary2906b3c2015-02-06 23:11:51 +0100614 shost_printk(KERN_ERR, sh, "Unable to determine IRQ level.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700615 return -1;
616 };
Ondrej Zary68ea9de2015-02-06 23:11:49 +0100617 sh->this_id = inquiry_result[2] & 7;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700618 return 0;
619}
620
621/* This function should only be called for 1542C boards - we can detect
622 the special firmware settings and unlock the board */
623
Ondrej Zary68ea9de2015-02-06 23:11:49 +0100624static int aha1542_mbenable(struct Scsi_Host *sh)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700625{
Ondrej Zarycb5b5702015-02-06 23:11:27 +0100626 static u8 mbenable_cmd[3];
627 static u8 mbenable_result[2];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700628 int retval;
629
630 retval = BIOS_TRANSLATION_6432;
631
Ondrej Zary68ea9de2015-02-06 23:11:49 +0100632 aha1542_outb(sh->io_port, CMD_EXTBIOS);
633 if (aha1542_in(sh->io_port, mbenable_result, 2, 100))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700634 return retval;
Ondrej Zary68ea9de2015-02-06 23:11:49 +0100635 if (!wait_mask(INTRFLAGS(sh->io_port), INTRMASK, HACC, 0, 100))
Ondrej Zary2093bfa2015-02-06 23:11:31 +0100636 goto fail;
Ondrej Zary68ea9de2015-02-06 23:11:49 +0100637 aha1542_intr_reset(sh->io_port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700638
639 if ((mbenable_result[0] & 0x08) || mbenable_result[1]) {
640 mbenable_cmd[0] = CMD_MBENABLE;
641 mbenable_cmd[1] = 0;
642 mbenable_cmd[2] = mbenable_result[1];
643
644 if ((mbenable_result[0] & 0x08) && (mbenable_result[1] & 0x03))
645 retval = BIOS_TRANSLATION_25563;
646
Ondrej Zary68ea9de2015-02-06 23:11:49 +0100647 if (aha1542_out(sh->io_port, mbenable_cmd, 3))
Ondrej Zary2093bfa2015-02-06 23:11:31 +0100648 goto fail;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700649 };
650 while (0) {
651fail:
Ondrej Zary2906b3c2015-02-06 23:11:51 +0100652 shost_printk(KERN_ERR, sh, "Mailbox init failed\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700653 }
Ondrej Zary68ea9de2015-02-06 23:11:49 +0100654 aha1542_intr_reset(sh->io_port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700655 return retval;
656}
657
658/* Query the board to find out if it is a 1542 or a 1740, or whatever. */
Ondrej Zary68ea9de2015-02-06 23:11:49 +0100659static int aha1542_query(struct Scsi_Host *sh)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700660{
Ondrej Zary68ea9de2015-02-06 23:11:49 +0100661 struct aha1542_hostdata *aha1542 = shost_priv(sh);
Ondrej Zarycb5b5702015-02-06 23:11:27 +0100662 u8 inquiry_result[4];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700663 int i;
Ondrej Zary68ea9de2015-02-06 23:11:49 +0100664 i = inb(STATUS(sh->io_port));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700665 if (i & DF) {
Ondrej Zary68ea9de2015-02-06 23:11:49 +0100666 i = inb(DATA(sh->io_port));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700667 };
Ondrej Zary68ea9de2015-02-06 23:11:49 +0100668 aha1542_outb(sh->io_port, CMD_INQUIRY);
669 aha1542_in(sh->io_port, inquiry_result, 4, 0);
670 if (!wait_mask(INTRFLAGS(sh->io_port), INTRMASK, HACC, 0, 0))
Ondrej Zary2906b3c2015-02-06 23:11:51 +0100671 shost_printk(KERN_ERR, sh, "error querying card type\n");
Ondrej Zary68ea9de2015-02-06 23:11:49 +0100672 aha1542_intr_reset(sh->io_port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700673
Ondrej Zary68ea9de2015-02-06 23:11:49 +0100674 aha1542->bios_translation = BIOS_TRANSLATION_6432; /* Default case */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700675
676 /* For an AHA1740 series board, we ignore the board since there is a
677 hardware bug which can lead to wrong blocks being returned if the board
678 is operating in the 1542 emulation mode. Since there is an extended mode
679 driver, we simply ignore the board and let the 1740 driver pick it up.
680 */
681
682 if (inquiry_result[0] == 0x43) {
Ondrej Zary2906b3c2015-02-06 23:11:51 +0100683 shost_printk(KERN_INFO, sh, "Emulation mode not supported for AHA-1740 hardware, use aha1740 driver instead.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700684 return 1;
685 };
686
687 /* Always call this - boards that do not support extended bios translation
688 will ignore the command, and we will set the proper default */
689
Ondrej Zary68ea9de2015-02-06 23:11:49 +0100690 aha1542->bios_translation = aha1542_mbenable(sh);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700691
692 return 0;
693}
694
Ondrej Zaryf71429a2015-02-06 23:11:41 +0100695static u8 dma_speed_hw(int dma_speed)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700696{
Ondrej Zaryf71429a2015-02-06 23:11:41 +0100697 switch (dma_speed) {
698 case 5:
699 return 0x00;
700 case 6:
701 return 0x04;
702 case 7:
703 return 0x01;
704 case 8:
705 return 0x02;
706 case 10:
707 return 0x03;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700708 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700709
Ondrej Zaryf71429a2015-02-06 23:11:41 +0100710 return 0xff; /* invalid */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700711}
712
Ondrej Zaryb847fd02015-02-06 23:11:38 +0100713/* Set the Bus on/off-times as not to ruin floppy performance */
Ondrej Zary37d607b2015-02-06 23:11:50 +0100714static void aha1542_set_bus_times(struct Scsi_Host *sh, int bus_on, int bus_off, int dma_speed)
Ondrej Zaryb847fd02015-02-06 23:11:38 +0100715{
Ondrej Zary37d607b2015-02-06 23:11:50 +0100716 if (bus_on > 0) {
717 u8 oncmd[] = { CMD_BUSON_TIME, clamp(bus_on, 2, 15) };
Ondrej Zaryb847fd02015-02-06 23:11:38 +0100718
Ondrej Zary37d607b2015-02-06 23:11:50 +0100719 aha1542_intr_reset(sh->io_port);
720 if (aha1542_out(sh->io_port, oncmd, 2))
Ondrej Zaryf71429a2015-02-06 23:11:41 +0100721 goto fail;
Ondrej Zaryb847fd02015-02-06 23:11:38 +0100722 }
Ondrej Zaryf71429a2015-02-06 23:11:41 +0100723
Ondrej Zary37d607b2015-02-06 23:11:50 +0100724 if (bus_off > 0) {
725 u8 offcmd[] = { CMD_BUSOFF_TIME, clamp(bus_off, 1, 64) };
Ondrej Zaryf71429a2015-02-06 23:11:41 +0100726
Ondrej Zary37d607b2015-02-06 23:11:50 +0100727 aha1542_intr_reset(sh->io_port);
728 if (aha1542_out(sh->io_port, offcmd, 2))
Ondrej Zaryf71429a2015-02-06 23:11:41 +0100729 goto fail;
730 }
731
Ondrej Zary37d607b2015-02-06 23:11:50 +0100732 if (dma_speed_hw(dma_speed) != 0xff) {
733 u8 dmacmd[] = { CMD_DMASPEED, dma_speed_hw(dma_speed) };
Ondrej Zaryf71429a2015-02-06 23:11:41 +0100734
Ondrej Zary37d607b2015-02-06 23:11:50 +0100735 aha1542_intr_reset(sh->io_port);
736 if (aha1542_out(sh->io_port, dmacmd, 2))
Ondrej Zaryb847fd02015-02-06 23:11:38 +0100737 goto fail;
738 }
Ondrej Zary37d607b2015-02-06 23:11:50 +0100739 aha1542_intr_reset(sh->io_port);
Ondrej Zaryb847fd02015-02-06 23:11:38 +0100740 return;
741fail:
Ondrej Zary2906b3c2015-02-06 23:11:51 +0100742 shost_printk(KERN_ERR, sh, "setting bus on/off-time failed\n");
Ondrej Zary37d607b2015-02-06 23:11:50 +0100743 aha1542_intr_reset(sh->io_port);
Ondrej Zaryb847fd02015-02-06 23:11:38 +0100744}
745
Linus Torvalds1da177e2005-04-16 15:20:36 -0700746/* return non-zero on detection */
Ondrej Zary643a7c42015-02-06 23:11:22 +0100747static struct Scsi_Host *aha1542_hw_init(struct scsi_host_template *tpnt, struct device *pdev, int indx)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700748{
Ondrej Zaryf71429a2015-02-06 23:11:41 +0100749 unsigned int base_io = io[indx];
Ondrej Zaryc2532f62015-02-06 23:11:45 +0100750 struct Scsi_Host *sh;
Ondrej Zarye98878f2015-02-06 23:11:25 +0100751 struct aha1542_hostdata *aha1542;
Ondrej Zary2906b3c2015-02-06 23:11:51 +0100752 char dma_info[] = "no DMA";
Linus Torvalds1da177e2005-04-16 15:20:36 -0700753
Ondrej Zary3a70c002015-02-06 23:11:40 +0100754 if (base_io == 0)
755 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700756
Ondrej Zary3a70c002015-02-06 23:11:40 +0100757 if (!request_region(base_io, AHA1542_REGION_SIZE, "aha1542"))
758 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700759
Ondrej Zaryc2532f62015-02-06 23:11:45 +0100760 sh = scsi_host_alloc(tpnt, sizeof(struct aha1542_hostdata));
761 if (!sh)
Ondrej Zary3a70c002015-02-06 23:11:40 +0100762 goto release;
Ondrej Zaryc2532f62015-02-06 23:11:45 +0100763 aha1542 = shost_priv(sh);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700764
Ondrej Zary68ea9de2015-02-06 23:11:49 +0100765 sh->unique_id = base_io;
766 sh->io_port = base_io;
767 sh->n_io_port = AHA1542_REGION_SIZE;
768 aha1542->aha1542_last_mbi_used = 2 * AHA1542_MAILBOXES - 1;
769 aha1542->aha1542_last_mbo_used = AHA1542_MAILBOXES - 1;
770
771 if (!aha1542_test_port(sh))
Ondrej Zary3a70c002015-02-06 23:11:40 +0100772 goto unregister;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700773
Ondrej Zary37d607b2015-02-06 23:11:50 +0100774 aha1542_set_bus_times(sh, bus_on[indx], bus_off[indx], dma_speed[indx]);
Ondrej Zary68ea9de2015-02-06 23:11:49 +0100775 if (aha1542_query(sh))
Ondrej Zary3a70c002015-02-06 23:11:40 +0100776 goto unregister;
Ondrej Zary68ea9de2015-02-06 23:11:49 +0100777 if (aha1542_getconfig(sh) == -1)
Ondrej Zary3a70c002015-02-06 23:11:40 +0100778 goto unregister;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700779
Ondrej Zaryc2532f62015-02-06 23:11:45 +0100780 if (sh->dma_channel != 0xFF)
Ondrej Zary2906b3c2015-02-06 23:11:51 +0100781 snprintf(dma_info, sizeof(dma_info), "DMA %d", sh->dma_channel);
782 shost_printk(KERN_INFO, sh, "Adaptec AHA-1542 (SCSI-ID %d) at IO 0x%x, IRQ %d, %s\n",
783 sh->this_id, base_io, sh->irq, dma_info);
Ondrej Zary3a70c002015-02-06 23:11:40 +0100784 if (aha1542->bios_translation == BIOS_TRANSLATION_25563)
Ondrej Zary2906b3c2015-02-06 23:11:51 +0100785 shost_printk(KERN_INFO, sh, "Using extended bios translation\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700786
Ondrej Zary68ea9de2015-02-06 23:11:49 +0100787 setup_mailboxes(sh);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700788
Ondrej Zaryc2532f62015-02-06 23:11:45 +0100789 if (request_irq(sh->irq, do_aha1542_intr_handle, 0,
790 "aha1542", sh)) {
Ondrej Zary2906b3c2015-02-06 23:11:51 +0100791 shost_printk(KERN_ERR, sh, "Unable to allocate IRQ.\n");
Ondrej Zary3a70c002015-02-06 23:11:40 +0100792 goto unregister;
793 }
Ondrej Zaryc2532f62015-02-06 23:11:45 +0100794 if (sh->dma_channel != 0xFF) {
795 if (request_dma(sh->dma_channel, "aha1542")) {
Ondrej Zary2906b3c2015-02-06 23:11:51 +0100796 shost_printk(KERN_ERR, sh, "Unable to allocate DMA channel.\n");
Ondrej Zary3a70c002015-02-06 23:11:40 +0100797 goto free_irq;
798 }
Ondrej Zaryc2532f62015-02-06 23:11:45 +0100799 if (sh->dma_channel == 0 || sh->dma_channel >= 5) {
800 set_dma_mode(sh->dma_channel, DMA_MODE_CASCADE);
801 enable_dma(sh->dma_channel);
Ondrej Zary3a70c002015-02-06 23:11:40 +0100802 }
803 }
Jeff Garzik87c4d7b2008-04-24 19:45:32 -0400804
Ondrej Zaryc2532f62015-02-06 23:11:45 +0100805 if (scsi_add_host(sh, pdev))
Ondrej Zary3a70c002015-02-06 23:11:40 +0100806 goto free_dma;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700807
Ondrej Zaryc2532f62015-02-06 23:11:45 +0100808 scsi_scan_host(sh);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700809
Ondrej Zaryc2532f62015-02-06 23:11:45 +0100810 return sh;
Ondrej Zary3a70c002015-02-06 23:11:40 +0100811free_dma:
Ondrej Zaryc2532f62015-02-06 23:11:45 +0100812 if (sh->dma_channel != 0xff)
813 free_dma(sh->dma_channel);
Ondrej Zary3a70c002015-02-06 23:11:40 +0100814free_irq:
Ondrej Zaryc2532f62015-02-06 23:11:45 +0100815 free_irq(sh->irq, sh);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700816unregister:
Ondrej Zaryc2532f62015-02-06 23:11:45 +0100817 scsi_host_put(sh);
Ondrej Zary3a70c002015-02-06 23:11:40 +0100818release:
819 release_region(base_io, AHA1542_REGION_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700820
Ondrej Zary643a7c42015-02-06 23:11:22 +0100821 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700822}
823
Ondrej Zaryc2532f62015-02-06 23:11:45 +0100824static int aha1542_release(struct Scsi_Host *sh)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700825{
Ondrej Zaryc2532f62015-02-06 23:11:45 +0100826 scsi_remove_host(sh);
827 if (sh->dma_channel != 0xff)
828 free_dma(sh->dma_channel);
829 if (sh->irq)
830 free_irq(sh->irq, sh);
831 if (sh->io_port && sh->n_io_port)
832 release_region(sh->io_port, sh->n_io_port);
833 scsi_host_put(sh);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700834 return 0;
835}
836
Linus Torvalds1da177e2005-04-16 15:20:36 -0700837
Linus Torvalds1da177e2005-04-16 15:20:36 -0700838/*
839 * This is a device reset. This is handled by sending a special command
840 * to the device.
841 */
Ondrej Zary55b28f92015-02-06 23:11:44 +0100842static int aha1542_dev_reset(struct scsi_cmnd *cmd)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700843{
Ondrej Zary55b28f92015-02-06 23:11:44 +0100844 struct aha1542_hostdata *aha1542 = shost_priv(cmd->device->host);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700845 unsigned long flags;
Ondrej Zarye98878f2015-02-06 23:11:25 +0100846 struct mailbox *mb = aha1542->mb;
Ondrej Zary55b28f92015-02-06 23:11:44 +0100847 u8 target = cmd->device->id;
848 u8 lun = cmd->device->lun;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700849 int mbo;
Ondrej Zarye98878f2015-02-06 23:11:25 +0100850 struct ccb *ccb = aha1542->ccb;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700851
Linus Torvalds1da177e2005-04-16 15:20:36 -0700852 spin_lock_irqsave(&aha1542_lock, flags);
Ondrej Zarye98878f2015-02-06 23:11:25 +0100853 mbo = aha1542->aha1542_last_mbo_used + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700854 if (mbo >= AHA1542_MAILBOXES)
855 mbo = 0;
856
857 do {
Ondrej Zary55b28f92015-02-06 23:11:44 +0100858 if (mb[mbo].status == 0 && aha1542->int_cmds[mbo] == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700859 break;
860 mbo++;
861 if (mbo >= AHA1542_MAILBOXES)
862 mbo = 0;
Ondrej Zarye98878f2015-02-06 23:11:25 +0100863 } while (mbo != aha1542->aha1542_last_mbo_used);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700864
Ondrej Zary55b28f92015-02-06 23:11:44 +0100865 if (mb[mbo].status || aha1542->int_cmds[mbo])
Linus Torvalds1da177e2005-04-16 15:20:36 -0700866 panic("Unable to find empty mailbox for aha1542.\n");
867
Ondrej Zary55b28f92015-02-06 23:11:44 +0100868 aha1542->int_cmds[mbo] = cmd; /* This will effectively
Ondrej Zarye98878f2015-02-06 23:11:25 +0100869 prevent someone else from
870 screwing with this cdb. */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700871
Ondrej Zarye98878f2015-02-06 23:11:25 +0100872 aha1542->aha1542_last_mbo_used = mbo;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700873 spin_unlock_irqrestore(&aha1542_lock, flags);
874
Ondrej Zary10be6252015-02-06 23:11:24 +0100875 any2scsi(mb[mbo].ccbptr, isa_virt_to_bus(&ccb[mbo])); /* This gets trashed for some reason */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700876
877 memset(&ccb[mbo], 0, sizeof(struct ccb));
878
879 ccb[mbo].op = 0x81; /* BUS DEVICE RESET */
880
881 ccb[mbo].idlun = (target & 7) << 5 | (lun & 7); /*SCSI Target Id */
882
883 ccb[mbo].linkptr[0] = ccb[mbo].linkptr[1] = ccb[mbo].linkptr[2] = 0;
884 ccb[mbo].commlinkid = 0;
885
886 /*
887 * Now tell the 1542 to flush all pending commands for this
888 * target
889 */
Ondrej Zary55b28f92015-02-06 23:11:44 +0100890 aha1542_outb(cmd->device->host->io_port, CMD_START_SCSI);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700891
Ondrej Zary55b28f92015-02-06 23:11:44 +0100892 scmd_printk(KERN_WARNING, cmd,
Jeff Garzik017560f2005-10-24 18:04:36 -0400893 "Trying device reset for target\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700894
895 return SUCCESS;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700896}
897
Ondrej Zary55b28f92015-02-06 23:11:44 +0100898static int aha1542_reset(struct scsi_cmnd *cmd, u8 reset_cmd)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700899{
Ondrej Zary55b28f92015-02-06 23:11:44 +0100900 struct aha1542_hostdata *aha1542 = shost_priv(cmd->device->host);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700901 int i;
902
903 /*
904 * This does a scsi reset for all devices on the bus.
905 * In principle, we could also reset the 1542 - should
906 * we do this? Try this first, and we can add that later
907 * if it turns out to be useful.
908 */
Ondrej Zary55b28f92015-02-06 23:11:44 +0100909 outb(reset_cmd, CONTROL(cmd->device->host->io_port));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700910
911 /*
912 * Wait for the thing to settle down a bit. Unfortunately
913 * this is going to basically lock up the machine while we
914 * wait for this to complete. To be 100% correct, we need to
915 * check for timeout, and if we are doing something like this
916 * we are pretty desperate anyways.
917 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700918 ssleep(4);
Ondrej Zary55b28f92015-02-06 23:11:44 +0100919 spin_lock_irq(cmd->device->host->host_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700920
Ondrej Zary55b28f92015-02-06 23:11:44 +0100921 if (!wait_mask(STATUS(cmd->device->host->io_port),
Ondrej Zarya13b3722015-02-06 23:11:34 +0100922 STATMASK, INIT | IDLE, STST | DIAGF | INVDCMD | DF | CDF, 0)) {
Ondrej Zary55b28f92015-02-06 23:11:44 +0100923 spin_unlock_irq(cmd->device->host->host_lock);
Ondrej Zarya13b3722015-02-06 23:11:34 +0100924 return FAILED;
925 }
Ondrej Zary8537cba2015-02-06 23:11:37 +0100926 /*
927 * We need to do this too before the 1542 can interact with
928 * us again after host reset.
929 */
930 if (reset_cmd & HRST)
Ondrej Zary68ea9de2015-02-06 23:11:49 +0100931 setup_mailboxes(cmd->device->host);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700932 /*
933 * Now try to pick up the pieces. For all pending commands,
934 * free any internal data structures, and basically clear things
935 * out. We do not try and restart any commands or anything -
936 * the strategy handler takes care of that crap.
937 */
Ondrej Zary2906b3c2015-02-06 23:11:51 +0100938 shost_printk(KERN_WARNING, cmd->device->host, "Sent BUS RESET to scsi host %d\n", cmd->device->host->host_no);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700939
940 for (i = 0; i < AHA1542_MAILBOXES; i++) {
Ondrej Zary55b28f92015-02-06 23:11:44 +0100941 if (aha1542->int_cmds[i] != NULL) {
942 struct scsi_cmnd *tmp_cmd;
943 tmp_cmd = aha1542->int_cmds[i];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700944
Ondrej Zary55b28f92015-02-06 23:11:44 +0100945 if (tmp_cmd->device->soft_reset) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700946 /*
947 * If this device implements the soft reset option,
948 * then it is still holding onto the command, and
949 * may yet complete it. In this case, we don't
950 * flush the data.
951 */
952 continue;
953 }
Ondrej Zary55b28f92015-02-06 23:11:44 +0100954 kfree(tmp_cmd->host_scribble);
955 tmp_cmd->host_scribble = NULL;
956 aha1542->int_cmds[i] = NULL;
Ondrej Zarye98878f2015-02-06 23:11:25 +0100957 aha1542->mb[i].status = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700958 }
959 }
960
Ondrej Zary55b28f92015-02-06 23:11:44 +0100961 spin_unlock_irq(cmd->device->host->host_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700962 return SUCCESS;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700963}
964
Ondrej Zary55b28f92015-02-06 23:11:44 +0100965static int aha1542_bus_reset(struct scsi_cmnd *cmd)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700966{
Ondrej Zary55b28f92015-02-06 23:11:44 +0100967 return aha1542_reset(cmd, SCRST);
Ondrej Zary8537cba2015-02-06 23:11:37 +0100968}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700969
Ondrej Zary55b28f92015-02-06 23:11:44 +0100970static int aha1542_host_reset(struct scsi_cmnd *cmd)
Ondrej Zary8537cba2015-02-06 23:11:37 +0100971{
Ondrej Zary55b28f92015-02-06 23:11:44 +0100972 return aha1542_reset(cmd, HRST | SCRST);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700973}
974
Linus Torvalds1da177e2005-04-16 15:20:36 -0700975static int aha1542_biosparam(struct scsi_device *sdev,
Ondrej Zary17787a02015-02-06 23:11:42 +0100976 struct block_device *bdev, sector_t capacity, int geom[])
Linus Torvalds1da177e2005-04-16 15:20:36 -0700977{
Ondrej Zarye98878f2015-02-06 23:11:25 +0100978 struct aha1542_hostdata *aha1542 = shost_priv(sdev->host);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700979
Ondrej Zary17787a02015-02-06 23:11:42 +0100980 if (capacity >= 0x200000 &&
981 aha1542->bios_translation == BIOS_TRANSLATION_25563) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700982 /* Please verify that this is the same as what DOS returns */
Ondrej Zary17787a02015-02-06 23:11:42 +0100983 geom[0] = 255; /* heads */
984 geom[1] = 63; /* sectors */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700985 } else {
Ondrej Zary17787a02015-02-06 23:11:42 +0100986 geom[0] = 64; /* heads */
987 geom[1] = 32; /* sectors */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700988 }
Ondrej Zary17787a02015-02-06 23:11:42 +0100989 geom[2] = sector_div(capacity, geom[0] * geom[1]); /* cylinders */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700990
991 return 0;
992}
993MODULE_LICENSE("GPL");
994
Christoph Hellwigd0be4a7d2005-10-31 18:31:40 +0100995static struct scsi_host_template driver_template = {
Ondrej Zary643a7c42015-02-06 23:11:22 +0100996 .module = THIS_MODULE,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700997 .proc_name = "aha1542",
998 .name = "Adaptec 1542",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700999 .queuecommand = aha1542_queuecommand,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001000 .eh_device_reset_handler= aha1542_dev_reset,
1001 .eh_bus_reset_handler = aha1542_bus_reset,
1002 .eh_host_reset_handler = aha1542_host_reset,
1003 .bios_param = aha1542_biosparam,
1004 .can_queue = AHA1542_MAILBOXES,
1005 .this_id = 7,
Ondrej Zary10be6252015-02-06 23:11:24 +01001006 .sg_tablesize = 16,
1007 .cmd_per_lun = 1,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001008 .unchecked_isa_dma = 1,
1009 .use_clustering = ENABLE_CLUSTERING,
1010};
Ondrej Zary643a7c42015-02-06 23:11:22 +01001011
1012static int aha1542_isa_match(struct device *pdev, unsigned int ndev)
1013{
1014 struct Scsi_Host *sh = aha1542_hw_init(&driver_template, pdev, ndev);
1015
1016 if (!sh)
1017 return 0;
1018
1019 dev_set_drvdata(pdev, sh);
1020 return 1;
1021}
1022
1023static int aha1542_isa_remove(struct device *pdev,
1024 unsigned int ndev)
1025{
1026 aha1542_release(dev_get_drvdata(pdev));
1027 dev_set_drvdata(pdev, NULL);
1028 return 0;
1029}
1030
1031static struct isa_driver aha1542_isa_driver = {
1032 .match = aha1542_isa_match,
1033 .remove = aha1542_isa_remove,
1034 .driver = {
1035 .name = "aha1542"
1036 },
1037};
1038static int isa_registered;
1039
1040#ifdef CONFIG_PNP
1041static struct pnp_device_id aha1542_pnp_ids[] = {
1042 { .id = "ADP1542" },
1043 { .id = "" }
1044};
1045MODULE_DEVICE_TABLE(pnp, aha1542_pnp_ids);
1046
1047static int aha1542_pnp_probe(struct pnp_dev *pdev, const struct pnp_device_id *id)
1048{
1049 int indx;
1050 struct Scsi_Host *sh;
1051
Ondrej Zaryf71429a2015-02-06 23:11:41 +01001052 for (indx = 0; indx < ARRAY_SIZE(io); indx++) {
1053 if (io[indx])
Ondrej Zary643a7c42015-02-06 23:11:22 +01001054 continue;
1055
1056 if (pnp_activate_dev(pdev) < 0)
1057 continue;
1058
Ondrej Zaryf71429a2015-02-06 23:11:41 +01001059 io[indx] = pnp_port_start(pdev, 0);
Ondrej Zary643a7c42015-02-06 23:11:22 +01001060
1061 /* The card can be queried for its DMA, we have
1062 the DMA set up that is enough */
1063
Ondrej Zary2906b3c2015-02-06 23:11:51 +01001064 dev_info(&pdev->dev, "ISAPnP found an AHA1535 at I/O 0x%03X", io[indx]);
Ondrej Zary643a7c42015-02-06 23:11:22 +01001065 }
1066
1067 sh = aha1542_hw_init(&driver_template, &pdev->dev, indx);
1068 if (!sh)
1069 return -ENODEV;
1070
1071 pnp_set_drvdata(pdev, sh);
1072 return 0;
1073}
1074
1075static void aha1542_pnp_remove(struct pnp_dev *pdev)
1076{
1077 aha1542_release(pnp_get_drvdata(pdev));
1078 pnp_set_drvdata(pdev, NULL);
1079}
1080
1081static struct pnp_driver aha1542_pnp_driver = {
1082 .name = "aha1542",
1083 .id_table = aha1542_pnp_ids,
1084 .probe = aha1542_pnp_probe,
1085 .remove = aha1542_pnp_remove,
1086};
1087static int pnp_registered;
1088#endif /* CONFIG_PNP */
1089
1090static int __init aha1542_init(void)
1091{
1092 int ret = 0;
Ondrej Zary643a7c42015-02-06 23:11:22 +01001093
1094#ifdef CONFIG_PNP
1095 if (isapnp) {
1096 ret = pnp_register_driver(&aha1542_pnp_driver);
1097 if (!ret)
1098 pnp_registered = 1;
1099 }
1100#endif
1101 ret = isa_register_driver(&aha1542_isa_driver, MAXBOARDS);
1102 if (!ret)
1103 isa_registered = 1;
1104
1105#ifdef CONFIG_PNP
1106 if (pnp_registered)
1107 ret = 0;
1108#endif
1109 if (isa_registered)
1110 ret = 0;
1111
1112 return ret;
1113}
1114
1115static void __exit aha1542_exit(void)
1116{
1117#ifdef CONFIG_PNP
1118 if (pnp_registered)
1119 pnp_unregister_driver(&aha1542_pnp_driver);
1120#endif
1121 if (isa_registered)
1122 isa_unregister_driver(&aha1542_isa_driver);
1123}
1124
1125module_init(aha1542_init);
1126module_exit(aha1542_exit);