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