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/rkt.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/rkt.c')
-rw-r--r-- | drivers/scsi/aacraid/rkt.c | 172 |
1 files changed, 110 insertions, 62 deletions
diff --git a/drivers/scsi/aacraid/rkt.c b/drivers/scsi/aacraid/rkt.c index 557287a0b80b..fc4c73c2a6a9 100644 --- a/drivers/scsi/aacraid/rkt.c +++ b/drivers/scsi/aacraid/rkt.c | |||
@@ -49,40 +49,57 @@ | |||
49 | static irqreturn_t aac_rkt_intr(int irq, void *dev_id, struct pt_regs *regs) | 49 | static irqreturn_t aac_rkt_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 | if (dev->new_comm_interface) { |
54 | intstat = rkt_readb(dev, MUnit.OISR); | 54 | u32 Index = rkt_readl(dev, MUnit.OutboundQueue); |
55 | /* | 55 | if (Index == 0xFFFFFFFFL) |
56 | * Read mask and invert because drawbridge is reversed. | 56 | Index = rkt_readl(dev, MUnit.OutboundQueue); |
57 | * This allows us to only service interrupts that have | 57 | if (Index != 0xFFFFFFFFL) { |
58 | * been enabled. | 58 | do { |
59 | */ | 59 | if (aac_intr_normal(dev, Index)) { |
60 | mask = ~(dev->OIMR); | 60 | rkt_writel(dev, MUnit.OutboundQueue, Index); |
61 | /* Check to see if this is our interrupt. If it isn't just return */ | 61 | rkt_writel(dev, MUnit.ODR, DoorBellAdapterNormRespReady); |
62 | if (intstat & mask) | 62 | } |
63 | { | 63 | Index = rkt_readl(dev, MUnit.OutboundQueue); |
64 | bellbits = rkt_readl(dev, OutboundDoorbellReg); | 64 | } while (Index != 0xFFFFFFFFL); |
65 | if (bellbits & DoorBellPrintfReady) { | 65 | return IRQ_HANDLED; |
66 | aac_printf(dev, rkt_readl(dev, IndexRegs.Mailbox[5])); | ||
67 | rkt_writel(dev, MUnit.ODR,DoorBellPrintfReady); | ||
68 | rkt_writel(dev, InboundDoorbellReg,DoorBellPrintfDone); | ||
69 | } | ||
70 | else if (bellbits & DoorBellAdapterNormCmdReady) { | ||
71 | rkt_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 | rkt_writel(dev, MUnit.ODR,DoorBellAdapterNormRespReady); | ||
77 | } | ||
78 | else if (bellbits & DoorBellAdapterNormCmdNotFull) { | ||
79 | rkt_writel(dev, MUnit.ODR, DoorBellAdapterNormCmdNotFull); | ||
80 | } | 66 | } |
81 | else if (bellbits & DoorBellAdapterNormRespNotFull) { | 67 | } else { |
82 | rkt_writel(dev, MUnit.ODR, DoorBellAdapterNormCmdNotFull); | 68 | unsigned long bellbits; |
83 | rkt_writel(dev, MUnit.ODR, DoorBellAdapterNormRespNotFull); | 69 | u8 intstat; |
70 | intstat = rkt_readb(dev, MUnit.OISR); | ||
71 | /* | ||
72 | * Read mask and invert because drawbridge is reversed. | ||
73 | * This allows us to only service interrupts that have | ||
74 | * been enabled. | ||
75 | * Check to see if this is our interrupt. If it isn't just return | ||
76 | */ | ||
77 | if (intstat & ~(dev->OIMR)) | ||
78 | { | ||
79 | bellbits = rkt_readl(dev, OutboundDoorbellReg); | ||
80 | if (bellbits & DoorBellPrintfReady) { | ||
81 | aac_printf(dev, rkt_readl (dev, IndexRegs.Mailbox[5])); | ||
82 | rkt_writel(dev, MUnit.ODR,DoorBellPrintfReady); | ||
83 | rkt_writel(dev, InboundDoorbellReg,DoorBellPrintfDone); | ||
84 | } | ||
85 | else if (bellbits & DoorBellAdapterNormCmdReady) { | ||
86 | rkt_writel(dev, MUnit.ODR, DoorBellAdapterNormCmdReady); | ||
87 | aac_command_normal(&dev->queues->queue[HostNormCmdQueue]); | ||
88 | // rkt_writel(dev, MUnit.ODR, DoorBellAdapterNormCmdReady); | ||
89 | } | ||
90 | else if (bellbits & DoorBellAdapterNormRespReady) { | ||
91 | rkt_writel(dev, MUnit.ODR,DoorBellAdapterNormRespReady); | ||
92 | aac_response_normal(&dev->queues->queue[HostNormRespQueue]); | ||
93 | } | ||
94 | else if (bellbits & DoorBellAdapterNormCmdNotFull) { | ||
95 | rkt_writel(dev, MUnit.ODR, DoorBellAdapterNormCmdNotFull); | ||
96 | } | ||
97 | else if (bellbits & DoorBellAdapterNormRespNotFull) { | ||
98 | rkt_writel(dev, MUnit.ODR, DoorBellAdapterNormCmdNotFull); | ||
99 | rkt_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 rkt_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 | rkt_writeb(dev, MUnit.OIMR, dev->OIMR = 0xfb); | 193 | if (dev->new_comm_interface) |
194 | rkt_writeb(dev, MUnit.OIMR, dev->OIMR = 0xf7); | ||
195 | else | ||
196 | rkt_writeb(dev, MUnit.OIMR, dev->OIMR = 0xfb); | ||
177 | return -ETIMEDOUT; | 197 | return -ETIMEDOUT; |
178 | } | 198 | } |
179 | /* | 199 | /* |
@@ -196,7 +216,10 @@ static int rkt_sync_cmd(struct aac_dev *dev, u32 command, | |||
196 | /* | 216 | /* |
197 | * Restore interrupt mask | 217 | * Restore interrupt mask |
198 | */ | 218 | */ |
199 | rkt_writeb(dev, MUnit.OIMR, dev->OIMR = 0xfb); | 219 | if (dev->new_comm_interface) |
220 | rkt_writeb(dev, MUnit.OIMR, dev->OIMR = 0xf7); | ||
221 | else | ||
222 | rkt_writeb(dev, MUnit.OIMR, dev->OIMR = 0xfb); | ||
200 | return 0; | 223 | return 0; |
201 | 224 | ||
202 | } | 225 | } |
@@ -268,15 +291,6 @@ static void aac_rkt_start_adapter(struct aac_dev *dev) | |||
268 | 291 | ||
269 | init = dev->init; | 292 | init = dev->init; |
270 | init->HostElapsedSeconds = cpu_to_le32(get_seconds()); | 293 | init->HostElapsedSeconds = cpu_to_le32(get_seconds()); |
271 | /* | ||
272 | * First clear out all interrupts. Then enable the one's that we | ||
273 | * can handle. | ||
274 | */ | ||
275 | rkt_writeb(dev, MUnit.OIMR, 0xff); | ||
276 | rkt_writel(dev, MUnit.ODR, 0xffffffff); | ||
277 | // rkt_writeb(dev, MUnit.OIMR, ~(u8)OUTBOUND_DOORBELL_INTERRUPT_MASK); | ||
278 | rkt_writeb(dev, MUnit.OIMR, dev->OIMR = 0xfb); | ||
279 | |||
280 | // We can only use a 32 bit address here | 294 | // We can only use a 32 bit address here |
281 | rkt_sync_cmd(dev, INIT_STRUCT_BASE_ADDRESS, (u32)(ulong)dev->init_pa, | 295 | rkt_sync_cmd(dev, INIT_STRUCT_BASE_ADDRESS, (u32)(ulong)dev->init_pa, |
282 | 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL); | 296 | 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL); |
@@ -350,6 +364,39 @@ static int aac_rkt_check_health(struct aac_dev *dev) | |||
350 | } | 364 | } |
351 | 365 | ||
352 | /** | 366 | /** |
367 | * aac_rkt_send | ||
368 | * @fib: fib to issue | ||
369 | * | ||
370 | * Will send a fib, returning 0 if successful. | ||
371 | */ | ||
372 | static int aac_rkt_send(struct fib * fib) | ||
373 | { | ||
374 | u64 addr = fib->hw_fib_pa; | ||
375 | struct aac_dev *dev = fib->dev; | ||
376 | volatile void __iomem *device = dev->regs.rkt; | ||
377 | u32 Index; | ||
378 | |||
379 | dprintk((KERN_DEBUG "%p->aac_rkt_send(%p->%llx)\n", dev, fib, addr)); | ||
380 | Index = rkt_readl(dev, MUnit.InboundQueue); | ||
381 | if (Index == 0xFFFFFFFFL) | ||
382 | Index = rkt_readl(dev, MUnit.InboundQueue); | ||
383 | dprintk((KERN_DEBUG "Index = 0x%x\n", Index)); | ||
384 | if (Index == 0xFFFFFFFFL) | ||
385 | return Index; | ||
386 | device += Index; | ||
387 | dprintk((KERN_DEBUG "entry = %x %x %u\n", (u32)(addr & 0xffffffff), | ||
388 | (u32)(addr >> 32), (u32)le16_to_cpu(fib->hw_fib->header.Size))); | ||
389 | writel((u32)(addr & 0xffffffff), device); | ||
390 | device += sizeof(u32); | ||
391 | writel((u32)(addr >> 32), device); | ||
392 | device += sizeof(u32); | ||
393 | writel(le16_to_cpu(fib->hw_fib->header.Size), device); | ||
394 | rkt_writel(dev, MUnit.InboundQueue, Index); | ||
395 | dprintk((KERN_DEBUG "aac_rkt_send - return 0\n")); | ||
396 | return 0; | ||
397 | } | ||
398 | |||
399 | /** | ||
353 | * aac_rkt_init - initialize an i960 based AAC card | 400 | * aac_rkt_init - initialize an i960 based AAC card |
354 | * @dev: device to configure | 401 | * @dev: device to configure |
355 | * | 402 | * |
@@ -369,13 +416,8 @@ int aac_rkt_init(struct aac_dev *dev) | |||
369 | name = dev->name; | 416 | name = dev->name; |
370 | 417 | ||
371 | /* | 418 | /* |
372 | * Map in the registers from the adapter. | 419 | * Check to see if the board panic'd while booting. |
373 | */ | 420 | */ |
374 | if((dev->regs.rkt = ioremap((unsigned long)dev->scsi_host_ptr->base, 8192))==NULL) | ||
375 | { | ||
376 | printk(KERN_WARNING "aacraid: unable to map i960.\n" ); | ||
377 | goto error_iounmap; | ||
378 | } | ||
379 | /* | 421 | /* |
380 | * Check to see if the board failed any self tests. | 422 | * Check to see if the board failed any self tests. |
381 | */ | 423 | */ |
@@ -426,6 +468,7 @@ int aac_rkt_init(struct aac_dev *dev) | |||
426 | dev->a_ops.adapter_notify = aac_rkt_notify_adapter; | 468 | dev->a_ops.adapter_notify = aac_rkt_notify_adapter; |
427 | dev->a_ops.adapter_sync_cmd = rkt_sync_cmd; | 469 | dev->a_ops.adapter_sync_cmd = rkt_sync_cmd; |
428 | dev->a_ops.adapter_check_health = aac_rkt_check_health; | 470 | dev->a_ops.adapter_check_health = aac_rkt_check_health; |
471 | dev->a_ops.adapter_send = aac_rkt_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,24 @@ int aac_rkt_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 | /* |
442 | */ | 485 | * FIB Setup has already been done, but we can minimize the |
443 | dev->thread_pid = kernel_thread((int (*)(void *))aac_command_thread, dev, 0); | 486 | * damage by at least ensuring the OS never issues more |
444 | if(dev->thread_pid < 0) | 487 | * commands than we can handle. The Rocket adapters currently |
445 | { | 488 | * can only handle 246 commands and 8 AIFs at the same time, |
446 | printk(KERN_ERR "aacraid: Unable to create rkt thread.\n"); | 489 | * and in fact do notify us accordingly if we negotiate the |
447 | goto error_kfree; | 490 | * FIB size. The problem that causes us to add this check is |
448 | } | 491 | * to ensure that we do not overdo it with the adapter when a |
492 | * hard coded FIB override is being utilized. This special | ||
493 | * case warrants this half baked, but convenient, check here. | ||
494 | */ | ||
495 | if (dev->scsi_host_ptr->can_queue > (246 - AAC_NUM_MGT_FIB)) { | ||
496 | dev->init->MaxIoCommands = cpu_to_le32(246); | ||
497 | dev->scsi_host_ptr->can_queue = 246 - AAC_NUM_MGT_FIB; | ||
498 | } | ||
499 | rkt_writeb(dev, MUnit.OIMR, dev->OIMR = 0xf7); | ||
500 | } | ||
449 | /* | 501 | /* |
450 | * Tell the adapter that all is configured, and it can start | 502 | * Tell the adapter that all is configured, and it can start |
451 | * accepting requests | 503 | * accepting requests |
@@ -453,15 +505,11 @@ int aac_rkt_init(struct aac_dev *dev) | |||
453 | aac_rkt_start_adapter(dev); | 505 | aac_rkt_start_adapter(dev); |
454 | return 0; | 506 | return 0; |
455 | 507 | ||
456 | error_kfree: | ||
457 | kfree(dev->queues); | ||
458 | |||
459 | error_irq: | 508 | error_irq: |
460 | rkt_writeb(dev, MUnit.OIMR, dev->OIMR = 0xff); | 509 | rkt_writeb(dev, MUnit.OIMR, dev->OIMR = 0xff); |
461 | free_irq(dev->scsi_host_ptr->irq, (void *)dev); | 510 | free_irq(dev->scsi_host_ptr->irq, (void *)dev); |
462 | 511 | ||
463 | error_iounmap: | 512 | error_iounmap: |
464 | iounmap(dev->regs.rkt); | ||
465 | 513 | ||
466 | return -1; | 514 | return -1; |
467 | } | 515 | } |