diff options
author | Mark Haverkamp <markh@osdl.org> | 2005-10-24 13:52:22 -0400 |
---|---|---|
committer | James Bottomley <jejb@mulgrave.(none)> | 2005-10-28 12:41:53 -0400 |
commit | 8e0c5ebde82b08f6d996e11983890fc4cc085fab (patch) | |
tree | 3ba38ff8e7b9203b47d038c215d9c7d623c250ba /drivers/scsi/aacraid/rx.c | |
parent | 38a9a621aba953ddb8051547e98c10ec3c741312 (diff) |
[SCSI] aacraid: Newer adapter communication iterface support
Received from Mark Salyzyn.
This patch adds the 'new comm' interface, which modern AAC based
adapters that are less than a year old support in the name of much
improved performance. These modern adapters support both the legacy and
the 'new comm' interfaces.
Signed-off-by: Mark Haverkamp <markh@osdl.org>
Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>
Diffstat (limited to 'drivers/scsi/aacraid/rx.c')
-rw-r--r-- | drivers/scsi/aacraid/rx.c | 157 |
1 files changed, 95 insertions, 62 deletions
diff --git a/drivers/scsi/aacraid/rx.c b/drivers/scsi/aacraid/rx.c index a8459faf87ca..da99046e5393 100644 --- a/drivers/scsi/aacraid/rx.c +++ b/drivers/scsi/aacraid/rx.c | |||
@@ -49,40 +49,57 @@ | |||
49 | static irqreturn_t aac_rx_intr(int irq, void *dev_id, struct pt_regs *regs) | 49 | static irqreturn_t aac_rx_intr(int irq, void *dev_id, struct pt_regs *regs) |
50 | { | 50 | { |
51 | struct aac_dev *dev = dev_id; | 51 | struct aac_dev *dev = dev_id; |
52 | unsigned long bellbits; | 52 | |
53 | u8 intstat, mask; | 53 | dprintk((KERN_DEBUG "aac_rx_intr(%d,%p,%p)\n", irq, dev_id, regs)); |
54 | intstat = rx_readb(dev, MUnit.OISR); | 54 | if (dev->new_comm_interface) { |
55 | /* | 55 | u32 Index = rx_readl(dev, MUnit.OutboundQueue); |
56 | * Read mask and invert because drawbridge is reversed. | 56 | if (Index == 0xFFFFFFFFL) |
57 | * This allows us to only service interrupts that have | 57 | Index = rx_readl(dev, MUnit.OutboundQueue); |
58 | * been enabled. | 58 | if (Index != 0xFFFFFFFFL) { |
59 | */ | 59 | do { |
60 | mask = ~(dev->OIMR); | 60 | if (aac_intr_normal(dev, Index)) { |
61 | /* Check to see if this is our interrupt. If it isn't just return */ | 61 | rx_writel(dev, MUnit.OutboundQueue, Index); |
62 | if (intstat & mask) | 62 | rx_writel(dev, MUnit.ODR, DoorBellAdapterNormRespReady); |
63 | { | 63 | } |
64 | bellbits = rx_readl(dev, OutboundDoorbellReg); | 64 | Index = rx_readl(dev, MUnit.OutboundQueue); |
65 | if (bellbits & DoorBellPrintfReady) { | 65 | } while (Index != 0xFFFFFFFFL); |
66 | aac_printf(dev, rx_readl(dev, IndexRegs.Mailbox[5])); | 66 | return IRQ_HANDLED; |
67 | rx_writel(dev, MUnit.ODR,DoorBellPrintfReady); | ||
68 | rx_writel(dev, InboundDoorbellReg,DoorBellPrintfDone); | ||
69 | } | ||
70 | else if (bellbits & DoorBellAdapterNormCmdReady) { | ||
71 | rx_writel(dev, MUnit.ODR, DoorBellAdapterNormCmdReady); | ||
72 | aac_command_normal(&dev->queues->queue[HostNormCmdQueue]); | ||
73 | } | ||
74 | else if (bellbits & DoorBellAdapterNormRespReady) { | ||
75 | aac_response_normal(&dev->queues->queue[HostNormRespQueue]); | ||
76 | rx_writel(dev, MUnit.ODR,DoorBellAdapterNormRespReady); | ||
77 | } | ||
78 | else if (bellbits & DoorBellAdapterNormCmdNotFull) { | ||
79 | rx_writel(dev, MUnit.ODR, DoorBellAdapterNormCmdNotFull); | ||
80 | } | 67 | } |
81 | else if (bellbits & DoorBellAdapterNormRespNotFull) { | 68 | } else { |
82 | rx_writel(dev, MUnit.ODR, DoorBellAdapterNormCmdNotFull); | 69 | unsigned long bellbits; |
83 | rx_writel(dev, MUnit.ODR, DoorBellAdapterNormRespNotFull); | 70 | u8 intstat; |
71 | intstat = rx_readb(dev, MUnit.OISR); | ||
72 | /* | ||
73 | * Read mask and invert because drawbridge is reversed. | ||
74 | * This allows us to only service interrupts that have | ||
75 | * been enabled. | ||
76 | * Check to see if this is our interrupt. If it isn't just return | ||
77 | */ | ||
78 | if (intstat & ~(dev->OIMR)) | ||
79 | { | ||
80 | bellbits = rx_readl(dev, OutboundDoorbellReg); | ||
81 | if (bellbits & DoorBellPrintfReady) { | ||
82 | aac_printf(dev, rx_readl (dev, IndexRegs.Mailbox[5])); | ||
83 | rx_writel(dev, MUnit.ODR,DoorBellPrintfReady); | ||
84 | rx_writel(dev, InboundDoorbellReg,DoorBellPrintfDone); | ||
85 | } | ||
86 | else if (bellbits & DoorBellAdapterNormCmdReady) { | ||
87 | rx_writel(dev, MUnit.ODR, DoorBellAdapterNormCmdReady); | ||
88 | aac_command_normal(&dev->queues->queue[HostNormCmdQueue]); | ||
89 | } | ||
90 | else if (bellbits & DoorBellAdapterNormRespReady) { | ||
91 | rx_writel(dev, MUnit.ODR,DoorBellAdapterNormRespReady); | ||
92 | aac_response_normal(&dev->queues->queue[HostNormRespQueue]); | ||
93 | } | ||
94 | else if (bellbits & DoorBellAdapterNormCmdNotFull) { | ||
95 | rx_writel(dev, MUnit.ODR, DoorBellAdapterNormCmdNotFull); | ||
96 | } | ||
97 | else if (bellbits & DoorBellAdapterNormRespNotFull) { | ||
98 | rx_writel(dev, MUnit.ODR, DoorBellAdapterNormCmdNotFull); | ||
99 | rx_writel(dev, MUnit.ODR, DoorBellAdapterNormRespNotFull); | ||
100 | } | ||
101 | return IRQ_HANDLED; | ||
84 | } | 102 | } |
85 | return IRQ_HANDLED; | ||
86 | } | 103 | } |
87 | return IRQ_NONE; | 104 | return IRQ_NONE; |
88 | } | 105 | } |
@@ -173,7 +190,10 @@ static int rx_sync_cmd(struct aac_dev *dev, u32 command, | |||
173 | /* | 190 | /* |
174 | * Restore interrupt mask even though we timed out | 191 | * Restore interrupt mask even though we timed out |
175 | */ | 192 | */ |
176 | rx_writeb(dev, MUnit.OIMR, dev->OIMR &= 0xfb); | 193 | if (dev->new_comm_interface) |
194 | rx_writeb(dev, MUnit.OIMR, dev->OIMR = 0xf7); | ||
195 | else | ||
196 | rx_writeb(dev, MUnit.OIMR, dev->OIMR = 0xfb); | ||
177 | return -ETIMEDOUT; | 197 | return -ETIMEDOUT; |
178 | } | 198 | } |
179 | /* | 199 | /* |
@@ -196,7 +216,10 @@ static int rx_sync_cmd(struct aac_dev *dev, u32 command, | |||
196 | /* | 216 | /* |
197 | * Restore interrupt mask | 217 | * Restore interrupt mask |
198 | */ | 218 | */ |
199 | rx_writeb(dev, MUnit.OIMR, dev->OIMR &= 0xfb); | 219 | if (dev->new_comm_interface) |
220 | rx_writeb(dev, MUnit.OIMR, dev->OIMR = 0xf7); | ||
221 | else | ||
222 | rx_writeb(dev, MUnit.OIMR, dev->OIMR = 0xfb); | ||
200 | return 0; | 223 | return 0; |
201 | 224 | ||
202 | } | 225 | } |
@@ -267,15 +290,6 @@ static void aac_rx_start_adapter(struct aac_dev *dev) | |||
267 | 290 | ||
268 | init = dev->init; | 291 | init = dev->init; |
269 | init->HostElapsedSeconds = cpu_to_le32(get_seconds()); | 292 | init->HostElapsedSeconds = cpu_to_le32(get_seconds()); |
270 | /* | ||
271 | * First clear out all interrupts. Then enable the one's that we | ||
272 | * can handle. | ||
273 | */ | ||
274 | rx_writeb(dev, MUnit.OIMR, 0xff); | ||
275 | rx_writel(dev, MUnit.ODR, 0xffffffff); | ||
276 | // rx_writeb(dev, MUnit.OIMR, ~(u8)OUTBOUND_DOORBELL_INTERRUPT_MASK); | ||
277 | rx_writeb(dev, MUnit.OIMR, dev->OIMR = 0xfb); | ||
278 | |||
279 | // We can only use a 32 bit address here | 293 | // We can only use a 32 bit address here |
280 | rx_sync_cmd(dev, INIT_STRUCT_BASE_ADDRESS, (u32)(ulong)dev->init_pa, | 294 | rx_sync_cmd(dev, INIT_STRUCT_BASE_ADDRESS, (u32)(ulong)dev->init_pa, |
281 | 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL); | 295 | 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL); |
@@ -349,6 +363,39 @@ static int aac_rx_check_health(struct aac_dev *dev) | |||
349 | } | 363 | } |
350 | 364 | ||
351 | /** | 365 | /** |
366 | * aac_rx_send | ||
367 | * @fib: fib to issue | ||
368 | * | ||
369 | * Will send a fib, returning 0 if successful. | ||
370 | */ | ||
371 | static int aac_rx_send(struct fib * fib) | ||
372 | { | ||
373 | u64 addr = fib->hw_fib_pa; | ||
374 | struct aac_dev *dev = fib->dev; | ||
375 | volatile void __iomem *device = dev->regs.rx; | ||
376 | u32 Index; | ||
377 | |||
378 | dprintk((KERN_DEBUG "%p->aac_rx_send(%p->%llx)\n", dev, fib, addr)); | ||
379 | Index = rx_readl(dev, MUnit.InboundQueue); | ||
380 | if (Index == 0xFFFFFFFFL) | ||
381 | Index = rx_readl(dev, MUnit.InboundQueue); | ||
382 | dprintk((KERN_DEBUG "Index = 0x%x\n", Index)); | ||
383 | if (Index == 0xFFFFFFFFL) | ||
384 | return Index; | ||
385 | device += Index; | ||
386 | dprintk((KERN_DEBUG "entry = %x %x %u\n", (u32)(addr & 0xffffffff), | ||
387 | (u32)(addr >> 32), (u32)le16_to_cpu(fib->hw_fib->header.Size))); | ||
388 | writel((u32)(addr & 0xffffffff), device); | ||
389 | device += sizeof(u32); | ||
390 | writel((u32)(addr >> 32), device); | ||
391 | device += sizeof(u32); | ||
392 | writel(le16_to_cpu(fib->hw_fib->header.Size), device); | ||
393 | rx_writel(dev, MUnit.InboundQueue, Index); | ||
394 | dprintk((KERN_DEBUG "aac_rx_send - return 0\n")); | ||
395 | return 0; | ||
396 | } | ||
397 | |||
398 | /** | ||
352 | * aac_rx_init - initialize an i960 based AAC card | 399 | * aac_rx_init - initialize an i960 based AAC card |
353 | * @dev: device to configure | 400 | * @dev: device to configure |
354 | * | 401 | * |
@@ -368,13 +415,8 @@ int aac_rx_init(struct aac_dev *dev) | |||
368 | name = dev->name; | 415 | name = dev->name; |
369 | 416 | ||
370 | /* | 417 | /* |
371 | * Map in the registers from the adapter. | 418 | * Check to see if the board panic'd while booting. |
372 | */ | 419 | */ |
373 | if((dev->regs.rx = ioremap((unsigned long)dev->scsi_host_ptr->base, 8192))==NULL) | ||
374 | { | ||
375 | printk(KERN_WARNING "aacraid: unable to map i960.\n" ); | ||
376 | return -1; | ||
377 | } | ||
378 | /* | 420 | /* |
379 | * Check to see if the board failed any self tests. | 421 | * Check to see if the board failed any self tests. |
380 | */ | 422 | */ |
@@ -426,6 +468,7 @@ int aac_rx_init(struct aac_dev *dev) | |||
426 | dev->a_ops.adapter_notify = aac_rx_notify_adapter; | 468 | dev->a_ops.adapter_notify = aac_rx_notify_adapter; |
427 | dev->a_ops.adapter_sync_cmd = rx_sync_cmd; | 469 | dev->a_ops.adapter_sync_cmd = rx_sync_cmd; |
428 | dev->a_ops.adapter_check_health = aac_rx_check_health; | 470 | dev->a_ops.adapter_check_health = aac_rx_check_health; |
471 | dev->a_ops.adapter_send = aac_rx_send; | ||
429 | 472 | ||
430 | /* | 473 | /* |
431 | * First clear out all interrupts. Then enable the one's that we | 474 | * First clear out all interrupts. Then enable the one's that we |
@@ -437,15 +480,9 @@ int aac_rx_init(struct aac_dev *dev) | |||
437 | 480 | ||
438 | if (aac_init_adapter(dev) == NULL) | 481 | if (aac_init_adapter(dev) == NULL) |
439 | goto error_irq; | 482 | goto error_irq; |
440 | /* | 483 | if (dev->new_comm_interface) |
441 | * Start any kernel threads needed | 484 | rx_writeb(dev, MUnit.OIMR, dev->OIMR = 0xf7); |
442 | */ | 485 | |
443 | dev->thread_pid = kernel_thread((int (*)(void *))aac_command_thread, dev, 0); | ||
444 | if(dev->thread_pid < 0) | ||
445 | { | ||
446 | printk(KERN_ERR "aacraid: Unable to create rx thread.\n"); | ||
447 | goto error_kfree; | ||
448 | } | ||
449 | /* | 486 | /* |
450 | * Tell the adapter that all is configured, and it can start | 487 | * Tell the adapter that all is configured, and it can start |
451 | * accepting requests | 488 | * accepting requests |
@@ -453,15 +490,11 @@ int aac_rx_init(struct aac_dev *dev) | |||
453 | aac_rx_start_adapter(dev); | 490 | aac_rx_start_adapter(dev); |
454 | return 0; | 491 | return 0; |
455 | 492 | ||
456 | error_kfree: | ||
457 | kfree(dev->queues); | ||
458 | |||
459 | error_irq: | 493 | error_irq: |
460 | rx_writeb(dev, MUnit.OIMR, dev->OIMR = 0xff); | 494 | rx_writeb(dev, MUnit.OIMR, dev->OIMR = 0xff); |
461 | free_irq(dev->scsi_host_ptr->irq, (void *)dev); | 495 | free_irq(dev->scsi_host_ptr->irq, (void *)dev); |
462 | 496 | ||
463 | error_iounmap: | 497 | error_iounmap: |
464 | iounmap(dev->regs.rx); | ||
465 | 498 | ||
466 | return -1; | 499 | return -1; |
467 | } | 500 | } |