blob: 161586545804c35e4be1ecb9189d9563873ce878 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/* $Id: aha1542.c,v 1.1 1992/07/24 06:27:38 root Exp root $
2 * linux/kernel/aha1542.c
3 *
4 * Copyright (C) 1992 Tommy Thorn
5 * Copyright (C) 1993, 1994, 1995 Eric Youngdale
6 *
7 * Modified by Eric Youngdale
8 * Use request_irq and request_dma to help prevent unexpected conflicts
9 * Set up on-board DMA controller, such that we do not have to
10 * have the bios enabled to use the aha1542.
11 * Modified by David Gentzel
12 * Don't call request_dma if dma mask is 0 (for BusLogic BT-445S VL-Bus
13 * controller).
14 * Modified by Matti Aarnio
15 * Accept parameters from LILO cmd-line. -- 1-Oct-94
16 * Modified by Mike McLagan <mike.mclagan@linux.org>
17 * Recognise extended mode on AHA1542CP, different bit than 1542CF
18 * 1-Jan-97
19 * Modified by Bjorn L. Thordarson and Einar Thor Einarsson
20 * Recognize that DMA0 is valid DMA channel -- 13-Jul-98
21 * Modified by Chris Faulhaber <jedgar@fxp.org>
22 * Added module command-line options
23 * 19-Jul-99
Joe Perches726a6452008-02-03 16:36:24 +020024 * Modified by Adam Fritzler
Paul Gortmakera88dc062012-05-16 20:33:52 -040025 * Added proper detection of the AHA-1640 (MCA, now deleted)
Linus Torvalds1da177e2005-04-16 15:20:36 -070026 */
27
Linus Torvalds1da177e2005-04-16 15:20:36 -070028#include <linux/module.h>
29#include <linux/interrupt.h>
30#include <linux/kernel.h>
31#include <linux/types.h>
32#include <linux/string.h>
33#include <linux/ioport.h>
34#include <linux/delay.h>
35#include <linux/proc_fs.h>
36#include <linux/init.h>
37#include <linux/spinlock.h>
Ondrej Zary643a7c42015-02-06 23:11:22 +010038#include <linux/isa.h>
39#include <linux/pnp.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070040#include <linux/blkdev.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090041#include <linux/slab.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070042
43#include <asm/dma.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070044#include <asm/io.h>
45
46#include "scsi.h"
47#include <scsi/scsi_host.h>
48#include "aha1542.h"
Paul Bolle6ac7d112012-06-06 14:17:46 +020049#include <linux/stat.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070050
51#ifdef DEBUG
52#define DEB(x) x
53#else
54#define DEB(x)
55#endif
Ondrej Zaryf71429a2015-02-06 23:11:41 +010056#define MAXBOARDS 4
Linus Torvalds1da177e2005-04-16 15:20:36 -070057
Ondrej Zaryf71429a2015-02-06 23:11:41 +010058static bool isapnp = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -070059module_param(isapnp, bool, 0);
Ondrej Zaryf71429a2015-02-06 23:11:41 +010060MODULE_PARM_DESC(isapnp, "enable PnP support (default=1)");
61
62static int io[MAXBOARDS] = { 0x330, 0x334, 0, 0 };
63module_param_array(io, int, NULL, 0);
64MODULE_PARM_DESC(io, "base IO address of controller (0x130,0x134,0x230,0x234,0x330,0x334, default=0x330,0x334)");
65
66/* time AHA spends on the AT-bus during data transfer */
67static int bus_on[MAXBOARDS] = { -1, -1, -1, -1 }; /* power-on default: 11us */
68module_param_array(bus_on, int, NULL, 0);
69MODULE_PARM_DESC(bus_on, "bus on time [us] (2-15, default=-1 [HW default: 11])");
70
71/* time AHA spends off the bus (not to monopolize it) during data transfer */
72static int bus_off[MAXBOARDS] = { -1, -1, -1, -1 }; /* power-on default: 4us */
73module_param_array(bus_off, int, NULL, 0);
74MODULE_PARM_DESC(bus_off, "bus off time [us] (1-64, default=-1 [HW default: 4])");
75
76/* default is jumper selected (J1 on 1542A), factory default = 5 MB/s */
77static int dma_speed[MAXBOARDS] = { -1, -1, -1, -1 };
78module_param_array(dma_speed, int, NULL, 0);
79MODULE_PARM_DESC(dma_speed, "DMA speed [MB/s] (5,6,7,8,10, default=-1 [by jumper])");
Linus Torvalds1da177e2005-04-16 15:20:36 -070080
Linus Torvalds1da177e2005-04-16 15:20:36 -070081#define BIOS_TRANSLATION_6432 1 /* Default case these days */
82#define BIOS_TRANSLATION_25563 2 /* Big disk case */
83
84struct aha1542_hostdata {
85 /* This will effectively start both of them at the first mailbox */
86 int bios_translation; /* Mapping bios uses - for compatibility */
87 int aha1542_last_mbi_used;
88 int aha1542_last_mbo_used;
89 Scsi_Cmnd *SCint[AHA1542_MAILBOXES];
90 struct mailbox mb[2 * AHA1542_MAILBOXES];
91 struct ccb ccb[AHA1542_MAILBOXES];
92};
93
Linus Torvalds1da177e2005-04-16 15:20:36 -070094static DEFINE_SPINLOCK(aha1542_lock);
95
Ondrej Zaryf1bbef62015-02-06 23:11:26 +010096static inline void aha1542_intr_reset(u16 base)
97{
98 outb(IRST, CONTROL(base));
99}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700100
Ondrej Zary2093bfa2015-02-06 23:11:31 +0100101static inline bool wait_mask(u16 port, u8 mask, u8 allof, u8 noneof, int timeout)
102{
103 bool delayed = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700104
Ondrej Zary2093bfa2015-02-06 23:11:31 +0100105 if (timeout == 0) {
106 timeout = 3000000;
107 delayed = false;
108 }
109
110 while (1) {
111 u8 bits = inb(port) & mask;
112 if ((bits & allof) == allof && ((bits & noneof) == 0))
113 break;
114 if (delayed)
115 mdelay(1);
116 if (--timeout == 0)
117 return false;
118 }
119
120 return true;
121}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700122
Linus Torvalds1da177e2005-04-16 15:20:36 -0700123/* This is a bit complicated, but we need to make sure that an interrupt
124 routine does not send something out while we are in the middle of this.
125 Fortunately, it is only at boot time that multi-byte messages
126 are ever sent. */
Ondrej Zary0c2b6482015-02-06 23:11:33 +0100127static int aha1542_outb(unsigned int base, u8 cmd)
128{
129 unsigned long flags;
130
131 while (1) {
132 if (!wait_mask(STATUS(base), CDF, 0, CDF, 0)) {
133 printk(KERN_ERR "aha1542_outb failed");
134 return 1;
135 }
136 spin_lock_irqsave(&aha1542_lock, flags);
137 if (inb(STATUS(base)) & CDF) {
138 spin_unlock_irqrestore(&aha1542_lock, flags);
139 continue;
140 }
141 outb(cmd, DATA(base));
142 spin_unlock_irqrestore(&aha1542_lock, flags);
143 return 0;
144 }
145}
146
Ondrej Zarycb5b5702015-02-06 23:11:27 +0100147static int aha1542_out(unsigned int base, u8 *cmdp, int len)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700148{
Ondrej Zary0c2b6482015-02-06 23:11:33 +0100149 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700150
Ondrej Zary0c2b6482015-02-06 23:11:33 +0100151 spin_lock_irqsave(&aha1542_lock, flags);
152 while (len--) {
153 if (!wait_mask(STATUS(base), CDF, 0, CDF, 0)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700154 spin_unlock_irqrestore(&aha1542_lock, flags);
Ondrej Zary0c2b6482015-02-06 23:11:33 +0100155 printk(KERN_ERR "aha1542_out failed(%d): ", len + 1);
156 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700157 }
Ondrej Zary0c2b6482015-02-06 23:11:33 +0100158 outb(*cmdp++, DATA(base));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700159 }
Ondrej Zary0c2b6482015-02-06 23:11:33 +0100160 spin_unlock_irqrestore(&aha1542_lock, flags);
Ondrej Zary23e69402015-02-06 23:11:39 +0100161 if (!wait_mask(INTRFLAGS(base), INTRMASK, HACC, 0, 0))
162 return 1;
Ondrej Zary0c2b6482015-02-06 23:11:33 +0100163
Linus Torvalds1da177e2005-04-16 15:20:36 -0700164 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700165}
166
167/* Only used at boot time, so we do not need to worry about latency as much
168 here */
169
Ondrej Zaryf8846be2015-02-06 23:11:32 +0100170static int aha1542_in(unsigned int base, u8 *cmdp, int len, int timeout)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700171{
172 unsigned long flags;
173
174 spin_lock_irqsave(&aha1542_lock, flags);
175 while (len--) {
Ondrej Zarya13b3722015-02-06 23:11:34 +0100176 if (!wait_mask(STATUS(base), DF, DF, 0, timeout)) {
177 spin_unlock_irqrestore(&aha1542_lock, flags);
178 if (timeout == 0)
179 printk(KERN_ERR "aha1542_in failed(%d): ", len + 1);
180 return 1;
181 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700182 *cmdp++ = inb(DATA(base));
183 }
184 spin_unlock_irqrestore(&aha1542_lock, flags);
185 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700186}
187
188static int makecode(unsigned hosterr, unsigned scsierr)
189{
190 switch (hosterr) {
191 case 0x0:
192 case 0xa: /* Linked command complete without error and linked normally */
193 case 0xb: /* Linked command complete without error, interrupt generated */
194 hosterr = 0;
195 break;
196
197 case 0x11: /* Selection time out-The initiator selection or target
198 reselection was not complete within the SCSI Time out period */
199 hosterr = DID_TIME_OUT;
200 break;
201
202 case 0x12: /* Data overrun/underrun-The target attempted to transfer more data
203 than was allocated by the Data Length field or the sum of the
204 Scatter / Gather Data Length fields. */
205
206 case 0x13: /* Unexpected bus free-The target dropped the SCSI BSY at an unexpected time. */
207
208 case 0x15: /* MBO command was not 00, 01 or 02-The first byte of the CB was
209 invalid. This usually indicates a software failure. */
210
211 case 0x16: /* Invalid CCB Operation Code-The first byte of the CCB was invalid.
212 This usually indicates a software failure. */
213
214 case 0x17: /* Linked CCB does not have the same LUN-A subsequent CCB of a set
215 of linked CCB's does not specify the same logical unit number as
216 the first. */
217 case 0x18: /* Invalid Target Direction received from Host-The direction of a
218 Target Mode CCB was invalid. */
219
220 case 0x19: /* Duplicate CCB Received in Target Mode-More than once CCB was
221 received to service data transfer between the same target LUN
222 and initiator SCSI ID in the same direction. */
223
224 case 0x1a: /* Invalid CCB or Segment List Parameter-A segment list with a zero
225 length segment or invalid segment list boundaries was received.
226 A CCB parameter was invalid. */
227 DEB(printk("Aha1542: %x %x\n", hosterr, scsierr));
228 hosterr = DID_ERROR; /* Couldn't find any better */
229 break;
230
231 case 0x14: /* Target bus phase sequence failure-An invalid bus phase or bus
232 phase sequence was requested by the target. The host adapter
233 will generate a SCSI Reset Condition, notifying the host with
234 a SCRD interrupt */
235 hosterr = DID_RESET;
236 break;
237 default:
238 printk(KERN_ERR "aha1542: makecode: unknown hoststatus %x\n", hosterr);
239 break;
240 }
241 return scsierr | (hosterr << 16);
242}
243
Ondrej Zary643a7c42015-02-06 23:11:22 +0100244static int aha1542_test_port(int bse, struct Scsi_Host *shpnt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700245{
Ondrej Zarycb5b5702015-02-06 23:11:27 +0100246 u8 inquiry_result[4];
247 u8 *cmdp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700248 int len;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700249
250 /* Quick and dirty test for presence of the card. */
251 if (inb(STATUS(bse)) == 0xff)
252 return 0;
253
254 /* Reset the adapter. I ought to make a hard reset, but it's not really necessary */
255
Linus Torvalds1da177e2005-04-16 15:20:36 -0700256 /* In case some other card was probing here, reset interrupts */
257 aha1542_intr_reset(bse); /* reset interrupts, so they don't block */
258
259 outb(SRST | IRST /*|SCRST */ , CONTROL(bse));
260
261 mdelay(20); /* Wait a little bit for things to settle down. */
262
Linus Torvalds1da177e2005-04-16 15:20:36 -0700263 /* Expect INIT and IDLE, any of the others are bad */
Ondrej Zary2093bfa2015-02-06 23:11:31 +0100264 if (!wait_mask(STATUS(bse), STATMASK, INIT | IDLE, STST | DIAGF | INVDCMD | DF | CDF, 0))
Ondrej Zarya13b3722015-02-06 23:11:34 +0100265 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700266
Linus Torvalds1da177e2005-04-16 15:20:36 -0700267 /* Shouldn't have generated any interrupts during reset */
268 if (inb(INTRFLAGS(bse)) & INTRMASK)
Ondrej Zarya13b3722015-02-06 23:11:34 +0100269 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700270
Linus Torvalds1da177e2005-04-16 15:20:36 -0700271 /* Perform a host adapter inquiry instead so we do not need to set
272 up the mailboxes ahead of time */
273
Ondrej Zary0c2b6482015-02-06 23:11:33 +0100274 aha1542_outb(bse, CMD_INQUIRY);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700275
Linus Torvalds1da177e2005-04-16 15:20:36 -0700276 len = 4;
277 cmdp = &inquiry_result[0];
278
279 while (len--) {
Ondrej Zary2093bfa2015-02-06 23:11:31 +0100280 if (!wait_mask(STATUS(bse), DF, DF, 0, 0))
Ondrej Zarya13b3722015-02-06 23:11:34 +0100281 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700282 *cmdp++ = inb(DATA(bse));
283 }
284
Linus Torvalds1da177e2005-04-16 15:20:36 -0700285 /* Reading port should reset DF */
286 if (inb(STATUS(bse)) & DF)
Ondrej Zarya13b3722015-02-06 23:11:34 +0100287 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700288
Linus Torvalds1da177e2005-04-16 15:20:36 -0700289 /* When HACC, command is completed, and we're though testing */
Ondrej Zary2093bfa2015-02-06 23:11:31 +0100290 if (!wait_mask(INTRFLAGS(bse), HACC, HACC, 0, 0))
Ondrej Zarya13b3722015-02-06 23:11:34 +0100291 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700292
Linus Torvalds1da177e2005-04-16 15:20:36 -0700293 /* Clear interrupts */
294 outb(IRST, CONTROL(bse));
295
Ondrej Zarybdebe222015-02-06 23:11:35 +0100296 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700297}
298
Linus Torvalds1da177e2005-04-16 15:20:36 -0700299/* A "high" level interrupt handler */
Jeff Garzik87c4d7b2008-04-24 19:45:32 -0400300static void aha1542_intr_handle(struct Scsi_Host *shost)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700301{
Ondrej Zarye98878f2015-02-06 23:11:25 +0100302 struct aha1542_hostdata *aha1542 = shost_priv(shost);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700303 void (*my_done) (Scsi_Cmnd *) = NULL;
304 int errstatus, mbi, mbo, mbistatus;
305 int number_serviced;
306 unsigned long flags;
307 Scsi_Cmnd *SCtmp;
308 int flag;
Ondrej Zarye98878f2015-02-06 23:11:25 +0100309 struct mailbox *mb = aha1542->mb;
310 struct ccb *ccb = aha1542->ccb;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700311
312#ifdef DEBUG
313 {
314 flag = inb(INTRFLAGS(shost->io_port));
315 printk(KERN_DEBUG "aha1542_intr_handle: ");
316 if (!(flag & ANYINTR))
317 printk("no interrupt?");
318 if (flag & MBIF)
319 printk("MBIF ");
320 if (flag & MBOA)
321 printk("MBOF ");
322 if (flag & HACC)
323 printk("HACC ");
324 if (flag & SCRD)
325 printk("SCRD ");
326 printk("status %02x\n", inb(STATUS(shost->io_port)));
327 };
328#endif
329 number_serviced = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700330
331 while (1 == 1) {
332 flag = inb(INTRFLAGS(shost->io_port));
333
334 /* Check for unusual interrupts. If any of these happen, we should
335 probably do something special, but for now just printing a message
336 is sufficient. A SCSI reset detected is something that we really
337 need to deal with in some way. */
338 if (flag & ~MBIF) {
339 if (flag & MBOA)
340 printk("MBOF ");
341 if (flag & HACC)
342 printk("HACC ");
Ondrej Zarydfd7c992015-02-06 23:11:36 +0100343 if (flag & SCRD)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700344 printk("SCRD ");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700345 }
346 aha1542_intr_reset(shost->io_port);
347
348 spin_lock_irqsave(&aha1542_lock, flags);
Ondrej Zarye98878f2015-02-06 23:11:25 +0100349 mbi = aha1542->aha1542_last_mbi_used + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700350 if (mbi >= 2 * AHA1542_MAILBOXES)
351 mbi = AHA1542_MAILBOXES;
352
353 do {
354 if (mb[mbi].status != 0)
355 break;
356 mbi++;
357 if (mbi >= 2 * AHA1542_MAILBOXES)
358 mbi = AHA1542_MAILBOXES;
Ondrej Zarye98878f2015-02-06 23:11:25 +0100359 } while (mbi != aha1542->aha1542_last_mbi_used);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700360
361 if (mb[mbi].status == 0) {
362 spin_unlock_irqrestore(&aha1542_lock, flags);
363 /* Hmm, no mail. Must have read it the last time around */
Ondrej Zarydfd7c992015-02-06 23:11:36 +0100364 if (!number_serviced)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700365 printk(KERN_WARNING "aha1542.c: interrupt received, but no mail.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700366 return;
367 };
368
Ondrej Zary10be6252015-02-06 23:11:24 +0100369 mbo = (scsi2int(mb[mbi].ccbptr) - (isa_virt_to_bus(&ccb[0]))) / sizeof(struct ccb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700370 mbistatus = mb[mbi].status;
371 mb[mbi].status = 0;
Ondrej Zarye98878f2015-02-06 23:11:25 +0100372 aha1542->aha1542_last_mbi_used = mbi;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700373 spin_unlock_irqrestore(&aha1542_lock, flags);
374
375#ifdef DEBUG
376 {
377 if (ccb[mbo].tarstat | ccb[mbo].hastat)
378 printk(KERN_DEBUG "aha1542_command: returning %x (status %d)\n",
379 ccb[mbo].tarstat + ((int) ccb[mbo].hastat << 16), mb[mbi].status);
380 };
381#endif
382
383 if (mbistatus == 3)
384 continue; /* Aborted command not found */
385
386#ifdef DEBUG
387 printk(KERN_DEBUG "...done %d %d\n", mbo, mbi);
388#endif
389
Ondrej Zarye98878f2015-02-06 23:11:25 +0100390 SCtmp = aha1542->SCint[mbo];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700391
392 if (!SCtmp || !SCtmp->scsi_done) {
393 printk(KERN_WARNING "aha1542_intr_handle: Unexpected interrupt\n");
394 printk(KERN_WARNING "tarstat=%x, hastat=%x idlun=%x ccb#=%d \n", ccb[mbo].tarstat,
395 ccb[mbo].hastat, ccb[mbo].idlun, mbo);
396 return;
397 }
398 my_done = SCtmp->scsi_done;
Jesper Juhlc9475cb2005-11-07 01:01:26 -0800399 kfree(SCtmp->host_scribble);
400 SCtmp->host_scribble = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700401 /* Fetch the sense data, and tuck it away, in the required slot. The
402 Adaptec automatically fetches it, and there is no guarantee that
403 we will still have it in the cdb when we come back */
404 if (ccb[mbo].tarstat == 2)
405 memcpy(SCtmp->sense_buffer, &ccb[mbo].cdb[ccb[mbo].cdblen],
FUJITA Tomonorib80ca4f2008-01-13 15:46:13 +0900406 SCSI_SENSE_BUFFERSIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700407
408
409 /* is there mail :-) */
410
411 /* more error checking left out here */
412 if (mbistatus != 1)
413 /* This is surely wrong, but I don't know what's right */
414 errstatus = makecode(ccb[mbo].hastat, ccb[mbo].tarstat);
415 else
416 errstatus = 0;
417
418#ifdef DEBUG
419 if (errstatus)
420 printk(KERN_DEBUG "(aha1542 error:%x %x %x) ", errstatus,
421 ccb[mbo].hastat, ccb[mbo].tarstat);
422#endif
423
424 if (ccb[mbo].tarstat == 2) {
425#ifdef DEBUG
426 int i;
427#endif
428 DEB(printk("aha1542_intr_handle: sense:"));
429#ifdef DEBUG
430 for (i = 0; i < 12; i++)
431 printk("%02x ", ccb[mbo].cdb[ccb[mbo].cdblen + i]);
432 printk("\n");
433#endif
434 /*
435 DEB(printk("aha1542_intr_handle: buf:"));
436 for (i = 0; i < bufflen; i++)
437 printk("%02x ", ((unchar *)buff)[i]);
438 printk("\n");
439 */
440 }
441 DEB(if (errstatus) printk("aha1542_intr_handle: returning %6x\n", errstatus));
442 SCtmp->result = errstatus;
Ondrej Zarye98878f2015-02-06 23:11:25 +0100443 aha1542->SCint[mbo] = NULL; /* This effectively frees up the mailbox slot, as
444 far as queuecommand is concerned */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700445 my_done(SCtmp);
446 number_serviced++;
447 };
448}
449
Ondrej Zary09a44832015-02-06 23:11:28 +0100450/* A quick wrapper for do_aha1542_intr_handle to grab the spin lock */
451static irqreturn_t do_aha1542_intr_handle(int dummy, void *dev_id)
452{
453 unsigned long flags;
454 struct Scsi_Host *shost = dev_id;
455
456 spin_lock_irqsave(shost->host_lock, flags);
457 aha1542_intr_handle(shost);
458 spin_unlock_irqrestore(shost->host_lock, flags);
459 return IRQ_HANDLED;
460}
461
Jeff Garzikf2812332010-11-16 02:10:29 -0500462static int aha1542_queuecommand_lck(Scsi_Cmnd * SCpnt, void (*done) (Scsi_Cmnd *))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700463{
Ondrej Zarye98878f2015-02-06 23:11:25 +0100464 struct aha1542_hostdata *aha1542 = shost_priv(SCpnt->device->host);
Ondrej Zarycb5b5702015-02-06 23:11:27 +0100465 u8 direction;
466 u8 *cmd = (u8 *) SCpnt->cmnd;
467 u8 target = SCpnt->device->id;
468 u8 lun = SCpnt->device->lun;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700469 unsigned long flags;
Boaz Harroshfc3fdfc2007-09-09 21:02:45 +0300470 int bufflen = scsi_bufflen(SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700471 int mbo;
Ondrej Zarye98878f2015-02-06 23:11:25 +0100472 struct mailbox *mb = aha1542->mb;
473 struct ccb *ccb = aha1542->ccb;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700474
475 DEB(int i);
476
Linus Torvalds1da177e2005-04-16 15:20:36 -0700477 DEB(if (target > 1) {
478 SCpnt->result = DID_TIME_OUT << 16;
479 done(SCpnt); return 0;
480 }
481 );
482
483 if (*cmd == REQUEST_SENSE) {
484 /* Don't do the command - we have the sense data already */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700485 SCpnt->result = 0;
486 done(SCpnt);
487 return 0;
488 }
489#ifdef DEBUG
490 if (*cmd == READ_10 || *cmd == WRITE_10)
491 i = xscsi2int(cmd + 2);
492 else if (*cmd == READ_6 || *cmd == WRITE_6)
493 i = scsi2int(cmd + 2);
494 else
495 i = -1;
496 if (done)
497 printk(KERN_DEBUG "aha1542_queuecommand: dev %d cmd %02x pos %d len %d ", target, *cmd, i, bufflen);
498 else
499 printk(KERN_DEBUG "aha1542_command: dev %d cmd %02x pos %d len %d ", target, *cmd, i, bufflen);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700500 printk(KERN_DEBUG "aha1542_queuecommand: dumping scsi cmd:");
501 for (i = 0; i < SCpnt->cmd_len; i++)
502 printk("%02x ", cmd[i]);
503 printk("\n");
504 if (*cmd == WRITE_10 || *cmd == WRITE_6)
505 return 0; /* we are still testing, so *don't* write */
506#endif
507 /* Use the outgoing mailboxes in a round-robin fashion, because this
508 is how the host adapter will scan for them */
509
510 spin_lock_irqsave(&aha1542_lock, flags);
Ondrej Zarye98878f2015-02-06 23:11:25 +0100511 mbo = aha1542->aha1542_last_mbo_used + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700512 if (mbo >= AHA1542_MAILBOXES)
513 mbo = 0;
514
515 do {
Ondrej Zarye98878f2015-02-06 23:11:25 +0100516 if (mb[mbo].status == 0 && aha1542->SCint[mbo] == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700517 break;
518 mbo++;
519 if (mbo >= AHA1542_MAILBOXES)
520 mbo = 0;
Ondrej Zarye98878f2015-02-06 23:11:25 +0100521 } while (mbo != aha1542->aha1542_last_mbo_used);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700522
Ondrej Zarye98878f2015-02-06 23:11:25 +0100523 if (mb[mbo].status || aha1542->SCint[mbo])
Linus Torvalds1da177e2005-04-16 15:20:36 -0700524 panic("Unable to find empty mailbox for aha1542.\n");
525
Ondrej Zarye98878f2015-02-06 23:11:25 +0100526 aha1542->SCint[mbo] = SCpnt; /* This will effectively prevent someone else from
527 screwing with this cdb. */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700528
Ondrej Zarye98878f2015-02-06 23:11:25 +0100529 aha1542->aha1542_last_mbo_used = mbo;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700530 spin_unlock_irqrestore(&aha1542_lock, flags);
531
532#ifdef DEBUG
533 printk(KERN_DEBUG "Sending command (%d %x)...", mbo, done);
534#endif
535
Ondrej Zary10be6252015-02-06 23:11:24 +0100536 any2scsi(mb[mbo].ccbptr, isa_virt_to_bus(&ccb[mbo])); /* This gets trashed for some reason */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700537
538 memset(&ccb[mbo], 0, sizeof(struct ccb));
539
540 ccb[mbo].cdblen = SCpnt->cmd_len;
541
542 direction = 0;
543 if (*cmd == READ_10 || *cmd == READ_6)
544 direction = 8;
545 else if (*cmd == WRITE_10 || *cmd == WRITE_6)
546 direction = 16;
547
548 memcpy(ccb[mbo].cdb, cmd, ccb[mbo].cdblen);
549
Boaz Harroshfc3fdfc2007-09-09 21:02:45 +0300550 if (bufflen) {
Jens Axboe51cf2242007-07-16 10:00:31 +0200551 struct scatterlist *sg;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700552 struct chain *cptr;
553#ifdef DEBUG
554 unsigned char *ptr;
555#endif
Boaz Harroshfc3fdfc2007-09-09 21:02:45 +0300556 int i, sg_count = scsi_sg_count(SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700557 ccb[mbo].op = 2; /* SCSI Initiator Command w/scatter-gather */
Boaz Harroshfc3fdfc2007-09-09 21:02:45 +0300558 SCpnt->host_scribble = kmalloc(sizeof(*cptr)*sg_count,
559 GFP_KERNEL | GFP_DMA);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700560 cptr = (struct chain *) SCpnt->host_scribble;
561 if (cptr == NULL) {
562 /* free the claimed mailbox slot */
Ondrej Zarye98878f2015-02-06 23:11:25 +0100563 aha1542->SCint[mbo] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700564 return SCSI_MLQUEUE_HOST_BUSY;
565 }
Boaz Harroshfc3fdfc2007-09-09 21:02:45 +0300566 scsi_for_each_sg(SCpnt, sg, sg_count, i) {
Ondrej Zary10be6252015-02-06 23:11:24 +0100567 any2scsi(cptr[i].dataptr, isa_page_to_bus(sg_page(sg))
568 + sg->offset);
Jens Axboe51cf2242007-07-16 10:00:31 +0200569 any2scsi(cptr[i].datalen, sg->length);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700570 };
Boaz Harroshfc3fdfc2007-09-09 21:02:45 +0300571 any2scsi(ccb[mbo].datalen, sg_count * sizeof(struct chain));
Ondrej Zary10be6252015-02-06 23:11:24 +0100572 any2scsi(ccb[mbo].dataptr, isa_virt_to_bus(cptr));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700573#ifdef DEBUG
574 printk("cptr %x: ", cptr);
575 ptr = (unsigned char *) cptr;
576 for (i = 0; i < 18; i++)
577 printk("%02x ", ptr[i]);
578#endif
579 } else {
580 ccb[mbo].op = 0; /* SCSI Initiator Command */
581 SCpnt->host_scribble = NULL;
Boaz Harroshfc3fdfc2007-09-09 21:02:45 +0300582 any2scsi(ccb[mbo].datalen, 0);
583 any2scsi(ccb[mbo].dataptr, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700584 };
585 ccb[mbo].idlun = (target & 7) << 5 | direction | (lun & 7); /*SCSI Target Id */
586 ccb[mbo].rsalen = 16;
587 ccb[mbo].linkptr[0] = ccb[mbo].linkptr[1] = ccb[mbo].linkptr[2] = 0;
588 ccb[mbo].commlinkid = 0;
589
590#ifdef DEBUG
591 {
592 int i;
593 printk(KERN_DEBUG "aha1542_command: sending.. ");
594 for (i = 0; i < sizeof(ccb[mbo]) - 10; i++)
Ondrej Zarycb5b5702015-02-06 23:11:27 +0100595 printk("%02x ", ((u8 *) &ccb[mbo])[i]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700596 };
597#endif
598
599 if (done) {
Ondrej Zaryf232d532015-02-06 23:11:29 +0100600 DEB(printk("aha1542_queuecommand: now waiting for interrupt "));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700601 SCpnt->scsi_done = done;
602 mb[mbo].status = 1;
Ondrej Zary0c2b6482015-02-06 23:11:33 +0100603 aha1542_outb(SCpnt->device->host->io_port, CMD_START_SCSI);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700604 } else
605 printk("aha1542_queuecommand: done can't be NULL\n");
606
607 return 0;
608}
609
Jeff Garzikf2812332010-11-16 02:10:29 -0500610static DEF_SCSI_QCMD(aha1542_queuecommand)
611
Linus Torvalds1da177e2005-04-16 15:20:36 -0700612/* Initialize mailboxes */
613static void setup_mailboxes(int bse, struct Scsi_Host *shpnt)
614{
Ondrej Zarye98878f2015-02-06 23:11:25 +0100615 struct aha1542_hostdata *aha1542 = shost_priv(shpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700616 int i;
Ondrej Zarye98878f2015-02-06 23:11:25 +0100617 struct mailbox *mb = aha1542->mb;
618 struct ccb *ccb = aha1542->ccb;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700619
Ondrej Zarycb5b5702015-02-06 23:11:27 +0100620 u8 cmd[5] = { CMD_MBINIT, AHA1542_MAILBOXES, 0, 0, 0};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700621
Linus Torvalds1da177e2005-04-16 15:20:36 -0700622 for (i = 0; i < AHA1542_MAILBOXES; i++) {
623 mb[i].status = mb[AHA1542_MAILBOXES + i].status = 0;
Ondrej Zary10be6252015-02-06 23:11:24 +0100624 any2scsi(mb[i].ccbptr, isa_virt_to_bus(&ccb[i]));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700625 };
626 aha1542_intr_reset(bse); /* reset interrupts, so they don't block */
Ondrej Zary10be6252015-02-06 23:11:24 +0100627 any2scsi((cmd + 2), isa_virt_to_bus(mb));
Ondrej Zary23e69402015-02-06 23:11:39 +0100628 if (aha1542_out(bse, cmd, 5))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700629 printk(KERN_ERR "aha1542_detect: failed setting up mailboxes\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700630 aha1542_intr_reset(bse);
631}
632
Ondrej Zary3a70c002015-02-06 23:11:40 +0100633static int aha1542_getconfig(int base_io, unsigned int *irq_level, unsigned char *dma_chan, unsigned int *scsi_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700634{
Ondrej Zarycb5b5702015-02-06 23:11:27 +0100635 u8 inquiry_result[3];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700636 int i;
637 i = inb(STATUS(base_io));
638 if (i & DF) {
639 i = inb(DATA(base_io));
640 };
Ondrej Zary0c2b6482015-02-06 23:11:33 +0100641 aha1542_outb(base_io, CMD_RETCONF);
Ondrej Zaryf8846be2015-02-06 23:11:32 +0100642 aha1542_in(base_io, inquiry_result, 3, 0);
Ondrej Zary2093bfa2015-02-06 23:11:31 +0100643 if (!wait_mask(INTRFLAGS(base_io), INTRMASK, HACC, 0, 0))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700644 printk(KERN_ERR "aha1542_detect: query board settings\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700645 aha1542_intr_reset(base_io);
646 switch (inquiry_result[0]) {
647 case 0x80:
648 *dma_chan = 7;
649 break;
650 case 0x40:
651 *dma_chan = 6;
652 break;
653 case 0x20:
654 *dma_chan = 5;
655 break;
656 case 0x01:
657 *dma_chan = 0;
658 break;
659 case 0:
660 /* This means that the adapter, although Adaptec 1542 compatible, doesn't use a DMA channel.
661 Currently only aware of the BusLogic BT-445S VL-Bus adapter which needs this. */
662 *dma_chan = 0xFF;
663 break;
664 default:
665 printk(KERN_ERR "Unable to determine Adaptec DMA priority. Disabling board\n");
666 return -1;
667 };
668 switch (inquiry_result[1]) {
669 case 0x40:
670 *irq_level = 15;
671 break;
672 case 0x20:
673 *irq_level = 14;
674 break;
675 case 0x8:
676 *irq_level = 12;
677 break;
678 case 0x4:
679 *irq_level = 11;
680 break;
681 case 0x2:
682 *irq_level = 10;
683 break;
684 case 0x1:
685 *irq_level = 9;
686 break;
687 default:
688 printk(KERN_ERR "Unable to determine Adaptec IRQ level. Disabling board\n");
689 return -1;
690 };
691 *scsi_id = inquiry_result[2] & 7;
692 return 0;
693}
694
695/* This function should only be called for 1542C boards - we can detect
696 the special firmware settings and unlock the board */
697
Ondrej Zary643a7c42015-02-06 23:11:22 +0100698static int aha1542_mbenable(int base)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700699{
Ondrej Zarycb5b5702015-02-06 23:11:27 +0100700 static u8 mbenable_cmd[3];
701 static u8 mbenable_result[2];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700702 int retval;
703
704 retval = BIOS_TRANSLATION_6432;
705
Ondrej Zary0c2b6482015-02-06 23:11:33 +0100706 aha1542_outb(base, CMD_EXTBIOS);
Ondrej Zaryf8846be2015-02-06 23:11:32 +0100707 if (aha1542_in(base, mbenable_result, 2, 100))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700708 return retval;
Ondrej Zary2093bfa2015-02-06 23:11:31 +0100709 if (!wait_mask(INTRFLAGS(base), INTRMASK, HACC, 0, 100))
710 goto fail;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700711 aha1542_intr_reset(base);
712
713 if ((mbenable_result[0] & 0x08) || mbenable_result[1]) {
714 mbenable_cmd[0] = CMD_MBENABLE;
715 mbenable_cmd[1] = 0;
716 mbenable_cmd[2] = mbenable_result[1];
717
718 if ((mbenable_result[0] & 0x08) && (mbenable_result[1] & 0x03))
719 retval = BIOS_TRANSLATION_25563;
720
Ondrej Zary23e69402015-02-06 23:11:39 +0100721 if (aha1542_out(base, mbenable_cmd, 3))
Ondrej Zary2093bfa2015-02-06 23:11:31 +0100722 goto fail;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700723 };
724 while (0) {
725fail:
726 printk(KERN_ERR "aha1542_mbenable: Mailbox init failed\n");
727 }
728 aha1542_intr_reset(base);
729 return retval;
730}
731
732/* Query the board to find out if it is a 1542 or a 1740, or whatever. */
Ondrej Zary643a7c42015-02-06 23:11:22 +0100733static int aha1542_query(int base_io, int *transl)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700734{
Ondrej Zarycb5b5702015-02-06 23:11:27 +0100735 u8 inquiry_result[4];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700736 int i;
737 i = inb(STATUS(base_io));
738 if (i & DF) {
739 i = inb(DATA(base_io));
740 };
Ondrej Zary0c2b6482015-02-06 23:11:33 +0100741 aha1542_outb(base_io, CMD_INQUIRY);
Ondrej Zaryf8846be2015-02-06 23:11:32 +0100742 aha1542_in(base_io, inquiry_result, 4, 0);
Ondrej Zary2093bfa2015-02-06 23:11:31 +0100743 if (!wait_mask(INTRFLAGS(base_io), INTRMASK, HACC, 0, 0))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700744 printk(KERN_ERR "aha1542_detect: query card type\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700745 aha1542_intr_reset(base_io);
746
747 *transl = BIOS_TRANSLATION_6432; /* Default case */
748
749 /* For an AHA1740 series board, we ignore the board since there is a
750 hardware bug which can lead to wrong blocks being returned if the board
751 is operating in the 1542 emulation mode. Since there is an extended mode
752 driver, we simply ignore the board and let the 1740 driver pick it up.
753 */
754
755 if (inquiry_result[0] == 0x43) {
756 printk(KERN_INFO "aha1542.c: Emulation mode not supported for AHA 174N hardware.\n");
757 return 1;
758 };
759
760 /* Always call this - boards that do not support extended bios translation
761 will ignore the command, and we will set the proper default */
762
763 *transl = aha1542_mbenable(base_io);
764
765 return 0;
766}
767
Ondrej Zaryf71429a2015-02-06 23:11:41 +0100768static u8 dma_speed_hw(int dma_speed)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700769{
Ondrej Zaryf71429a2015-02-06 23:11:41 +0100770 switch (dma_speed) {
771 case 5:
772 return 0x00;
773 case 6:
774 return 0x04;
775 case 7:
776 return 0x01;
777 case 8:
778 return 0x02;
779 case 10:
780 return 0x03;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700781 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700782
Ondrej Zaryf71429a2015-02-06 23:11:41 +0100783 return 0xff; /* invalid */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700784}
785
Ondrej Zaryb847fd02015-02-06 23:11:38 +0100786/* Set the Bus on/off-times as not to ruin floppy performance */
787static void aha1542_set_bus_times(int indx)
788{
Ondrej Zaryf71429a2015-02-06 23:11:41 +0100789 unsigned int base_io = io[indx];
Ondrej Zaryb847fd02015-02-06 23:11:38 +0100790
Ondrej Zaryf71429a2015-02-06 23:11:41 +0100791 if (bus_on[indx] > 0) {
792 u8 oncmd[] = { CMD_BUSON_TIME, clamp(bus_on[indx], 2, 15) };
793
794 aha1542_intr_reset(base_io);
795 if (aha1542_out(base_io, oncmd, 2))
796 goto fail;
Ondrej Zaryb847fd02015-02-06 23:11:38 +0100797 }
Ondrej Zaryf71429a2015-02-06 23:11:41 +0100798
799 if (bus_off[indx] > 0) {
800 u8 offcmd[] = { CMD_BUSOFF_TIME, clamp(bus_off[indx], 1, 64) };
801
802 aha1542_intr_reset(base_io);
803 if (aha1542_out(base_io, offcmd, 2))
804 goto fail;
805 }
806
807 if (dma_speed_hw(dma_speed[indx]) != 0xff) {
808 u8 dmacmd[] = { CMD_DMASPEED, dma_speed_hw(dma_speed[indx]) };
809
Ondrej Zaryb847fd02015-02-06 23:11:38 +0100810 aha1542_intr_reset(base_io);
Ondrej Zary23e69402015-02-06 23:11:39 +0100811 if (aha1542_out(base_io, dmacmd, 2))
Ondrej Zaryb847fd02015-02-06 23:11:38 +0100812 goto fail;
813 }
814 aha1542_intr_reset(base_io);
815 return;
816fail:
817 printk(KERN_ERR "setting bus on/off-time failed\n");
818 aha1542_intr_reset(base_io);
819}
820
Linus Torvalds1da177e2005-04-16 15:20:36 -0700821/* return non-zero on detection */
Ondrej Zary643a7c42015-02-06 23:11:22 +0100822static struct Scsi_Host *aha1542_hw_init(struct scsi_host_template *tpnt, struct device *pdev, int indx)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700823{
Ondrej Zaryf71429a2015-02-06 23:11:41 +0100824 unsigned int base_io = io[indx];
Ondrej Zary3a70c002015-02-06 23:11:40 +0100825 struct Scsi_Host *shpnt;
Ondrej Zarye98878f2015-02-06 23:11:25 +0100826 struct aha1542_hostdata *aha1542;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700827
Ondrej Zary3a70c002015-02-06 23:11:40 +0100828 if (base_io == 0)
829 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700830
Ondrej Zary3a70c002015-02-06 23:11:40 +0100831 if (!request_region(base_io, AHA1542_REGION_SIZE, "aha1542"))
832 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700833
Ondrej Zary3a70c002015-02-06 23:11:40 +0100834 shpnt = scsi_host_alloc(tpnt, sizeof(struct aha1542_hostdata));
835 if (!shpnt)
836 goto release;
837 aha1542 = shost_priv(shpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700838
Ondrej Zary3a70c002015-02-06 23:11:40 +0100839 if (!aha1542_test_port(base_io, shpnt))
840 goto unregister;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700841
Ondrej Zary3a70c002015-02-06 23:11:40 +0100842 aha1542_set_bus_times(indx);
843 if (aha1542_query(base_io, &aha1542->bios_translation))
844 goto unregister;
845 if (aha1542_getconfig(base_io, &shpnt->irq, &shpnt->dma_channel, &shpnt->this_id) == -1)
846 goto unregister;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700847
Ondrej Zary3a70c002015-02-06 23:11:40 +0100848 printk(KERN_INFO "Adaptec AHA-1542 (SCSI-ID %d) at IO 0x%x, IRQ %d", shpnt->this_id, base_io, shpnt->irq);
849 if (shpnt->dma_channel != 0xFF)
850 printk(", DMA %d", shpnt->dma_channel);
851 printk("\n");
852 if (aha1542->bios_translation == BIOS_TRANSLATION_25563)
853 printk(KERN_INFO "aha1542.c: Using extended bios translation\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700854
Ondrej Zary3a70c002015-02-06 23:11:40 +0100855 setup_mailboxes(base_io, shpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700856
Ondrej Zary3a70c002015-02-06 23:11:40 +0100857 if (request_irq(shpnt->irq, do_aha1542_intr_handle, 0,
Jeff Garzik87c4d7b2008-04-24 19:45:32 -0400858 "aha1542", shpnt)) {
Ondrej Zary3a70c002015-02-06 23:11:40 +0100859 printk(KERN_ERR "Unable to allocate IRQ for adaptec controller.\n");
860 goto unregister;
861 }
862 if (shpnt->dma_channel != 0xFF) {
863 if (request_dma(shpnt->dma_channel, "aha1542")) {
864 printk(KERN_ERR "Unable to allocate DMA channel for Adaptec.\n");
865 goto free_irq;
866 }
867 if (shpnt->dma_channel == 0 || shpnt->dma_channel >= 5) {
868 set_dma_mode(shpnt->dma_channel, DMA_MODE_CASCADE);
869 enable_dma(shpnt->dma_channel);
870 }
871 }
Jeff Garzik87c4d7b2008-04-24 19:45:32 -0400872
Ondrej Zary3a70c002015-02-06 23:11:40 +0100873 shpnt->unique_id = base_io;
874 shpnt->io_port = base_io;
875 shpnt->n_io_port = AHA1542_REGION_SIZE;
876 aha1542->aha1542_last_mbi_used = 2 * AHA1542_MAILBOXES - 1;
877 aha1542->aha1542_last_mbo_used = AHA1542_MAILBOXES - 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700878
Ondrej Zary3a70c002015-02-06 23:11:40 +0100879 if (scsi_add_host(shpnt, pdev))
880 goto free_dma;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700881
Ondrej Zary3a70c002015-02-06 23:11:40 +0100882 scsi_scan_host(shpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700883
Ondrej Zary3a70c002015-02-06 23:11:40 +0100884 return shpnt;
885free_dma:
886 if (shpnt->dma_channel != 0xff)
887 free_dma(shpnt->dma_channel);
888free_irq:
889 free_irq(shpnt->irq, shpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700890unregister:
Ondrej Zary3a70c002015-02-06 23:11:40 +0100891 scsi_host_put(shpnt);
892release:
893 release_region(base_io, AHA1542_REGION_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700894
Ondrej Zary643a7c42015-02-06 23:11:22 +0100895 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700896}
897
898static int aha1542_release(struct Scsi_Host *shost)
899{
Ondrej Zary643a7c42015-02-06 23:11:22 +0100900 scsi_remove_host(shost);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700901 if (shost->dma_channel != 0xff)
902 free_dma(shost->dma_channel);
Ondrej Zary3a70c002015-02-06 23:11:40 +0100903 if (shost->irq)
904 free_irq(shost->irq, shost);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700905 if (shost->io_port && shost->n_io_port)
906 release_region(shost->io_port, shost->n_io_port);
Ondrej Zary643a7c42015-02-06 23:11:22 +0100907 scsi_host_put(shost);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700908 return 0;
909}
910
Linus Torvalds1da177e2005-04-16 15:20:36 -0700911
Linus Torvalds1da177e2005-04-16 15:20:36 -0700912/*
913 * This is a device reset. This is handled by sending a special command
914 * to the device.
915 */
916static int aha1542_dev_reset(Scsi_Cmnd * SCpnt)
917{
Ondrej Zarye98878f2015-02-06 23:11:25 +0100918 struct aha1542_hostdata *aha1542 = shost_priv(SCpnt->device->host);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700919 unsigned long flags;
Ondrej Zarye98878f2015-02-06 23:11:25 +0100920 struct mailbox *mb = aha1542->mb;
Ondrej Zarycb5b5702015-02-06 23:11:27 +0100921 u8 target = SCpnt->device->id;
922 u8 lun = SCpnt->device->lun;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700923 int mbo;
Ondrej Zarye98878f2015-02-06 23:11:25 +0100924 struct ccb *ccb = aha1542->ccb;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700925
Linus Torvalds1da177e2005-04-16 15:20:36 -0700926 spin_lock_irqsave(&aha1542_lock, flags);
Ondrej Zarye98878f2015-02-06 23:11:25 +0100927 mbo = aha1542->aha1542_last_mbo_used + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700928 if (mbo >= AHA1542_MAILBOXES)
929 mbo = 0;
930
931 do {
Ondrej Zarye98878f2015-02-06 23:11:25 +0100932 if (mb[mbo].status == 0 && aha1542->SCint[mbo] == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700933 break;
934 mbo++;
935 if (mbo >= AHA1542_MAILBOXES)
936 mbo = 0;
Ondrej Zarye98878f2015-02-06 23:11:25 +0100937 } while (mbo != aha1542->aha1542_last_mbo_used);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700938
Ondrej Zarye98878f2015-02-06 23:11:25 +0100939 if (mb[mbo].status || aha1542->SCint[mbo])
Linus Torvalds1da177e2005-04-16 15:20:36 -0700940 panic("Unable to find empty mailbox for aha1542.\n");
941
Ondrej Zarye98878f2015-02-06 23:11:25 +0100942 aha1542->SCint[mbo] = SCpnt; /* This will effectively
943 prevent someone else from
944 screwing with this cdb. */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700945
Ondrej Zarye98878f2015-02-06 23:11:25 +0100946 aha1542->aha1542_last_mbo_used = mbo;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700947 spin_unlock_irqrestore(&aha1542_lock, flags);
948
Ondrej Zary10be6252015-02-06 23:11:24 +0100949 any2scsi(mb[mbo].ccbptr, isa_virt_to_bus(&ccb[mbo])); /* This gets trashed for some reason */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700950
951 memset(&ccb[mbo], 0, sizeof(struct ccb));
952
953 ccb[mbo].op = 0x81; /* BUS DEVICE RESET */
954
955 ccb[mbo].idlun = (target & 7) << 5 | (lun & 7); /*SCSI Target Id */
956
957 ccb[mbo].linkptr[0] = ccb[mbo].linkptr[1] = ccb[mbo].linkptr[2] = 0;
958 ccb[mbo].commlinkid = 0;
959
960 /*
961 * Now tell the 1542 to flush all pending commands for this
962 * target
963 */
Ondrej Zary0c2b6482015-02-06 23:11:33 +0100964 aha1542_outb(SCpnt->device->host->io_port, CMD_START_SCSI);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700965
Jeff Garzik017560f2005-10-24 18:04:36 -0400966 scmd_printk(KERN_WARNING, SCpnt,
967 "Trying device reset for target\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700968
969 return SUCCESS;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700970}
971
Ondrej Zary8537cba2015-02-06 23:11:37 +0100972static int aha1542_reset(Scsi_Cmnd *SCpnt, u8 reset_cmd)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700973{
Ondrej Zarye98878f2015-02-06 23:11:25 +0100974 struct aha1542_hostdata *aha1542 = shost_priv(SCpnt->device->host);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700975 int i;
976
977 /*
978 * This does a scsi reset for all devices on the bus.
979 * In principle, we could also reset the 1542 - should
980 * we do this? Try this first, and we can add that later
981 * if it turns out to be useful.
982 */
Ondrej Zary8537cba2015-02-06 23:11:37 +0100983 outb(reset_cmd, CONTROL(SCpnt->device->host->io_port));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700984
985 /*
986 * Wait for the thing to settle down a bit. Unfortunately
987 * this is going to basically lock up the machine while we
988 * wait for this to complete. To be 100% correct, we need to
989 * check for timeout, and if we are doing something like this
990 * we are pretty desperate anyways.
991 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700992 ssleep(4);
993 spin_lock_irq(SCpnt->device->host->host_lock);
994
Ondrej Zary2093bfa2015-02-06 23:11:31 +0100995 if (!wait_mask(STATUS(SCpnt->device->host->io_port),
Ondrej Zarya13b3722015-02-06 23:11:34 +0100996 STATMASK, INIT | IDLE, STST | DIAGF | INVDCMD | DF | CDF, 0)) {
997 spin_unlock_irq(SCpnt->device->host->host_lock);
998 return FAILED;
999 }
Ondrej Zary8537cba2015-02-06 23:11:37 +01001000 /*
1001 * We need to do this too before the 1542 can interact with
1002 * us again after host reset.
1003 */
1004 if (reset_cmd & HRST)
1005 setup_mailboxes(SCpnt->device->host->io_port, SCpnt->device->host);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001006 /*
1007 * Now try to pick up the pieces. For all pending commands,
1008 * free any internal data structures, and basically clear things
1009 * out. We do not try and restart any commands or anything -
1010 * the strategy handler takes care of that crap.
1011 */
1012 printk(KERN_WARNING "Sent BUS RESET to scsi host %d\n", SCpnt->device->host->host_no);
1013
1014 for (i = 0; i < AHA1542_MAILBOXES; i++) {
Ondrej Zarye98878f2015-02-06 23:11:25 +01001015 if (aha1542->SCint[i] != NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001016 Scsi_Cmnd *SCtmp;
Ondrej Zarye98878f2015-02-06 23:11:25 +01001017 SCtmp = aha1542->SCint[i];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001018
Linus Torvalds1da177e2005-04-16 15:20:36 -07001019 if (SCtmp->device->soft_reset) {
1020 /*
1021 * If this device implements the soft reset option,
1022 * then it is still holding onto the command, and
1023 * may yet complete it. In this case, we don't
1024 * flush the data.
1025 */
1026 continue;
1027 }
Jesper Juhlc9475cb2005-11-07 01:01:26 -08001028 kfree(SCtmp->host_scribble);
1029 SCtmp->host_scribble = NULL;
Ondrej Zarye98878f2015-02-06 23:11:25 +01001030 aha1542->SCint[i] = NULL;
1031 aha1542->mb[i].status = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001032 }
1033 }
1034
Jeff Garzik 68b3aa72005-05-28 07:56:31 -04001035 spin_unlock_irq(SCpnt->device->host->host_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001036 return SUCCESS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001037}
1038
Ondrej Zary8537cba2015-02-06 23:11:37 +01001039static int aha1542_bus_reset(Scsi_Cmnd *SCpnt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001040{
Ondrej Zary8537cba2015-02-06 23:11:37 +01001041 return aha1542_reset(SCpnt, SCRST);
1042}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001043
Ondrej Zary8537cba2015-02-06 23:11:37 +01001044static int aha1542_host_reset(Scsi_Cmnd *SCpnt)
1045{
1046 return aha1542_reset(SCpnt, HRST | SCRST);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001047}
1048
Linus Torvalds1da177e2005-04-16 15:20:36 -07001049static int aha1542_biosparam(struct scsi_device *sdev,
Ondrej Zary17787a02015-02-06 23:11:42 +01001050 struct block_device *bdev, sector_t capacity, int geom[])
Linus Torvalds1da177e2005-04-16 15:20:36 -07001051{
Ondrej Zarye98878f2015-02-06 23:11:25 +01001052 struct aha1542_hostdata *aha1542 = shost_priv(sdev->host);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001053
Ondrej Zary17787a02015-02-06 23:11:42 +01001054 if (capacity >= 0x200000 &&
1055 aha1542->bios_translation == BIOS_TRANSLATION_25563) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001056 /* Please verify that this is the same as what DOS returns */
Ondrej Zary17787a02015-02-06 23:11:42 +01001057 geom[0] = 255; /* heads */
1058 geom[1] = 63; /* sectors */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001059 } else {
Ondrej Zary17787a02015-02-06 23:11:42 +01001060 geom[0] = 64; /* heads */
1061 geom[1] = 32; /* sectors */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001062 }
Ondrej Zary17787a02015-02-06 23:11:42 +01001063 geom[2] = sector_div(capacity, geom[0] * geom[1]); /* cylinders */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001064
1065 return 0;
1066}
1067MODULE_LICENSE("GPL");
1068
Christoph Hellwigd0be4a7d2005-10-31 18:31:40 +01001069static struct scsi_host_template driver_template = {
Ondrej Zary643a7c42015-02-06 23:11:22 +01001070 .module = THIS_MODULE,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001071 .proc_name = "aha1542",
1072 .name = "Adaptec 1542",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001073 .queuecommand = aha1542_queuecommand,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001074 .eh_device_reset_handler= aha1542_dev_reset,
1075 .eh_bus_reset_handler = aha1542_bus_reset,
1076 .eh_host_reset_handler = aha1542_host_reset,
1077 .bios_param = aha1542_biosparam,
1078 .can_queue = AHA1542_MAILBOXES,
1079 .this_id = 7,
Ondrej Zary10be6252015-02-06 23:11:24 +01001080 .sg_tablesize = 16,
1081 .cmd_per_lun = 1,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001082 .unchecked_isa_dma = 1,
1083 .use_clustering = ENABLE_CLUSTERING,
1084};
Ondrej Zary643a7c42015-02-06 23:11:22 +01001085
1086static int aha1542_isa_match(struct device *pdev, unsigned int ndev)
1087{
1088 struct Scsi_Host *sh = aha1542_hw_init(&driver_template, pdev, ndev);
1089
1090 if (!sh)
1091 return 0;
1092
1093 dev_set_drvdata(pdev, sh);
1094 return 1;
1095}
1096
1097static int aha1542_isa_remove(struct device *pdev,
1098 unsigned int ndev)
1099{
1100 aha1542_release(dev_get_drvdata(pdev));
1101 dev_set_drvdata(pdev, NULL);
1102 return 0;
1103}
1104
1105static struct isa_driver aha1542_isa_driver = {
1106 .match = aha1542_isa_match,
1107 .remove = aha1542_isa_remove,
1108 .driver = {
1109 .name = "aha1542"
1110 },
1111};
1112static int isa_registered;
1113
1114#ifdef CONFIG_PNP
1115static struct pnp_device_id aha1542_pnp_ids[] = {
1116 { .id = "ADP1542" },
1117 { .id = "" }
1118};
1119MODULE_DEVICE_TABLE(pnp, aha1542_pnp_ids);
1120
1121static int aha1542_pnp_probe(struct pnp_dev *pdev, const struct pnp_device_id *id)
1122{
1123 int indx;
1124 struct Scsi_Host *sh;
1125
Ondrej Zaryf71429a2015-02-06 23:11:41 +01001126 for (indx = 0; indx < ARRAY_SIZE(io); indx++) {
1127 if (io[indx])
Ondrej Zary643a7c42015-02-06 23:11:22 +01001128 continue;
1129
1130 if (pnp_activate_dev(pdev) < 0)
1131 continue;
1132
Ondrej Zaryf71429a2015-02-06 23:11:41 +01001133 io[indx] = pnp_port_start(pdev, 0);
Ondrej Zary643a7c42015-02-06 23:11:22 +01001134
1135 /* The card can be queried for its DMA, we have
1136 the DMA set up that is enough */
1137
Ondrej Zaryf71429a2015-02-06 23:11:41 +01001138 printk(KERN_INFO "ISAPnP found an AHA1535 at I/O 0x%03X\n", io[indx]);
Ondrej Zary643a7c42015-02-06 23:11:22 +01001139 }
1140
1141 sh = aha1542_hw_init(&driver_template, &pdev->dev, indx);
1142 if (!sh)
1143 return -ENODEV;
1144
1145 pnp_set_drvdata(pdev, sh);
1146 return 0;
1147}
1148
1149static void aha1542_pnp_remove(struct pnp_dev *pdev)
1150{
1151 aha1542_release(pnp_get_drvdata(pdev));
1152 pnp_set_drvdata(pdev, NULL);
1153}
1154
1155static struct pnp_driver aha1542_pnp_driver = {
1156 .name = "aha1542",
1157 .id_table = aha1542_pnp_ids,
1158 .probe = aha1542_pnp_probe,
1159 .remove = aha1542_pnp_remove,
1160};
1161static int pnp_registered;
1162#endif /* CONFIG_PNP */
1163
1164static int __init aha1542_init(void)
1165{
1166 int ret = 0;
Ondrej Zary643a7c42015-02-06 23:11:22 +01001167
1168#ifdef CONFIG_PNP
1169 if (isapnp) {
1170 ret = pnp_register_driver(&aha1542_pnp_driver);
1171 if (!ret)
1172 pnp_registered = 1;
1173 }
1174#endif
1175 ret = isa_register_driver(&aha1542_isa_driver, MAXBOARDS);
1176 if (!ret)
1177 isa_registered = 1;
1178
1179#ifdef CONFIG_PNP
1180 if (pnp_registered)
1181 ret = 0;
1182#endif
1183 if (isa_registered)
1184 ret = 0;
1185
1186 return ret;
1187}
1188
1189static void __exit aha1542_exit(void)
1190{
1191#ifdef CONFIG_PNP
1192 if (pnp_registered)
1193 pnp_unregister_driver(&aha1542_pnp_driver);
1194#endif
1195 if (isa_registered)
1196 isa_unregister_driver(&aha1542_isa_driver);
1197}
1198
1199module_init(aha1542_init);
1200module_exit(aha1542_exit);