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 49 static irqreturn_t aac_sa_intr(int irq, void *dev_id, struct pt_regs *regs) 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 aac_command_normal(&dev->queues->queue[HostNormCmdQueue]); 70 sa_writew(dev, DoorbellClrReg_p, DOORBELL_1); 71 } else if (intstat & DOORBELL_2) { // dev -> Host Normal Response Ready 72 aac_response_normal(&dev->queues->queue[HostNormRespQueue]); 73 sa_writew(dev, DoorbellClrReg_p, DOORBELL_2); 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_notify_adapter - handle adapter notification 86 * @dev: Adapter that notification is for 87 * @event: Event to notidy 88 * 89 * Notify the adapter of an event 90 */ 91 92 void aac_sa_notify_adapter(struct aac_dev *dev, u32 event) 93 { 94 switch (event) { 95 96 case AdapNormCmdQue: 97 sa_writew(dev, DoorbellReg_s,DOORBELL_1); 98 break; 99 case HostNormRespNotFull: 100 sa_writew(dev, DoorbellReg_s,DOORBELL_4); 101 break; 102 case AdapNormRespQue: 103 sa_writew(dev, DoorbellReg_s,DOORBELL_2); 104 break; 105 case HostNormCmdNotFull: 106 sa_writew(dev, DoorbellReg_s,DOORBELL_3); 107 break; 108 case HostShutdown: 109 //sa_sync_cmd(dev, HOST_CRASHING, 0, &ret); 110 break; 111 case FastIo: 112 sa_writew(dev, DoorbellReg_s,DOORBELL_6); 113 break; 114 case AdapPrintfDone: 115 sa_writew(dev, DoorbellReg_s,DOORBELL_5); 116 break; 117 default: 118 BUG(); 119 break; 120 } 121 } 122 123 124 /** 125 * sa_sync_cmd - send a command and wait 126 * @dev: Adapter 127 * @command: Command to execute 128 * @p1: first parameter 129 * @ret: adapter status 130 * 131 * This routine will send a synchronous command to the adapter and wait 132 * for its completion. 133 */ 134 135 static int sa_sync_cmd(struct aac_dev *dev, u32 command, u32 p1, u32 *ret) 136 { 137 unsigned long start; 138 int ok; 139 /* 140 * Write the Command into Mailbox 0 141 */ 142 sa_writel(dev, Mailbox0, command); 143 /* 144 * Write the parameters into Mailboxes 1 - 4 145 */ 146 sa_writel(dev, Mailbox1, p1); 147 sa_writel(dev, Mailbox2, 0); 148 sa_writel(dev, Mailbox3, 0); 149 sa_writel(dev, Mailbox4, 0); 150 /* 151 * Clear the synch command doorbell to start on a clean slate. 152 */ 153 sa_writew(dev, DoorbellClrReg_p, DOORBELL_0); 154 /* 155 * Signal that there is a new synch command 156 */ 157 sa_writew(dev, DoorbellReg_s, DOORBELL_0); 158 159 ok = 0; 160 start = jiffies; 161 162 while(time_before(jiffies, start+30*HZ)) 163 { 164 /* 165 * Delay 5uS so that the monitor gets access 166 */ 167 udelay(5); 168 /* 169 * Mon110 will set doorbell0 bit when it has 170 * completed the command. 171 */ 172 if(sa_readw(dev, DoorbellReg_p) & DOORBELL_0) { 173 ok = 1; 174 break; 175 } 176 set_current_state(TASK_UNINTERRUPTIBLE); 177 schedule_timeout(1); 178 } 179 180 if (ok != 1) 181 return -ETIMEDOUT; 182 /* 183 * Clear the synch command doorbell. 184 */ 185 sa_writew(dev, DoorbellClrReg_p, DOORBELL_0); 186 /* 187 * Pull the synch status from Mailbox 0. 188 */ 189 if (ret) 190 *ret = sa_readl(dev, Mailbox0); 191 return 0; 192 } 193 194 /** 195 * aac_sa_interrupt_adapter - interrupt an adapter 196 * @dev: Which adapter to enable. 197 * 198 * Breakpoint an adapter. 199 */ 200 201 static void aac_sa_interrupt_adapter (struct aac_dev *dev) 202 { 203 u32 ret; 204 sa_sync_cmd(dev, BREAKPOINT_REQUEST, 0, &ret); 205 } 206 207 /** 208 * aac_sa_start_adapter - activate adapter 209 * @dev: Adapter 210 * 211 * Start up processing on an ARM based AAC adapter 212 */ 213 214 static void aac_sa_start_adapter(struct aac_dev *dev) 215 { 216 u32 ret; 217 struct aac_init *init; 218 /* 219 * Fill in the remaining pieces of the init. 220 */ 221 init = dev->init; 222 init->HostElapsedSeconds = cpu_to_le32(get_seconds()); 223 224 /* 225 * Tell the adapter we are back and up and running so it will scan its command 226 * queues and enable our interrupts 227 */ 228 dev->irq_mask = (PrintfReady | DOORBELL_1 | DOORBELL_2 | DOORBELL_3 | DOORBELL_4); 229 /* 230 * First clear out all interrupts. Then enable the one's that 231 * we can handle. 232 */ 233 sa_writew(dev, SaDbCSR.PRISETIRQMASK, cpu_to_le16(0xffff)); 234 sa_writew(dev, SaDbCSR.PRICLEARIRQMASK, (PrintfReady | DOORBELL_1 | DOORBELL_2 | DOORBELL_3 | DOORBELL_4)); 235 /* We can only use a 32 bit address here */ 236 sa_sync_cmd(dev, INIT_STRUCT_BASE_ADDRESS, (u32)(ulong)dev->init_pa, &ret); 237 } 238 239 /** 240 * aac_sa_check_health 241 * @dev: device to check if healthy 242 * 243 * Will attempt to determine if the specified adapter is alive and 244 * capable of handling requests, returning 0 if alive. 245 */ 246 static int aac_sa_check_health(struct aac_dev *dev) 247 { 248 long status = sa_readl(dev, Mailbox7); 249 250 /* 251 * Check to see if the board failed any self tests. 252 */ 253 if (status & SELF_TEST_FAILED) 254 return -1; 255 /* 256 * Check to see if the board panic'd while booting. 257 */ 258 if (status & KERNEL_PANIC) 259 return -2; 260 /* 261 * Wait for the adapter to be up and running. Wait up to 3 minutes 262 */ 263 if (!(status & KERNEL_UP_AND_RUNNING)) 264 return -3; 265 /* 266 * Everything is OK 267 */ 268 return 0; 269 } 270 271 /** 272 * aac_sa_init - initialize an ARM based AAC card 273 * @dev: device to configure 274 * 275 * Allocate and set up resources for the ARM based AAC variants. The 276 * device_interface in the commregion will be allocated and linked 277 * to the comm region. 278 */ 279 280 int aac_sa_init(struct aac_dev *dev) 281 { 282 unsigned long start; 283 unsigned long status; 284 int instance; 285 const char *name; 286 287 instance = dev->id; 288 name = dev->name; 289 290 /* 291 * Map in the registers from the adapter. 292 */ 293 294 if((dev->regs.sa = ioremap((unsigned long)dev->scsi_host_ptr->base, 8192))==NULL) 295 { 296 printk(KERN_WARNING "aacraid: unable to map ARM.\n" ); 297 goto error_iounmap; 298 } 299 /* 300 * Check to see if the board failed any self tests. 301 */ 302 if (sa_readl(dev, Mailbox7) & SELF_TEST_FAILED) { 303 printk(KERN_WARNING "%s%d: adapter self-test failed.\n", name, instance); 304 goto error_iounmap; 305 } 306 /* 307 * Check to see if the board panic'd while booting. 308 */ 309 if (sa_readl(dev, Mailbox7) & KERNEL_PANIC) { 310 printk(KERN_WARNING "%s%d: adapter kernel panic'd.\n", name, instance); 311 goto error_iounmap; 312 } 313 start = jiffies; 314 /* 315 * Wait for the adapter to be up and running. Wait up to 3 minutes. 316 */ 317 while (!(sa_readl(dev, Mailbox7) & KERNEL_UP_AND_RUNNING)) { 318 if (time_after(jiffies, start+180*HZ)) { 319 status = sa_readl(dev, Mailbox7); 320 printk(KERN_WARNING "%s%d: adapter kernel failed to start, init status = %lx.\n", 321 name, instance, status); 322 goto error_iounmap; 323 } 324 set_current_state(TASK_UNINTERRUPTIBLE); 325 schedule_timeout(1); 326 } 327 328 if (request_irq(dev->scsi_host_ptr->irq, aac_sa_intr, SA_SHIRQ|SA_INTERRUPT, "aacraid", (void *)dev ) < 0) { 329 printk(KERN_WARNING "%s%d: Interrupt unavailable.\n", name, instance); 330 goto error_iounmap; 331 } 332 333 /* 334 * Fill in the function dispatch table. 335 */ 336 337 dev->a_ops.adapter_interrupt = aac_sa_interrupt_adapter; 338 dev->a_ops.adapter_notify = aac_sa_notify_adapter; 339 dev->a_ops.adapter_sync_cmd = sa_sync_cmd; 340 dev->a_ops.adapter_check_health = aac_sa_check_health; 341 342 343 if(aac_init_adapter(dev) == NULL) 344 goto error_irq; 345 346 /* 347 * Start any kernel threads needed 348 */ 349 dev->thread_pid = kernel_thread((int (*)(void *))aac_command_thread, dev, 0); 350 if (dev->thread_pid < 0) { 351 printk(KERN_ERR "aacraid: Unable to create command thread.\n"); 352 goto error_kfree; 353 } 354 355 /* 356 * Tell the adapter that all is configure, and it can start 357 * accepting requests 358 */ 359 aac_sa_start_adapter(dev); 360 return 0; 361 362 363 error_kfree: 364 kfree(dev->queues); 365 366 error_irq: 367 free_irq(dev->scsi_host_ptr->irq, (void *)dev); 368 369 error_iounmap: 370 iounmap(dev->regs.sa); 371 372 return -1; 373 } 374 375