rx.c
上传用户:jlfgdled
上传日期:2013-04-10
资源大小:33168k
文件大小:10k
源码类别:

Linux/Unix编程

开发平台:

Unix_Linux

  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.  *  rx.c
  26.  *
  27.  * Abstract: Hardware miniport for Drawbridge specific hardware functions.
  28.  *
  29.  */
  30. #include <linux/config.h>
  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/blk.h>
  39. #include <linux/delay.h>
  40. #include <linux/completion.h>
  41. #include <asm/semaphore.h>
  42. #include "scsi.h"
  43. #include "hosts.h"
  44. #include "aacraid.h"
  45. static void aac_rx_intr(int irq, void *dev_id, struct pt_regs *regs)
  46. {
  47. struct aac_dev *dev = dev_id;
  48. unsigned long bellbits;
  49. u8 intstat, mask;
  50. intstat = rx_readb(dev, MUnit.OISR);
  51. /*
  52.  * Read mask and invert because drawbridge is reversed.
  53.  * This allows us to only service interrupts that have 
  54.  * been enabled.
  55.  */
  56. mask = ~(rx_readb(dev, MUnit.OIMR));
  57. /* Check to see if this is our interrupt.  If it isn't just return */
  58. if (intstat & mask) 
  59. {
  60. bellbits = rx_readl(dev, OutboundDoorbellReg);
  61. if (bellbits & DoorBellPrintfReady) {
  62. aac_printf(dev, le32_to_cpu(rx_readl (dev, IndexRegs.Mailbox[5])));
  63. rx_writel(dev, MUnit.ODR,DoorBellPrintfReady);
  64. rx_writel(dev, InboundDoorbellReg,DoorBellPrintfDone);
  65. }
  66. else if (bellbits & DoorBellAdapterNormCmdReady) {
  67. aac_command_normal(&dev->queues->queue[HostNormCmdQueue]);
  68. rx_writel(dev, MUnit.ODR, DoorBellAdapterNormCmdReady);
  69. }
  70. else if (bellbits & DoorBellAdapterNormRespReady) {
  71. aac_response_normal(&dev->queues->queue[HostNormRespQueue]);
  72. rx_writel(dev, MUnit.ODR,DoorBellAdapterNormRespReady);
  73. }
  74. else if (bellbits & DoorBellAdapterNormCmdNotFull) {
  75. rx_writel(dev, MUnit.ODR, DoorBellAdapterNormCmdNotFull);
  76. }
  77. else if (bellbits & DoorBellAdapterNormRespNotFull) {
  78. rx_writel(dev, MUnit.ODR, DoorBellAdapterNormCmdNotFull);
  79. rx_writel(dev, MUnit.ODR, DoorBellAdapterNormRespNotFull);
  80. }
  81. }
  82. }
  83. /**
  84.  * aac_rx_enable_interrupt - Enable event reporting
  85.  * @dev: Adapter
  86.  * @event: Event to enable
  87.  *
  88.  * Enable event reporting from the i960 for a given event.
  89.  */
  90.  
  91. static void aac_rx_enable_interrupt(struct aac_dev * dev, u32 event)
  92. {
  93. switch (event) {
  94. case HostNormCmdQue:
  95. dev->irq_mask &= ~(OUTBOUNDDOORBELL_1);
  96. break;
  97. case HostNormRespQue:
  98. dev->irq_mask &= ~(OUTBOUNDDOORBELL_2);
  99. break;
  100. case AdapNormCmdNotFull:
  101. dev->irq_mask &= ~(OUTBOUNDDOORBELL_3);
  102. break;
  103. case AdapNormRespNotFull:
  104. dev->irq_mask &= ~(OUTBOUNDDOORBELL_4);
  105. break;
  106. }
  107. }
  108. /**
  109.  * aac_rx_disable_interrupt - Disable event reporting
  110.  * @dev: Adapter
  111.  * @event: Event to enable
  112.  *
  113.  * Disable event reporting from the i960 for a given event.
  114.  */
  115. static void aac_rx_disable_interrupt(struct aac_dev *dev, u32 event)
  116. {
  117. switch (event) {
  118. case HostNormCmdQue:
  119. dev->irq_mask |= (OUTBOUNDDOORBELL_1);
  120. break;
  121. case HostNormRespQue:
  122. dev->irq_mask |= (OUTBOUNDDOORBELL_2);
  123. break;
  124. case AdapNormCmdNotFull:
  125. dev->irq_mask |= (OUTBOUNDDOORBELL_3);
  126. break;
  127. case AdapNormRespNotFull:
  128. dev->irq_mask |= (OUTBOUNDDOORBELL_4);
  129. break;
  130. }
  131. }
  132. /**
  133.  * rx_sync_cmd - send a command and wait
  134.  * @dev: Adapter
  135.  * @command: Command to execute
  136.  * @p1: first parameter
  137.  * @ret: adapter status
  138.  *
  139.  * This routine will send a synchronous comamnd to the adapter and wait 
  140.  * for its completion.
  141.  */
  142. static int rx_sync_cmd(struct aac_dev *dev, u32 command, u32 p1, u32 *status)
  143. {
  144. unsigned long start;
  145. int ok;
  146. /*
  147.  * Write the command into Mailbox 0
  148.  */
  149. rx_writel(dev, InboundMailbox0, cpu_to_le32(command));
  150. /*
  151.  * Write the parameters into Mailboxes 1 - 4
  152.  */
  153. rx_writel(dev, InboundMailbox1, cpu_to_le32(p1));
  154. rx_writel(dev, InboundMailbox2, 0);
  155. rx_writel(dev, InboundMailbox3, 0);
  156. rx_writel(dev, InboundMailbox4, 0);
  157. /*
  158.  * Clear the synch command doorbell to start on a clean slate.
  159.  */
  160. rx_writel(dev, OutboundDoorbellReg, OUTBOUNDDOORBELL_0);
  161. /*
  162.  * Disable doorbell interrupts
  163.  */
  164. rx_writeb(dev, MUnit.OIMR, rx_readb(dev, MUnit.OIMR) | 0x04);
  165. /*
  166.  * Force the completion of the mask register write before issuing
  167.  * the interrupt.
  168.  */
  169. rx_readb (dev, MUnit.OIMR);
  170. /*
  171.  * Signal that there is a new synch command
  172.  */
  173. rx_writel(dev, InboundDoorbellReg, INBOUNDDOORBELL_0);
  174. ok = 0;
  175. start = jiffies;
  176. /*
  177.  * Wait up to 30 seconds
  178.  */
  179. while (time_before(jiffies, start+30*HZ)) 
  180. {
  181. udelay(5); /* Delay 5 microseconds to let Mon960 get info. */
  182. /*
  183.  * Mon960 will set doorbell0 bit when it has completed the command.
  184.  */
  185. if (rx_readl(dev, OutboundDoorbellReg) & OUTBOUNDDOORBELL_0) {
  186. /*
  187.  * Clear the doorbell.
  188.  */
  189. rx_writel(dev, OutboundDoorbellReg, OUTBOUNDDOORBELL_0);
  190. ok = 1;
  191. break;
  192. }
  193. /*
  194.  * Yield the processor in case we are slow 
  195.  */
  196. set_current_state(TASK_UNINTERRUPTIBLE);
  197. schedule_timeout(1);
  198. }
  199. if (ok != 1) {
  200. /*
  201.  * Restore interrupt mask even though we timed out
  202.  */
  203. rx_writeb(dev, MUnit.OIMR, rx_readl(dev, MUnit.OIMR) & 0xfb);
  204. return -ETIMEDOUT;
  205. }
  206. /*
  207.  * Pull the synch status from Mailbox 0.
  208.  */
  209. *status = le32_to_cpu(rx_readl(dev, IndexRegs.Mailbox[0]));
  210. /*
  211.  * Clear the synch command doorbell.
  212.  */
  213. rx_writel(dev, OutboundDoorbellReg, OUTBOUNDDOORBELL_0);
  214. /*
  215.  * Restore interrupt mask
  216.  */
  217. rx_writeb(dev, MUnit.OIMR, rx_readl(dev, MUnit.OIMR) & 0xfb);
  218. return 0;
  219. }
  220. /**
  221.  * aac_rx_interrupt_adapter - interrupt adapter
  222.  * @dev: Adapter
  223.  *
  224.  * Send an interrupt to the i960 and breakpoint it.
  225.  */
  226. static void aac_rx_interrupt_adapter(struct aac_dev *dev)
  227. {
  228. u32 ret;
  229. rx_sync_cmd(dev, BREAKPOINT_REQUEST, 0, &ret);
  230. }
  231. /**
  232.  * aac_rx_notify_adapter - send an event to the adapter
  233.  * @dev: Adapter
  234.  * @event: Event to send
  235.  *
  236.  * Notify the i960 that something it probably cares about has
  237.  * happened.
  238.  */
  239. static void aac_rx_notify_adapter(struct aac_dev *dev, u32 event)
  240. {
  241. switch (event) {
  242. case AdapNormCmdQue:
  243. rx_writel(dev, MUnit.IDR,INBOUNDDOORBELL_1);
  244. break;
  245. case HostNormRespNotFull:
  246. rx_writel(dev, MUnit.IDR,INBOUNDDOORBELL_4);
  247. break;
  248. case AdapNormRespQue:
  249. rx_writel(dev, MUnit.IDR,INBOUNDDOORBELL_2);
  250. break;
  251. case HostNormCmdNotFull:
  252. rx_writel(dev, MUnit.IDR,INBOUNDDOORBELL_3);
  253. break;
  254. case HostShutdown:
  255. // rx_sync_cmd(dev, HOST_CRASHING, 0, 0, 0, 0, &ret);
  256. break;
  257. case FastIo:
  258. rx_writel(dev, MUnit.IDR,INBOUNDDOORBELL_6);
  259. break;
  260. case AdapPrintfDone:
  261. rx_writel(dev, MUnit.IDR,INBOUNDDOORBELL_5);
  262. break;
  263. default:
  264. BUG();
  265. break;
  266. }
  267. }
  268. /**
  269.  * aac_rx_start_adapter - activate adapter
  270.  * @dev: Adapter
  271.  *
  272.  * Start up processing on an i960 based AAC adapter
  273.  */
  274. static void aac_rx_start_adapter(struct aac_dev *dev)
  275. {
  276. u32 status;
  277. struct aac_init *init;
  278. init = dev->init;
  279. init->HostElapsedSeconds = cpu_to_le32(jiffies/HZ);
  280. /*
  281.  * Tell the adapter we are back and up and running so it will scan
  282.  * its command queues and enable our interrupts
  283.  */
  284. dev->irq_mask = (DoorBellPrintfReady | OUTBOUNDDOORBELL_1 | OUTBOUNDDOORBELL_2 | OUTBOUNDDOORBELL_3 | OUTBOUNDDOORBELL_4);
  285. /*
  286.  * First clear out all interrupts.  Then enable the one's that we
  287.  * can handle.
  288.  */
  289. rx_writeb(dev, MUnit.OIMR, 0xff);
  290. rx_writel(dev, MUnit.ODR, 0xffffffff);
  291. // rx_writeb(dev, MUnit.OIMR, ~(u8)OUTBOUND_DOORBELL_INTERRUPT_MASK);
  292. rx_writeb(dev, MUnit.OIMR, 0xfb);
  293. // We can only use a 32 bit address here
  294. rx_sync_cmd(dev, INIT_STRUCT_BASE_ADDRESS, (u32)(ulong)dev->init_pa, &status);
  295. }
  296. /**
  297.  * aac_rx_init - initialize an i960 based AAC card
  298.  * @dev: device to configure
  299.  * @devnum: adapter number
  300.  *
  301.  * Allocate and set up resources for the i960 based AAC variants. The 
  302.  * device_interface in the commregion will be allocated and linked 
  303.  * to the comm region.
  304.  */
  305. int aac_rx_init(struct aac_dev *dev, unsigned long num)
  306. {
  307. unsigned long start;
  308. unsigned long status;
  309. int instance;
  310. const char * name;
  311. dev->devnum = num;
  312. instance = dev->id;
  313. name     = dev->name;
  314. /*
  315.  * Map in the registers from the adapter.
  316.  */
  317. if((dev->regs.rx = (struct rx_registers *)ioremap((unsigned long)dev->scsi_host_ptr->base, 8192))==NULL)
  318. {
  319. printk(KERN_WARNING "aacraid: unable to map i960.n" );
  320. return -1;
  321. }
  322. /*
  323.  * Check to see if the board failed any self tests.
  324.  */
  325. if (rx_readl(dev, IndexRegs.Mailbox[7]) & SELF_TEST_FAILED) {
  326. printk(KERN_ERR "%s%d: adapter self-test failed.n", dev->name, instance);
  327. return -1;
  328. }
  329. /*
  330.  * Check to see if the board panic'd while booting.
  331.  */
  332. if (rx_readl(dev, IndexRegs.Mailbox[7]) & KERNEL_PANIC) {
  333. printk(KERN_ERR "%s%d: adapter kernel panic'd.n", dev->name, instance);
  334. return -1;
  335. }
  336. start = jiffies;
  337. /*
  338.  * Wait for the adapter to be up and running. Wait up to 3 minutes
  339.  */
  340. while (!(rx_readl(dev, IndexRegs.Mailbox[7]) & KERNEL_UP_AND_RUNNING)) 
  341. {
  342. if(time_after(jiffies, start+180*HZ))
  343. {
  344. status = rx_readl(dev, IndexRegs.Mailbox[7]) >> 16;
  345. printk(KERN_ERR "%s%d: adapter kernel failed to start, init status = %ld.n", dev->name, instance, status);
  346. return -1;
  347. }
  348. set_current_state(TASK_UNINTERRUPTIBLE);
  349. schedule_timeout(1);
  350. }
  351. if (request_irq(dev->scsi_host_ptr->irq, aac_rx_intr, SA_SHIRQ|SA_INTERRUPT, "aacraid", (void *)dev)<0) 
  352. {
  353. printk(KERN_ERR "%s%d: Interrupt unavailable.n", name, instance);
  354. return -1;
  355. }
  356. /*
  357.  * Fill in the function dispatch table.
  358.  */
  359. dev->a_ops.adapter_interrupt = aac_rx_interrupt_adapter;
  360. dev->a_ops.adapter_enable_int = aac_rx_enable_interrupt;
  361. dev->a_ops.adapter_disable_int = aac_rx_disable_interrupt;
  362. dev->a_ops.adapter_notify = aac_rx_notify_adapter;
  363. dev->a_ops.adapter_sync_cmd = rx_sync_cmd;
  364. if (aac_init_adapter(dev) == NULL)
  365. return -1;
  366. /*
  367.  * Start any kernel threads needed
  368.  */
  369. dev->thread_pid = kernel_thread((int (*)(void *))aac_command_thread, dev, 0);
  370. /*
  371.  * Tell the adapter that all is configured, and it can start
  372.  * accepting requests
  373.  */
  374. aac_rx_start_adapter(dev);
  375. return 0;
  376. }