Linux kernel & device driver programming

Cross-Referenced Linux and Device Driver Code

[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ]
Version: [ 2.6.11.8 ] [ 2.6.25 ] [ 2.6.25.8 ] [ 2.6.31.13 ] Architecture: [ i386 ]
  1 /*
  2  *      Adaptec AAC series RAID controller driver
  3  *      (c) Copyright 2001 Red Hat Inc.
  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/pci.h>
 35 #include <linux/spinlock.h>
 36 #include <linux/slab.h>
 37 #include <linux/blkdev.h>
 38 #include <linux/delay.h>
 39 #include <linux/completion.h>
 40 #include <linux/time.h>
 41 #include <linux/interrupt.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->pdev->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->pdev->irq, (void *)dev);
407 
408 error_iounmap:
409 
410         return -1;
411 }
412 
413 
  This page was automatically generated by the LXR engine.