diff options
author | Markus Lidel <Markus.Lidel@shadowconnect.com> | 2005-06-24 01:02:16 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-06-24 03:05:28 -0400 |
commit | f10378fff658f61307496e0ae00095041725cf07 (patch) | |
tree | 0c0413649317677771fa325dded94f1e12a6a0b7 /drivers/message/i2o/iop.c | |
parent | f88e119c4b824a5017456fa094950d0f4092d96c (diff) |
[PATCH] I2O: new sysfs attributes and Adaptec specific block device access and 64-bit DMA support
Changes:
- Added Bus-OSM which could be used by user space programs to reset a
channel on the controller
- Make ioctl's in Config-OSM obsolete in prefer for sysfs attributes and
move those to its own file
- Added sysfs attribute for firmware read and write access for I2O
controllers
- Added special handling of firmware read and write access for Adaptec
controllers
- Added vendor id and product id as sysfs-attribute to Executive classes
- Added automatic notification of LCT change handling to Exec-OSM
- Added flushing function to Block-OSM for later barrier implementation
- Use PRIVATE messages for Block access on Adaptec controllers, which are
faster then BLOCK class access
- Cleaned up support for Promise controller
- New messages are now detected using the IRQ status register as
suggested by the I2O spec
- Added i2o_dma_high() and i2o_dma_low() functions
- Added facility for SG tablesize calculation when using 32-bit and
64-bit DMA addresses
- Added i2o_dma_map_single() and i2o_dma_map_sg() which could build the
SG list for 32-bit as well as 64-bit DMA addresses
Signed-off-by: Markus Lidel <Markus.Lidel@shadowconnect.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'drivers/message/i2o/iop.c')
-rw-r--r-- | drivers/message/i2o/iop.c | 263 |
1 files changed, 117 insertions, 146 deletions
diff --git a/drivers/message/i2o/iop.c b/drivers/message/i2o/iop.c index 62b0d8bed186..40312053b38d 100644 --- a/drivers/message/i2o/iop.c +++ b/drivers/message/i2o/iop.c | |||
@@ -456,6 +456,70 @@ static int i2o_iop_clear(struct i2o_controller *c) | |||
456 | } | 456 | } |
457 | 457 | ||
458 | /** | 458 | /** |
459 | * i2o_iop_init_outbound_queue - setup the outbound message queue | ||
460 | * @c: I2O controller | ||
461 | * | ||
462 | * Clear and (re)initialize IOP's outbound queue and post the message | ||
463 | * frames to the IOP. | ||
464 | * | ||
465 | * Returns 0 on success or a negative errno code on failure. | ||
466 | */ | ||
467 | static int i2o_iop_init_outbound_queue(struct i2o_controller *c) | ||
468 | { | ||
469 | u8 *status = c->status.virt; | ||
470 | u32 m; | ||
471 | struct i2o_message __iomem *msg; | ||
472 | ulong timeout; | ||
473 | int i; | ||
474 | |||
475 | osm_debug("%s: Initializing Outbound Queue...\n", c->name); | ||
476 | |||
477 | memset(status, 0, 4); | ||
478 | |||
479 | m = i2o_msg_get_wait(c, &msg, I2O_TIMEOUT_MESSAGE_GET); | ||
480 | if (m == I2O_QUEUE_EMPTY) | ||
481 | return -ETIMEDOUT; | ||
482 | |||
483 | writel(EIGHT_WORD_MSG_SIZE | TRL_OFFSET_6, &msg->u.head[0]); | ||
484 | writel(I2O_CMD_OUTBOUND_INIT << 24 | HOST_TID << 12 | ADAPTER_TID, | ||
485 | &msg->u.head[1]); | ||
486 | writel(i2o_exec_driver.context, &msg->u.s.icntxt); | ||
487 | writel(0x0106, &msg->u.s.tcntxt); /* FIXME: why 0x0106, maybe in | ||
488 | Spec? */ | ||
489 | writel(PAGE_SIZE, &msg->body[0]); | ||
490 | /* Outbound msg frame size in words and Initcode */ | ||
491 | writel(MSG_FRAME_SIZE << 16 | 0x80, &msg->body[1]); | ||
492 | writel(0xd0000004, &msg->body[2]); | ||
493 | writel(i2o_dma_low(c->status.phys), &msg->body[3]); | ||
494 | writel(i2o_dma_high(c->status.phys), &msg->body[4]); | ||
495 | |||
496 | i2o_msg_post(c, m); | ||
497 | |||
498 | timeout = jiffies + I2O_TIMEOUT_INIT_OUTBOUND_QUEUE * HZ; | ||
499 | while (*status <= I2O_CMD_IN_PROGRESS) { | ||
500 | if (time_after(jiffies, timeout)) { | ||
501 | osm_warn("%s: Timeout Initializing\n", c->name); | ||
502 | return -ETIMEDOUT; | ||
503 | } | ||
504 | set_current_state(TASK_UNINTERRUPTIBLE); | ||
505 | schedule_timeout(1); | ||
506 | |||
507 | rmb(); | ||
508 | } | ||
509 | |||
510 | m = c->out_queue.phys; | ||
511 | |||
512 | /* Post frames */ | ||
513 | for (i = 0; i < NMBR_MSG_FRAMES; i++) { | ||
514 | i2o_flush_reply(c, m); | ||
515 | udelay(1); /* Promise */ | ||
516 | m += MSG_FRAME_SIZE * 4; | ||
517 | } | ||
518 | |||
519 | return 0; | ||
520 | } | ||
521 | |||
522 | /** | ||
459 | * i2o_iop_reset - reset an I2O controller | 523 | * i2o_iop_reset - reset an I2O controller |
460 | * @c: controller to reset | 524 | * @c: controller to reset |
461 | * | 525 | * |
@@ -491,25 +555,16 @@ static int i2o_iop_reset(struct i2o_controller *c) | |||
491 | writel(0, &msg->u.s.tcntxt); //FIXME: use reasonable transaction context | 555 | writel(0, &msg->u.s.tcntxt); //FIXME: use reasonable transaction context |
492 | writel(0, &msg->body[0]); | 556 | writel(0, &msg->body[0]); |
493 | writel(0, &msg->body[1]); | 557 | writel(0, &msg->body[1]); |
494 | writel(i2o_ptr_low((void *)c->status.phys), &msg->body[2]); | 558 | writel(i2o_dma_low(c->status.phys), &msg->body[2]); |
495 | writel(i2o_ptr_high((void *)c->status.phys), &msg->body[3]); | 559 | writel(i2o_dma_high(c->status.phys), &msg->body[3]); |
496 | 560 | ||
497 | i2o_msg_post(c, m); | 561 | i2o_msg_post(c, m); |
498 | 562 | ||
499 | /* Wait for a reply */ | 563 | /* Wait for a reply */ |
500 | timeout = jiffies + I2O_TIMEOUT_RESET * HZ; | 564 | timeout = jiffies + I2O_TIMEOUT_RESET * HZ; |
501 | while (!*status) { | 565 | while (!*status) { |
502 | if (time_after(jiffies, timeout)) { | 566 | if (time_after(jiffies, timeout)) |
503 | printk(KERN_ERR "%s: IOP reset timeout.\n", c->name); | ||
504 | rc = -ETIMEDOUT; | ||
505 | goto exit; | ||
506 | } | ||
507 | |||
508 | /* Promise bug */ | ||
509 | if (status[1] || status[4]) { | ||
510 | *status = 0; | ||
511 | break; | 567 | break; |
512 | } | ||
513 | 568 | ||
514 | set_current_state(TASK_UNINTERRUPTIBLE); | 569 | set_current_state(TASK_UNINTERRUPTIBLE); |
515 | schedule_timeout(1); | 570 | schedule_timeout(1); |
@@ -517,14 +572,20 @@ static int i2o_iop_reset(struct i2o_controller *c) | |||
517 | rmb(); | 572 | rmb(); |
518 | } | 573 | } |
519 | 574 | ||
520 | if (*status == I2O_CMD_IN_PROGRESS) { | 575 | switch (*status) { |
576 | case I2O_CMD_REJECTED: | ||
577 | osm_warn("%s: IOP reset rejected\n", c->name); | ||
578 | rc = -EPERM; | ||
579 | break; | ||
580 | |||
581 | case I2O_CMD_IN_PROGRESS: | ||
521 | /* | 582 | /* |
522 | * Once the reset is sent, the IOP goes into the INIT state | 583 | * Once the reset is sent, the IOP goes into the INIT state |
523 | * which is indeterminate. We need to wait until the IOP | 584 | * which is indeterminate. We need to wait until the IOP has |
524 | * has rebooted before we can let the system talk to | 585 | * rebooted before we can let the system talk to it. We read |
525 | * it. We read the inbound Free_List until a message is | 586 | * the inbound Free_List until a message is available. If we |
526 | * available. If we can't read one in the given ammount of | 587 | * can't read one in the given ammount of time, we assume the |
527 | * time, we assume the IOP could not reboot properly. | 588 | * IOP could not reboot properly. |
528 | */ | 589 | */ |
529 | pr_debug("%s: Reset in progress, waiting for reboot...\n", | 590 | pr_debug("%s: Reset in progress, waiting for reboot...\n", |
530 | c->name); | 591 | c->name); |
@@ -543,19 +604,26 @@ static int i2o_iop_reset(struct i2o_controller *c) | |||
543 | m = i2o_msg_get_wait(c, &msg, I2O_TIMEOUT_RESET); | 604 | m = i2o_msg_get_wait(c, &msg, I2O_TIMEOUT_RESET); |
544 | } | 605 | } |
545 | i2o_msg_nop(c, m); | 606 | i2o_msg_nop(c, m); |
546 | } | ||
547 | 607 | ||
548 | /* from here all quiesce commands are safe */ | 608 | /* from here all quiesce commands are safe */ |
549 | c->no_quiesce = 0; | 609 | c->no_quiesce = 0; |
550 | 610 | ||
551 | /* If IopReset was rejected or didn't perform reset, try IopClear */ | 611 | /* verify if controller is in state RESET */ |
552 | i2o_status_get(c); | 612 | i2o_status_get(c); |
553 | if (*status == I2O_CMD_REJECTED || sb->iop_state != ADAPTER_STATE_RESET) { | 613 | |
554 | printk(KERN_WARNING "%s: Reset rejected, trying to clear\n", | 614 | if (!c->promise && (sb->iop_state != ADAPTER_STATE_RESET)) |
555 | c->name); | 615 | osm_warn("%s: reset completed, but adapter not in RESET" |
556 | i2o_iop_clear(c); | 616 | " state.\n", c->name); |
557 | } else | 617 | else |
558 | pr_debug("%s: Reset completed.\n", c->name); | 618 | osm_debug("%s: reset completed.\n", c->name); |
619 | |||
620 | break; | ||
621 | |||
622 | default: | ||
623 | osm_err("%s: IOP reset timeout.\n", c->name); | ||
624 | rc = -ETIMEDOUT; | ||
625 | break; | ||
626 | } | ||
559 | 627 | ||
560 | exit: | 628 | exit: |
561 | /* Enable all IOPs */ | 629 | /* Enable all IOPs */ |
@@ -565,87 +633,6 @@ static int i2o_iop_reset(struct i2o_controller *c) | |||
565 | }; | 633 | }; |
566 | 634 | ||
567 | /** | 635 | /** |
568 | * i2o_iop_init_outbound_queue - setup the outbound message queue | ||
569 | * @c: I2O controller | ||
570 | * | ||
571 | * Clear and (re)initialize IOP's outbound queue and post the message | ||
572 | * frames to the IOP. | ||
573 | * | ||
574 | * Returns 0 on success or a negative errno code on failure. | ||
575 | */ | ||
576 | static int i2o_iop_init_outbound_queue(struct i2o_controller *c) | ||
577 | { | ||
578 | u8 *status = c->status.virt; | ||
579 | u32 m; | ||
580 | struct i2o_message __iomem *msg; | ||
581 | ulong timeout; | ||
582 | int i; | ||
583 | |||
584 | pr_debug("%s: Initializing Outbound Queue...\n", c->name); | ||
585 | |||
586 | memset(status, 0, 4); | ||
587 | |||
588 | m = i2o_msg_get_wait(c, &msg, I2O_TIMEOUT_MESSAGE_GET); | ||
589 | if (m == I2O_QUEUE_EMPTY) | ||
590 | return -ETIMEDOUT; | ||
591 | |||
592 | writel(EIGHT_WORD_MSG_SIZE | SGL_OFFSET_6, &msg->u.head[0]); | ||
593 | writel(I2O_CMD_OUTBOUND_INIT << 24 | HOST_TID << 12 | ADAPTER_TID, | ||
594 | &msg->u.head[1]); | ||
595 | writel(i2o_exec_driver.context, &msg->u.s.icntxt); | ||
596 | writel(0x00000000, &msg->u.s.tcntxt); | ||
597 | writel(PAGE_SIZE, &msg->body[0]); | ||
598 | writel(MSG_FRAME_SIZE << 16 | 0x80, &msg->body[1]); /* Outbound msg frame | ||
599 | size in words and Initcode */ | ||
600 | writel(0xd0000004, &msg->body[2]); | ||
601 | writel(i2o_ptr_low((void *)c->status.phys), &msg->body[3]); | ||
602 | writel(i2o_ptr_high((void *)c->status.phys), &msg->body[4]); | ||
603 | |||
604 | i2o_msg_post(c, m); | ||
605 | |||
606 | timeout = jiffies + I2O_TIMEOUT_INIT_OUTBOUND_QUEUE * HZ; | ||
607 | while (*status <= I2O_CMD_IN_PROGRESS) { | ||
608 | if (time_after(jiffies, timeout)) { | ||
609 | printk(KERN_WARNING "%s: Timeout Initializing\n", | ||
610 | c->name); | ||
611 | return -ETIMEDOUT; | ||
612 | } | ||
613 | set_current_state(TASK_UNINTERRUPTIBLE); | ||
614 | schedule_timeout(1); | ||
615 | |||
616 | rmb(); | ||
617 | } | ||
618 | |||
619 | m = c->out_queue.phys; | ||
620 | |||
621 | /* Post frames */ | ||
622 | for (i = 0; i < NMBR_MSG_FRAMES; i++) { | ||
623 | i2o_flush_reply(c, m); | ||
624 | udelay(1); /* Promise */ | ||
625 | m += MSG_FRAME_SIZE * 4; | ||
626 | } | ||
627 | |||
628 | return 0; | ||
629 | } | ||
630 | |||
631 | /** | ||
632 | * i2o_iop_send_nop - send a core NOP message | ||
633 | * @c: controller | ||
634 | * | ||
635 | * Send a no-operation message with a reply set to cause no | ||
636 | * action either. Needed for bringing up promise controllers. | ||
637 | */ | ||
638 | static int i2o_iop_send_nop(struct i2o_controller *c) | ||
639 | { | ||
640 | struct i2o_message __iomem *msg; | ||
641 | u32 m = i2o_msg_get_wait(c, &msg, HZ); | ||
642 | if (m == I2O_QUEUE_EMPTY) | ||
643 | return -ETIMEDOUT; | ||
644 | i2o_msg_nop(c, m); | ||
645 | return 0; | ||
646 | } | ||
647 | |||
648 | /** | ||
649 | * i2o_iop_activate - Bring controller up to HOLD | 636 | * i2o_iop_activate - Bring controller up to HOLD |
650 | * @c: controller | 637 | * @c: controller |
651 | * | 638 | * |
@@ -656,26 +643,9 @@ static int i2o_iop_send_nop(struct i2o_controller *c) | |||
656 | */ | 643 | */ |
657 | static int i2o_iop_activate(struct i2o_controller *c) | 644 | static int i2o_iop_activate(struct i2o_controller *c) |
658 | { | 645 | { |
659 | struct pci_dev *i960 = NULL; | ||
660 | i2o_status_block *sb = c->status_block.virt; | 646 | i2o_status_block *sb = c->status_block.virt; |
661 | int rc; | 647 | int rc; |
662 | 648 | int state; | |
663 | if (c->promise) { | ||
664 | /* Beat up the hardware first of all */ | ||
665 | i960 = | ||
666 | pci_find_slot(c->pdev->bus->number, | ||
667 | PCI_DEVFN(PCI_SLOT(c->pdev->devfn), 0)); | ||
668 | if (i960) | ||
669 | pci_write_config_word(i960, 0x42, 0); | ||
670 | |||
671 | /* Follow this sequence precisely or the controller | ||
672 | ceases to perform useful functions until reboot */ | ||
673 | if ((rc = i2o_iop_send_nop(c))) | ||
674 | return rc; | ||
675 | |||
676 | if ((rc = i2o_iop_reset(c))) | ||
677 | return rc; | ||
678 | } | ||
679 | 649 | ||
680 | /* In INIT state, Wait Inbound Q to initialize (in i2o_status_get) */ | 650 | /* In INIT state, Wait Inbound Q to initialize (in i2o_status_get) */ |
681 | /* In READY state, Get status */ | 651 | /* In READY state, Get status */ |
@@ -684,7 +654,8 @@ static int i2o_iop_activate(struct i2o_controller *c) | |||
684 | if (rc) { | 654 | if (rc) { |
685 | printk(KERN_INFO "%s: Unable to obtain status, " | 655 | printk(KERN_INFO "%s: Unable to obtain status, " |
686 | "attempting a reset.\n", c->name); | 656 | "attempting a reset.\n", c->name); |
687 | if (i2o_iop_reset(c)) | 657 | rc = i2o_iop_reset(c); |
658 | if (rc) | ||
688 | return rc; | 659 | return rc; |
689 | } | 660 | } |
690 | 661 | ||
@@ -697,37 +668,37 @@ static int i2o_iop_activate(struct i2o_controller *c) | |||
697 | switch (sb->iop_state) { | 668 | switch (sb->iop_state) { |
698 | case ADAPTER_STATE_FAULTED: | 669 | case ADAPTER_STATE_FAULTED: |
699 | printk(KERN_CRIT "%s: hardware fault\n", c->name); | 670 | printk(KERN_CRIT "%s: hardware fault\n", c->name); |
700 | return -ENODEV; | 671 | return -EFAULT; |
701 | 672 | ||
702 | case ADAPTER_STATE_READY: | 673 | case ADAPTER_STATE_READY: |
703 | case ADAPTER_STATE_OPERATIONAL: | 674 | case ADAPTER_STATE_OPERATIONAL: |
704 | case ADAPTER_STATE_HOLD: | 675 | case ADAPTER_STATE_HOLD: |
705 | case ADAPTER_STATE_FAILED: | 676 | case ADAPTER_STATE_FAILED: |
706 | pr_debug("%s: already running, trying to reset...\n", c->name); | 677 | pr_debug("%s: already running, trying to reset...\n", c->name); |
707 | if (i2o_iop_reset(c)) | 678 | rc = i2o_iop_reset(c); |
708 | return -ENODEV; | 679 | if (rc) |
680 | return rc; | ||
709 | } | 681 | } |
710 | 682 | ||
683 | /* preserve state */ | ||
684 | state = sb->iop_state; | ||
685 | |||
711 | rc = i2o_iop_init_outbound_queue(c); | 686 | rc = i2o_iop_init_outbound_queue(c); |
712 | if (rc) | 687 | if (rc) |
713 | return rc; | 688 | return rc; |
714 | 689 | ||
715 | if (c->promise) { | 690 | /* if adapter was not in RESET state clear now */ |
716 | if ((rc = i2o_iop_send_nop(c))) | 691 | if (state != ADAPTER_STATE_RESET) |
717 | return rc; | 692 | i2o_iop_clear(c); |
718 | 693 | ||
719 | if ((rc = i2o_status_get(c))) | 694 | i2o_status_get(c); |
720 | return rc; | ||
721 | 695 | ||
722 | if (i960) | 696 | if (sb->iop_state != ADAPTER_STATE_HOLD) { |
723 | pci_write_config_word(i960, 0x42, 0x3FF); | 697 | osm_err("%s: failed to bring IOP into HOLD state\n", c->name); |
698 | return -EIO; | ||
724 | } | 699 | } |
725 | 700 | ||
726 | /* In HOLD state */ | 701 | return i2o_hrt_get(c); |
727 | |||
728 | rc = i2o_hrt_get(c); | ||
729 | |||
730 | return rc; | ||
731 | }; | 702 | }; |
732 | 703 | ||
733 | /** | 704 | /** |
@@ -1030,8 +1001,8 @@ int i2o_status_get(struct i2o_controller *c) | |||
1030 | writel(0, &msg->u.s.tcntxt); // FIXME: use resonable transaction context | 1001 | writel(0, &msg->u.s.tcntxt); // FIXME: use resonable transaction context |
1031 | writel(0, &msg->body[0]); | 1002 | writel(0, &msg->body[0]); |
1032 | writel(0, &msg->body[1]); | 1003 | writel(0, &msg->body[1]); |
1033 | writel(i2o_ptr_low((void *)c->status_block.phys), &msg->body[2]); | 1004 | writel(i2o_dma_low(c->status_block.phys), &msg->body[2]); |
1034 | writel(i2o_ptr_high((void *)c->status_block.phys), &msg->body[3]); | 1005 | writel(i2o_dma_high(c->status_block.phys), &msg->body[3]); |
1035 | writel(sizeof(i2o_status_block), &msg->body[4]); /* always 88 bytes */ | 1006 | writel(sizeof(i2o_status_block), &msg->body[4]); /* always 88 bytes */ |
1036 | 1007 | ||
1037 | i2o_msg_post(c, m); | 1008 | i2o_msg_post(c, m); |