blob: d607f59f922a0681665a9f12f74f5550509b4184 [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
27#ifdef DEBUG
28#define DEB(x) x
29#else
30#define DEB(x)
31#endif
Ondrej Zaryf71429a2015-02-06 23:11:41 +010032#define MAXBOARDS 4
Linus Torvalds1da177e2005-04-16 15:20:36 -070033
Ondrej Zaryf71429a2015-02-06 23:11:41 +010034static bool isapnp = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -070035module_param(isapnp, bool, 0);
Ondrej Zaryf71429a2015-02-06 23:11:41 +010036MODULE_PARM_DESC(isapnp, "enable PnP support (default=1)");
37
38static int io[MAXBOARDS] = { 0x330, 0x334, 0, 0 };
39module_param_array(io, int, NULL, 0);
40MODULE_PARM_DESC(io, "base IO address of controller (0x130,0x134,0x230,0x234,0x330,0x334, default=0x330,0x334)");
41
42/* time AHA spends on the AT-bus during data transfer */
43static int bus_on[MAXBOARDS] = { -1, -1, -1, -1 }; /* power-on default: 11us */
44module_param_array(bus_on, int, NULL, 0);
45MODULE_PARM_DESC(bus_on, "bus on time [us] (2-15, default=-1 [HW default: 11])");
46
47/* time AHA spends off the bus (not to monopolize it) during data transfer */
48static int bus_off[MAXBOARDS] = { -1, -1, -1, -1 }; /* power-on default: 4us */
49module_param_array(bus_off, int, NULL, 0);
50MODULE_PARM_DESC(bus_off, "bus off time [us] (1-64, default=-1 [HW default: 4])");
51
52/* default is jumper selected (J1 on 1542A), factory default = 5 MB/s */
53static int dma_speed[MAXBOARDS] = { -1, -1, -1, -1 };
54module_param_array(dma_speed, int, NULL, 0);
55MODULE_PARM_DESC(dma_speed, "DMA speed [MB/s] (5,6,7,8,10, default=-1 [by jumper])");
Linus Torvalds1da177e2005-04-16 15:20:36 -070056
Linus Torvalds1da177e2005-04-16 15:20:36 -070057#define BIOS_TRANSLATION_6432 1 /* Default case these days */
58#define BIOS_TRANSLATION_25563 2 /* Big disk case */
59
60struct aha1542_hostdata {
61 /* This will effectively start both of them at the first mailbox */
62 int bios_translation; /* Mapping bios uses - for compatibility */
63 int aha1542_last_mbi_used;
64 int aha1542_last_mbo_used;
Ondrej Zary55b28f92015-02-06 23:11:44 +010065 struct scsi_cmnd *int_cmds[AHA1542_MAILBOXES];
Linus Torvalds1da177e2005-04-16 15:20:36 -070066 struct mailbox mb[2 * AHA1542_MAILBOXES];
67 struct ccb ccb[AHA1542_MAILBOXES];
68};
69
Linus Torvalds1da177e2005-04-16 15:20:36 -070070static DEFINE_SPINLOCK(aha1542_lock);
71
Ondrej Zaryf1bbef62015-02-06 23:11:26 +010072static inline void aha1542_intr_reset(u16 base)
73{
74 outb(IRST, CONTROL(base));
75}
Linus Torvalds1da177e2005-04-16 15:20:36 -070076
Ondrej Zary2093bfa2015-02-06 23:11:31 +010077static inline bool wait_mask(u16 port, u8 mask, u8 allof, u8 noneof, int timeout)
78{
79 bool delayed = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -070080
Ondrej Zary2093bfa2015-02-06 23:11:31 +010081 if (timeout == 0) {
82 timeout = 3000000;
83 delayed = false;
84 }
85
86 while (1) {
87 u8 bits = inb(port) & mask;
88 if ((bits & allof) == allof && ((bits & noneof) == 0))
89 break;
90 if (delayed)
91 mdelay(1);
92 if (--timeout == 0)
93 return false;
94 }
95
96 return true;
97}
Linus Torvalds1da177e2005-04-16 15:20:36 -070098
Linus Torvalds1da177e2005-04-16 15:20:36 -070099/* This is a bit complicated, but we need to make sure that an interrupt
100 routine does not send something out while we are in the middle of this.
101 Fortunately, it is only at boot time that multi-byte messages
102 are ever sent. */
Ondrej Zarycad2fc72015-02-06 23:11:43 +0100103static int aha1542_outb(unsigned int base, u8 val)
Ondrej Zary0c2b6482015-02-06 23:11:33 +0100104{
105 unsigned long flags;
106
107 while (1) {
Ondrej Zary2906b3c2015-02-06 23:11:51 +0100108 if (!wait_mask(STATUS(base), CDF, 0, CDF, 0))
Ondrej Zary0c2b6482015-02-06 23:11:33 +0100109 return 1;
Ondrej Zary0c2b6482015-02-06 23:11:33 +0100110 spin_lock_irqsave(&aha1542_lock, flags);
111 if (inb(STATUS(base)) & CDF) {
112 spin_unlock_irqrestore(&aha1542_lock, flags);
113 continue;
114 }
Ondrej Zarycad2fc72015-02-06 23:11:43 +0100115 outb(val, DATA(base));
Ondrej Zary0c2b6482015-02-06 23:11:33 +0100116 spin_unlock_irqrestore(&aha1542_lock, flags);
117 return 0;
118 }
119}
120
Ondrej Zarycad2fc72015-02-06 23:11:43 +0100121static int aha1542_out(unsigned int base, u8 *buf, int len)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700122{
Ondrej Zary0c2b6482015-02-06 23:11:33 +0100123 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700124
Ondrej Zary0c2b6482015-02-06 23:11:33 +0100125 spin_lock_irqsave(&aha1542_lock, flags);
126 while (len--) {
127 if (!wait_mask(STATUS(base), CDF, 0, CDF, 0)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700128 spin_unlock_irqrestore(&aha1542_lock, flags);
Ondrej Zary0c2b6482015-02-06 23:11:33 +0100129 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700130 }
Ondrej Zarycad2fc72015-02-06 23:11:43 +0100131 outb(*buf++, DATA(base));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700132 }
Ondrej Zary0c2b6482015-02-06 23:11:33 +0100133 spin_unlock_irqrestore(&aha1542_lock, flags);
Ondrej Zary23e69402015-02-06 23:11:39 +0100134 if (!wait_mask(INTRFLAGS(base), INTRMASK, HACC, 0, 0))
135 return 1;
Ondrej Zary0c2b6482015-02-06 23:11:33 +0100136
Linus Torvalds1da177e2005-04-16 15:20:36 -0700137 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700138}
139
140/* Only used at boot time, so we do not need to worry about latency as much
141 here */
142
Ondrej Zarycad2fc72015-02-06 23:11:43 +0100143static int aha1542_in(unsigned int base, u8 *buf, int len, int timeout)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700144{
145 unsigned long flags;
146
147 spin_lock_irqsave(&aha1542_lock, flags);
148 while (len--) {
Ondrej Zarya13b3722015-02-06 23:11:34 +0100149 if (!wait_mask(STATUS(base), DF, DF, 0, timeout)) {
150 spin_unlock_irqrestore(&aha1542_lock, flags);
Ondrej Zarya13b3722015-02-06 23:11:34 +0100151 return 1;
152 }
Ondrej Zarycad2fc72015-02-06 23:11:43 +0100153 *buf++ = inb(DATA(base));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700154 }
155 spin_unlock_irqrestore(&aha1542_lock, flags);
156 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700157}
158
159static int makecode(unsigned hosterr, unsigned scsierr)
160{
161 switch (hosterr) {
162 case 0x0:
163 case 0xa: /* Linked command complete without error and linked normally */
164 case 0xb: /* Linked command complete without error, interrupt generated */
165 hosterr = 0;
166 break;
167
168 case 0x11: /* Selection time out-The initiator selection or target
169 reselection was not complete within the SCSI Time out period */
170 hosterr = DID_TIME_OUT;
171 break;
172
173 case 0x12: /* Data overrun/underrun-The target attempted to transfer more data
174 than was allocated by the Data Length field or the sum of the
175 Scatter / Gather Data Length fields. */
176
177 case 0x13: /* Unexpected bus free-The target dropped the SCSI BSY at an unexpected time. */
178
179 case 0x15: /* MBO command was not 00, 01 or 02-The first byte of the CB was
180 invalid. This usually indicates a software failure. */
181
182 case 0x16: /* Invalid CCB Operation Code-The first byte of the CCB was invalid.
183 This usually indicates a software failure. */
184
185 case 0x17: /* Linked CCB does not have the same LUN-A subsequent CCB of a set
186 of linked CCB's does not specify the same logical unit number as
187 the first. */
188 case 0x18: /* Invalid Target Direction received from Host-The direction of a
189 Target Mode CCB was invalid. */
190
191 case 0x19: /* Duplicate CCB Received in Target Mode-More than once CCB was
192 received to service data transfer between the same target LUN
193 and initiator SCSI ID in the same direction. */
194
195 case 0x1a: /* Invalid CCB or Segment List Parameter-A segment list with a zero
196 length segment or invalid segment list boundaries was received.
197 A CCB parameter was invalid. */
198 DEB(printk("Aha1542: %x %x\n", hosterr, scsierr));
199 hosterr = DID_ERROR; /* Couldn't find any better */
200 break;
201
202 case 0x14: /* Target bus phase sequence failure-An invalid bus phase or bus
203 phase sequence was requested by the target. The host adapter
204 will generate a SCSI Reset Condition, notifying the host with
205 a SCRD interrupt */
206 hosterr = DID_RESET;
207 break;
208 default:
209 printk(KERN_ERR "aha1542: makecode: unknown hoststatus %x\n", hosterr);
210 break;
211 }
212 return scsierr | (hosterr << 16);
213}
214
Ondrej Zary68ea9de2015-02-06 23:11:49 +0100215static int aha1542_test_port(struct Scsi_Host *sh)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700216{
Ondrej Zarycb5b5702015-02-06 23:11:27 +0100217 u8 inquiry_result[4];
Ondrej Zarycad2fc72015-02-06 23:11:43 +0100218 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700219
220 /* Quick and dirty test for presence of the card. */
Ondrej Zary68ea9de2015-02-06 23:11:49 +0100221 if (inb(STATUS(sh->io_port)) == 0xff)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700222 return 0;
223
224 /* Reset the adapter. I ought to make a hard reset, but it's not really necessary */
225
Linus Torvalds1da177e2005-04-16 15:20:36 -0700226 /* In case some other card was probing here, reset interrupts */
Ondrej Zary68ea9de2015-02-06 23:11:49 +0100227 aha1542_intr_reset(sh->io_port); /* reset interrupts, so they don't block */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700228
Ondrej Zary68ea9de2015-02-06 23:11:49 +0100229 outb(SRST | IRST /*|SCRST */ , CONTROL(sh->io_port));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700230
231 mdelay(20); /* Wait a little bit for things to settle down. */
232
Linus Torvalds1da177e2005-04-16 15:20:36 -0700233 /* Expect INIT and IDLE, any of the others are bad */
Ondrej Zary68ea9de2015-02-06 23:11:49 +0100234 if (!wait_mask(STATUS(sh->io_port), STATMASK, INIT | IDLE, STST | DIAGF | INVDCMD | DF | CDF, 0))
Ondrej Zarya13b3722015-02-06 23:11:34 +0100235 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700236
Linus Torvalds1da177e2005-04-16 15:20:36 -0700237 /* Shouldn't have generated any interrupts during reset */
Ondrej Zary68ea9de2015-02-06 23:11:49 +0100238 if (inb(INTRFLAGS(sh->io_port)) & INTRMASK)
Ondrej Zarya13b3722015-02-06 23:11:34 +0100239 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700240
Linus Torvalds1da177e2005-04-16 15:20:36 -0700241 /* Perform a host adapter inquiry instead so we do not need to set
242 up the mailboxes ahead of time */
243
Ondrej Zary68ea9de2015-02-06 23:11:49 +0100244 aha1542_outb(sh->io_port, CMD_INQUIRY);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700245
Ondrej Zarycad2fc72015-02-06 23:11:43 +0100246 for (i = 0; i < 4; i++) {
Ondrej Zary68ea9de2015-02-06 23:11:49 +0100247 if (!wait_mask(STATUS(sh->io_port), DF, DF, 0, 0))
Ondrej Zarya13b3722015-02-06 23:11:34 +0100248 return 0;
Ondrej Zary68ea9de2015-02-06 23:11:49 +0100249 inquiry_result[i] = inb(DATA(sh->io_port));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700250 }
251
Linus Torvalds1da177e2005-04-16 15:20:36 -0700252 /* Reading port should reset DF */
Ondrej Zary68ea9de2015-02-06 23:11:49 +0100253 if (inb(STATUS(sh->io_port)) & DF)
Ondrej Zarya13b3722015-02-06 23:11:34 +0100254 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700255
Linus Torvalds1da177e2005-04-16 15:20:36 -0700256 /* When HACC, command is completed, and we're though testing */
Ondrej Zary68ea9de2015-02-06 23:11:49 +0100257 if (!wait_mask(INTRFLAGS(sh->io_port), HACC, HACC, 0, 0))
Ondrej Zarya13b3722015-02-06 23:11:34 +0100258 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700259
Linus Torvalds1da177e2005-04-16 15:20:36 -0700260 /* Clear interrupts */
Ondrej Zary68ea9de2015-02-06 23:11:49 +0100261 outb(IRST, CONTROL(sh->io_port));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700262
Ondrej Zarybdebe222015-02-06 23:11:35 +0100263 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700264}
265
Linus Torvalds1da177e2005-04-16 15:20:36 -0700266/* A "high" level interrupt handler */
Ondrej Zaryc2532f62015-02-06 23:11:45 +0100267static void aha1542_intr_handle(struct Scsi_Host *sh)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700268{
Ondrej Zaryc2532f62015-02-06 23:11:45 +0100269 struct aha1542_hostdata *aha1542 = shost_priv(sh);
Ondrej Zary55b28f92015-02-06 23:11:44 +0100270 void (*my_done)(struct scsi_cmnd *) = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700271 int errstatus, mbi, mbo, mbistatus;
272 int number_serviced;
273 unsigned long flags;
Ondrej Zary55b28f92015-02-06 23:11:44 +0100274 struct scsi_cmnd *tmp_cmd;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700275 int flag;
Ondrej Zarye98878f2015-02-06 23:11:25 +0100276 struct mailbox *mb = aha1542->mb;
277 struct ccb *ccb = aha1542->ccb;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700278
279#ifdef DEBUG
280 {
Ondrej Zaryc2532f62015-02-06 23:11:45 +0100281 flag = inb(INTRFLAGS(sh->io_port));
Ondrej Zary2906b3c2015-02-06 23:11:51 +0100282 shost_printk(KERN_DEBUG, sh, "aha1542_intr_handle: ");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700283 if (!(flag & ANYINTR))
284 printk("no interrupt?");
285 if (flag & MBIF)
286 printk("MBIF ");
287 if (flag & MBOA)
288 printk("MBOF ");
289 if (flag & HACC)
290 printk("HACC ");
291 if (flag & SCRD)
292 printk("SCRD ");
Ondrej Zaryc2532f62015-02-06 23:11:45 +0100293 printk("status %02x\n", inb(STATUS(sh->io_port)));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700294 };
295#endif
296 number_serviced = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700297
298 while (1 == 1) {
Ondrej Zaryc2532f62015-02-06 23:11:45 +0100299 flag = inb(INTRFLAGS(sh->io_port));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700300
301 /* Check for unusual interrupts. If any of these happen, we should
302 probably do something special, but for now just printing a message
303 is sufficient. A SCSI reset detected is something that we really
304 need to deal with in some way. */
305 if (flag & ~MBIF) {
306 if (flag & MBOA)
307 printk("MBOF ");
308 if (flag & HACC)
309 printk("HACC ");
Ondrej Zarydfd7c992015-02-06 23:11:36 +0100310 if (flag & SCRD)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700311 printk("SCRD ");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700312 }
Ondrej Zaryc2532f62015-02-06 23:11:45 +0100313 aha1542_intr_reset(sh->io_port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700314
315 spin_lock_irqsave(&aha1542_lock, flags);
Ondrej Zarye98878f2015-02-06 23:11:25 +0100316 mbi = aha1542->aha1542_last_mbi_used + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700317 if (mbi >= 2 * AHA1542_MAILBOXES)
318 mbi = AHA1542_MAILBOXES;
319
320 do {
321 if (mb[mbi].status != 0)
322 break;
323 mbi++;
324 if (mbi >= 2 * AHA1542_MAILBOXES)
325 mbi = AHA1542_MAILBOXES;
Ondrej Zarye98878f2015-02-06 23:11:25 +0100326 } while (mbi != aha1542->aha1542_last_mbi_used);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700327
328 if (mb[mbi].status == 0) {
329 spin_unlock_irqrestore(&aha1542_lock, flags);
330 /* Hmm, no mail. Must have read it the last time around */
Ondrej Zarydfd7c992015-02-06 23:11:36 +0100331 if (!number_serviced)
Ondrej Zary2906b3c2015-02-06 23:11:51 +0100332 shost_printk(KERN_WARNING, sh, "interrupt received, but no mail.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700333 return;
334 };
335
Ondrej Zary10be6252015-02-06 23:11:24 +0100336 mbo = (scsi2int(mb[mbi].ccbptr) - (isa_virt_to_bus(&ccb[0]))) / sizeof(struct ccb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700337 mbistatus = mb[mbi].status;
338 mb[mbi].status = 0;
Ondrej Zarye98878f2015-02-06 23:11:25 +0100339 aha1542->aha1542_last_mbi_used = mbi;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700340 spin_unlock_irqrestore(&aha1542_lock, flags);
341
342#ifdef DEBUG
343 {
344 if (ccb[mbo].tarstat | ccb[mbo].hastat)
Ondrej Zary2906b3c2015-02-06 23:11:51 +0100345 shost_printk(KERN_DEBUG, sh, "aha1542_command: returning %x (status %d)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700346 ccb[mbo].tarstat + ((int) ccb[mbo].hastat << 16), mb[mbi].status);
347 };
348#endif
349
350 if (mbistatus == 3)
351 continue; /* Aborted command not found */
352
353#ifdef DEBUG
Ondrej Zary2906b3c2015-02-06 23:11:51 +0100354 shost_printk(KERN_DEBUG, sh, "...done %d %d\n", mbo, mbi);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700355#endif
356
Ondrej Zary55b28f92015-02-06 23:11:44 +0100357 tmp_cmd = aha1542->int_cmds[mbo];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700358
Ondrej Zary55b28f92015-02-06 23:11:44 +0100359 if (!tmp_cmd || !tmp_cmd->scsi_done) {
Ondrej Zary2906b3c2015-02-06 23:11:51 +0100360 shost_printk(KERN_WARNING, sh, "Unexpected interrupt\n");
361 shost_printk(KERN_WARNING, sh, "tarstat=%x, hastat=%x idlun=%x ccb#=%d\n", ccb[mbo].tarstat,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700362 ccb[mbo].hastat, ccb[mbo].idlun, mbo);
363 return;
364 }
Ondrej Zary55b28f92015-02-06 23:11:44 +0100365 my_done = tmp_cmd->scsi_done;
366 kfree(tmp_cmd->host_scribble);
367 tmp_cmd->host_scribble = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700368 /* Fetch the sense data, and tuck it away, in the required slot. The
369 Adaptec automatically fetches it, and there is no guarantee that
370 we will still have it in the cdb when we come back */
371 if (ccb[mbo].tarstat == 2)
Ondrej Zary55b28f92015-02-06 23:11:44 +0100372 memcpy(tmp_cmd->sense_buffer, &ccb[mbo].cdb[ccb[mbo].cdblen],
FUJITA Tomonorib80ca4f2008-01-13 15:46:13 +0900373 SCSI_SENSE_BUFFERSIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700374
375
376 /* is there mail :-) */
377
378 /* more error checking left out here */
379 if (mbistatus != 1)
380 /* This is surely wrong, but I don't know what's right */
381 errstatus = makecode(ccb[mbo].hastat, ccb[mbo].tarstat);
382 else
383 errstatus = 0;
384
385#ifdef DEBUG
386 if (errstatus)
Ondrej Zary2906b3c2015-02-06 23:11:51 +0100387 shost_printk(KERN_DEBUG, sh, "(aha1542 error:%x %x %x) ", errstatus,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700388 ccb[mbo].hastat, ccb[mbo].tarstat);
389#endif
390
391 if (ccb[mbo].tarstat == 2) {
392#ifdef DEBUG
393 int i;
394#endif
395 DEB(printk("aha1542_intr_handle: sense:"));
396#ifdef DEBUG
397 for (i = 0; i < 12; i++)
398 printk("%02x ", ccb[mbo].cdb[ccb[mbo].cdblen + i]);
399 printk("\n");
400#endif
401 /*
402 DEB(printk("aha1542_intr_handle: buf:"));
403 for (i = 0; i < bufflen; i++)
404 printk("%02x ", ((unchar *)buff)[i]);
405 printk("\n");
406 */
407 }
408 DEB(if (errstatus) printk("aha1542_intr_handle: returning %6x\n", errstatus));
Ondrej Zary55b28f92015-02-06 23:11:44 +0100409 tmp_cmd->result = errstatus;
410 aha1542->int_cmds[mbo] = NULL; /* This effectively frees up the mailbox slot, as
Ondrej Zarye98878f2015-02-06 23:11:25 +0100411 far as queuecommand is concerned */
Ondrej Zary55b28f92015-02-06 23:11:44 +0100412 my_done(tmp_cmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700413 number_serviced++;
414 };
415}
416
Ondrej Zary09a44832015-02-06 23:11:28 +0100417/* A quick wrapper for do_aha1542_intr_handle to grab the spin lock */
418static irqreturn_t do_aha1542_intr_handle(int dummy, void *dev_id)
419{
420 unsigned long flags;
Ondrej Zaryc2532f62015-02-06 23:11:45 +0100421 struct Scsi_Host *sh = dev_id;
Ondrej Zary09a44832015-02-06 23:11:28 +0100422
Ondrej Zaryc2532f62015-02-06 23:11:45 +0100423 spin_lock_irqsave(sh->host_lock, flags);
424 aha1542_intr_handle(sh);
425 spin_unlock_irqrestore(sh->host_lock, flags);
Ondrej Zary09a44832015-02-06 23:11:28 +0100426 return IRQ_HANDLED;
427}
428
Ondrej Zary55b28f92015-02-06 23:11:44 +0100429static int aha1542_queuecommand_lck(struct scsi_cmnd *cmd, void (*done) (struct scsi_cmnd *))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700430{
Ondrej Zary2906b3c2015-02-06 23:11:51 +0100431 struct Scsi_Host *sh = cmd->device->host;
432 struct aha1542_hostdata *aha1542 = shost_priv(sh);
Ondrej Zarycb5b5702015-02-06 23:11:27 +0100433 u8 direction;
Ondrej Zary55b28f92015-02-06 23:11:44 +0100434 u8 target = cmd->device->id;
435 u8 lun = cmd->device->lun;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700436 unsigned long flags;
Ondrej Zary55b28f92015-02-06 23:11:44 +0100437 int bufflen = scsi_bufflen(cmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700438 int mbo;
Ondrej Zarye98878f2015-02-06 23:11:25 +0100439 struct mailbox *mb = aha1542->mb;
440 struct ccb *ccb = aha1542->ccb;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700441
442 DEB(int i);
443
Linus Torvalds1da177e2005-04-16 15:20:36 -0700444 DEB(if (target > 1) {
Ondrej Zary55b28f92015-02-06 23:11:44 +0100445 cmd->result = DID_TIME_OUT << 16;
446 done(cmd); return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700447 }
448 );
449
Ondrej Zary55b28f92015-02-06 23:11:44 +0100450 if (*cmd->cmnd == REQUEST_SENSE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700451 /* Don't do the command - we have the sense data already */
Ondrej Zary55b28f92015-02-06 23:11:44 +0100452 cmd->result = 0;
453 done(cmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700454 return 0;
455 }
456#ifdef DEBUG
Ondrej Zary55b28f92015-02-06 23:11:44 +0100457 if (*cmd->cmnd == READ_10 || *cmd->cmnd == WRITE_10)
458 i = xscsi2int(cmd->cmnd + 2);
459 else if (*cmd->cmnd == READ_6 || *cmd->cmnd == WRITE_6)
460 i = scsi2int(cmd->cmnd + 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700461 else
462 i = -1;
463 if (done)
Ondrej Zary2906b3c2015-02-06 23:11:51 +0100464 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 -0700465 else
Ondrej Zary2906b3c2015-02-06 23:11:51 +0100466 shost_printk(KERN_DEBUG, sh, "aha1542_command: dev %d cmd %02x pos %d len %d ", target, *cmd->cmnd, i, bufflen);
467 shost_printk(KERN_DEBUG, sh, "aha1542_queuecommand: dumping scsi cmd:");
Ondrej Zary55b28f92015-02-06 23:11:44 +0100468 for (i = 0; i < cmd->cmd_len; i++)
469 printk("%02x ", cmd->cmnd[i]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700470 printk("\n");
Ondrej Zary55b28f92015-02-06 23:11:44 +0100471 if (*cmd->cmnd == WRITE_10 || *cmd->cmnd == WRITE_6)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700472 return 0; /* we are still testing, so *don't* write */
473#endif
474 /* Use the outgoing mailboxes in a round-robin fashion, because this
475 is how the host adapter will scan for them */
476
477 spin_lock_irqsave(&aha1542_lock, flags);
Ondrej Zarye98878f2015-02-06 23:11:25 +0100478 mbo = aha1542->aha1542_last_mbo_used + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700479 if (mbo >= AHA1542_MAILBOXES)
480 mbo = 0;
481
482 do {
Ondrej Zary55b28f92015-02-06 23:11:44 +0100483 if (mb[mbo].status == 0 && aha1542->int_cmds[mbo] == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700484 break;
485 mbo++;
486 if (mbo >= AHA1542_MAILBOXES)
487 mbo = 0;
Ondrej Zarye98878f2015-02-06 23:11:25 +0100488 } while (mbo != aha1542->aha1542_last_mbo_used);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700489
Ondrej Zary55b28f92015-02-06 23:11:44 +0100490 if (mb[mbo].status || aha1542->int_cmds[mbo])
Linus Torvalds1da177e2005-04-16 15:20:36 -0700491 panic("Unable to find empty mailbox for aha1542.\n");
492
Ondrej Zary55b28f92015-02-06 23:11:44 +0100493 aha1542->int_cmds[mbo] = cmd; /* This will effectively prevent someone else from
Ondrej Zarye98878f2015-02-06 23:11:25 +0100494 screwing with this cdb. */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700495
Ondrej Zarye98878f2015-02-06 23:11:25 +0100496 aha1542->aha1542_last_mbo_used = mbo;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700497 spin_unlock_irqrestore(&aha1542_lock, flags);
498
499#ifdef DEBUG
Ondrej Zary2906b3c2015-02-06 23:11:51 +0100500 shost_printk(KERN_DEBUG, sh, "Sending command (%d %x)...", mbo, done);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700501#endif
502
Ondrej Zary10be6252015-02-06 23:11:24 +0100503 any2scsi(mb[mbo].ccbptr, isa_virt_to_bus(&ccb[mbo])); /* This gets trashed for some reason */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700504
505 memset(&ccb[mbo], 0, sizeof(struct ccb));
506
Ondrej Zary55b28f92015-02-06 23:11:44 +0100507 ccb[mbo].cdblen = cmd->cmd_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700508
509 direction = 0;
Ondrej Zary55b28f92015-02-06 23:11:44 +0100510 if (*cmd->cmnd == READ_10 || *cmd->cmnd == READ_6)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700511 direction = 8;
Ondrej Zary55b28f92015-02-06 23:11:44 +0100512 else if (*cmd->cmnd == WRITE_10 || *cmd->cmnd == WRITE_6)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700513 direction = 16;
514
Ondrej Zary55b28f92015-02-06 23:11:44 +0100515 memcpy(ccb[mbo].cdb, cmd->cmnd, ccb[mbo].cdblen);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700516
Boaz Harroshfc3fdfc2007-09-09 21:02:45 +0300517 if (bufflen) {
Jens Axboe51cf2242007-07-16 10:00:31 +0200518 struct scatterlist *sg;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700519 struct chain *cptr;
520#ifdef DEBUG
521 unsigned char *ptr;
522#endif
Ondrej Zary55b28f92015-02-06 23:11:44 +0100523 int i, sg_count = scsi_sg_count(cmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700524 ccb[mbo].op = 2; /* SCSI Initiator Command w/scatter-gather */
Ondrej Zary55b28f92015-02-06 23:11:44 +0100525 cmd->host_scribble = kmalloc(sizeof(*cptr)*sg_count,
Boaz Harroshfc3fdfc2007-09-09 21:02:45 +0300526 GFP_KERNEL | GFP_DMA);
Ondrej Zary55b28f92015-02-06 23:11:44 +0100527 cptr = (struct chain *) cmd->host_scribble;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700528 if (cptr == NULL) {
529 /* free the claimed mailbox slot */
Ondrej Zary55b28f92015-02-06 23:11:44 +0100530 aha1542->int_cmds[mbo] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700531 return SCSI_MLQUEUE_HOST_BUSY;
532 }
Ondrej Zary55b28f92015-02-06 23:11:44 +0100533 scsi_for_each_sg(cmd, sg, sg_count, i) {
Ondrej Zary10be6252015-02-06 23:11:24 +0100534 any2scsi(cptr[i].dataptr, isa_page_to_bus(sg_page(sg))
535 + sg->offset);
Jens Axboe51cf2242007-07-16 10:00:31 +0200536 any2scsi(cptr[i].datalen, sg->length);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700537 };
Boaz Harroshfc3fdfc2007-09-09 21:02:45 +0300538 any2scsi(ccb[mbo].datalen, sg_count * sizeof(struct chain));
Ondrej Zary10be6252015-02-06 23:11:24 +0100539 any2scsi(ccb[mbo].dataptr, isa_virt_to_bus(cptr));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700540#ifdef DEBUG
541 printk("cptr %x: ", cptr);
542 ptr = (unsigned char *) cptr;
543 for (i = 0; i < 18; i++)
544 printk("%02x ", ptr[i]);
545#endif
546 } else {
547 ccb[mbo].op = 0; /* SCSI Initiator Command */
Ondrej Zary55b28f92015-02-06 23:11:44 +0100548 cmd->host_scribble = NULL;
Boaz Harroshfc3fdfc2007-09-09 21:02:45 +0300549 any2scsi(ccb[mbo].datalen, 0);
550 any2scsi(ccb[mbo].dataptr, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700551 };
552 ccb[mbo].idlun = (target & 7) << 5 | direction | (lun & 7); /*SCSI Target Id */
553 ccb[mbo].rsalen = 16;
554 ccb[mbo].linkptr[0] = ccb[mbo].linkptr[1] = ccb[mbo].linkptr[2] = 0;
555 ccb[mbo].commlinkid = 0;
556
557#ifdef DEBUG
558 {
559 int i;
Ondrej Zary2906b3c2015-02-06 23:11:51 +0100560 shost_printk(KERN_DEBUG, sh, "aha1542_command: sending.. ");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700561 for (i = 0; i < sizeof(ccb[mbo]) - 10; i++)
Ondrej Zarycb5b5702015-02-06 23:11:27 +0100562 printk("%02x ", ((u8 *) &ccb[mbo])[i]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700563 };
564#endif
565
566 if (done) {
Ondrej Zaryf232d532015-02-06 23:11:29 +0100567 DEB(printk("aha1542_queuecommand: now waiting for interrupt "));
Ondrej Zary55b28f92015-02-06 23:11:44 +0100568 cmd->scsi_done = done;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700569 mb[mbo].status = 1;
Ondrej Zary55b28f92015-02-06 23:11:44 +0100570 aha1542_outb(cmd->device->host->io_port, CMD_START_SCSI);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700571 } else
572 printk("aha1542_queuecommand: done can't be NULL\n");
573
574 return 0;
575}
576
Jeff Garzikf2812332010-11-16 02:10:29 -0500577static DEF_SCSI_QCMD(aha1542_queuecommand)
578
Linus Torvalds1da177e2005-04-16 15:20:36 -0700579/* Initialize mailboxes */
Ondrej Zary68ea9de2015-02-06 23:11:49 +0100580static void setup_mailboxes(struct Scsi_Host *sh)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700581{
Ondrej Zaryc2532f62015-02-06 23:11:45 +0100582 struct aha1542_hostdata *aha1542 = shost_priv(sh);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700583 int i;
Ondrej Zarye98878f2015-02-06 23:11:25 +0100584 struct mailbox *mb = aha1542->mb;
585 struct ccb *ccb = aha1542->ccb;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700586
Ondrej Zarycad2fc72015-02-06 23:11:43 +0100587 u8 mb_cmd[5] = { CMD_MBINIT, AHA1542_MAILBOXES, 0, 0, 0};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700588
Linus Torvalds1da177e2005-04-16 15:20:36 -0700589 for (i = 0; i < AHA1542_MAILBOXES; i++) {
590 mb[i].status = mb[AHA1542_MAILBOXES + i].status = 0;
Ondrej Zary10be6252015-02-06 23:11:24 +0100591 any2scsi(mb[i].ccbptr, isa_virt_to_bus(&ccb[i]));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700592 };
Ondrej Zary68ea9de2015-02-06 23:11:49 +0100593 aha1542_intr_reset(sh->io_port); /* reset interrupts, so they don't block */
Ondrej Zarycad2fc72015-02-06 23:11:43 +0100594 any2scsi((mb_cmd + 2), isa_virt_to_bus(mb));
Ondrej Zary68ea9de2015-02-06 23:11:49 +0100595 if (aha1542_out(sh->io_port, mb_cmd, 5))
Ondrej Zary2906b3c2015-02-06 23:11:51 +0100596 shost_printk(KERN_ERR, sh, "failed setting up mailboxes\n");
Ondrej Zary68ea9de2015-02-06 23:11:49 +0100597 aha1542_intr_reset(sh->io_port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700598}
599
Ondrej Zary68ea9de2015-02-06 23:11:49 +0100600static int aha1542_getconfig(struct Scsi_Host *sh)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700601{
Ondrej Zarycb5b5702015-02-06 23:11:27 +0100602 u8 inquiry_result[3];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700603 int i;
Ondrej Zary68ea9de2015-02-06 23:11:49 +0100604 i = inb(STATUS(sh->io_port));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700605 if (i & DF) {
Ondrej Zary68ea9de2015-02-06 23:11:49 +0100606 i = inb(DATA(sh->io_port));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700607 };
Ondrej Zary68ea9de2015-02-06 23:11:49 +0100608 aha1542_outb(sh->io_port, CMD_RETCONF);
609 aha1542_in(sh->io_port, inquiry_result, 3, 0);
610 if (!wait_mask(INTRFLAGS(sh->io_port), INTRMASK, HACC, 0, 0))
Ondrej Zary2906b3c2015-02-06 23:11:51 +0100611 shost_printk(KERN_ERR, sh, "error querying board settings\n");
Ondrej Zary68ea9de2015-02-06 23:11:49 +0100612 aha1542_intr_reset(sh->io_port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700613 switch (inquiry_result[0]) {
614 case 0x80:
Ondrej Zary68ea9de2015-02-06 23:11:49 +0100615 sh->dma_channel = 7;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700616 break;
617 case 0x40:
Ondrej Zary68ea9de2015-02-06 23:11:49 +0100618 sh->dma_channel = 6;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700619 break;
620 case 0x20:
Ondrej Zary68ea9de2015-02-06 23:11:49 +0100621 sh->dma_channel = 5;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700622 break;
623 case 0x01:
Ondrej Zary68ea9de2015-02-06 23:11:49 +0100624 sh->dma_channel = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700625 break;
626 case 0:
627 /* This means that the adapter, although Adaptec 1542 compatible, doesn't use a DMA channel.
628 Currently only aware of the BusLogic BT-445S VL-Bus adapter which needs this. */
Ondrej Zary68ea9de2015-02-06 23:11:49 +0100629 sh->dma_channel = 0xFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700630 break;
631 default:
Ondrej Zary2906b3c2015-02-06 23:11:51 +0100632 shost_printk(KERN_ERR, sh, "Unable to determine DMA channel.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700633 return -1;
634 };
635 switch (inquiry_result[1]) {
636 case 0x40:
Ondrej Zary68ea9de2015-02-06 23:11:49 +0100637 sh->irq = 15;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700638 break;
639 case 0x20:
Ondrej Zary68ea9de2015-02-06 23:11:49 +0100640 sh->irq = 14;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700641 break;
642 case 0x8:
Ondrej Zary68ea9de2015-02-06 23:11:49 +0100643 sh->irq = 12;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700644 break;
645 case 0x4:
Ondrej Zary68ea9de2015-02-06 23:11:49 +0100646 sh->irq = 11;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700647 break;
648 case 0x2:
Ondrej Zary68ea9de2015-02-06 23:11:49 +0100649 sh->irq = 10;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700650 break;
651 case 0x1:
Ondrej Zary68ea9de2015-02-06 23:11:49 +0100652 sh->irq = 9;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700653 break;
654 default:
Ondrej Zary2906b3c2015-02-06 23:11:51 +0100655 shost_printk(KERN_ERR, sh, "Unable to determine IRQ level.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700656 return -1;
657 };
Ondrej Zary68ea9de2015-02-06 23:11:49 +0100658 sh->this_id = inquiry_result[2] & 7;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700659 return 0;
660}
661
662/* This function should only be called for 1542C boards - we can detect
663 the special firmware settings and unlock the board */
664
Ondrej Zary68ea9de2015-02-06 23:11:49 +0100665static int aha1542_mbenable(struct Scsi_Host *sh)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700666{
Ondrej Zarycb5b5702015-02-06 23:11:27 +0100667 static u8 mbenable_cmd[3];
668 static u8 mbenable_result[2];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700669 int retval;
670
671 retval = BIOS_TRANSLATION_6432;
672
Ondrej Zary68ea9de2015-02-06 23:11:49 +0100673 aha1542_outb(sh->io_port, CMD_EXTBIOS);
674 if (aha1542_in(sh->io_port, mbenable_result, 2, 100))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700675 return retval;
Ondrej Zary68ea9de2015-02-06 23:11:49 +0100676 if (!wait_mask(INTRFLAGS(sh->io_port), INTRMASK, HACC, 0, 100))
Ondrej Zary2093bfa2015-02-06 23:11:31 +0100677 goto fail;
Ondrej Zary68ea9de2015-02-06 23:11:49 +0100678 aha1542_intr_reset(sh->io_port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700679
680 if ((mbenable_result[0] & 0x08) || mbenable_result[1]) {
681 mbenable_cmd[0] = CMD_MBENABLE;
682 mbenable_cmd[1] = 0;
683 mbenable_cmd[2] = mbenable_result[1];
684
685 if ((mbenable_result[0] & 0x08) && (mbenable_result[1] & 0x03))
686 retval = BIOS_TRANSLATION_25563;
687
Ondrej Zary68ea9de2015-02-06 23:11:49 +0100688 if (aha1542_out(sh->io_port, mbenable_cmd, 3))
Ondrej Zary2093bfa2015-02-06 23:11:31 +0100689 goto fail;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700690 };
691 while (0) {
692fail:
Ondrej Zary2906b3c2015-02-06 23:11:51 +0100693 shost_printk(KERN_ERR, sh, "Mailbox init failed\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700694 }
Ondrej Zary68ea9de2015-02-06 23:11:49 +0100695 aha1542_intr_reset(sh->io_port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700696 return retval;
697}
698
699/* Query the board to find out if it is a 1542 or a 1740, or whatever. */
Ondrej Zary68ea9de2015-02-06 23:11:49 +0100700static int aha1542_query(struct Scsi_Host *sh)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700701{
Ondrej Zary68ea9de2015-02-06 23:11:49 +0100702 struct aha1542_hostdata *aha1542 = shost_priv(sh);
Ondrej Zarycb5b5702015-02-06 23:11:27 +0100703 u8 inquiry_result[4];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700704 int i;
Ondrej Zary68ea9de2015-02-06 23:11:49 +0100705 i = inb(STATUS(sh->io_port));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700706 if (i & DF) {
Ondrej Zary68ea9de2015-02-06 23:11:49 +0100707 i = inb(DATA(sh->io_port));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700708 };
Ondrej Zary68ea9de2015-02-06 23:11:49 +0100709 aha1542_outb(sh->io_port, CMD_INQUIRY);
710 aha1542_in(sh->io_port, inquiry_result, 4, 0);
711 if (!wait_mask(INTRFLAGS(sh->io_port), INTRMASK, HACC, 0, 0))
Ondrej Zary2906b3c2015-02-06 23:11:51 +0100712 shost_printk(KERN_ERR, sh, "error querying card type\n");
Ondrej Zary68ea9de2015-02-06 23:11:49 +0100713 aha1542_intr_reset(sh->io_port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700714
Ondrej Zary68ea9de2015-02-06 23:11:49 +0100715 aha1542->bios_translation = BIOS_TRANSLATION_6432; /* Default case */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700716
717 /* For an AHA1740 series board, we ignore the board since there is a
718 hardware bug which can lead to wrong blocks being returned if the board
719 is operating in the 1542 emulation mode. Since there is an extended mode
720 driver, we simply ignore the board and let the 1740 driver pick it up.
721 */
722
723 if (inquiry_result[0] == 0x43) {
Ondrej Zary2906b3c2015-02-06 23:11:51 +0100724 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 -0700725 return 1;
726 };
727
728 /* Always call this - boards that do not support extended bios translation
729 will ignore the command, and we will set the proper default */
730
Ondrej Zary68ea9de2015-02-06 23:11:49 +0100731 aha1542->bios_translation = aha1542_mbenable(sh);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700732
733 return 0;
734}
735
Ondrej Zaryf71429a2015-02-06 23:11:41 +0100736static u8 dma_speed_hw(int dma_speed)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700737{
Ondrej Zaryf71429a2015-02-06 23:11:41 +0100738 switch (dma_speed) {
739 case 5:
740 return 0x00;
741 case 6:
742 return 0x04;
743 case 7:
744 return 0x01;
745 case 8:
746 return 0x02;
747 case 10:
748 return 0x03;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700749 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700750
Ondrej Zaryf71429a2015-02-06 23:11:41 +0100751 return 0xff; /* invalid */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700752}
753
Ondrej Zaryb847fd02015-02-06 23:11:38 +0100754/* Set the Bus on/off-times as not to ruin floppy performance */
Ondrej Zary37d607b2015-02-06 23:11:50 +0100755static 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 +0100756{
Ondrej Zary37d607b2015-02-06 23:11:50 +0100757 if (bus_on > 0) {
758 u8 oncmd[] = { CMD_BUSON_TIME, clamp(bus_on, 2, 15) };
Ondrej Zaryb847fd02015-02-06 23:11:38 +0100759
Ondrej Zary37d607b2015-02-06 23:11:50 +0100760 aha1542_intr_reset(sh->io_port);
761 if (aha1542_out(sh->io_port, oncmd, 2))
Ondrej Zaryf71429a2015-02-06 23:11:41 +0100762 goto fail;
Ondrej Zaryb847fd02015-02-06 23:11:38 +0100763 }
Ondrej Zaryf71429a2015-02-06 23:11:41 +0100764
Ondrej Zary37d607b2015-02-06 23:11:50 +0100765 if (bus_off > 0) {
766 u8 offcmd[] = { CMD_BUSOFF_TIME, clamp(bus_off, 1, 64) };
Ondrej Zaryf71429a2015-02-06 23:11:41 +0100767
Ondrej Zary37d607b2015-02-06 23:11:50 +0100768 aha1542_intr_reset(sh->io_port);
769 if (aha1542_out(sh->io_port, offcmd, 2))
Ondrej Zaryf71429a2015-02-06 23:11:41 +0100770 goto fail;
771 }
772
Ondrej Zary37d607b2015-02-06 23:11:50 +0100773 if (dma_speed_hw(dma_speed) != 0xff) {
774 u8 dmacmd[] = { CMD_DMASPEED, dma_speed_hw(dma_speed) };
Ondrej Zaryf71429a2015-02-06 23:11:41 +0100775
Ondrej Zary37d607b2015-02-06 23:11:50 +0100776 aha1542_intr_reset(sh->io_port);
777 if (aha1542_out(sh->io_port, dmacmd, 2))
Ondrej Zaryb847fd02015-02-06 23:11:38 +0100778 goto fail;
779 }
Ondrej Zary37d607b2015-02-06 23:11:50 +0100780 aha1542_intr_reset(sh->io_port);
Ondrej Zaryb847fd02015-02-06 23:11:38 +0100781 return;
782fail:
Ondrej Zary2906b3c2015-02-06 23:11:51 +0100783 shost_printk(KERN_ERR, sh, "setting bus on/off-time failed\n");
Ondrej Zary37d607b2015-02-06 23:11:50 +0100784 aha1542_intr_reset(sh->io_port);
Ondrej Zaryb847fd02015-02-06 23:11:38 +0100785}
786
Linus Torvalds1da177e2005-04-16 15:20:36 -0700787/* return non-zero on detection */
Ondrej Zary643a7c42015-02-06 23:11:22 +0100788static struct Scsi_Host *aha1542_hw_init(struct scsi_host_template *tpnt, struct device *pdev, int indx)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700789{
Ondrej Zaryf71429a2015-02-06 23:11:41 +0100790 unsigned int base_io = io[indx];
Ondrej Zaryc2532f62015-02-06 23:11:45 +0100791 struct Scsi_Host *sh;
Ondrej Zarye98878f2015-02-06 23:11:25 +0100792 struct aha1542_hostdata *aha1542;
Ondrej Zary2906b3c2015-02-06 23:11:51 +0100793 char dma_info[] = "no DMA";
Linus Torvalds1da177e2005-04-16 15:20:36 -0700794
Ondrej Zary3a70c002015-02-06 23:11:40 +0100795 if (base_io == 0)
796 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700797
Ondrej Zary3a70c002015-02-06 23:11:40 +0100798 if (!request_region(base_io, AHA1542_REGION_SIZE, "aha1542"))
799 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700800
Ondrej Zaryc2532f62015-02-06 23:11:45 +0100801 sh = scsi_host_alloc(tpnt, sizeof(struct aha1542_hostdata));
802 if (!sh)
Ondrej Zary3a70c002015-02-06 23:11:40 +0100803 goto release;
Ondrej Zaryc2532f62015-02-06 23:11:45 +0100804 aha1542 = shost_priv(sh);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700805
Ondrej Zary68ea9de2015-02-06 23:11:49 +0100806 sh->unique_id = base_io;
807 sh->io_port = base_io;
808 sh->n_io_port = AHA1542_REGION_SIZE;
809 aha1542->aha1542_last_mbi_used = 2 * AHA1542_MAILBOXES - 1;
810 aha1542->aha1542_last_mbo_used = AHA1542_MAILBOXES - 1;
811
812 if (!aha1542_test_port(sh))
Ondrej Zary3a70c002015-02-06 23:11:40 +0100813 goto unregister;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700814
Ondrej Zary37d607b2015-02-06 23:11:50 +0100815 aha1542_set_bus_times(sh, bus_on[indx], bus_off[indx], dma_speed[indx]);
Ondrej Zary68ea9de2015-02-06 23:11:49 +0100816 if (aha1542_query(sh))
Ondrej Zary3a70c002015-02-06 23:11:40 +0100817 goto unregister;
Ondrej Zary68ea9de2015-02-06 23:11:49 +0100818 if (aha1542_getconfig(sh) == -1)
Ondrej Zary3a70c002015-02-06 23:11:40 +0100819 goto unregister;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700820
Ondrej Zaryc2532f62015-02-06 23:11:45 +0100821 if (sh->dma_channel != 0xFF)
Ondrej Zary2906b3c2015-02-06 23:11:51 +0100822 snprintf(dma_info, sizeof(dma_info), "DMA %d", sh->dma_channel);
823 shost_printk(KERN_INFO, sh, "Adaptec AHA-1542 (SCSI-ID %d) at IO 0x%x, IRQ %d, %s\n",
824 sh->this_id, base_io, sh->irq, dma_info);
Ondrej Zary3a70c002015-02-06 23:11:40 +0100825 if (aha1542->bios_translation == BIOS_TRANSLATION_25563)
Ondrej Zary2906b3c2015-02-06 23:11:51 +0100826 shost_printk(KERN_INFO, sh, "Using extended bios translation\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700827
Ondrej Zary68ea9de2015-02-06 23:11:49 +0100828 setup_mailboxes(sh);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700829
Ondrej Zaryc2532f62015-02-06 23:11:45 +0100830 if (request_irq(sh->irq, do_aha1542_intr_handle, 0,
831 "aha1542", sh)) {
Ondrej Zary2906b3c2015-02-06 23:11:51 +0100832 shost_printk(KERN_ERR, sh, "Unable to allocate IRQ.\n");
Ondrej Zary3a70c002015-02-06 23:11:40 +0100833 goto unregister;
834 }
Ondrej Zaryc2532f62015-02-06 23:11:45 +0100835 if (sh->dma_channel != 0xFF) {
836 if (request_dma(sh->dma_channel, "aha1542")) {
Ondrej Zary2906b3c2015-02-06 23:11:51 +0100837 shost_printk(KERN_ERR, sh, "Unable to allocate DMA channel.\n");
Ondrej Zary3a70c002015-02-06 23:11:40 +0100838 goto free_irq;
839 }
Ondrej Zaryc2532f62015-02-06 23:11:45 +0100840 if (sh->dma_channel == 0 || sh->dma_channel >= 5) {
841 set_dma_mode(sh->dma_channel, DMA_MODE_CASCADE);
842 enable_dma(sh->dma_channel);
Ondrej Zary3a70c002015-02-06 23:11:40 +0100843 }
844 }
Jeff Garzik87c4d7b2008-04-24 19:45:32 -0400845
Ondrej Zaryc2532f62015-02-06 23:11:45 +0100846 if (scsi_add_host(sh, pdev))
Ondrej Zary3a70c002015-02-06 23:11:40 +0100847 goto free_dma;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700848
Ondrej Zaryc2532f62015-02-06 23:11:45 +0100849 scsi_scan_host(sh);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700850
Ondrej Zaryc2532f62015-02-06 23:11:45 +0100851 return sh;
Ondrej Zary3a70c002015-02-06 23:11:40 +0100852free_dma:
Ondrej Zaryc2532f62015-02-06 23:11:45 +0100853 if (sh->dma_channel != 0xff)
854 free_dma(sh->dma_channel);
Ondrej Zary3a70c002015-02-06 23:11:40 +0100855free_irq:
Ondrej Zaryc2532f62015-02-06 23:11:45 +0100856 free_irq(sh->irq, sh);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700857unregister:
Ondrej Zaryc2532f62015-02-06 23:11:45 +0100858 scsi_host_put(sh);
Ondrej Zary3a70c002015-02-06 23:11:40 +0100859release:
860 release_region(base_io, AHA1542_REGION_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700861
Ondrej Zary643a7c42015-02-06 23:11:22 +0100862 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700863}
864
Ondrej Zaryc2532f62015-02-06 23:11:45 +0100865static int aha1542_release(struct Scsi_Host *sh)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700866{
Ondrej Zaryc2532f62015-02-06 23:11:45 +0100867 scsi_remove_host(sh);
868 if (sh->dma_channel != 0xff)
869 free_dma(sh->dma_channel);
870 if (sh->irq)
871 free_irq(sh->irq, sh);
872 if (sh->io_port && sh->n_io_port)
873 release_region(sh->io_port, sh->n_io_port);
874 scsi_host_put(sh);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700875 return 0;
876}
877
Linus Torvalds1da177e2005-04-16 15:20:36 -0700878
Linus Torvalds1da177e2005-04-16 15:20:36 -0700879/*
880 * This is a device reset. This is handled by sending a special command
881 * to the device.
882 */
Ondrej Zary55b28f92015-02-06 23:11:44 +0100883static int aha1542_dev_reset(struct scsi_cmnd *cmd)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700884{
Ondrej Zary55b28f92015-02-06 23:11:44 +0100885 struct aha1542_hostdata *aha1542 = shost_priv(cmd->device->host);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700886 unsigned long flags;
Ondrej Zarye98878f2015-02-06 23:11:25 +0100887 struct mailbox *mb = aha1542->mb;
Ondrej Zary55b28f92015-02-06 23:11:44 +0100888 u8 target = cmd->device->id;
889 u8 lun = cmd->device->lun;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700890 int mbo;
Ondrej Zarye98878f2015-02-06 23:11:25 +0100891 struct ccb *ccb = aha1542->ccb;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700892
Linus Torvalds1da177e2005-04-16 15:20:36 -0700893 spin_lock_irqsave(&aha1542_lock, flags);
Ondrej Zarye98878f2015-02-06 23:11:25 +0100894 mbo = aha1542->aha1542_last_mbo_used + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700895 if (mbo >= AHA1542_MAILBOXES)
896 mbo = 0;
897
898 do {
Ondrej Zary55b28f92015-02-06 23:11:44 +0100899 if (mb[mbo].status == 0 && aha1542->int_cmds[mbo] == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700900 break;
901 mbo++;
902 if (mbo >= AHA1542_MAILBOXES)
903 mbo = 0;
Ondrej Zarye98878f2015-02-06 23:11:25 +0100904 } while (mbo != aha1542->aha1542_last_mbo_used);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700905
Ondrej Zary55b28f92015-02-06 23:11:44 +0100906 if (mb[mbo].status || aha1542->int_cmds[mbo])
Linus Torvalds1da177e2005-04-16 15:20:36 -0700907 panic("Unable to find empty mailbox for aha1542.\n");
908
Ondrej Zary55b28f92015-02-06 23:11:44 +0100909 aha1542->int_cmds[mbo] = cmd; /* This will effectively
Ondrej Zarye98878f2015-02-06 23:11:25 +0100910 prevent someone else from
911 screwing with this cdb. */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700912
Ondrej Zarye98878f2015-02-06 23:11:25 +0100913 aha1542->aha1542_last_mbo_used = mbo;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700914 spin_unlock_irqrestore(&aha1542_lock, flags);
915
Ondrej Zary10be6252015-02-06 23:11:24 +0100916 any2scsi(mb[mbo].ccbptr, isa_virt_to_bus(&ccb[mbo])); /* This gets trashed for some reason */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700917
918 memset(&ccb[mbo], 0, sizeof(struct ccb));
919
920 ccb[mbo].op = 0x81; /* BUS DEVICE RESET */
921
922 ccb[mbo].idlun = (target & 7) << 5 | (lun & 7); /*SCSI Target Id */
923
924 ccb[mbo].linkptr[0] = ccb[mbo].linkptr[1] = ccb[mbo].linkptr[2] = 0;
925 ccb[mbo].commlinkid = 0;
926
927 /*
928 * Now tell the 1542 to flush all pending commands for this
929 * target
930 */
Ondrej Zary55b28f92015-02-06 23:11:44 +0100931 aha1542_outb(cmd->device->host->io_port, CMD_START_SCSI);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700932
Ondrej Zary55b28f92015-02-06 23:11:44 +0100933 scmd_printk(KERN_WARNING, cmd,
Jeff Garzik017560f2005-10-24 18:04:36 -0400934 "Trying device reset for target\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700935
936 return SUCCESS;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700937}
938
Ondrej Zary55b28f92015-02-06 23:11:44 +0100939static int aha1542_reset(struct scsi_cmnd *cmd, u8 reset_cmd)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700940{
Ondrej Zary55b28f92015-02-06 23:11:44 +0100941 struct aha1542_hostdata *aha1542 = shost_priv(cmd->device->host);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700942 int i;
943
944 /*
945 * This does a scsi reset for all devices on the bus.
946 * In principle, we could also reset the 1542 - should
947 * we do this? Try this first, and we can add that later
948 * if it turns out to be useful.
949 */
Ondrej Zary55b28f92015-02-06 23:11:44 +0100950 outb(reset_cmd, CONTROL(cmd->device->host->io_port));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700951
952 /*
953 * Wait for the thing to settle down a bit. Unfortunately
954 * this is going to basically lock up the machine while we
955 * wait for this to complete. To be 100% correct, we need to
956 * check for timeout, and if we are doing something like this
957 * we are pretty desperate anyways.
958 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700959 ssleep(4);
Ondrej Zary55b28f92015-02-06 23:11:44 +0100960 spin_lock_irq(cmd->device->host->host_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700961
Ondrej Zary55b28f92015-02-06 23:11:44 +0100962 if (!wait_mask(STATUS(cmd->device->host->io_port),
Ondrej Zarya13b3722015-02-06 23:11:34 +0100963 STATMASK, INIT | IDLE, STST | DIAGF | INVDCMD | DF | CDF, 0)) {
Ondrej Zary55b28f92015-02-06 23:11:44 +0100964 spin_unlock_irq(cmd->device->host->host_lock);
Ondrej Zarya13b3722015-02-06 23:11:34 +0100965 return FAILED;
966 }
Ondrej Zary8537cba2015-02-06 23:11:37 +0100967 /*
968 * We need to do this too before the 1542 can interact with
969 * us again after host reset.
970 */
971 if (reset_cmd & HRST)
Ondrej Zary68ea9de2015-02-06 23:11:49 +0100972 setup_mailboxes(cmd->device->host);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700973 /*
974 * Now try to pick up the pieces. For all pending commands,
975 * free any internal data structures, and basically clear things
976 * out. We do not try and restart any commands or anything -
977 * the strategy handler takes care of that crap.
978 */
Ondrej Zary2906b3c2015-02-06 23:11:51 +0100979 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 -0700980
981 for (i = 0; i < AHA1542_MAILBOXES; i++) {
Ondrej Zary55b28f92015-02-06 23:11:44 +0100982 if (aha1542->int_cmds[i] != NULL) {
983 struct scsi_cmnd *tmp_cmd;
984 tmp_cmd = aha1542->int_cmds[i];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700985
Ondrej Zary55b28f92015-02-06 23:11:44 +0100986 if (tmp_cmd->device->soft_reset) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700987 /*
988 * If this device implements the soft reset option,
989 * then it is still holding onto the command, and
990 * may yet complete it. In this case, we don't
991 * flush the data.
992 */
993 continue;
994 }
Ondrej Zary55b28f92015-02-06 23:11:44 +0100995 kfree(tmp_cmd->host_scribble);
996 tmp_cmd->host_scribble = NULL;
997 aha1542->int_cmds[i] = NULL;
Ondrej Zarye98878f2015-02-06 23:11:25 +0100998 aha1542->mb[i].status = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700999 }
1000 }
1001
Ondrej Zary55b28f92015-02-06 23:11:44 +01001002 spin_unlock_irq(cmd->device->host->host_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001003 return SUCCESS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001004}
1005
Ondrej Zary55b28f92015-02-06 23:11:44 +01001006static int aha1542_bus_reset(struct scsi_cmnd *cmd)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001007{
Ondrej Zary55b28f92015-02-06 23:11:44 +01001008 return aha1542_reset(cmd, SCRST);
Ondrej Zary8537cba2015-02-06 23:11:37 +01001009}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001010
Ondrej Zary55b28f92015-02-06 23:11:44 +01001011static int aha1542_host_reset(struct scsi_cmnd *cmd)
Ondrej Zary8537cba2015-02-06 23:11:37 +01001012{
Ondrej Zary55b28f92015-02-06 23:11:44 +01001013 return aha1542_reset(cmd, HRST | SCRST);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001014}
1015
Linus Torvalds1da177e2005-04-16 15:20:36 -07001016static int aha1542_biosparam(struct scsi_device *sdev,
Ondrej Zary17787a02015-02-06 23:11:42 +01001017 struct block_device *bdev, sector_t capacity, int geom[])
Linus Torvalds1da177e2005-04-16 15:20:36 -07001018{
Ondrej Zarye98878f2015-02-06 23:11:25 +01001019 struct aha1542_hostdata *aha1542 = shost_priv(sdev->host);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001020
Ondrej Zary17787a02015-02-06 23:11:42 +01001021 if (capacity >= 0x200000 &&
1022 aha1542->bios_translation == BIOS_TRANSLATION_25563) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001023 /* Please verify that this is the same as what DOS returns */
Ondrej Zary17787a02015-02-06 23:11:42 +01001024 geom[0] = 255; /* heads */
1025 geom[1] = 63; /* sectors */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001026 } else {
Ondrej Zary17787a02015-02-06 23:11:42 +01001027 geom[0] = 64; /* heads */
1028 geom[1] = 32; /* sectors */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001029 }
Ondrej Zary17787a02015-02-06 23:11:42 +01001030 geom[2] = sector_div(capacity, geom[0] * geom[1]); /* cylinders */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001031
1032 return 0;
1033}
1034MODULE_LICENSE("GPL");
1035
Christoph Hellwigd0be4a7d2005-10-31 18:31:40 +01001036static struct scsi_host_template driver_template = {
Ondrej Zary643a7c42015-02-06 23:11:22 +01001037 .module = THIS_MODULE,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001038 .proc_name = "aha1542",
1039 .name = "Adaptec 1542",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001040 .queuecommand = aha1542_queuecommand,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001041 .eh_device_reset_handler= aha1542_dev_reset,
1042 .eh_bus_reset_handler = aha1542_bus_reset,
1043 .eh_host_reset_handler = aha1542_host_reset,
1044 .bios_param = aha1542_biosparam,
1045 .can_queue = AHA1542_MAILBOXES,
1046 .this_id = 7,
Ondrej Zary10be6252015-02-06 23:11:24 +01001047 .sg_tablesize = 16,
1048 .cmd_per_lun = 1,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001049 .unchecked_isa_dma = 1,
1050 .use_clustering = ENABLE_CLUSTERING,
1051};
Ondrej Zary643a7c42015-02-06 23:11:22 +01001052
1053static int aha1542_isa_match(struct device *pdev, unsigned int ndev)
1054{
1055 struct Scsi_Host *sh = aha1542_hw_init(&driver_template, pdev, ndev);
1056
1057 if (!sh)
1058 return 0;
1059
1060 dev_set_drvdata(pdev, sh);
1061 return 1;
1062}
1063
1064static int aha1542_isa_remove(struct device *pdev,
1065 unsigned int ndev)
1066{
1067 aha1542_release(dev_get_drvdata(pdev));
1068 dev_set_drvdata(pdev, NULL);
1069 return 0;
1070}
1071
1072static struct isa_driver aha1542_isa_driver = {
1073 .match = aha1542_isa_match,
1074 .remove = aha1542_isa_remove,
1075 .driver = {
1076 .name = "aha1542"
1077 },
1078};
1079static int isa_registered;
1080
1081#ifdef CONFIG_PNP
1082static struct pnp_device_id aha1542_pnp_ids[] = {
1083 { .id = "ADP1542" },
1084 { .id = "" }
1085};
1086MODULE_DEVICE_TABLE(pnp, aha1542_pnp_ids);
1087
1088static int aha1542_pnp_probe(struct pnp_dev *pdev, const struct pnp_device_id *id)
1089{
1090 int indx;
1091 struct Scsi_Host *sh;
1092
Ondrej Zaryf71429a2015-02-06 23:11:41 +01001093 for (indx = 0; indx < ARRAY_SIZE(io); indx++) {
1094 if (io[indx])
Ondrej Zary643a7c42015-02-06 23:11:22 +01001095 continue;
1096
1097 if (pnp_activate_dev(pdev) < 0)
1098 continue;
1099
Ondrej Zaryf71429a2015-02-06 23:11:41 +01001100 io[indx] = pnp_port_start(pdev, 0);
Ondrej Zary643a7c42015-02-06 23:11:22 +01001101
1102 /* The card can be queried for its DMA, we have
1103 the DMA set up that is enough */
1104
Ondrej Zary2906b3c2015-02-06 23:11:51 +01001105 dev_info(&pdev->dev, "ISAPnP found an AHA1535 at I/O 0x%03X", io[indx]);
Ondrej Zary643a7c42015-02-06 23:11:22 +01001106 }
1107
1108 sh = aha1542_hw_init(&driver_template, &pdev->dev, indx);
1109 if (!sh)
1110 return -ENODEV;
1111
1112 pnp_set_drvdata(pdev, sh);
1113 return 0;
1114}
1115
1116static void aha1542_pnp_remove(struct pnp_dev *pdev)
1117{
1118 aha1542_release(pnp_get_drvdata(pdev));
1119 pnp_set_drvdata(pdev, NULL);
1120}
1121
1122static struct pnp_driver aha1542_pnp_driver = {
1123 .name = "aha1542",
1124 .id_table = aha1542_pnp_ids,
1125 .probe = aha1542_pnp_probe,
1126 .remove = aha1542_pnp_remove,
1127};
1128static int pnp_registered;
1129#endif /* CONFIG_PNP */
1130
1131static int __init aha1542_init(void)
1132{
1133 int ret = 0;
Ondrej Zary643a7c42015-02-06 23:11:22 +01001134
1135#ifdef CONFIG_PNP
1136 if (isapnp) {
1137 ret = pnp_register_driver(&aha1542_pnp_driver);
1138 if (!ret)
1139 pnp_registered = 1;
1140 }
1141#endif
1142 ret = isa_register_driver(&aha1542_isa_driver, MAXBOARDS);
1143 if (!ret)
1144 isa_registered = 1;
1145
1146#ifdef CONFIG_PNP
1147 if (pnp_registered)
1148 ret = 0;
1149#endif
1150 if (isa_registered)
1151 ret = 0;
1152
1153 return ret;
1154}
1155
1156static void __exit aha1542_exit(void)
1157{
1158#ifdef CONFIG_PNP
1159 if (pnp_registered)
1160 pnp_unregister_driver(&aha1542_pnp_driver);
1161#endif
1162 if (isa_registered)
1163 isa_unregister_driver(&aha1542_isa_driver);
1164}
1165
1166module_init(aha1542_init);
1167module_exit(aha1542_exit);