blob: 87017fbdbc8431bca40c0b4c5758e94e883324f7 [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;
Ondrej Zaryfde1fb82015-02-06 23:11:52 +0100421#ifdef DEBUG
422 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700423
Ondrej Zaryfde1fb82015-02-06 23:11:52 +0100424 if (target > 1) {
425 cmd->result = DID_TIME_OUT << 16;
426 done(cmd);
427 return 0;
428 }
429#endif
Ondrej Zary55b28f92015-02-06 23:11:44 +0100430 if (*cmd->cmnd == REQUEST_SENSE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700431 /* Don't do the command - we have the sense data already */
Ondrej Zary55b28f92015-02-06 23:11:44 +0100432 cmd->result = 0;
433 done(cmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700434 return 0;
435 }
436#ifdef DEBUG
Ondrej Zary55b28f92015-02-06 23:11:44 +0100437 if (*cmd->cmnd == READ_10 || *cmd->cmnd == WRITE_10)
438 i = xscsi2int(cmd->cmnd + 2);
439 else if (*cmd->cmnd == READ_6 || *cmd->cmnd == WRITE_6)
440 i = scsi2int(cmd->cmnd + 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700441 else
442 i = -1;
443 if (done)
Ondrej Zary2906b3c2015-02-06 23:11:51 +0100444 shost_printk(KERN_DEBUG, sh, "aha1542_queuecommand: dev %d cmd %02x pos %d len %d ", target, *cmd->cmnd, i, bufflen);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700445 else
Ondrej Zary2906b3c2015-02-06 23:11:51 +0100446 shost_printk(KERN_DEBUG, sh, "aha1542_command: dev %d cmd %02x pos %d len %d ", target, *cmd->cmnd, i, bufflen);
Ondrej Zary6ddc8cf2015-02-06 23:11:53 +0100447 print_hex_dump_bytes("command: ", DUMP_PREFIX_NONE, cmd->cmnd, cmd->cmd_len);
Ondrej Zary55b28f92015-02-06 23:11:44 +0100448 if (*cmd->cmnd == WRITE_10 || *cmd->cmnd == WRITE_6)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700449 return 0; /* we are still testing, so *don't* write */
450#endif
451 /* Use the outgoing mailboxes in a round-robin fashion, because this
452 is how the host adapter will scan for them */
453
454 spin_lock_irqsave(&aha1542_lock, flags);
Ondrej Zarye98878f2015-02-06 23:11:25 +0100455 mbo = aha1542->aha1542_last_mbo_used + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700456 if (mbo >= AHA1542_MAILBOXES)
457 mbo = 0;
458
459 do {
Ondrej Zary55b28f92015-02-06 23:11:44 +0100460 if (mb[mbo].status == 0 && aha1542->int_cmds[mbo] == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700461 break;
462 mbo++;
463 if (mbo >= AHA1542_MAILBOXES)
464 mbo = 0;
Ondrej Zarye98878f2015-02-06 23:11:25 +0100465 } while (mbo != aha1542->aha1542_last_mbo_used);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700466
Ondrej Zary55b28f92015-02-06 23:11:44 +0100467 if (mb[mbo].status || aha1542->int_cmds[mbo])
Linus Torvalds1da177e2005-04-16 15:20:36 -0700468 panic("Unable to find empty mailbox for aha1542.\n");
469
Ondrej Zary55b28f92015-02-06 23:11:44 +0100470 aha1542->int_cmds[mbo] = cmd; /* This will effectively prevent someone else from
Ondrej Zarye98878f2015-02-06 23:11:25 +0100471 screwing with this cdb. */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700472
Ondrej Zarye98878f2015-02-06 23:11:25 +0100473 aha1542->aha1542_last_mbo_used = mbo;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700474 spin_unlock_irqrestore(&aha1542_lock, flags);
475
476#ifdef DEBUG
Ondrej Zary6ddc8cf2015-02-06 23:11:53 +0100477 shost_printk(KERN_DEBUG, sh, "Sending command (%d %p)...", mbo, done);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700478#endif
479
Ondrej Zary10be6252015-02-06 23:11:24 +0100480 any2scsi(mb[mbo].ccbptr, isa_virt_to_bus(&ccb[mbo])); /* This gets trashed for some reason */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700481
482 memset(&ccb[mbo], 0, sizeof(struct ccb));
483
Ondrej Zary55b28f92015-02-06 23:11:44 +0100484 ccb[mbo].cdblen = cmd->cmd_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700485
486 direction = 0;
Ondrej Zary55b28f92015-02-06 23:11:44 +0100487 if (*cmd->cmnd == READ_10 || *cmd->cmnd == READ_6)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700488 direction = 8;
Ondrej Zary55b28f92015-02-06 23:11:44 +0100489 else if (*cmd->cmnd == WRITE_10 || *cmd->cmnd == WRITE_6)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700490 direction = 16;
491
Ondrej Zary55b28f92015-02-06 23:11:44 +0100492 memcpy(ccb[mbo].cdb, cmd->cmnd, ccb[mbo].cdblen);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700493
Boaz Harroshfc3fdfc2007-09-09 21:02:45 +0300494 if (bufflen) {
Jens Axboe51cf2242007-07-16 10:00:31 +0200495 struct scatterlist *sg;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700496 struct chain *cptr;
Ondrej Zary55b28f92015-02-06 23:11:44 +0100497 int i, sg_count = scsi_sg_count(cmd);
Ondrej Zary6ddc8cf2015-02-06 23:11:53 +0100498
Linus Torvalds1da177e2005-04-16 15:20:36 -0700499 ccb[mbo].op = 2; /* SCSI Initiator Command w/scatter-gather */
Ondrej Zary55b28f92015-02-06 23:11:44 +0100500 cmd->host_scribble = kmalloc(sizeof(*cptr)*sg_count,
Boaz Harroshfc3fdfc2007-09-09 21:02:45 +0300501 GFP_KERNEL | GFP_DMA);
Ondrej Zary55b28f92015-02-06 23:11:44 +0100502 cptr = (struct chain *) cmd->host_scribble;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700503 if (cptr == NULL) {
504 /* free the claimed mailbox slot */
Ondrej Zary55b28f92015-02-06 23:11:44 +0100505 aha1542->int_cmds[mbo] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700506 return SCSI_MLQUEUE_HOST_BUSY;
507 }
Ondrej Zary55b28f92015-02-06 23:11:44 +0100508 scsi_for_each_sg(cmd, sg, sg_count, i) {
Ondrej Zary10be6252015-02-06 23:11:24 +0100509 any2scsi(cptr[i].dataptr, isa_page_to_bus(sg_page(sg))
510 + sg->offset);
Jens Axboe51cf2242007-07-16 10:00:31 +0200511 any2scsi(cptr[i].datalen, sg->length);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700512 };
Boaz Harroshfc3fdfc2007-09-09 21:02:45 +0300513 any2scsi(ccb[mbo].datalen, sg_count * sizeof(struct chain));
Ondrej Zary10be6252015-02-06 23:11:24 +0100514 any2scsi(ccb[mbo].dataptr, isa_virt_to_bus(cptr));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700515#ifdef DEBUG
Ondrej Zary6ddc8cf2015-02-06 23:11:53 +0100516 shost_printk(KERN_DEBUG, sh, "cptr %p: ", cptr);
517 print_hex_dump_bytes("cptr: ", DUMP_PREFIX_NONE, cptr, 18);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700518#endif
519 } else {
520 ccb[mbo].op = 0; /* SCSI Initiator Command */
Ondrej Zary55b28f92015-02-06 23:11:44 +0100521 cmd->host_scribble = NULL;
Boaz Harroshfc3fdfc2007-09-09 21:02:45 +0300522 any2scsi(ccb[mbo].datalen, 0);
523 any2scsi(ccb[mbo].dataptr, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700524 };
525 ccb[mbo].idlun = (target & 7) << 5 | direction | (lun & 7); /*SCSI Target Id */
526 ccb[mbo].rsalen = 16;
527 ccb[mbo].linkptr[0] = ccb[mbo].linkptr[1] = ccb[mbo].linkptr[2] = 0;
528 ccb[mbo].commlinkid = 0;
529
530#ifdef DEBUG
Ondrej Zary6ddc8cf2015-02-06 23:11:53 +0100531 print_hex_dump_bytes("sending: ", DUMP_PREFIX_NONE, &ccb[mbo], sizeof(ccb[mbo]) - 10);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700532#endif
533
534 if (done) {
Ondrej Zaryfde1fb82015-02-06 23:11:52 +0100535#ifdef DEBUG
536 printk("aha1542_queuecommand: now waiting for interrupt ");
537#endif
Ondrej Zary55b28f92015-02-06 23:11:44 +0100538 cmd->scsi_done = done;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700539 mb[mbo].status = 1;
Ondrej Zary55b28f92015-02-06 23:11:44 +0100540 aha1542_outb(cmd->device->host->io_port, CMD_START_SCSI);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700541 } else
542 printk("aha1542_queuecommand: done can't be NULL\n");
543
544 return 0;
545}
546
Jeff Garzikf2812332010-11-16 02:10:29 -0500547static DEF_SCSI_QCMD(aha1542_queuecommand)
548
Linus Torvalds1da177e2005-04-16 15:20:36 -0700549/* Initialize mailboxes */
Ondrej Zary68ea9de2015-02-06 23:11:49 +0100550static void setup_mailboxes(struct Scsi_Host *sh)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700551{
Ondrej Zaryc2532f62015-02-06 23:11:45 +0100552 struct aha1542_hostdata *aha1542 = shost_priv(sh);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700553 int i;
Ondrej Zarye98878f2015-02-06 23:11:25 +0100554 struct mailbox *mb = aha1542->mb;
555 struct ccb *ccb = aha1542->ccb;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700556
Ondrej Zarycad2fc72015-02-06 23:11:43 +0100557 u8 mb_cmd[5] = { CMD_MBINIT, AHA1542_MAILBOXES, 0, 0, 0};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700558
Linus Torvalds1da177e2005-04-16 15:20:36 -0700559 for (i = 0; i < AHA1542_MAILBOXES; i++) {
560 mb[i].status = mb[AHA1542_MAILBOXES + i].status = 0;
Ondrej Zary10be6252015-02-06 23:11:24 +0100561 any2scsi(mb[i].ccbptr, isa_virt_to_bus(&ccb[i]));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700562 };
Ondrej Zary68ea9de2015-02-06 23:11:49 +0100563 aha1542_intr_reset(sh->io_port); /* reset interrupts, so they don't block */
Ondrej Zarycad2fc72015-02-06 23:11:43 +0100564 any2scsi((mb_cmd + 2), isa_virt_to_bus(mb));
Ondrej Zary68ea9de2015-02-06 23:11:49 +0100565 if (aha1542_out(sh->io_port, mb_cmd, 5))
Ondrej Zary2906b3c2015-02-06 23:11:51 +0100566 shost_printk(KERN_ERR, sh, "failed setting up mailboxes\n");
Ondrej Zary68ea9de2015-02-06 23:11:49 +0100567 aha1542_intr_reset(sh->io_port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700568}
569
Ondrej Zary68ea9de2015-02-06 23:11:49 +0100570static int aha1542_getconfig(struct Scsi_Host *sh)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700571{
Ondrej Zarycb5b5702015-02-06 23:11:27 +0100572 u8 inquiry_result[3];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700573 int i;
Ondrej Zary68ea9de2015-02-06 23:11:49 +0100574 i = inb(STATUS(sh->io_port));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700575 if (i & DF) {
Ondrej Zary68ea9de2015-02-06 23:11:49 +0100576 i = inb(DATA(sh->io_port));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700577 };
Ondrej Zary68ea9de2015-02-06 23:11:49 +0100578 aha1542_outb(sh->io_port, CMD_RETCONF);
579 aha1542_in(sh->io_port, inquiry_result, 3, 0);
580 if (!wait_mask(INTRFLAGS(sh->io_port), INTRMASK, HACC, 0, 0))
Ondrej Zary2906b3c2015-02-06 23:11:51 +0100581 shost_printk(KERN_ERR, sh, "error querying board settings\n");
Ondrej Zary68ea9de2015-02-06 23:11:49 +0100582 aha1542_intr_reset(sh->io_port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700583 switch (inquiry_result[0]) {
584 case 0x80:
Ondrej Zary68ea9de2015-02-06 23:11:49 +0100585 sh->dma_channel = 7;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700586 break;
587 case 0x40:
Ondrej Zary68ea9de2015-02-06 23:11:49 +0100588 sh->dma_channel = 6;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700589 break;
590 case 0x20:
Ondrej Zary68ea9de2015-02-06 23:11:49 +0100591 sh->dma_channel = 5;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700592 break;
593 case 0x01:
Ondrej Zary68ea9de2015-02-06 23:11:49 +0100594 sh->dma_channel = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700595 break;
596 case 0:
597 /* This means that the adapter, although Adaptec 1542 compatible, doesn't use a DMA channel.
598 Currently only aware of the BusLogic BT-445S VL-Bus adapter which needs this. */
Ondrej Zary68ea9de2015-02-06 23:11:49 +0100599 sh->dma_channel = 0xFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700600 break;
601 default:
Ondrej Zary2906b3c2015-02-06 23:11:51 +0100602 shost_printk(KERN_ERR, sh, "Unable to determine DMA channel.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700603 return -1;
604 };
605 switch (inquiry_result[1]) {
606 case 0x40:
Ondrej Zary68ea9de2015-02-06 23:11:49 +0100607 sh->irq = 15;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700608 break;
609 case 0x20:
Ondrej Zary68ea9de2015-02-06 23:11:49 +0100610 sh->irq = 14;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700611 break;
612 case 0x8:
Ondrej Zary68ea9de2015-02-06 23:11:49 +0100613 sh->irq = 12;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700614 break;
615 case 0x4:
Ondrej Zary68ea9de2015-02-06 23:11:49 +0100616 sh->irq = 11;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700617 break;
618 case 0x2:
Ondrej Zary68ea9de2015-02-06 23:11:49 +0100619 sh->irq = 10;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700620 break;
621 case 0x1:
Ondrej Zary68ea9de2015-02-06 23:11:49 +0100622 sh->irq = 9;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700623 break;
624 default:
Ondrej Zary2906b3c2015-02-06 23:11:51 +0100625 shost_printk(KERN_ERR, sh, "Unable to determine IRQ level.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700626 return -1;
627 };
Ondrej Zary68ea9de2015-02-06 23:11:49 +0100628 sh->this_id = inquiry_result[2] & 7;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700629 return 0;
630}
631
632/* This function should only be called for 1542C boards - we can detect
633 the special firmware settings and unlock the board */
634
Ondrej Zary68ea9de2015-02-06 23:11:49 +0100635static int aha1542_mbenable(struct Scsi_Host *sh)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700636{
Ondrej Zarycb5b5702015-02-06 23:11:27 +0100637 static u8 mbenable_cmd[3];
638 static u8 mbenable_result[2];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700639 int retval;
640
641 retval = BIOS_TRANSLATION_6432;
642
Ondrej Zary68ea9de2015-02-06 23:11:49 +0100643 aha1542_outb(sh->io_port, CMD_EXTBIOS);
644 if (aha1542_in(sh->io_port, mbenable_result, 2, 100))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700645 return retval;
Ondrej Zary68ea9de2015-02-06 23:11:49 +0100646 if (!wait_mask(INTRFLAGS(sh->io_port), INTRMASK, HACC, 0, 100))
Ondrej Zary2093bfa2015-02-06 23:11:31 +0100647 goto fail;
Ondrej Zary68ea9de2015-02-06 23:11:49 +0100648 aha1542_intr_reset(sh->io_port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700649
650 if ((mbenable_result[0] & 0x08) || mbenable_result[1]) {
651 mbenable_cmd[0] = CMD_MBENABLE;
652 mbenable_cmd[1] = 0;
653 mbenable_cmd[2] = mbenable_result[1];
654
655 if ((mbenable_result[0] & 0x08) && (mbenable_result[1] & 0x03))
656 retval = BIOS_TRANSLATION_25563;
657
Ondrej Zary68ea9de2015-02-06 23:11:49 +0100658 if (aha1542_out(sh->io_port, mbenable_cmd, 3))
Ondrej Zary2093bfa2015-02-06 23:11:31 +0100659 goto fail;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700660 };
661 while (0) {
662fail:
Ondrej Zary2906b3c2015-02-06 23:11:51 +0100663 shost_printk(KERN_ERR, sh, "Mailbox init failed\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700664 }
Ondrej Zary68ea9de2015-02-06 23:11:49 +0100665 aha1542_intr_reset(sh->io_port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700666 return retval;
667}
668
669/* Query the board to find out if it is a 1542 or a 1740, or whatever. */
Ondrej Zary68ea9de2015-02-06 23:11:49 +0100670static int aha1542_query(struct Scsi_Host *sh)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700671{
Ondrej Zary68ea9de2015-02-06 23:11:49 +0100672 struct aha1542_hostdata *aha1542 = shost_priv(sh);
Ondrej Zarycb5b5702015-02-06 23:11:27 +0100673 u8 inquiry_result[4];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700674 int i;
Ondrej Zary68ea9de2015-02-06 23:11:49 +0100675 i = inb(STATUS(sh->io_port));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700676 if (i & DF) {
Ondrej Zary68ea9de2015-02-06 23:11:49 +0100677 i = inb(DATA(sh->io_port));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700678 };
Ondrej Zary68ea9de2015-02-06 23:11:49 +0100679 aha1542_outb(sh->io_port, CMD_INQUIRY);
680 aha1542_in(sh->io_port, inquiry_result, 4, 0);
681 if (!wait_mask(INTRFLAGS(sh->io_port), INTRMASK, HACC, 0, 0))
Ondrej Zary2906b3c2015-02-06 23:11:51 +0100682 shost_printk(KERN_ERR, sh, "error querying card type\n");
Ondrej Zary68ea9de2015-02-06 23:11:49 +0100683 aha1542_intr_reset(sh->io_port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700684
Ondrej Zary68ea9de2015-02-06 23:11:49 +0100685 aha1542->bios_translation = BIOS_TRANSLATION_6432; /* Default case */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700686
687 /* For an AHA1740 series board, we ignore the board since there is a
688 hardware bug which can lead to wrong blocks being returned if the board
689 is operating in the 1542 emulation mode. Since there is an extended mode
690 driver, we simply ignore the board and let the 1740 driver pick it up.
691 */
692
693 if (inquiry_result[0] == 0x43) {
Ondrej Zary2906b3c2015-02-06 23:11:51 +0100694 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 -0700695 return 1;
696 };
697
698 /* Always call this - boards that do not support extended bios translation
699 will ignore the command, and we will set the proper default */
700
Ondrej Zary68ea9de2015-02-06 23:11:49 +0100701 aha1542->bios_translation = aha1542_mbenable(sh);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700702
703 return 0;
704}
705
Ondrej Zaryf71429a2015-02-06 23:11:41 +0100706static u8 dma_speed_hw(int dma_speed)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700707{
Ondrej Zaryf71429a2015-02-06 23:11:41 +0100708 switch (dma_speed) {
709 case 5:
710 return 0x00;
711 case 6:
712 return 0x04;
713 case 7:
714 return 0x01;
715 case 8:
716 return 0x02;
717 case 10:
718 return 0x03;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700719 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700720
Ondrej Zaryf71429a2015-02-06 23:11:41 +0100721 return 0xff; /* invalid */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700722}
723
Ondrej Zaryb847fd02015-02-06 23:11:38 +0100724/* Set the Bus on/off-times as not to ruin floppy performance */
Ondrej Zary37d607b2015-02-06 23:11:50 +0100725static 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 +0100726{
Ondrej Zary37d607b2015-02-06 23:11:50 +0100727 if (bus_on > 0) {
728 u8 oncmd[] = { CMD_BUSON_TIME, clamp(bus_on, 2, 15) };
Ondrej Zaryb847fd02015-02-06 23:11:38 +0100729
Ondrej Zary37d607b2015-02-06 23:11:50 +0100730 aha1542_intr_reset(sh->io_port);
731 if (aha1542_out(sh->io_port, oncmd, 2))
Ondrej Zaryf71429a2015-02-06 23:11:41 +0100732 goto fail;
Ondrej Zaryb847fd02015-02-06 23:11:38 +0100733 }
Ondrej Zaryf71429a2015-02-06 23:11:41 +0100734
Ondrej Zary37d607b2015-02-06 23:11:50 +0100735 if (bus_off > 0) {
736 u8 offcmd[] = { CMD_BUSOFF_TIME, clamp(bus_off, 1, 64) };
Ondrej Zaryf71429a2015-02-06 23:11:41 +0100737
Ondrej Zary37d607b2015-02-06 23:11:50 +0100738 aha1542_intr_reset(sh->io_port);
739 if (aha1542_out(sh->io_port, offcmd, 2))
Ondrej Zaryf71429a2015-02-06 23:11:41 +0100740 goto fail;
741 }
742
Ondrej Zary37d607b2015-02-06 23:11:50 +0100743 if (dma_speed_hw(dma_speed) != 0xff) {
744 u8 dmacmd[] = { CMD_DMASPEED, dma_speed_hw(dma_speed) };
Ondrej Zaryf71429a2015-02-06 23:11:41 +0100745
Ondrej Zary37d607b2015-02-06 23:11:50 +0100746 aha1542_intr_reset(sh->io_port);
747 if (aha1542_out(sh->io_port, dmacmd, 2))
Ondrej Zaryb847fd02015-02-06 23:11:38 +0100748 goto fail;
749 }
Ondrej Zary37d607b2015-02-06 23:11:50 +0100750 aha1542_intr_reset(sh->io_port);
Ondrej Zaryb847fd02015-02-06 23:11:38 +0100751 return;
752fail:
Ondrej Zary2906b3c2015-02-06 23:11:51 +0100753 shost_printk(KERN_ERR, sh, "setting bus on/off-time failed\n");
Ondrej Zary37d607b2015-02-06 23:11:50 +0100754 aha1542_intr_reset(sh->io_port);
Ondrej Zaryb847fd02015-02-06 23:11:38 +0100755}
756
Linus Torvalds1da177e2005-04-16 15:20:36 -0700757/* return non-zero on detection */
Ondrej Zary643a7c42015-02-06 23:11:22 +0100758static struct Scsi_Host *aha1542_hw_init(struct scsi_host_template *tpnt, struct device *pdev, int indx)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700759{
Ondrej Zaryf71429a2015-02-06 23:11:41 +0100760 unsigned int base_io = io[indx];
Ondrej Zaryc2532f62015-02-06 23:11:45 +0100761 struct Scsi_Host *sh;
Ondrej Zarye98878f2015-02-06 23:11:25 +0100762 struct aha1542_hostdata *aha1542;
Ondrej Zary2906b3c2015-02-06 23:11:51 +0100763 char dma_info[] = "no DMA";
Linus Torvalds1da177e2005-04-16 15:20:36 -0700764
Ondrej Zary3a70c002015-02-06 23:11:40 +0100765 if (base_io == 0)
766 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700767
Ondrej Zary3a70c002015-02-06 23:11:40 +0100768 if (!request_region(base_io, AHA1542_REGION_SIZE, "aha1542"))
769 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700770
Ondrej Zaryc2532f62015-02-06 23:11:45 +0100771 sh = scsi_host_alloc(tpnt, sizeof(struct aha1542_hostdata));
772 if (!sh)
Ondrej Zary3a70c002015-02-06 23:11:40 +0100773 goto release;
Ondrej Zaryc2532f62015-02-06 23:11:45 +0100774 aha1542 = shost_priv(sh);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700775
Ondrej Zary68ea9de2015-02-06 23:11:49 +0100776 sh->unique_id = base_io;
777 sh->io_port = base_io;
778 sh->n_io_port = AHA1542_REGION_SIZE;
779 aha1542->aha1542_last_mbi_used = 2 * AHA1542_MAILBOXES - 1;
780 aha1542->aha1542_last_mbo_used = AHA1542_MAILBOXES - 1;
781
782 if (!aha1542_test_port(sh))
Ondrej Zary3a70c002015-02-06 23:11:40 +0100783 goto unregister;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700784
Ondrej Zary37d607b2015-02-06 23:11:50 +0100785 aha1542_set_bus_times(sh, bus_on[indx], bus_off[indx], dma_speed[indx]);
Ondrej Zary68ea9de2015-02-06 23:11:49 +0100786 if (aha1542_query(sh))
Ondrej Zary3a70c002015-02-06 23:11:40 +0100787 goto unregister;
Ondrej Zary68ea9de2015-02-06 23:11:49 +0100788 if (aha1542_getconfig(sh) == -1)
Ondrej Zary3a70c002015-02-06 23:11:40 +0100789 goto unregister;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700790
Ondrej Zaryc2532f62015-02-06 23:11:45 +0100791 if (sh->dma_channel != 0xFF)
Ondrej Zary2906b3c2015-02-06 23:11:51 +0100792 snprintf(dma_info, sizeof(dma_info), "DMA %d", sh->dma_channel);
793 shost_printk(KERN_INFO, sh, "Adaptec AHA-1542 (SCSI-ID %d) at IO 0x%x, IRQ %d, %s\n",
794 sh->this_id, base_io, sh->irq, dma_info);
Ondrej Zary3a70c002015-02-06 23:11:40 +0100795 if (aha1542->bios_translation == BIOS_TRANSLATION_25563)
Ondrej Zary2906b3c2015-02-06 23:11:51 +0100796 shost_printk(KERN_INFO, sh, "Using extended bios translation\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700797
Ondrej Zary68ea9de2015-02-06 23:11:49 +0100798 setup_mailboxes(sh);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700799
Ondrej Zaryc2532f62015-02-06 23:11:45 +0100800 if (request_irq(sh->irq, do_aha1542_intr_handle, 0,
801 "aha1542", sh)) {
Ondrej Zary2906b3c2015-02-06 23:11:51 +0100802 shost_printk(KERN_ERR, sh, "Unable to allocate IRQ.\n");
Ondrej Zary3a70c002015-02-06 23:11:40 +0100803 goto unregister;
804 }
Ondrej Zaryc2532f62015-02-06 23:11:45 +0100805 if (sh->dma_channel != 0xFF) {
806 if (request_dma(sh->dma_channel, "aha1542")) {
Ondrej Zary2906b3c2015-02-06 23:11:51 +0100807 shost_printk(KERN_ERR, sh, "Unable to allocate DMA channel.\n");
Ondrej Zary3a70c002015-02-06 23:11:40 +0100808 goto free_irq;
809 }
Ondrej Zaryc2532f62015-02-06 23:11:45 +0100810 if (sh->dma_channel == 0 || sh->dma_channel >= 5) {
811 set_dma_mode(sh->dma_channel, DMA_MODE_CASCADE);
812 enable_dma(sh->dma_channel);
Ondrej Zary3a70c002015-02-06 23:11:40 +0100813 }
814 }
Jeff Garzik87c4d7b2008-04-24 19:45:32 -0400815
Ondrej Zaryc2532f62015-02-06 23:11:45 +0100816 if (scsi_add_host(sh, pdev))
Ondrej Zary3a70c002015-02-06 23:11:40 +0100817 goto free_dma;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700818
Ondrej Zaryc2532f62015-02-06 23:11:45 +0100819 scsi_scan_host(sh);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700820
Ondrej Zaryc2532f62015-02-06 23:11:45 +0100821 return sh;
Ondrej Zary3a70c002015-02-06 23:11:40 +0100822free_dma:
Ondrej Zaryc2532f62015-02-06 23:11:45 +0100823 if (sh->dma_channel != 0xff)
824 free_dma(sh->dma_channel);
Ondrej Zary3a70c002015-02-06 23:11:40 +0100825free_irq:
Ondrej Zaryc2532f62015-02-06 23:11:45 +0100826 free_irq(sh->irq, sh);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700827unregister:
Ondrej Zaryc2532f62015-02-06 23:11:45 +0100828 scsi_host_put(sh);
Ondrej Zary3a70c002015-02-06 23:11:40 +0100829release:
830 release_region(base_io, AHA1542_REGION_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700831
Ondrej Zary643a7c42015-02-06 23:11:22 +0100832 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700833}
834
Ondrej Zaryc2532f62015-02-06 23:11:45 +0100835static int aha1542_release(struct Scsi_Host *sh)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700836{
Ondrej Zaryc2532f62015-02-06 23:11:45 +0100837 scsi_remove_host(sh);
838 if (sh->dma_channel != 0xff)
839 free_dma(sh->dma_channel);
840 if (sh->irq)
841 free_irq(sh->irq, sh);
842 if (sh->io_port && sh->n_io_port)
843 release_region(sh->io_port, sh->n_io_port);
844 scsi_host_put(sh);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700845 return 0;
846}
847
Linus Torvalds1da177e2005-04-16 15:20:36 -0700848
Linus Torvalds1da177e2005-04-16 15:20:36 -0700849/*
850 * This is a device reset. This is handled by sending a special command
851 * to the device.
852 */
Ondrej Zary55b28f92015-02-06 23:11:44 +0100853static int aha1542_dev_reset(struct scsi_cmnd *cmd)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700854{
Ondrej Zary55b28f92015-02-06 23:11:44 +0100855 struct aha1542_hostdata *aha1542 = shost_priv(cmd->device->host);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700856 unsigned long flags;
Ondrej Zarye98878f2015-02-06 23:11:25 +0100857 struct mailbox *mb = aha1542->mb;
Ondrej Zary55b28f92015-02-06 23:11:44 +0100858 u8 target = cmd->device->id;
859 u8 lun = cmd->device->lun;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700860 int mbo;
Ondrej Zarye98878f2015-02-06 23:11:25 +0100861 struct ccb *ccb = aha1542->ccb;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700862
Linus Torvalds1da177e2005-04-16 15:20:36 -0700863 spin_lock_irqsave(&aha1542_lock, flags);
Ondrej Zarye98878f2015-02-06 23:11:25 +0100864 mbo = aha1542->aha1542_last_mbo_used + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700865 if (mbo >= AHA1542_MAILBOXES)
866 mbo = 0;
867
868 do {
Ondrej Zary55b28f92015-02-06 23:11:44 +0100869 if (mb[mbo].status == 0 && aha1542->int_cmds[mbo] == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700870 break;
871 mbo++;
872 if (mbo >= AHA1542_MAILBOXES)
873 mbo = 0;
Ondrej Zarye98878f2015-02-06 23:11:25 +0100874 } while (mbo != aha1542->aha1542_last_mbo_used);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700875
Ondrej Zary55b28f92015-02-06 23:11:44 +0100876 if (mb[mbo].status || aha1542->int_cmds[mbo])
Linus Torvalds1da177e2005-04-16 15:20:36 -0700877 panic("Unable to find empty mailbox for aha1542.\n");
878
Ondrej Zary55b28f92015-02-06 23:11:44 +0100879 aha1542->int_cmds[mbo] = cmd; /* This will effectively
Ondrej Zarye98878f2015-02-06 23:11:25 +0100880 prevent someone else from
881 screwing with this cdb. */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700882
Ondrej Zarye98878f2015-02-06 23:11:25 +0100883 aha1542->aha1542_last_mbo_used = mbo;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700884 spin_unlock_irqrestore(&aha1542_lock, flags);
885
Ondrej Zary10be6252015-02-06 23:11:24 +0100886 any2scsi(mb[mbo].ccbptr, isa_virt_to_bus(&ccb[mbo])); /* This gets trashed for some reason */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700887
888 memset(&ccb[mbo], 0, sizeof(struct ccb));
889
890 ccb[mbo].op = 0x81; /* BUS DEVICE RESET */
891
892 ccb[mbo].idlun = (target & 7) << 5 | (lun & 7); /*SCSI Target Id */
893
894 ccb[mbo].linkptr[0] = ccb[mbo].linkptr[1] = ccb[mbo].linkptr[2] = 0;
895 ccb[mbo].commlinkid = 0;
896
897 /*
898 * Now tell the 1542 to flush all pending commands for this
899 * target
900 */
Ondrej Zary55b28f92015-02-06 23:11:44 +0100901 aha1542_outb(cmd->device->host->io_port, CMD_START_SCSI);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700902
Ondrej Zary55b28f92015-02-06 23:11:44 +0100903 scmd_printk(KERN_WARNING, cmd,
Jeff Garzik017560f2005-10-24 18:04:36 -0400904 "Trying device reset for target\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700905
906 return SUCCESS;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700907}
908
Ondrej Zary55b28f92015-02-06 23:11:44 +0100909static int aha1542_reset(struct scsi_cmnd *cmd, u8 reset_cmd)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700910{
Ondrej Zary55b28f92015-02-06 23:11:44 +0100911 struct aha1542_hostdata *aha1542 = shost_priv(cmd->device->host);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700912 int i;
913
914 /*
915 * This does a scsi reset for all devices on the bus.
916 * In principle, we could also reset the 1542 - should
917 * we do this? Try this first, and we can add that later
918 * if it turns out to be useful.
919 */
Ondrej Zary55b28f92015-02-06 23:11:44 +0100920 outb(reset_cmd, CONTROL(cmd->device->host->io_port));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700921
922 /*
923 * Wait for the thing to settle down a bit. Unfortunately
924 * this is going to basically lock up the machine while we
925 * wait for this to complete. To be 100% correct, we need to
926 * check for timeout, and if we are doing something like this
927 * we are pretty desperate anyways.
928 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700929 ssleep(4);
Ondrej Zary55b28f92015-02-06 23:11:44 +0100930 spin_lock_irq(cmd->device->host->host_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700931
Ondrej Zary55b28f92015-02-06 23:11:44 +0100932 if (!wait_mask(STATUS(cmd->device->host->io_port),
Ondrej Zarya13b3722015-02-06 23:11:34 +0100933 STATMASK, INIT | IDLE, STST | DIAGF | INVDCMD | DF | CDF, 0)) {
Ondrej Zary55b28f92015-02-06 23:11:44 +0100934 spin_unlock_irq(cmd->device->host->host_lock);
Ondrej Zarya13b3722015-02-06 23:11:34 +0100935 return FAILED;
936 }
Ondrej Zary8537cba2015-02-06 23:11:37 +0100937 /*
938 * We need to do this too before the 1542 can interact with
939 * us again after host reset.
940 */
941 if (reset_cmd & HRST)
Ondrej Zary68ea9de2015-02-06 23:11:49 +0100942 setup_mailboxes(cmd->device->host);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700943 /*
944 * Now try to pick up the pieces. For all pending commands,
945 * free any internal data structures, and basically clear things
946 * out. We do not try and restart any commands or anything -
947 * the strategy handler takes care of that crap.
948 */
Ondrej Zary2906b3c2015-02-06 23:11:51 +0100949 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 -0700950
951 for (i = 0; i < AHA1542_MAILBOXES; i++) {
Ondrej Zary55b28f92015-02-06 23:11:44 +0100952 if (aha1542->int_cmds[i] != NULL) {
953 struct scsi_cmnd *tmp_cmd;
954 tmp_cmd = aha1542->int_cmds[i];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700955
Ondrej Zary55b28f92015-02-06 23:11:44 +0100956 if (tmp_cmd->device->soft_reset) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700957 /*
958 * If this device implements the soft reset option,
959 * then it is still holding onto the command, and
960 * may yet complete it. In this case, we don't
961 * flush the data.
962 */
963 continue;
964 }
Ondrej Zary55b28f92015-02-06 23:11:44 +0100965 kfree(tmp_cmd->host_scribble);
966 tmp_cmd->host_scribble = NULL;
967 aha1542->int_cmds[i] = NULL;
Ondrej Zarye98878f2015-02-06 23:11:25 +0100968 aha1542->mb[i].status = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700969 }
970 }
971
Ondrej Zary55b28f92015-02-06 23:11:44 +0100972 spin_unlock_irq(cmd->device->host->host_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700973 return SUCCESS;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700974}
975
Ondrej Zary55b28f92015-02-06 23:11:44 +0100976static int aha1542_bus_reset(struct scsi_cmnd *cmd)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700977{
Ondrej Zary55b28f92015-02-06 23:11:44 +0100978 return aha1542_reset(cmd, SCRST);
Ondrej Zary8537cba2015-02-06 23:11:37 +0100979}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700980
Ondrej Zary55b28f92015-02-06 23:11:44 +0100981static int aha1542_host_reset(struct scsi_cmnd *cmd)
Ondrej Zary8537cba2015-02-06 23:11:37 +0100982{
Ondrej Zary55b28f92015-02-06 23:11:44 +0100983 return aha1542_reset(cmd, HRST | SCRST);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700984}
985
Linus Torvalds1da177e2005-04-16 15:20:36 -0700986static int aha1542_biosparam(struct scsi_device *sdev,
Ondrej Zary17787a02015-02-06 23:11:42 +0100987 struct block_device *bdev, sector_t capacity, int geom[])
Linus Torvalds1da177e2005-04-16 15:20:36 -0700988{
Ondrej Zarye98878f2015-02-06 23:11:25 +0100989 struct aha1542_hostdata *aha1542 = shost_priv(sdev->host);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700990
Ondrej Zary17787a02015-02-06 23:11:42 +0100991 if (capacity >= 0x200000 &&
992 aha1542->bios_translation == BIOS_TRANSLATION_25563) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700993 /* Please verify that this is the same as what DOS returns */
Ondrej Zary17787a02015-02-06 23:11:42 +0100994 geom[0] = 255; /* heads */
995 geom[1] = 63; /* sectors */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700996 } else {
Ondrej Zary17787a02015-02-06 23:11:42 +0100997 geom[0] = 64; /* heads */
998 geom[1] = 32; /* sectors */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700999 }
Ondrej Zary17787a02015-02-06 23:11:42 +01001000 geom[2] = sector_div(capacity, geom[0] * geom[1]); /* cylinders */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001001
1002 return 0;
1003}
1004MODULE_LICENSE("GPL");
1005
Christoph Hellwigd0be4a7d2005-10-31 18:31:40 +01001006static struct scsi_host_template driver_template = {
Ondrej Zary643a7c42015-02-06 23:11:22 +01001007 .module = THIS_MODULE,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001008 .proc_name = "aha1542",
1009 .name = "Adaptec 1542",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001010 .queuecommand = aha1542_queuecommand,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001011 .eh_device_reset_handler= aha1542_dev_reset,
1012 .eh_bus_reset_handler = aha1542_bus_reset,
1013 .eh_host_reset_handler = aha1542_host_reset,
1014 .bios_param = aha1542_biosparam,
1015 .can_queue = AHA1542_MAILBOXES,
1016 .this_id = 7,
Ondrej Zary10be6252015-02-06 23:11:24 +01001017 .sg_tablesize = 16,
1018 .cmd_per_lun = 1,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001019 .unchecked_isa_dma = 1,
1020 .use_clustering = ENABLE_CLUSTERING,
1021};
Ondrej Zary643a7c42015-02-06 23:11:22 +01001022
1023static int aha1542_isa_match(struct device *pdev, unsigned int ndev)
1024{
1025 struct Scsi_Host *sh = aha1542_hw_init(&driver_template, pdev, ndev);
1026
1027 if (!sh)
1028 return 0;
1029
1030 dev_set_drvdata(pdev, sh);
1031 return 1;
1032}
1033
1034static int aha1542_isa_remove(struct device *pdev,
1035 unsigned int ndev)
1036{
1037 aha1542_release(dev_get_drvdata(pdev));
1038 dev_set_drvdata(pdev, NULL);
1039 return 0;
1040}
1041
1042static struct isa_driver aha1542_isa_driver = {
1043 .match = aha1542_isa_match,
1044 .remove = aha1542_isa_remove,
1045 .driver = {
1046 .name = "aha1542"
1047 },
1048};
1049static int isa_registered;
1050
1051#ifdef CONFIG_PNP
1052static struct pnp_device_id aha1542_pnp_ids[] = {
1053 { .id = "ADP1542" },
1054 { .id = "" }
1055};
1056MODULE_DEVICE_TABLE(pnp, aha1542_pnp_ids);
1057
1058static int aha1542_pnp_probe(struct pnp_dev *pdev, const struct pnp_device_id *id)
1059{
1060 int indx;
1061 struct Scsi_Host *sh;
1062
Ondrej Zaryf71429a2015-02-06 23:11:41 +01001063 for (indx = 0; indx < ARRAY_SIZE(io); indx++) {
1064 if (io[indx])
Ondrej Zary643a7c42015-02-06 23:11:22 +01001065 continue;
1066
1067 if (pnp_activate_dev(pdev) < 0)
1068 continue;
1069
Ondrej Zaryf71429a2015-02-06 23:11:41 +01001070 io[indx] = pnp_port_start(pdev, 0);
Ondrej Zary643a7c42015-02-06 23:11:22 +01001071
1072 /* The card can be queried for its DMA, we have
1073 the DMA set up that is enough */
1074
Ondrej Zary2906b3c2015-02-06 23:11:51 +01001075 dev_info(&pdev->dev, "ISAPnP found an AHA1535 at I/O 0x%03X", io[indx]);
Ondrej Zary643a7c42015-02-06 23:11:22 +01001076 }
1077
1078 sh = aha1542_hw_init(&driver_template, &pdev->dev, indx);
1079 if (!sh)
1080 return -ENODEV;
1081
1082 pnp_set_drvdata(pdev, sh);
1083 return 0;
1084}
1085
1086static void aha1542_pnp_remove(struct pnp_dev *pdev)
1087{
1088 aha1542_release(pnp_get_drvdata(pdev));
1089 pnp_set_drvdata(pdev, NULL);
1090}
1091
1092static struct pnp_driver aha1542_pnp_driver = {
1093 .name = "aha1542",
1094 .id_table = aha1542_pnp_ids,
1095 .probe = aha1542_pnp_probe,
1096 .remove = aha1542_pnp_remove,
1097};
1098static int pnp_registered;
1099#endif /* CONFIG_PNP */
1100
1101static int __init aha1542_init(void)
1102{
1103 int ret = 0;
Ondrej Zary643a7c42015-02-06 23:11:22 +01001104
1105#ifdef CONFIG_PNP
1106 if (isapnp) {
1107 ret = pnp_register_driver(&aha1542_pnp_driver);
1108 if (!ret)
1109 pnp_registered = 1;
1110 }
1111#endif
1112 ret = isa_register_driver(&aha1542_isa_driver, MAXBOARDS);
1113 if (!ret)
1114 isa_registered = 1;
1115
1116#ifdef CONFIG_PNP
1117 if (pnp_registered)
1118 ret = 0;
1119#endif
1120 if (isa_registered)
1121 ret = 0;
1122
1123 return ret;
1124}
1125
1126static void __exit aha1542_exit(void)
1127{
1128#ifdef CONFIG_PNP
1129 if (pnp_registered)
1130 pnp_unregister_driver(&aha1542_pnp_driver);
1131#endif
1132 if (isa_registered)
1133 isa_unregister_driver(&aha1542_isa_driver);
1134}
1135
1136module_init(aha1542_init);
1137module_exit(aha1542_exit);