blob: 6d4532c5185e3e72b3703ec433641e26b0b904e2 [file] [log] [blame]
Ondrej Zary1d084d22015-02-06 23:11:47 +01001/*
2 * Driver for Adaptec AHA-1542 SCSI host adapters
Linus Torvalds1da177e2005-04-16 15:20:36 -07003 *
4 * Copyright (C) 1992 Tommy Thorn
5 * Copyright (C) 1993, 1994, 1995 Eric Youngdale
Ondrej Zary1d084d22015-02-06 23:11:47 +01006 * Copyright (C) 2015 Ondrej Zary
Linus Torvalds1da177e2005-04-16 15:20:36 -07007 */
8
Linus Torvalds1da177e2005-04-16 15:20:36 -07009#include <linux/module.h>
10#include <linux/interrupt.h>
11#include <linux/kernel.h>
12#include <linux/types.h>
13#include <linux/string.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070014#include <linux/delay.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070015#include <linux/init.h>
16#include <linux/spinlock.h>
Ondrej Zary643a7c42015-02-06 23:11:22 +010017#include <linux/isa.h>
18#include <linux/pnp.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090019#include <linux/slab.h>
Ondrej Zary954a9fd2015-02-06 23:11:48 +010020#include <linux/io.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070021#include <asm/dma.h>
Ondrej Zary954a9fd2015-02-06 23:11:48 +010022#include <scsi/scsi_cmnd.h>
23#include <scsi/scsi_device.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070024#include <scsi/scsi_host.h>
25#include "aha1542.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070026
Ondrej Zaryf71429a2015-02-06 23:11:41 +010027#define MAXBOARDS 4
Linus Torvalds1da177e2005-04-16 15:20:36 -070028
Ondrej Zaryf71429a2015-02-06 23:11:41 +010029static bool isapnp = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -070030module_param(isapnp, bool, 0);
Ondrej Zaryf71429a2015-02-06 23:11:41 +010031MODULE_PARM_DESC(isapnp, "enable PnP support (default=1)");
32
33static int io[MAXBOARDS] = { 0x330, 0x334, 0, 0 };
34module_param_array(io, int, NULL, 0);
35MODULE_PARM_DESC(io, "base IO address of controller (0x130,0x134,0x230,0x234,0x330,0x334, default=0x330,0x334)");
36
37/* time AHA spends on the AT-bus during data transfer */
38static int bus_on[MAXBOARDS] = { -1, -1, -1, -1 }; /* power-on default: 11us */
39module_param_array(bus_on, int, NULL, 0);
40MODULE_PARM_DESC(bus_on, "bus on time [us] (2-15, default=-1 [HW default: 11])");
41
42/* time AHA spends off the bus (not to monopolize it) during data transfer */
43static int bus_off[MAXBOARDS] = { -1, -1, -1, -1 }; /* power-on default: 4us */
44module_param_array(bus_off, int, NULL, 0);
45MODULE_PARM_DESC(bus_off, "bus off time [us] (1-64, default=-1 [HW default: 4])");
46
47/* default is jumper selected (J1 on 1542A), factory default = 5 MB/s */
48static int dma_speed[MAXBOARDS] = { -1, -1, -1, -1 };
49module_param_array(dma_speed, int, NULL, 0);
50MODULE_PARM_DESC(dma_speed, "DMA speed [MB/s] (5,6,7,8,10, default=-1 [by jumper])");
Linus Torvalds1da177e2005-04-16 15:20:36 -070051
Linus Torvalds1da177e2005-04-16 15:20:36 -070052#define BIOS_TRANSLATION_6432 1 /* Default case these days */
53#define BIOS_TRANSLATION_25563 2 /* Big disk case */
54
55struct aha1542_hostdata {
56 /* This will effectively start both of them at the first mailbox */
57 int bios_translation; /* Mapping bios uses - for compatibility */
58 int aha1542_last_mbi_used;
59 int aha1542_last_mbo_used;
Ondrej Zary55b28f92015-02-06 23:11:44 +010060 struct scsi_cmnd *int_cmds[AHA1542_MAILBOXES];
Linus Torvalds1da177e2005-04-16 15:20:36 -070061 struct mailbox mb[2 * AHA1542_MAILBOXES];
62 struct ccb ccb[AHA1542_MAILBOXES];
63};
64
Linus Torvalds1da177e2005-04-16 15:20:36 -070065static DEFINE_SPINLOCK(aha1542_lock);
66
Ondrej Zaryf1bbef62015-02-06 23:11:26 +010067static inline void aha1542_intr_reset(u16 base)
68{
69 outb(IRST, CONTROL(base));
70}
Linus Torvalds1da177e2005-04-16 15:20:36 -070071
Ondrej Zary2093bfa2015-02-06 23:11:31 +010072static inline bool wait_mask(u16 port, u8 mask, u8 allof, u8 noneof, int timeout)
73{
74 bool delayed = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -070075
Ondrej Zary2093bfa2015-02-06 23:11:31 +010076 if (timeout == 0) {
77 timeout = 3000000;
78 delayed = false;
79 }
80
81 while (1) {
82 u8 bits = inb(port) & mask;
83 if ((bits & allof) == allof && ((bits & noneof) == 0))
84 break;
85 if (delayed)
86 mdelay(1);
87 if (--timeout == 0)
88 return false;
89 }
90
91 return true;
92}
Linus Torvalds1da177e2005-04-16 15:20:36 -070093
Linus Torvalds1da177e2005-04-16 15:20:36 -070094/* This is a bit complicated, but we need to make sure that an interrupt
95 routine does not send something out while we are in the middle of this.
96 Fortunately, it is only at boot time that multi-byte messages
97 are ever sent. */
Ondrej Zarycad2fc72015-02-06 23:11:43 +010098static int aha1542_outb(unsigned int base, u8 val)
Ondrej Zary0c2b6482015-02-06 23:11:33 +010099{
100 unsigned long flags;
101
102 while (1) {
Ondrej Zary2906b3c2015-02-06 23:11:51 +0100103 if (!wait_mask(STATUS(base), CDF, 0, CDF, 0))
Ondrej Zary0c2b6482015-02-06 23:11:33 +0100104 return 1;
Ondrej Zary0c2b6482015-02-06 23:11:33 +0100105 spin_lock_irqsave(&aha1542_lock, flags);
106 if (inb(STATUS(base)) & CDF) {
107 spin_unlock_irqrestore(&aha1542_lock, flags);
108 continue;
109 }
Ondrej Zarycad2fc72015-02-06 23:11:43 +0100110 outb(val, DATA(base));
Ondrej Zary0c2b6482015-02-06 23:11:33 +0100111 spin_unlock_irqrestore(&aha1542_lock, flags);
112 return 0;
113 }
114}
115
Ondrej Zarycad2fc72015-02-06 23:11:43 +0100116static int aha1542_out(unsigned int base, u8 *buf, int len)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700117{
Ondrej Zary0c2b6482015-02-06 23:11:33 +0100118 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700119
Ondrej Zary0c2b6482015-02-06 23:11:33 +0100120 spin_lock_irqsave(&aha1542_lock, flags);
121 while (len--) {
122 if (!wait_mask(STATUS(base), CDF, 0, CDF, 0)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700123 spin_unlock_irqrestore(&aha1542_lock, flags);
Ondrej Zary0c2b6482015-02-06 23:11:33 +0100124 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700125 }
Ondrej Zarycad2fc72015-02-06 23:11:43 +0100126 outb(*buf++, DATA(base));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700127 }
Ondrej Zary0c2b6482015-02-06 23:11:33 +0100128 spin_unlock_irqrestore(&aha1542_lock, flags);
Ondrej Zary23e69402015-02-06 23:11:39 +0100129 if (!wait_mask(INTRFLAGS(base), INTRMASK, HACC, 0, 0))
130 return 1;
Ondrej Zary0c2b6482015-02-06 23:11:33 +0100131
Linus Torvalds1da177e2005-04-16 15:20:36 -0700132 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700133}
134
135/* Only used at boot time, so we do not need to worry about latency as much
136 here */
137
Ondrej Zarycad2fc72015-02-06 23:11:43 +0100138static int aha1542_in(unsigned int base, u8 *buf, int len, int timeout)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700139{
140 unsigned long flags;
141
142 spin_lock_irqsave(&aha1542_lock, flags);
143 while (len--) {
Ondrej Zarya13b3722015-02-06 23:11:34 +0100144 if (!wait_mask(STATUS(base), DF, DF, 0, timeout)) {
145 spin_unlock_irqrestore(&aha1542_lock, flags);
Ondrej Zarya13b3722015-02-06 23:11:34 +0100146 return 1;
147 }
Ondrej Zarycad2fc72015-02-06 23:11:43 +0100148 *buf++ = inb(DATA(base));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700149 }
150 spin_unlock_irqrestore(&aha1542_lock, flags);
151 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700152}
153
154static int makecode(unsigned hosterr, unsigned scsierr)
155{
156 switch (hosterr) {
157 case 0x0:
158 case 0xa: /* Linked command complete without error and linked normally */
159 case 0xb: /* Linked command complete without error, interrupt generated */
160 hosterr = 0;
161 break;
162
163 case 0x11: /* Selection time out-The initiator selection or target
164 reselection was not complete within the SCSI Time out period */
165 hosterr = DID_TIME_OUT;
166 break;
167
168 case 0x12: /* Data overrun/underrun-The target attempted to transfer more data
169 than was allocated by the Data Length field or the sum of the
170 Scatter / Gather Data Length fields. */
171
172 case 0x13: /* Unexpected bus free-The target dropped the SCSI BSY at an unexpected time. */
173
174 case 0x15: /* MBO command was not 00, 01 or 02-The first byte of the CB was
175 invalid. This usually indicates a software failure. */
176
177 case 0x16: /* Invalid CCB Operation Code-The first byte of the CCB was invalid.
178 This usually indicates a software failure. */
179
180 case 0x17: /* Linked CCB does not have the same LUN-A subsequent CCB of a set
181 of linked CCB's does not specify the same logical unit number as
182 the first. */
183 case 0x18: /* Invalid Target Direction received from Host-The direction of a
184 Target Mode CCB was invalid. */
185
186 case 0x19: /* Duplicate CCB Received in Target Mode-More than once CCB was
187 received to service data transfer between the same target LUN
188 and initiator SCSI ID in the same direction. */
189
190 case 0x1a: /* Invalid CCB or Segment List Parameter-A segment list with a zero
191 length segment or invalid segment list boundaries was received.
192 A CCB parameter was invalid. */
Ondrej Zaryfde1fb82015-02-06 23:11:52 +0100193#ifdef DEBUG
194 printk("Aha1542: %x %x\n", hosterr, scsierr);
195#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700196 hosterr = DID_ERROR; /* Couldn't find any better */
197 break;
198
199 case 0x14: /* Target bus phase sequence failure-An invalid bus phase or bus
200 phase sequence was requested by the target. The host adapter
201 will generate a SCSI Reset Condition, notifying the host with
202 a SCRD interrupt */
203 hosterr = DID_RESET;
204 break;
205 default:
206 printk(KERN_ERR "aha1542: makecode: unknown hoststatus %x\n", hosterr);
207 break;
208 }
209 return scsierr | (hosterr << 16);
210}
211
Ondrej Zary68ea9de2015-02-06 23:11:49 +0100212static int aha1542_test_port(struct Scsi_Host *sh)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700213{
Ondrej Zarycb5b5702015-02-06 23:11:27 +0100214 u8 inquiry_result[4];
Ondrej Zarycad2fc72015-02-06 23:11:43 +0100215 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700216
217 /* Quick and dirty test for presence of the card. */
Ondrej Zary68ea9de2015-02-06 23:11:49 +0100218 if (inb(STATUS(sh->io_port)) == 0xff)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700219 return 0;
220
221 /* Reset the adapter. I ought to make a hard reset, but it's not really necessary */
222
Linus Torvalds1da177e2005-04-16 15:20:36 -0700223 /* In case some other card was probing here, reset interrupts */
Ondrej Zary68ea9de2015-02-06 23:11:49 +0100224 aha1542_intr_reset(sh->io_port); /* reset interrupts, so they don't block */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700225
Ondrej Zary68ea9de2015-02-06 23:11:49 +0100226 outb(SRST | IRST /*|SCRST */ , CONTROL(sh->io_port));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700227
228 mdelay(20); /* Wait a little bit for things to settle down. */
229
Linus Torvalds1da177e2005-04-16 15:20:36 -0700230 /* Expect INIT and IDLE, any of the others are bad */
Ondrej Zary68ea9de2015-02-06 23:11:49 +0100231 if (!wait_mask(STATUS(sh->io_port), STATMASK, INIT | IDLE, STST | DIAGF | INVDCMD | DF | CDF, 0))
Ondrej Zarya13b3722015-02-06 23:11:34 +0100232 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700233
Linus Torvalds1da177e2005-04-16 15:20:36 -0700234 /* Shouldn't have generated any interrupts during reset */
Ondrej Zary68ea9de2015-02-06 23:11:49 +0100235 if (inb(INTRFLAGS(sh->io_port)) & INTRMASK)
Ondrej Zarya13b3722015-02-06 23:11:34 +0100236 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700237
Linus Torvalds1da177e2005-04-16 15:20:36 -0700238 /* Perform a host adapter inquiry instead so we do not need to set
239 up the mailboxes ahead of time */
240
Ondrej Zary68ea9de2015-02-06 23:11:49 +0100241 aha1542_outb(sh->io_port, CMD_INQUIRY);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700242
Ondrej Zarycad2fc72015-02-06 23:11:43 +0100243 for (i = 0; i < 4; i++) {
Ondrej Zary68ea9de2015-02-06 23:11:49 +0100244 if (!wait_mask(STATUS(sh->io_port), DF, DF, 0, 0))
Ondrej Zarya13b3722015-02-06 23:11:34 +0100245 return 0;
Ondrej Zary68ea9de2015-02-06 23:11:49 +0100246 inquiry_result[i] = inb(DATA(sh->io_port));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700247 }
248
Linus Torvalds1da177e2005-04-16 15:20:36 -0700249 /* Reading port should reset DF */
Ondrej Zary68ea9de2015-02-06 23:11:49 +0100250 if (inb(STATUS(sh->io_port)) & DF)
Ondrej Zarya13b3722015-02-06 23:11:34 +0100251 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700252
Linus Torvalds1da177e2005-04-16 15:20:36 -0700253 /* When HACC, command is completed, and we're though testing */
Ondrej Zary68ea9de2015-02-06 23:11:49 +0100254 if (!wait_mask(INTRFLAGS(sh->io_port), HACC, HACC, 0, 0))
Ondrej Zarya13b3722015-02-06 23:11:34 +0100255 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700256
Linus Torvalds1da177e2005-04-16 15:20:36 -0700257 /* Clear interrupts */
Ondrej Zary68ea9de2015-02-06 23:11:49 +0100258 outb(IRST, CONTROL(sh->io_port));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700259
Ondrej Zarybdebe222015-02-06 23:11:35 +0100260 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700261}
262
Linus Torvalds1da177e2005-04-16 15:20:36 -0700263/* A "high" level interrupt handler */
Ondrej Zaryc2532f62015-02-06 23:11:45 +0100264static void aha1542_intr_handle(struct Scsi_Host *sh)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700265{
Ondrej Zaryc2532f62015-02-06 23:11:45 +0100266 struct aha1542_hostdata *aha1542 = shost_priv(sh);
Ondrej Zary55b28f92015-02-06 23:11:44 +0100267 void (*my_done)(struct scsi_cmnd *) = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700268 int errstatus, mbi, mbo, mbistatus;
269 int number_serviced;
270 unsigned long flags;
Ondrej Zary55b28f92015-02-06 23:11:44 +0100271 struct scsi_cmnd *tmp_cmd;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700272 int flag;
Ondrej Zarye98878f2015-02-06 23:11:25 +0100273 struct mailbox *mb = aha1542->mb;
274 struct ccb *ccb = aha1542->ccb;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700275
276#ifdef DEBUG
277 {
Ondrej Zaryc2532f62015-02-06 23:11:45 +0100278 flag = inb(INTRFLAGS(sh->io_port));
Ondrej Zary2906b3c2015-02-06 23:11:51 +0100279 shost_printk(KERN_DEBUG, sh, "aha1542_intr_handle: ");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700280 if (!(flag & ANYINTR))
281 printk("no interrupt?");
282 if (flag & MBIF)
283 printk("MBIF ");
284 if (flag & MBOA)
285 printk("MBOF ");
286 if (flag & HACC)
287 printk("HACC ");
288 if (flag & SCRD)
289 printk("SCRD ");
Ondrej Zaryc2532f62015-02-06 23:11:45 +0100290 printk("status %02x\n", inb(STATUS(sh->io_port)));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700291 };
292#endif
293 number_serviced = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700294
295 while (1 == 1) {
Ondrej Zaryc2532f62015-02-06 23:11:45 +0100296 flag = inb(INTRFLAGS(sh->io_port));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700297
298 /* Check for unusual interrupts. If any of these happen, we should
299 probably do something special, but for now just printing a message
300 is sufficient. A SCSI reset detected is something that we really
301 need to deal with in some way. */
302 if (flag & ~MBIF) {
303 if (flag & MBOA)
304 printk("MBOF ");
305 if (flag & HACC)
306 printk("HACC ");
Ondrej Zarydfd7c992015-02-06 23:11:36 +0100307 if (flag & SCRD)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700308 printk("SCRD ");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700309 }
Ondrej Zaryc2532f62015-02-06 23:11:45 +0100310 aha1542_intr_reset(sh->io_port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700311
312 spin_lock_irqsave(&aha1542_lock, flags);
Ondrej Zarye98878f2015-02-06 23:11:25 +0100313 mbi = aha1542->aha1542_last_mbi_used + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700314 if (mbi >= 2 * AHA1542_MAILBOXES)
315 mbi = AHA1542_MAILBOXES;
316
317 do {
318 if (mb[mbi].status != 0)
319 break;
320 mbi++;
321 if (mbi >= 2 * AHA1542_MAILBOXES)
322 mbi = AHA1542_MAILBOXES;
Ondrej Zarye98878f2015-02-06 23:11:25 +0100323 } while (mbi != aha1542->aha1542_last_mbi_used);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700324
325 if (mb[mbi].status == 0) {
326 spin_unlock_irqrestore(&aha1542_lock, flags);
327 /* Hmm, no mail. Must have read it the last time around */
Ondrej Zarydfd7c992015-02-06 23:11:36 +0100328 if (!number_serviced)
Ondrej Zary2906b3c2015-02-06 23:11:51 +0100329 shost_printk(KERN_WARNING, sh, "interrupt received, but no mail.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700330 return;
331 };
332
Ondrej Zary10be6252015-02-06 23:11:24 +0100333 mbo = (scsi2int(mb[mbi].ccbptr) - (isa_virt_to_bus(&ccb[0]))) / sizeof(struct ccb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700334 mbistatus = mb[mbi].status;
335 mb[mbi].status = 0;
Ondrej Zarye98878f2015-02-06 23:11:25 +0100336 aha1542->aha1542_last_mbi_used = mbi;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700337 spin_unlock_irqrestore(&aha1542_lock, flags);
338
339#ifdef DEBUG
Ondrej Zaryfde1fb82015-02-06 23:11:52 +0100340 if (ccb[mbo].tarstat | ccb[mbo].hastat)
341 shost_printk(KERN_DEBUG, sh, "aha1542_command: returning %x (status %d)\n",
342 ccb[mbo].tarstat + ((int) ccb[mbo].hastat << 16), mb[mbi].status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700343#endif
344
345 if (mbistatus == 3)
346 continue; /* Aborted command not found */
347
348#ifdef DEBUG
Ondrej Zary2906b3c2015-02-06 23:11:51 +0100349 shost_printk(KERN_DEBUG, sh, "...done %d %d\n", mbo, mbi);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700350#endif
351
Ondrej Zary55b28f92015-02-06 23:11:44 +0100352 tmp_cmd = aha1542->int_cmds[mbo];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700353
Ondrej Zary55b28f92015-02-06 23:11:44 +0100354 if (!tmp_cmd || !tmp_cmd->scsi_done) {
Ondrej Zary2906b3c2015-02-06 23:11:51 +0100355 shost_printk(KERN_WARNING, sh, "Unexpected interrupt\n");
356 shost_printk(KERN_WARNING, sh, "tarstat=%x, hastat=%x idlun=%x ccb#=%d\n", ccb[mbo].tarstat,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700357 ccb[mbo].hastat, ccb[mbo].idlun, mbo);
358 return;
359 }
Ondrej Zary55b28f92015-02-06 23:11:44 +0100360 my_done = tmp_cmd->scsi_done;
361 kfree(tmp_cmd->host_scribble);
362 tmp_cmd->host_scribble = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700363 /* Fetch the sense data, and tuck it away, in the required slot. The
364 Adaptec automatically fetches it, and there is no guarantee that
365 we will still have it in the cdb when we come back */
366 if (ccb[mbo].tarstat == 2)
Ondrej Zary55b28f92015-02-06 23:11:44 +0100367 memcpy(tmp_cmd->sense_buffer, &ccb[mbo].cdb[ccb[mbo].cdblen],
FUJITA Tomonorib80ca4f2008-01-13 15:46:13 +0900368 SCSI_SENSE_BUFFERSIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700369
370
371 /* is there mail :-) */
372
373 /* more error checking left out here */
374 if (mbistatus != 1)
375 /* This is surely wrong, but I don't know what's right */
376 errstatus = makecode(ccb[mbo].hastat, ccb[mbo].tarstat);
377 else
378 errstatus = 0;
379
380#ifdef DEBUG
381 if (errstatus)
Ondrej Zary2906b3c2015-02-06 23:11:51 +0100382 shost_printk(KERN_DEBUG, sh, "(aha1542 error:%x %x %x) ", errstatus,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700383 ccb[mbo].hastat, ccb[mbo].tarstat);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700384 if (ccb[mbo].tarstat == 2) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700385 int i;
Ondrej Zaryfde1fb82015-02-06 23:11:52 +0100386
387 printk("aha1542_intr_handle: sense:");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700388 for (i = 0; i < 12; i++)
389 printk("%02x ", ccb[mbo].cdb[ccb[mbo].cdblen + i]);
390 printk("\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700391 }
Ondrej Zaryfde1fb82015-02-06 23:11:52 +0100392 if (errstatus)
393 printk("aha1542_intr_handle: returning %6x\n", errstatus);
394#endif
Ondrej Zary55b28f92015-02-06 23:11:44 +0100395 tmp_cmd->result = errstatus;
396 aha1542->int_cmds[mbo] = NULL; /* This effectively frees up the mailbox slot, as
Ondrej Zarye98878f2015-02-06 23:11:25 +0100397 far as queuecommand is concerned */
Ondrej Zary55b28f92015-02-06 23:11:44 +0100398 my_done(tmp_cmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700399 number_serviced++;
400 };
401}
402
Ondrej Zary09a44832015-02-06 23:11:28 +0100403/* A quick wrapper for do_aha1542_intr_handle to grab the spin lock */
404static irqreturn_t do_aha1542_intr_handle(int dummy, void *dev_id)
405{
406 unsigned long flags;
Ondrej Zaryc2532f62015-02-06 23:11:45 +0100407 struct Scsi_Host *sh = dev_id;
Ondrej Zary09a44832015-02-06 23:11:28 +0100408
Ondrej Zaryc2532f62015-02-06 23:11:45 +0100409 spin_lock_irqsave(sh->host_lock, flags);
410 aha1542_intr_handle(sh);
411 spin_unlock_irqrestore(sh->host_lock, flags);
Ondrej Zary09a44832015-02-06 23:11:28 +0100412 return IRQ_HANDLED;
413}
414
Ondrej Zary55b28f92015-02-06 23:11:44 +0100415static int aha1542_queuecommand_lck(struct scsi_cmnd *cmd, void (*done) (struct scsi_cmnd *))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700416{
Ondrej Zary2906b3c2015-02-06 23:11:51 +0100417 struct Scsi_Host *sh = cmd->device->host;
418 struct aha1542_hostdata *aha1542 = shost_priv(sh);
Ondrej Zarycb5b5702015-02-06 23:11:27 +0100419 u8 direction;
Ondrej Zary55b28f92015-02-06 23:11:44 +0100420 u8 target = cmd->device->id;
421 u8 lun = cmd->device->lun;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700422 unsigned long flags;
Ondrej Zary55b28f92015-02-06 23:11:44 +0100423 int bufflen = scsi_bufflen(cmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700424 int mbo;
Ondrej Zarye98878f2015-02-06 23:11:25 +0100425 struct mailbox *mb = aha1542->mb;
426 struct ccb *ccb = aha1542->ccb;
Ondrej Zaryfde1fb82015-02-06 23:11:52 +0100427#ifdef DEBUG
428 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700429
Ondrej Zaryfde1fb82015-02-06 23:11:52 +0100430 if (target > 1) {
431 cmd->result = DID_TIME_OUT << 16;
432 done(cmd);
433 return 0;
434 }
435#endif
Ondrej Zary55b28f92015-02-06 23:11:44 +0100436 if (*cmd->cmnd == REQUEST_SENSE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700437 /* Don't do the command - we have the sense data already */
Ondrej Zary55b28f92015-02-06 23:11:44 +0100438 cmd->result = 0;
439 done(cmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700440 return 0;
441 }
442#ifdef DEBUG
Ondrej Zary55b28f92015-02-06 23:11:44 +0100443 if (*cmd->cmnd == READ_10 || *cmd->cmnd == WRITE_10)
444 i = xscsi2int(cmd->cmnd + 2);
445 else if (*cmd->cmnd == READ_6 || *cmd->cmnd == WRITE_6)
446 i = scsi2int(cmd->cmnd + 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700447 else
448 i = -1;
449 if (done)
Ondrej Zary2906b3c2015-02-06 23:11:51 +0100450 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 -0700451 else
Ondrej Zary2906b3c2015-02-06 23:11:51 +0100452 shost_printk(KERN_DEBUG, sh, "aha1542_command: dev %d cmd %02x pos %d len %d ", target, *cmd->cmnd, i, bufflen);
453 shost_printk(KERN_DEBUG, sh, "aha1542_queuecommand: dumping scsi cmd:");
Ondrej Zary55b28f92015-02-06 23:11:44 +0100454 for (i = 0; i < cmd->cmd_len; i++)
455 printk("%02x ", cmd->cmnd[i]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700456 printk("\n");
Ondrej Zary55b28f92015-02-06 23:11:44 +0100457 if (*cmd->cmnd == WRITE_10 || *cmd->cmnd == WRITE_6)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700458 return 0; /* we are still testing, so *don't* write */
459#endif
460 /* Use the outgoing mailboxes in a round-robin fashion, because this
461 is how the host adapter will scan for them */
462
463 spin_lock_irqsave(&aha1542_lock, flags);
Ondrej Zarye98878f2015-02-06 23:11:25 +0100464 mbo = aha1542->aha1542_last_mbo_used + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700465 if (mbo >= AHA1542_MAILBOXES)
466 mbo = 0;
467
468 do {
Ondrej Zary55b28f92015-02-06 23:11:44 +0100469 if (mb[mbo].status == 0 && aha1542->int_cmds[mbo] == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700470 break;
471 mbo++;
472 if (mbo >= AHA1542_MAILBOXES)
473 mbo = 0;
Ondrej Zarye98878f2015-02-06 23:11:25 +0100474 } while (mbo != aha1542->aha1542_last_mbo_used);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700475
Ondrej Zary55b28f92015-02-06 23:11:44 +0100476 if (mb[mbo].status || aha1542->int_cmds[mbo])
Linus Torvalds1da177e2005-04-16 15:20:36 -0700477 panic("Unable to find empty mailbox for aha1542.\n");
478
Ondrej Zary55b28f92015-02-06 23:11:44 +0100479 aha1542->int_cmds[mbo] = cmd; /* This will effectively prevent someone else from
Ondrej Zarye98878f2015-02-06 23:11:25 +0100480 screwing with this cdb. */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700481
Ondrej Zarye98878f2015-02-06 23:11:25 +0100482 aha1542->aha1542_last_mbo_used = mbo;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700483 spin_unlock_irqrestore(&aha1542_lock, flags);
484
485#ifdef DEBUG
Ondrej Zary2906b3c2015-02-06 23:11:51 +0100486 shost_printk(KERN_DEBUG, sh, "Sending command (%d %x)...", mbo, done);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700487#endif
488
Ondrej Zary10be6252015-02-06 23:11:24 +0100489 any2scsi(mb[mbo].ccbptr, isa_virt_to_bus(&ccb[mbo])); /* This gets trashed for some reason */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700490
491 memset(&ccb[mbo], 0, sizeof(struct ccb));
492
Ondrej Zary55b28f92015-02-06 23:11:44 +0100493 ccb[mbo].cdblen = cmd->cmd_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700494
495 direction = 0;
Ondrej Zary55b28f92015-02-06 23:11:44 +0100496 if (*cmd->cmnd == READ_10 || *cmd->cmnd == READ_6)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700497 direction = 8;
Ondrej Zary55b28f92015-02-06 23:11:44 +0100498 else if (*cmd->cmnd == WRITE_10 || *cmd->cmnd == WRITE_6)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700499 direction = 16;
500
Ondrej Zary55b28f92015-02-06 23:11:44 +0100501 memcpy(ccb[mbo].cdb, cmd->cmnd, ccb[mbo].cdblen);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700502
Boaz Harroshfc3fdfc2007-09-09 21:02:45 +0300503 if (bufflen) {
Jens Axboe51cf2242007-07-16 10:00:31 +0200504 struct scatterlist *sg;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700505 struct chain *cptr;
506#ifdef DEBUG
507 unsigned char *ptr;
508#endif
Ondrej Zary55b28f92015-02-06 23:11:44 +0100509 int i, sg_count = scsi_sg_count(cmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700510 ccb[mbo].op = 2; /* SCSI Initiator Command w/scatter-gather */
Ondrej Zary55b28f92015-02-06 23:11:44 +0100511 cmd->host_scribble = kmalloc(sizeof(*cptr)*sg_count,
Boaz Harroshfc3fdfc2007-09-09 21:02:45 +0300512 GFP_KERNEL | GFP_DMA);
Ondrej Zary55b28f92015-02-06 23:11:44 +0100513 cptr = (struct chain *) cmd->host_scribble;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700514 if (cptr == NULL) {
515 /* free the claimed mailbox slot */
Ondrej Zary55b28f92015-02-06 23:11:44 +0100516 aha1542->int_cmds[mbo] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700517 return SCSI_MLQUEUE_HOST_BUSY;
518 }
Ondrej Zary55b28f92015-02-06 23:11:44 +0100519 scsi_for_each_sg(cmd, sg, sg_count, i) {
Ondrej Zary10be6252015-02-06 23:11:24 +0100520 any2scsi(cptr[i].dataptr, isa_page_to_bus(sg_page(sg))
521 + sg->offset);
Jens Axboe51cf2242007-07-16 10:00:31 +0200522 any2scsi(cptr[i].datalen, sg->length);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700523 };
Boaz Harroshfc3fdfc2007-09-09 21:02:45 +0300524 any2scsi(ccb[mbo].datalen, sg_count * sizeof(struct chain));
Ondrej Zary10be6252015-02-06 23:11:24 +0100525 any2scsi(ccb[mbo].dataptr, isa_virt_to_bus(cptr));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700526#ifdef DEBUG
527 printk("cptr %x: ", cptr);
528 ptr = (unsigned char *) cptr;
529 for (i = 0; i < 18; i++)
530 printk("%02x ", ptr[i]);
531#endif
532 } else {
533 ccb[mbo].op = 0; /* SCSI Initiator Command */
Ondrej Zary55b28f92015-02-06 23:11:44 +0100534 cmd->host_scribble = NULL;
Boaz Harroshfc3fdfc2007-09-09 21:02:45 +0300535 any2scsi(ccb[mbo].datalen, 0);
536 any2scsi(ccb[mbo].dataptr, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700537 };
538 ccb[mbo].idlun = (target & 7) << 5 | direction | (lun & 7); /*SCSI Target Id */
539 ccb[mbo].rsalen = 16;
540 ccb[mbo].linkptr[0] = ccb[mbo].linkptr[1] = ccb[mbo].linkptr[2] = 0;
541 ccb[mbo].commlinkid = 0;
542
543#ifdef DEBUG
544 {
545 int i;
Ondrej Zary2906b3c2015-02-06 23:11:51 +0100546 shost_printk(KERN_DEBUG, sh, "aha1542_command: sending.. ");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700547 for (i = 0; i < sizeof(ccb[mbo]) - 10; i++)
Ondrej Zarycb5b5702015-02-06 23:11:27 +0100548 printk("%02x ", ((u8 *) &ccb[mbo])[i]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700549 };
550#endif
551
552 if (done) {
Ondrej Zaryfde1fb82015-02-06 23:11:52 +0100553#ifdef DEBUG
554 printk("aha1542_queuecommand: now waiting for interrupt ");
555#endif
Ondrej Zary55b28f92015-02-06 23:11:44 +0100556 cmd->scsi_done = done;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700557 mb[mbo].status = 1;
Ondrej Zary55b28f92015-02-06 23:11:44 +0100558 aha1542_outb(cmd->device->host->io_port, CMD_START_SCSI);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700559 } else
560 printk("aha1542_queuecommand: done can't be NULL\n");
561
562 return 0;
563}
564
Jeff Garzikf2812332010-11-16 02:10:29 -0500565static DEF_SCSI_QCMD(aha1542_queuecommand)
566
Linus Torvalds1da177e2005-04-16 15:20:36 -0700567/* Initialize mailboxes */
Ondrej Zary68ea9de2015-02-06 23:11:49 +0100568static void setup_mailboxes(struct Scsi_Host *sh)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700569{
Ondrej Zaryc2532f62015-02-06 23:11:45 +0100570 struct aha1542_hostdata *aha1542 = shost_priv(sh);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700571 int i;
Ondrej Zarye98878f2015-02-06 23:11:25 +0100572 struct mailbox *mb = aha1542->mb;
573 struct ccb *ccb = aha1542->ccb;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700574
Ondrej Zarycad2fc72015-02-06 23:11:43 +0100575 u8 mb_cmd[5] = { CMD_MBINIT, AHA1542_MAILBOXES, 0, 0, 0};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700576
Linus Torvalds1da177e2005-04-16 15:20:36 -0700577 for (i = 0; i < AHA1542_MAILBOXES; i++) {
578 mb[i].status = mb[AHA1542_MAILBOXES + i].status = 0;
Ondrej Zary10be6252015-02-06 23:11:24 +0100579 any2scsi(mb[i].ccbptr, isa_virt_to_bus(&ccb[i]));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700580 };
Ondrej Zary68ea9de2015-02-06 23:11:49 +0100581 aha1542_intr_reset(sh->io_port); /* reset interrupts, so they don't block */
Ondrej Zarycad2fc72015-02-06 23:11:43 +0100582 any2scsi((mb_cmd + 2), isa_virt_to_bus(mb));
Ondrej Zary68ea9de2015-02-06 23:11:49 +0100583 if (aha1542_out(sh->io_port, mb_cmd, 5))
Ondrej Zary2906b3c2015-02-06 23:11:51 +0100584 shost_printk(KERN_ERR, sh, "failed setting up mailboxes\n");
Ondrej Zary68ea9de2015-02-06 23:11:49 +0100585 aha1542_intr_reset(sh->io_port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700586}
587
Ondrej Zary68ea9de2015-02-06 23:11:49 +0100588static int aha1542_getconfig(struct Scsi_Host *sh)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700589{
Ondrej Zarycb5b5702015-02-06 23:11:27 +0100590 u8 inquiry_result[3];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700591 int i;
Ondrej Zary68ea9de2015-02-06 23:11:49 +0100592 i = inb(STATUS(sh->io_port));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700593 if (i & DF) {
Ondrej Zary68ea9de2015-02-06 23:11:49 +0100594 i = inb(DATA(sh->io_port));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700595 };
Ondrej Zary68ea9de2015-02-06 23:11:49 +0100596 aha1542_outb(sh->io_port, CMD_RETCONF);
597 aha1542_in(sh->io_port, inquiry_result, 3, 0);
598 if (!wait_mask(INTRFLAGS(sh->io_port), INTRMASK, HACC, 0, 0))
Ondrej Zary2906b3c2015-02-06 23:11:51 +0100599 shost_printk(KERN_ERR, sh, "error querying board settings\n");
Ondrej Zary68ea9de2015-02-06 23:11:49 +0100600 aha1542_intr_reset(sh->io_port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700601 switch (inquiry_result[0]) {
602 case 0x80:
Ondrej Zary68ea9de2015-02-06 23:11:49 +0100603 sh->dma_channel = 7;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700604 break;
605 case 0x40:
Ondrej Zary68ea9de2015-02-06 23:11:49 +0100606 sh->dma_channel = 6;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700607 break;
608 case 0x20:
Ondrej Zary68ea9de2015-02-06 23:11:49 +0100609 sh->dma_channel = 5;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700610 break;
611 case 0x01:
Ondrej Zary68ea9de2015-02-06 23:11:49 +0100612 sh->dma_channel = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700613 break;
614 case 0:
615 /* This means that the adapter, although Adaptec 1542 compatible, doesn't use a DMA channel.
616 Currently only aware of the BusLogic BT-445S VL-Bus adapter which needs this. */
Ondrej Zary68ea9de2015-02-06 23:11:49 +0100617 sh->dma_channel = 0xFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700618 break;
619 default:
Ondrej Zary2906b3c2015-02-06 23:11:51 +0100620 shost_printk(KERN_ERR, sh, "Unable to determine DMA channel.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700621 return -1;
622 };
623 switch (inquiry_result[1]) {
624 case 0x40:
Ondrej Zary68ea9de2015-02-06 23:11:49 +0100625 sh->irq = 15;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700626 break;
627 case 0x20:
Ondrej Zary68ea9de2015-02-06 23:11:49 +0100628 sh->irq = 14;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700629 break;
630 case 0x8:
Ondrej Zary68ea9de2015-02-06 23:11:49 +0100631 sh->irq = 12;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700632 break;
633 case 0x4:
Ondrej Zary68ea9de2015-02-06 23:11:49 +0100634 sh->irq = 11;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700635 break;
636 case 0x2:
Ondrej Zary68ea9de2015-02-06 23:11:49 +0100637 sh->irq = 10;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700638 break;
639 case 0x1:
Ondrej Zary68ea9de2015-02-06 23:11:49 +0100640 sh->irq = 9;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700641 break;
642 default:
Ondrej Zary2906b3c2015-02-06 23:11:51 +0100643 shost_printk(KERN_ERR, sh, "Unable to determine IRQ level.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700644 return -1;
645 };
Ondrej Zary68ea9de2015-02-06 23:11:49 +0100646 sh->this_id = inquiry_result[2] & 7;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700647 return 0;
648}
649
650/* This function should only be called for 1542C boards - we can detect
651 the special firmware settings and unlock the board */
652
Ondrej Zary68ea9de2015-02-06 23:11:49 +0100653static int aha1542_mbenable(struct Scsi_Host *sh)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700654{
Ondrej Zarycb5b5702015-02-06 23:11:27 +0100655 static u8 mbenable_cmd[3];
656 static u8 mbenable_result[2];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700657 int retval;
658
659 retval = BIOS_TRANSLATION_6432;
660
Ondrej Zary68ea9de2015-02-06 23:11:49 +0100661 aha1542_outb(sh->io_port, CMD_EXTBIOS);
662 if (aha1542_in(sh->io_port, mbenable_result, 2, 100))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700663 return retval;
Ondrej Zary68ea9de2015-02-06 23:11:49 +0100664 if (!wait_mask(INTRFLAGS(sh->io_port), INTRMASK, HACC, 0, 100))
Ondrej Zary2093bfa2015-02-06 23:11:31 +0100665 goto fail;
Ondrej Zary68ea9de2015-02-06 23:11:49 +0100666 aha1542_intr_reset(sh->io_port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700667
668 if ((mbenable_result[0] & 0x08) || mbenable_result[1]) {
669 mbenable_cmd[0] = CMD_MBENABLE;
670 mbenable_cmd[1] = 0;
671 mbenable_cmd[2] = mbenable_result[1];
672
673 if ((mbenable_result[0] & 0x08) && (mbenable_result[1] & 0x03))
674 retval = BIOS_TRANSLATION_25563;
675
Ondrej Zary68ea9de2015-02-06 23:11:49 +0100676 if (aha1542_out(sh->io_port, mbenable_cmd, 3))
Ondrej Zary2093bfa2015-02-06 23:11:31 +0100677 goto fail;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700678 };
679 while (0) {
680fail:
Ondrej Zary2906b3c2015-02-06 23:11:51 +0100681 shost_printk(KERN_ERR, sh, "Mailbox init failed\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700682 }
Ondrej Zary68ea9de2015-02-06 23:11:49 +0100683 aha1542_intr_reset(sh->io_port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700684 return retval;
685}
686
687/* Query the board to find out if it is a 1542 or a 1740, or whatever. */
Ondrej Zary68ea9de2015-02-06 23:11:49 +0100688static int aha1542_query(struct Scsi_Host *sh)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700689{
Ondrej Zary68ea9de2015-02-06 23:11:49 +0100690 struct aha1542_hostdata *aha1542 = shost_priv(sh);
Ondrej Zarycb5b5702015-02-06 23:11:27 +0100691 u8 inquiry_result[4];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700692 int i;
Ondrej Zary68ea9de2015-02-06 23:11:49 +0100693 i = inb(STATUS(sh->io_port));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700694 if (i & DF) {
Ondrej Zary68ea9de2015-02-06 23:11:49 +0100695 i = inb(DATA(sh->io_port));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700696 };
Ondrej Zary68ea9de2015-02-06 23:11:49 +0100697 aha1542_outb(sh->io_port, CMD_INQUIRY);
698 aha1542_in(sh->io_port, inquiry_result, 4, 0);
699 if (!wait_mask(INTRFLAGS(sh->io_port), INTRMASK, HACC, 0, 0))
Ondrej Zary2906b3c2015-02-06 23:11:51 +0100700 shost_printk(KERN_ERR, sh, "error querying card type\n");
Ondrej Zary68ea9de2015-02-06 23:11:49 +0100701 aha1542_intr_reset(sh->io_port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700702
Ondrej Zary68ea9de2015-02-06 23:11:49 +0100703 aha1542->bios_translation = BIOS_TRANSLATION_6432; /* Default case */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700704
705 /* For an AHA1740 series board, we ignore the board since there is a
706 hardware bug which can lead to wrong blocks being returned if the board
707 is operating in the 1542 emulation mode. Since there is an extended mode
708 driver, we simply ignore the board and let the 1740 driver pick it up.
709 */
710
711 if (inquiry_result[0] == 0x43) {
Ondrej Zary2906b3c2015-02-06 23:11:51 +0100712 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 -0700713 return 1;
714 };
715
716 /* Always call this - boards that do not support extended bios translation
717 will ignore the command, and we will set the proper default */
718
Ondrej Zary68ea9de2015-02-06 23:11:49 +0100719 aha1542->bios_translation = aha1542_mbenable(sh);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700720
721 return 0;
722}
723
Ondrej Zaryf71429a2015-02-06 23:11:41 +0100724static u8 dma_speed_hw(int dma_speed)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700725{
Ondrej Zaryf71429a2015-02-06 23:11:41 +0100726 switch (dma_speed) {
727 case 5:
728 return 0x00;
729 case 6:
730 return 0x04;
731 case 7:
732 return 0x01;
733 case 8:
734 return 0x02;
735 case 10:
736 return 0x03;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700737 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700738
Ondrej Zaryf71429a2015-02-06 23:11:41 +0100739 return 0xff; /* invalid */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700740}
741
Ondrej Zaryb847fd02015-02-06 23:11:38 +0100742/* Set the Bus on/off-times as not to ruin floppy performance */
Ondrej Zary37d607b2015-02-06 23:11:50 +0100743static 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 +0100744{
Ondrej Zary37d607b2015-02-06 23:11:50 +0100745 if (bus_on > 0) {
746 u8 oncmd[] = { CMD_BUSON_TIME, clamp(bus_on, 2, 15) };
Ondrej Zaryb847fd02015-02-06 23:11:38 +0100747
Ondrej Zary37d607b2015-02-06 23:11:50 +0100748 aha1542_intr_reset(sh->io_port);
749 if (aha1542_out(sh->io_port, oncmd, 2))
Ondrej Zaryf71429a2015-02-06 23:11:41 +0100750 goto fail;
Ondrej Zaryb847fd02015-02-06 23:11:38 +0100751 }
Ondrej Zaryf71429a2015-02-06 23:11:41 +0100752
Ondrej Zary37d607b2015-02-06 23:11:50 +0100753 if (bus_off > 0) {
754 u8 offcmd[] = { CMD_BUSOFF_TIME, clamp(bus_off, 1, 64) };
Ondrej Zaryf71429a2015-02-06 23:11:41 +0100755
Ondrej Zary37d607b2015-02-06 23:11:50 +0100756 aha1542_intr_reset(sh->io_port);
757 if (aha1542_out(sh->io_port, offcmd, 2))
Ondrej Zaryf71429a2015-02-06 23:11:41 +0100758 goto fail;
759 }
760
Ondrej Zary37d607b2015-02-06 23:11:50 +0100761 if (dma_speed_hw(dma_speed) != 0xff) {
762 u8 dmacmd[] = { CMD_DMASPEED, dma_speed_hw(dma_speed) };
Ondrej Zaryf71429a2015-02-06 23:11:41 +0100763
Ondrej Zary37d607b2015-02-06 23:11:50 +0100764 aha1542_intr_reset(sh->io_port);
765 if (aha1542_out(sh->io_port, dmacmd, 2))
Ondrej Zaryb847fd02015-02-06 23:11:38 +0100766 goto fail;
767 }
Ondrej Zary37d607b2015-02-06 23:11:50 +0100768 aha1542_intr_reset(sh->io_port);
Ondrej Zaryb847fd02015-02-06 23:11:38 +0100769 return;
770fail:
Ondrej Zary2906b3c2015-02-06 23:11:51 +0100771 shost_printk(KERN_ERR, sh, "setting bus on/off-time failed\n");
Ondrej Zary37d607b2015-02-06 23:11:50 +0100772 aha1542_intr_reset(sh->io_port);
Ondrej Zaryb847fd02015-02-06 23:11:38 +0100773}
774
Linus Torvalds1da177e2005-04-16 15:20:36 -0700775/* return non-zero on detection */
Ondrej Zary643a7c42015-02-06 23:11:22 +0100776static struct Scsi_Host *aha1542_hw_init(struct scsi_host_template *tpnt, struct device *pdev, int indx)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700777{
Ondrej Zaryf71429a2015-02-06 23:11:41 +0100778 unsigned int base_io = io[indx];
Ondrej Zaryc2532f62015-02-06 23:11:45 +0100779 struct Scsi_Host *sh;
Ondrej Zarye98878f2015-02-06 23:11:25 +0100780 struct aha1542_hostdata *aha1542;
Ondrej Zary2906b3c2015-02-06 23:11:51 +0100781 char dma_info[] = "no DMA";
Linus Torvalds1da177e2005-04-16 15:20:36 -0700782
Ondrej Zary3a70c002015-02-06 23:11:40 +0100783 if (base_io == 0)
784 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700785
Ondrej Zary3a70c002015-02-06 23:11:40 +0100786 if (!request_region(base_io, AHA1542_REGION_SIZE, "aha1542"))
787 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700788
Ondrej Zaryc2532f62015-02-06 23:11:45 +0100789 sh = scsi_host_alloc(tpnt, sizeof(struct aha1542_hostdata));
790 if (!sh)
Ondrej Zary3a70c002015-02-06 23:11:40 +0100791 goto release;
Ondrej Zaryc2532f62015-02-06 23:11:45 +0100792 aha1542 = shost_priv(sh);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700793
Ondrej Zary68ea9de2015-02-06 23:11:49 +0100794 sh->unique_id = base_io;
795 sh->io_port = base_io;
796 sh->n_io_port = AHA1542_REGION_SIZE;
797 aha1542->aha1542_last_mbi_used = 2 * AHA1542_MAILBOXES - 1;
798 aha1542->aha1542_last_mbo_used = AHA1542_MAILBOXES - 1;
799
800 if (!aha1542_test_port(sh))
Ondrej Zary3a70c002015-02-06 23:11:40 +0100801 goto unregister;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700802
Ondrej Zary37d607b2015-02-06 23:11:50 +0100803 aha1542_set_bus_times(sh, bus_on[indx], bus_off[indx], dma_speed[indx]);
Ondrej Zary68ea9de2015-02-06 23:11:49 +0100804 if (aha1542_query(sh))
Ondrej Zary3a70c002015-02-06 23:11:40 +0100805 goto unregister;
Ondrej Zary68ea9de2015-02-06 23:11:49 +0100806 if (aha1542_getconfig(sh) == -1)
Ondrej Zary3a70c002015-02-06 23:11:40 +0100807 goto unregister;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700808
Ondrej Zaryc2532f62015-02-06 23:11:45 +0100809 if (sh->dma_channel != 0xFF)
Ondrej Zary2906b3c2015-02-06 23:11:51 +0100810 snprintf(dma_info, sizeof(dma_info), "DMA %d", sh->dma_channel);
811 shost_printk(KERN_INFO, sh, "Adaptec AHA-1542 (SCSI-ID %d) at IO 0x%x, IRQ %d, %s\n",
812 sh->this_id, base_io, sh->irq, dma_info);
Ondrej Zary3a70c002015-02-06 23:11:40 +0100813 if (aha1542->bios_translation == BIOS_TRANSLATION_25563)
Ondrej Zary2906b3c2015-02-06 23:11:51 +0100814 shost_printk(KERN_INFO, sh, "Using extended bios translation\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700815
Ondrej Zary68ea9de2015-02-06 23:11:49 +0100816 setup_mailboxes(sh);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700817
Ondrej Zaryc2532f62015-02-06 23:11:45 +0100818 if (request_irq(sh->irq, do_aha1542_intr_handle, 0,
819 "aha1542", sh)) {
Ondrej Zary2906b3c2015-02-06 23:11:51 +0100820 shost_printk(KERN_ERR, sh, "Unable to allocate IRQ.\n");
Ondrej Zary3a70c002015-02-06 23:11:40 +0100821 goto unregister;
822 }
Ondrej Zaryc2532f62015-02-06 23:11:45 +0100823 if (sh->dma_channel != 0xFF) {
824 if (request_dma(sh->dma_channel, "aha1542")) {
Ondrej Zary2906b3c2015-02-06 23:11:51 +0100825 shost_printk(KERN_ERR, sh, "Unable to allocate DMA channel.\n");
Ondrej Zary3a70c002015-02-06 23:11:40 +0100826 goto free_irq;
827 }
Ondrej Zaryc2532f62015-02-06 23:11:45 +0100828 if (sh->dma_channel == 0 || sh->dma_channel >= 5) {
829 set_dma_mode(sh->dma_channel, DMA_MODE_CASCADE);
830 enable_dma(sh->dma_channel);
Ondrej Zary3a70c002015-02-06 23:11:40 +0100831 }
832 }
Jeff Garzik87c4d7b2008-04-24 19:45:32 -0400833
Ondrej Zaryc2532f62015-02-06 23:11:45 +0100834 if (scsi_add_host(sh, pdev))
Ondrej Zary3a70c002015-02-06 23:11:40 +0100835 goto free_dma;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700836
Ondrej Zaryc2532f62015-02-06 23:11:45 +0100837 scsi_scan_host(sh);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700838
Ondrej Zaryc2532f62015-02-06 23:11:45 +0100839 return sh;
Ondrej Zary3a70c002015-02-06 23:11:40 +0100840free_dma:
Ondrej Zaryc2532f62015-02-06 23:11:45 +0100841 if (sh->dma_channel != 0xff)
842 free_dma(sh->dma_channel);
Ondrej Zary3a70c002015-02-06 23:11:40 +0100843free_irq:
Ondrej Zaryc2532f62015-02-06 23:11:45 +0100844 free_irq(sh->irq, sh);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700845unregister:
Ondrej Zaryc2532f62015-02-06 23:11:45 +0100846 scsi_host_put(sh);
Ondrej Zary3a70c002015-02-06 23:11:40 +0100847release:
848 release_region(base_io, AHA1542_REGION_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700849
Ondrej Zary643a7c42015-02-06 23:11:22 +0100850 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700851}
852
Ondrej Zaryc2532f62015-02-06 23:11:45 +0100853static int aha1542_release(struct Scsi_Host *sh)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700854{
Ondrej Zaryc2532f62015-02-06 23:11:45 +0100855 scsi_remove_host(sh);
856 if (sh->dma_channel != 0xff)
857 free_dma(sh->dma_channel);
858 if (sh->irq)
859 free_irq(sh->irq, sh);
860 if (sh->io_port && sh->n_io_port)
861 release_region(sh->io_port, sh->n_io_port);
862 scsi_host_put(sh);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700863 return 0;
864}
865
Linus Torvalds1da177e2005-04-16 15:20:36 -0700866
Linus Torvalds1da177e2005-04-16 15:20:36 -0700867/*
868 * This is a device reset. This is handled by sending a special command
869 * to the device.
870 */
Ondrej Zary55b28f92015-02-06 23:11:44 +0100871static int aha1542_dev_reset(struct scsi_cmnd *cmd)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700872{
Ondrej Zary55b28f92015-02-06 23:11:44 +0100873 struct aha1542_hostdata *aha1542 = shost_priv(cmd->device->host);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700874 unsigned long flags;
Ondrej Zarye98878f2015-02-06 23:11:25 +0100875 struct mailbox *mb = aha1542->mb;
Ondrej Zary55b28f92015-02-06 23:11:44 +0100876 u8 target = cmd->device->id;
877 u8 lun = cmd->device->lun;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700878 int mbo;
Ondrej Zarye98878f2015-02-06 23:11:25 +0100879 struct ccb *ccb = aha1542->ccb;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700880
Linus Torvalds1da177e2005-04-16 15:20:36 -0700881 spin_lock_irqsave(&aha1542_lock, flags);
Ondrej Zarye98878f2015-02-06 23:11:25 +0100882 mbo = aha1542->aha1542_last_mbo_used + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700883 if (mbo >= AHA1542_MAILBOXES)
884 mbo = 0;
885
886 do {
Ondrej Zary55b28f92015-02-06 23:11:44 +0100887 if (mb[mbo].status == 0 && aha1542->int_cmds[mbo] == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700888 break;
889 mbo++;
890 if (mbo >= AHA1542_MAILBOXES)
891 mbo = 0;
Ondrej Zarye98878f2015-02-06 23:11:25 +0100892 } while (mbo != aha1542->aha1542_last_mbo_used);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700893
Ondrej Zary55b28f92015-02-06 23:11:44 +0100894 if (mb[mbo].status || aha1542->int_cmds[mbo])
Linus Torvalds1da177e2005-04-16 15:20:36 -0700895 panic("Unable to find empty mailbox for aha1542.\n");
896
Ondrej Zary55b28f92015-02-06 23:11:44 +0100897 aha1542->int_cmds[mbo] = cmd; /* This will effectively
Ondrej Zarye98878f2015-02-06 23:11:25 +0100898 prevent someone else from
899 screwing with this cdb. */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700900
Ondrej Zarye98878f2015-02-06 23:11:25 +0100901 aha1542->aha1542_last_mbo_used = mbo;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700902 spin_unlock_irqrestore(&aha1542_lock, flags);
903
Ondrej Zary10be6252015-02-06 23:11:24 +0100904 any2scsi(mb[mbo].ccbptr, isa_virt_to_bus(&ccb[mbo])); /* This gets trashed for some reason */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700905
906 memset(&ccb[mbo], 0, sizeof(struct ccb));
907
908 ccb[mbo].op = 0x81; /* BUS DEVICE RESET */
909
910 ccb[mbo].idlun = (target & 7) << 5 | (lun & 7); /*SCSI Target Id */
911
912 ccb[mbo].linkptr[0] = ccb[mbo].linkptr[1] = ccb[mbo].linkptr[2] = 0;
913 ccb[mbo].commlinkid = 0;
914
915 /*
916 * Now tell the 1542 to flush all pending commands for this
917 * target
918 */
Ondrej Zary55b28f92015-02-06 23:11:44 +0100919 aha1542_outb(cmd->device->host->io_port, CMD_START_SCSI);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700920
Ondrej Zary55b28f92015-02-06 23:11:44 +0100921 scmd_printk(KERN_WARNING, cmd,
Jeff Garzik017560f2005-10-24 18:04:36 -0400922 "Trying device reset for target\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700923
924 return SUCCESS;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700925}
926
Ondrej Zary55b28f92015-02-06 23:11:44 +0100927static int aha1542_reset(struct scsi_cmnd *cmd, u8 reset_cmd)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700928{
Ondrej Zary55b28f92015-02-06 23:11:44 +0100929 struct aha1542_hostdata *aha1542 = shost_priv(cmd->device->host);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700930 int i;
931
932 /*
933 * This does a scsi reset for all devices on the bus.
934 * In principle, we could also reset the 1542 - should
935 * we do this? Try this first, and we can add that later
936 * if it turns out to be useful.
937 */
Ondrej Zary55b28f92015-02-06 23:11:44 +0100938 outb(reset_cmd, CONTROL(cmd->device->host->io_port));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700939
940 /*
941 * Wait for the thing to settle down a bit. Unfortunately
942 * this is going to basically lock up the machine while we
943 * wait for this to complete. To be 100% correct, we need to
944 * check for timeout, and if we are doing something like this
945 * we are pretty desperate anyways.
946 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700947 ssleep(4);
Ondrej Zary55b28f92015-02-06 23:11:44 +0100948 spin_lock_irq(cmd->device->host->host_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700949
Ondrej Zary55b28f92015-02-06 23:11:44 +0100950 if (!wait_mask(STATUS(cmd->device->host->io_port),
Ondrej Zarya13b3722015-02-06 23:11:34 +0100951 STATMASK, INIT | IDLE, STST | DIAGF | INVDCMD | DF | CDF, 0)) {
Ondrej Zary55b28f92015-02-06 23:11:44 +0100952 spin_unlock_irq(cmd->device->host->host_lock);
Ondrej Zarya13b3722015-02-06 23:11:34 +0100953 return FAILED;
954 }
Ondrej Zary8537cba2015-02-06 23:11:37 +0100955 /*
956 * We need to do this too before the 1542 can interact with
957 * us again after host reset.
958 */
959 if (reset_cmd & HRST)
Ondrej Zary68ea9de2015-02-06 23:11:49 +0100960 setup_mailboxes(cmd->device->host);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700961 /*
962 * Now try to pick up the pieces. For all pending commands,
963 * free any internal data structures, and basically clear things
964 * out. We do not try and restart any commands or anything -
965 * the strategy handler takes care of that crap.
966 */
Ondrej Zary2906b3c2015-02-06 23:11:51 +0100967 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 -0700968
969 for (i = 0; i < AHA1542_MAILBOXES; i++) {
Ondrej Zary55b28f92015-02-06 23:11:44 +0100970 if (aha1542->int_cmds[i] != NULL) {
971 struct scsi_cmnd *tmp_cmd;
972 tmp_cmd = aha1542->int_cmds[i];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700973
Ondrej Zary55b28f92015-02-06 23:11:44 +0100974 if (tmp_cmd->device->soft_reset) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700975 /*
976 * If this device implements the soft reset option,
977 * then it is still holding onto the command, and
978 * may yet complete it. In this case, we don't
979 * flush the data.
980 */
981 continue;
982 }
Ondrej Zary55b28f92015-02-06 23:11:44 +0100983 kfree(tmp_cmd->host_scribble);
984 tmp_cmd->host_scribble = NULL;
985 aha1542->int_cmds[i] = NULL;
Ondrej Zarye98878f2015-02-06 23:11:25 +0100986 aha1542->mb[i].status = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700987 }
988 }
989
Ondrej Zary55b28f92015-02-06 23:11:44 +0100990 spin_unlock_irq(cmd->device->host->host_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700991 return SUCCESS;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700992}
993
Ondrej Zary55b28f92015-02-06 23:11:44 +0100994static int aha1542_bus_reset(struct scsi_cmnd *cmd)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700995{
Ondrej Zary55b28f92015-02-06 23:11:44 +0100996 return aha1542_reset(cmd, SCRST);
Ondrej Zary8537cba2015-02-06 23:11:37 +0100997}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700998
Ondrej Zary55b28f92015-02-06 23:11:44 +0100999static int aha1542_host_reset(struct scsi_cmnd *cmd)
Ondrej Zary8537cba2015-02-06 23:11:37 +01001000{
Ondrej Zary55b28f92015-02-06 23:11:44 +01001001 return aha1542_reset(cmd, HRST | SCRST);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001002}
1003
Linus Torvalds1da177e2005-04-16 15:20:36 -07001004static int aha1542_biosparam(struct scsi_device *sdev,
Ondrej Zary17787a02015-02-06 23:11:42 +01001005 struct block_device *bdev, sector_t capacity, int geom[])
Linus Torvalds1da177e2005-04-16 15:20:36 -07001006{
Ondrej Zarye98878f2015-02-06 23:11:25 +01001007 struct aha1542_hostdata *aha1542 = shost_priv(sdev->host);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001008
Ondrej Zary17787a02015-02-06 23:11:42 +01001009 if (capacity >= 0x200000 &&
1010 aha1542->bios_translation == BIOS_TRANSLATION_25563) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001011 /* Please verify that this is the same as what DOS returns */
Ondrej Zary17787a02015-02-06 23:11:42 +01001012 geom[0] = 255; /* heads */
1013 geom[1] = 63; /* sectors */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001014 } else {
Ondrej Zary17787a02015-02-06 23:11:42 +01001015 geom[0] = 64; /* heads */
1016 geom[1] = 32; /* sectors */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001017 }
Ondrej Zary17787a02015-02-06 23:11:42 +01001018 geom[2] = sector_div(capacity, geom[0] * geom[1]); /* cylinders */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001019
1020 return 0;
1021}
1022MODULE_LICENSE("GPL");
1023
Christoph Hellwigd0be4a7d2005-10-31 18:31:40 +01001024static struct scsi_host_template driver_template = {
Ondrej Zary643a7c42015-02-06 23:11:22 +01001025 .module = THIS_MODULE,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001026 .proc_name = "aha1542",
1027 .name = "Adaptec 1542",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001028 .queuecommand = aha1542_queuecommand,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001029 .eh_device_reset_handler= aha1542_dev_reset,
1030 .eh_bus_reset_handler = aha1542_bus_reset,
1031 .eh_host_reset_handler = aha1542_host_reset,
1032 .bios_param = aha1542_biosparam,
1033 .can_queue = AHA1542_MAILBOXES,
1034 .this_id = 7,
Ondrej Zary10be6252015-02-06 23:11:24 +01001035 .sg_tablesize = 16,
1036 .cmd_per_lun = 1,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001037 .unchecked_isa_dma = 1,
1038 .use_clustering = ENABLE_CLUSTERING,
1039};
Ondrej Zary643a7c42015-02-06 23:11:22 +01001040
1041static int aha1542_isa_match(struct device *pdev, unsigned int ndev)
1042{
1043 struct Scsi_Host *sh = aha1542_hw_init(&driver_template, pdev, ndev);
1044
1045 if (!sh)
1046 return 0;
1047
1048 dev_set_drvdata(pdev, sh);
1049 return 1;
1050}
1051
1052static int aha1542_isa_remove(struct device *pdev,
1053 unsigned int ndev)
1054{
1055 aha1542_release(dev_get_drvdata(pdev));
1056 dev_set_drvdata(pdev, NULL);
1057 return 0;
1058}
1059
1060static struct isa_driver aha1542_isa_driver = {
1061 .match = aha1542_isa_match,
1062 .remove = aha1542_isa_remove,
1063 .driver = {
1064 .name = "aha1542"
1065 },
1066};
1067static int isa_registered;
1068
1069#ifdef CONFIG_PNP
1070static struct pnp_device_id aha1542_pnp_ids[] = {
1071 { .id = "ADP1542" },
1072 { .id = "" }
1073};
1074MODULE_DEVICE_TABLE(pnp, aha1542_pnp_ids);
1075
1076static int aha1542_pnp_probe(struct pnp_dev *pdev, const struct pnp_device_id *id)
1077{
1078 int indx;
1079 struct Scsi_Host *sh;
1080
Ondrej Zaryf71429a2015-02-06 23:11:41 +01001081 for (indx = 0; indx < ARRAY_SIZE(io); indx++) {
1082 if (io[indx])
Ondrej Zary643a7c42015-02-06 23:11:22 +01001083 continue;
1084
1085 if (pnp_activate_dev(pdev) < 0)
1086 continue;
1087
Ondrej Zaryf71429a2015-02-06 23:11:41 +01001088 io[indx] = pnp_port_start(pdev, 0);
Ondrej Zary643a7c42015-02-06 23:11:22 +01001089
1090 /* The card can be queried for its DMA, we have
1091 the DMA set up that is enough */
1092
Ondrej Zary2906b3c2015-02-06 23:11:51 +01001093 dev_info(&pdev->dev, "ISAPnP found an AHA1535 at I/O 0x%03X", io[indx]);
Ondrej Zary643a7c42015-02-06 23:11:22 +01001094 }
1095
1096 sh = aha1542_hw_init(&driver_template, &pdev->dev, indx);
1097 if (!sh)
1098 return -ENODEV;
1099
1100 pnp_set_drvdata(pdev, sh);
1101 return 0;
1102}
1103
1104static void aha1542_pnp_remove(struct pnp_dev *pdev)
1105{
1106 aha1542_release(pnp_get_drvdata(pdev));
1107 pnp_set_drvdata(pdev, NULL);
1108}
1109
1110static struct pnp_driver aha1542_pnp_driver = {
1111 .name = "aha1542",
1112 .id_table = aha1542_pnp_ids,
1113 .probe = aha1542_pnp_probe,
1114 .remove = aha1542_pnp_remove,
1115};
1116static int pnp_registered;
1117#endif /* CONFIG_PNP */
1118
1119static int __init aha1542_init(void)
1120{
1121 int ret = 0;
Ondrej Zary643a7c42015-02-06 23:11:22 +01001122
1123#ifdef CONFIG_PNP
1124 if (isapnp) {
1125 ret = pnp_register_driver(&aha1542_pnp_driver);
1126 if (!ret)
1127 pnp_registered = 1;
1128 }
1129#endif
1130 ret = isa_register_driver(&aha1542_isa_driver, MAXBOARDS);
1131 if (!ret)
1132 isa_registered = 1;
1133
1134#ifdef CONFIG_PNP
1135 if (pnp_registered)
1136 ret = 0;
1137#endif
1138 if (isa_registered)
1139 ret = 0;
1140
1141 return ret;
1142}
1143
1144static void __exit aha1542_exit(void)
1145{
1146#ifdef CONFIG_PNP
1147 if (pnp_registered)
1148 pnp_unregister_driver(&aha1542_pnp_driver);
1149#endif
1150 if (isa_registered)
1151 isa_unregister_driver(&aha1542_isa_driver);
1152}
1153
1154module_init(aha1542_init);
1155module_exit(aha1542_exit);