diff options
-rw-r--r-- | drivers/scsi/scsi_transport_spi.c | 77 |
1 files changed, 53 insertions, 24 deletions
diff --git a/drivers/scsi/scsi_transport_spi.c b/drivers/scsi/scsi_transport_spi.c index 67c6cc40ce16..c87ae469d707 100644 --- a/drivers/scsi/scsi_transport_spi.c +++ b/drivers/scsi/scsi_transport_spi.c | |||
@@ -669,6 +669,7 @@ spi_dv_retrain(struct scsi_request *sreq, u8 *buffer, u8 *ptr, | |||
669 | { | 669 | { |
670 | struct spi_internal *i = to_spi_internal(sreq->sr_host->transportt); | 670 | struct spi_internal *i = to_spi_internal(sreq->sr_host->transportt); |
671 | struct scsi_device *sdev = sreq->sr_device; | 671 | struct scsi_device *sdev = sreq->sr_device; |
672 | struct scsi_target *starget = sdev->sdev_target; | ||
672 | int period = 0, prevperiod = 0; | 673 | int period = 0, prevperiod = 0; |
673 | enum spi_compare_returns retval; | 674 | enum spi_compare_returns retval; |
674 | 675 | ||
@@ -682,24 +683,40 @@ spi_dv_retrain(struct scsi_request *sreq, u8 *buffer, u8 *ptr, | |||
682 | break; | 683 | break; |
683 | 684 | ||
684 | /* OK, retrain, fallback */ | 685 | /* OK, retrain, fallback */ |
686 | if (i->f->get_iu) | ||
687 | i->f->get_iu(starget); | ||
688 | if (i->f->get_qas) | ||
689 | i->f->get_qas(starget); | ||
685 | if (i->f->get_period) | 690 | if (i->f->get_period) |
686 | i->f->get_period(sdev->sdev_target); | 691 | i->f->get_period(sdev->sdev_target); |
687 | newperiod = spi_period(sdev->sdev_target); | 692 | |
688 | period = newperiod > period ? newperiod : period; | 693 | /* Here's the fallback sequence; first try turning off |
689 | if (period < 0x0d) | 694 | * IU, then QAS (if we can control them), then finally |
690 | period++; | 695 | * fall down the periods */ |
691 | else | 696 | if (i->f->set_iu && spi_iu(starget)) { |
692 | period += period >> 1; | 697 | SPI_PRINTK(starget, KERN_ERR, "Domain Validation Disabing Information Units\n"); |
693 | 698 | DV_SET(iu, 0); | |
694 | if (unlikely(period > 0xff || period == prevperiod)) { | 699 | } else if (i->f->set_qas && spi_qas(starget)) { |
695 | /* Total failure; set to async and return */ | 700 | SPI_PRINTK(starget, KERN_ERR, "Domain Validation Disabing Quick Arbitration and Selection\n"); |
696 | SPI_PRINTK(sdev->sdev_target, KERN_ERR, "Domain Validation Failure, dropping back to Asynchronous\n"); | 701 | DV_SET(qas, 0); |
697 | DV_SET(offset, 0); | 702 | } else { |
698 | return SPI_COMPARE_FAILURE; | 703 | newperiod = spi_period(starget); |
704 | period = newperiod > period ? newperiod : period; | ||
705 | if (period < 0x0d) | ||
706 | period++; | ||
707 | else | ||
708 | period += period >> 1; | ||
709 | |||
710 | if (unlikely(period > 0xff || period == prevperiod)) { | ||
711 | /* Total failure; set to async and return */ | ||
712 | SPI_PRINTK(starget, KERN_ERR, "Domain Validation Failure, dropping back to Asynchronous\n"); | ||
713 | DV_SET(offset, 0); | ||
714 | return SPI_COMPARE_FAILURE; | ||
715 | } | ||
716 | SPI_PRINTK(starget, KERN_ERR, "Domain Validation detected failure, dropping back\n"); | ||
717 | DV_SET(period, period); | ||
718 | prevperiod = period; | ||
699 | } | 719 | } |
700 | SPI_PRINTK(sdev->sdev_target, KERN_ERR, "Domain Validation detected failure, dropping back\n"); | ||
701 | DV_SET(period, period); | ||
702 | prevperiod = period; | ||
703 | } | 720 | } |
704 | return retval; | 721 | return retval; |
705 | } | 722 | } |
@@ -768,23 +785,21 @@ spi_dv_device_internal(struct scsi_request *sreq, u8 *buffer) | |||
768 | 785 | ||
769 | if (spi_dv_device_compare_inquiry(sreq, buffer, buffer, DV_LOOPS) | 786 | if (spi_dv_device_compare_inquiry(sreq, buffer, buffer, DV_LOOPS) |
770 | != SPI_COMPARE_SUCCESS) { | 787 | != SPI_COMPARE_SUCCESS) { |
771 | SPI_PRINTK(sdev->sdev_target, KERN_ERR, "Domain Validation Initial Inquiry Failed\n"); | 788 | SPI_PRINTK(starget, KERN_ERR, "Domain Validation Initial Inquiry Failed\n"); |
772 | /* FIXME: should probably offline the device here? */ | 789 | /* FIXME: should probably offline the device here? */ |
773 | return; | 790 | return; |
774 | } | 791 | } |
775 | 792 | ||
776 | /* test width */ | 793 | /* test width */ |
777 | if (i->f->set_width && spi_max_width(starget) && sdev->wdtr) { | 794 | if (i->f->set_width && spi_max_width(starget) && sdev->wdtr) { |
778 | i->f->set_width(sdev->sdev_target, 1); | 795 | i->f->set_width(starget, 1); |
779 | |||
780 | printk("WIDTH IS %d\n", spi_max_width(starget)); | ||
781 | 796 | ||
782 | if (spi_dv_device_compare_inquiry(sreq, buffer, | 797 | if (spi_dv_device_compare_inquiry(sreq, buffer, |
783 | buffer + len, | 798 | buffer + len, |
784 | DV_LOOPS) | 799 | DV_LOOPS) |
785 | != SPI_COMPARE_SUCCESS) { | 800 | != SPI_COMPARE_SUCCESS) { |
786 | SPI_PRINTK(sdev->sdev_target, KERN_ERR, "Wide Transfers Fail\n"); | 801 | SPI_PRINTK(starget, KERN_ERR, "Wide Transfers Fail\n"); |
787 | i->f->set_width(sdev->sdev_target, 0); | 802 | i->f->set_width(starget, 0); |
788 | } | 803 | } |
789 | } | 804 | } |
790 | 805 | ||
@@ -792,7 +807,7 @@ spi_dv_device_internal(struct scsi_request *sreq, u8 *buffer) | |||
792 | return; | 807 | return; |
793 | 808 | ||
794 | /* device can't handle synchronous */ | 809 | /* device can't handle synchronous */ |
795 | if(!sdev->ppr && !sdev->sdtr) | 810 | if (!sdev->ppr && !sdev->sdtr) |
796 | return; | 811 | return; |
797 | 812 | ||
798 | /* see if the device has an echo buffer. If it does we can | 813 | /* see if the device has an echo buffer. If it does we can |
@@ -807,16 +822,30 @@ spi_dv_device_internal(struct scsi_request *sreq, u8 *buffer) | |||
807 | /* now set up to the maximum */ | 822 | /* now set up to the maximum */ |
808 | DV_SET(offset, spi_max_offset(starget)); | 823 | DV_SET(offset, spi_max_offset(starget)); |
809 | DV_SET(period, spi_min_period(starget)); | 824 | DV_SET(period, spi_min_period(starget)); |
825 | /* try QAS requests; this should be harmless to set if the | ||
826 | * target supports it */ | ||
827 | DV_SET(qas, 1); | ||
828 | /* Also try IU transfers */ | ||
829 | DV_SET(iu, 1); | ||
830 | if (spi_min_period(starget) < 9) { | ||
831 | /* This u320 (or u640). Ignore the coupled parameters | ||
832 | * like DT and IU, but set the optional ones */ | ||
833 | DV_SET(rd_strm, 1); | ||
834 | DV_SET(wr_flow, 1); | ||
835 | DV_SET(rti, 1); | ||
836 | if (spi_min_period(starget) == 8) | ||
837 | DV_SET(pcomp_en, 1); | ||
838 | } | ||
810 | 839 | ||
811 | if (len == 0) { | 840 | if (len == 0) { |
812 | SPI_PRINTK(sdev->sdev_target, KERN_INFO, "Domain Validation skipping write tests\n"); | 841 | SPI_PRINTK(starget, KERN_INFO, "Domain Validation skipping write tests\n"); |
813 | spi_dv_retrain(sreq, buffer, buffer + len, | 842 | spi_dv_retrain(sreq, buffer, buffer + len, |
814 | spi_dv_device_compare_inquiry); | 843 | spi_dv_device_compare_inquiry); |
815 | return; | 844 | return; |
816 | } | 845 | } |
817 | 846 | ||
818 | if (len > SPI_MAX_ECHO_BUFFER_SIZE) { | 847 | if (len > SPI_MAX_ECHO_BUFFER_SIZE) { |
819 | SPI_PRINTK(sdev->sdev_target, KERN_WARNING, "Echo buffer size %d is too big, trimming to %d\n", len, SPI_MAX_ECHO_BUFFER_SIZE); | 848 | SPI_PRINTK(starget, KERN_WARNING, "Echo buffer size %d is too big, trimming to %d\n", len, SPI_MAX_ECHO_BUFFER_SIZE); |
820 | len = SPI_MAX_ECHO_BUFFER_SIZE; | 849 | len = SPI_MAX_ECHO_BUFFER_SIZE; |
821 | } | 850 | } |
822 | 851 | ||