Merge branch 'for-linus' of git://oss.sgi.com:8090/xfs/xfs-2.6
[linux-2.6] / drivers / scsi / aacraid / sa.c
1 /*
2  *      Adaptec AAC series RAID controller driver
3  *      (c) Copyright 2001 Red Hat Inc. <alan@redhat.com>
4  *
5  * based on the old aacraid driver that is..
6  * Adaptec aacraid device driver for Linux.
7  *
8  * Copyright (c) 2000-2007 Adaptec, Inc. (aacraid@adaptec.com)
9  *
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2, or (at your option)
13  * any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; see the file COPYING.  If not, write to
22  * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
23  *
24  * Module Name:
25  *  sa.c
26  *
27  * Abstract: Drawbridge specific support functions
28  *
29  */
30
31 #include <linux/kernel.h>
32 #include <linux/init.h>
33 #include <linux/types.h>
34 #include <linux/spinlock.h>
35 #include <linux/slab.h>
36 #include <linux/blkdev.h>
37 #include <linux/delay.h>
38 #include <linux/completion.h>
39 #include <linux/time.h>
40 #include <linux/interrupt.h>
41 #include <asm/semaphore.h>
42
43 #include <scsi/scsi_host.h>
44
45 #include "aacraid.h"
46
47 static irqreturn_t aac_sa_intr(int irq, void *dev_id)
48 {
49         struct aac_dev *dev = dev_id;
50         unsigned short intstat, mask;
51
52         intstat = sa_readw(dev, DoorbellReg_p);
53         /*
54          *      Read mask and invert because drawbridge is reversed.
55          *      This allows us to only service interrupts that have been enabled.
56          */
57         mask = ~(sa_readw(dev, SaDbCSR.PRISETIRQMASK));
58
59         /* Check to see if this is our interrupt.  If it isn't just return */
60
61         if (intstat & mask) {
62                 if (intstat & PrintfReady) {
63                         aac_printf(dev, sa_readl(dev, Mailbox5));
64                         sa_writew(dev, DoorbellClrReg_p, PrintfReady); /* clear PrintfReady */
65                         sa_writew(dev, DoorbellReg_s, PrintfDone);
66                 } else if (intstat & DOORBELL_1) {      // dev -> Host Normal Command Ready
67                         sa_writew(dev, DoorbellClrReg_p, DOORBELL_1);
68                         aac_command_normal(&dev->queues->queue[HostNormCmdQueue]);
69                 } else if (intstat & DOORBELL_2) {      // dev -> Host Normal Response Ready
70                         sa_writew(dev, DoorbellClrReg_p, DOORBELL_2);
71                         aac_response_normal(&dev->queues->queue[HostNormRespQueue]);
72                 } else if (intstat & DOORBELL_3) {      // dev -> Host Normal Command Not Full
73                         sa_writew(dev, DoorbellClrReg_p, DOORBELL_3);
74                 } else if (intstat & DOORBELL_4) {      // dev -> Host Normal Response Not Full
75                         sa_writew(dev, DoorbellClrReg_p, DOORBELL_4);
76                 }
77                 return IRQ_HANDLED;
78         }
79         return IRQ_NONE;
80 }
81
82 /**
83  *      aac_sa_disable_interrupt        -       disable interrupt
84  *      @dev: Which adapter to enable.
85  */
86
87 static void aac_sa_disable_interrupt (struct aac_dev *dev)
88 {
89         sa_writew(dev, SaDbCSR.PRISETIRQMASK, 0xffff);
90 }
91
92 /**
93  *      aac_sa_enable_interrupt -       enable interrupt
94  *      @dev: Which adapter to enable.
95  */
96
97 static void aac_sa_enable_interrupt (struct aac_dev *dev)
98 {
99         sa_writew(dev, SaDbCSR.PRICLEARIRQMASK, (PrintfReady | DOORBELL_1 |
100                                 DOORBELL_2 | DOORBELL_3 | DOORBELL_4));
101 }
102
103 /**
104  *      aac_sa_notify_adapter           -       handle adapter notification
105  *      @dev:   Adapter that notification is for
106  *      @event: Event to notidy
107  *
108  *      Notify the adapter of an event
109  */
110  
111 static void aac_sa_notify_adapter(struct aac_dev *dev, u32 event)
112 {
113         switch (event) {
114
115         case AdapNormCmdQue:
116                 sa_writew(dev, DoorbellReg_s,DOORBELL_1);
117                 break;
118         case HostNormRespNotFull:
119                 sa_writew(dev, DoorbellReg_s,DOORBELL_4);
120                 break;
121         case AdapNormRespQue:
122                 sa_writew(dev, DoorbellReg_s,DOORBELL_2);
123                 break;
124         case HostNormCmdNotFull:
125                 sa_writew(dev, DoorbellReg_s,DOORBELL_3);
126                 break;
127         case HostShutdown:
128                 /*
129                 sa_sync_cmd(dev, HOST_CRASHING, 0, 0, 0, 0, 0, 0,
130                 NULL, NULL, NULL, NULL, NULL);
131                 */
132                 break;
133         case FastIo:
134                 sa_writew(dev, DoorbellReg_s,DOORBELL_6);
135                 break;
136         case AdapPrintfDone:
137                 sa_writew(dev, DoorbellReg_s,DOORBELL_5);
138                 break;
139         default:
140                 BUG();
141                 break;
142         }
143 }
144
145
146 /**
147  *      sa_sync_cmd     -       send a command and wait
148  *      @dev: Adapter
149  *      @command: Command to execute
150  *      @p1: first parameter
151  *      @ret: adapter status
152  *
153  *      This routine will send a synchronous command to the adapter and wait 
154  *      for its completion.
155  */
156
157 static int sa_sync_cmd(struct aac_dev *dev, u32 command, 
158                 u32 p1, u32 p2, u32 p3, u32 p4, u32 p5, u32 p6,
159                 u32 *ret, u32 *r1, u32 *r2, u32 *r3, u32 *r4)
160 {
161         unsigned long start;
162         int ok;
163         /*
164          *      Write the Command into Mailbox 0
165          */
166         sa_writel(dev, Mailbox0, command);
167         /*
168          *      Write the parameters into Mailboxes 1 - 4
169          */
170         sa_writel(dev, Mailbox1, p1);
171         sa_writel(dev, Mailbox2, p2);
172         sa_writel(dev, Mailbox3, p3);
173         sa_writel(dev, Mailbox4, p4);
174
175         /*
176          *      Clear the synch command doorbell to start on a clean slate.
177          */
178         sa_writew(dev, DoorbellClrReg_p, DOORBELL_0);
179         /*
180          *      Signal that there is a new synch command
181          */
182         sa_writew(dev, DoorbellReg_s, DOORBELL_0);
183
184         ok = 0;
185         start = jiffies;
186
187         while(time_before(jiffies, start+30*HZ))
188         {
189                 /*
190                  *      Delay 5uS so that the monitor gets access
191                  */
192                 udelay(5);
193                 /*
194                  *      Mon110 will set doorbell0 bit when it has 
195                  *      completed the command.
196                  */
197                 if(sa_readw(dev, DoorbellReg_p) & DOORBELL_0)  {
198                         ok = 1;
199                         break;
200                 }
201                 msleep(1);
202         }
203
204         if (ok != 1)
205                 return -ETIMEDOUT;
206         /*
207          *      Clear the synch command doorbell.
208          */
209         sa_writew(dev, DoorbellClrReg_p, DOORBELL_0);
210         /*
211          *      Pull the synch status from Mailbox 0.
212          */
213         if (ret)
214                 *ret = sa_readl(dev, Mailbox0);
215         if (r1)
216                 *r1 = sa_readl(dev, Mailbox1);
217         if (r2)
218                 *r2 = sa_readl(dev, Mailbox2);
219         if (r3)
220                 *r3 = sa_readl(dev, Mailbox3);
221         if (r4)
222                 *r4 = sa_readl(dev, Mailbox4);
223         return 0;
224 }
225
226 /**
227  *      aac_sa_interrupt_adapter        -       interrupt an adapter
228  *      @dev: Which adapter to enable.
229  *
230  *      Breakpoint an adapter.
231  */
232  
233 static void aac_sa_interrupt_adapter (struct aac_dev *dev)
234 {
235         sa_sync_cmd(dev, BREAKPOINT_REQUEST, 0, 0, 0, 0, 0, 0,
236                         NULL, NULL, NULL, NULL, NULL);
237 }
238
239 /**
240  *      aac_sa_start_adapter            -       activate adapter
241  *      @dev:   Adapter
242  *
243  *      Start up processing on an ARM based AAC adapter
244  */
245
246 static void aac_sa_start_adapter(struct aac_dev *dev)
247 {
248         struct aac_init *init;
249         /*
250          * Fill in the remaining pieces of the init.
251          */
252         init = dev->init;
253         init->HostElapsedSeconds = cpu_to_le32(get_seconds());
254         /* We can only use a 32 bit address here */
255         sa_sync_cmd(dev, INIT_STRUCT_BASE_ADDRESS, 
256                         (u32)(ulong)dev->init_pa, 0, 0, 0, 0, 0,
257                         NULL, NULL, NULL, NULL, NULL);
258 }
259
260 static int aac_sa_restart_adapter(struct aac_dev *dev, int bled)
261 {
262         return -EINVAL;
263 }
264
265 /**
266  *      aac_sa_check_health
267  *      @dev: device to check if healthy
268  *
269  *      Will attempt to determine if the specified adapter is alive and
270  *      capable of handling requests, returning 0 if alive.
271  */
272 static int aac_sa_check_health(struct aac_dev *dev)
273 {
274         long status = sa_readl(dev, Mailbox7);
275
276         /*
277          *      Check to see if the board failed any self tests.
278          */
279         if (status & SELF_TEST_FAILED)
280                 return -1;
281         /*
282          *      Check to see if the board panic'd while booting.
283          */
284         if (status & KERNEL_PANIC)
285                 return -2;
286         /*
287          *      Wait for the adapter to be up and running. Wait up to 3 minutes
288          */
289         if (!(status & KERNEL_UP_AND_RUNNING))
290                 return -3;
291         /*
292          *      Everything is OK
293          */
294         return 0;
295 }
296
297 /**
298  *      aac_sa_ioremap
299  *      @size: mapping resize request
300  *
301  */
302 static int aac_sa_ioremap(struct aac_dev * dev, u32 size)
303 {
304         if (!size) {
305                 iounmap(dev->regs.sa);
306                 return 0;
307         }
308         dev->base = dev->regs.sa = ioremap(dev->scsi_host_ptr->base, size);
309         return (dev->base == NULL) ? -1 : 0;
310 }
311
312 /**
313  *      aac_sa_init     -       initialize an ARM based AAC card
314  *      @dev: device to configure
315  *
316  *      Allocate and set up resources for the ARM based AAC variants. The 
317  *      device_interface in the commregion will be allocated and linked 
318  *      to the comm region.
319  */
320
321 int aac_sa_init(struct aac_dev *dev)
322 {
323         unsigned long start;
324         unsigned long status;
325         int instance;
326         const char *name;
327
328         instance = dev->id;
329         name     = dev->name;
330
331         if (aac_sa_ioremap(dev, dev->base_size)) {
332                 printk(KERN_WARNING "%s: unable to map adapter.\n", name);
333                 goto error_iounmap;
334         }
335
336         /*
337          *      Check to see if the board failed any self tests.
338          */
339         if (sa_readl(dev, Mailbox7) & SELF_TEST_FAILED) {
340                 printk(KERN_WARNING "%s%d: adapter self-test failed.\n", name, instance);
341                 goto error_iounmap;
342         }
343         /*
344          *      Check to see if the board panic'd while booting.
345          */
346         if (sa_readl(dev, Mailbox7) & KERNEL_PANIC) {
347                 printk(KERN_WARNING "%s%d: adapter kernel panic'd.\n", name, instance);
348                 goto error_iounmap;
349         }
350         start = jiffies;
351         /*
352          *      Wait for the adapter to be up and running. Wait up to 3 minutes.
353          */
354         while (!(sa_readl(dev, Mailbox7) & KERNEL_UP_AND_RUNNING)) {
355                 if (time_after(jiffies, start+startup_timeout*HZ)) {
356                         status = sa_readl(dev, Mailbox7);
357                         printk(KERN_WARNING "%s%d: adapter kernel failed to start, init status = %lx.\n", 
358                                         name, instance, status);
359                         goto error_iounmap;
360                 }
361                 msleep(1);
362         }
363
364         /*
365          *      Fill in the function dispatch table.
366          */
367
368         dev->a_ops.adapter_interrupt = aac_sa_interrupt_adapter;
369         dev->a_ops.adapter_disable_int = aac_sa_disable_interrupt;
370         dev->a_ops.adapter_enable_int = aac_sa_enable_interrupt;
371         dev->a_ops.adapter_notify = aac_sa_notify_adapter;
372         dev->a_ops.adapter_sync_cmd = sa_sync_cmd;
373         dev->a_ops.adapter_check_health = aac_sa_check_health;
374         dev->a_ops.adapter_restart = aac_sa_restart_adapter;
375         dev->a_ops.adapter_intr = aac_sa_intr;
376         dev->a_ops.adapter_deliver = aac_rx_deliver_producer;
377         dev->a_ops.adapter_ioremap = aac_sa_ioremap;
378
379         /*
380          *      First clear out all interrupts.  Then enable the one's that 
381          *      we can handle.
382          */
383         aac_adapter_disable_int(dev);
384         aac_adapter_enable_int(dev);
385
386         if(aac_init_adapter(dev) == NULL)
387                 goto error_irq;
388         if (request_irq(dev->scsi_host_ptr->irq, dev->a_ops.adapter_intr,
389                         IRQF_SHARED|IRQF_DISABLED,
390                         "aacraid", (void *)dev ) < 0) {
391                 printk(KERN_WARNING "%s%d: Interrupt unavailable.\n",
392                         name, instance);
393                 goto error_iounmap;
394         }
395         aac_adapter_enable_int(dev);
396
397         /*
398          *      Tell the adapter that all is configure, and it can start 
399          *      accepting requests
400          */
401         aac_sa_start_adapter(dev);
402         return 0;
403
404 error_irq:
405         aac_sa_disable_interrupt(dev);
406         free_irq(dev->scsi_host_ptr->irq, (void *)dev);
407
408 error_iounmap:
409
410         return -1;
411 }
412