Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 9a8bc9b8 authored by James Bottomley's avatar James Bottomley Committed by James Bottomley
Browse files

[SCSI] update spi transport class so that u320 Domain Validation works



There are several extra things that have to be considered when running
Domain Validation on a u320 target (notably how you fall back).

Hopefully this should help us when someone adds this transport class to
aic79xx.

I've tested this on the lsi1030, so I know it works correctly up to
u320.

Signed-off-by: default avatarJames Bottomley <James.Bottomley@SteelEye.com>
parent 597487b9
Loading
Loading
Loading
Loading
+53 −24
Original line number Diff line number Diff line
@@ -669,6 +669,7 @@ spi_dv_retrain(struct scsi_request *sreq, u8 *buffer, u8 *ptr,
{
	struct spi_internal *i = to_spi_internal(sreq->sr_host->transportt);
	struct scsi_device *sdev = sreq->sr_device;
	struct scsi_target *starget = sdev->sdev_target;
	int period = 0, prevperiod = 0; 
	enum spi_compare_returns retval;

@@ -682,9 +683,24 @@ spi_dv_retrain(struct scsi_request *sreq, u8 *buffer, u8 *ptr,
			break;

		/* OK, retrain, fallback */
		if (i->f->get_iu)
			i->f->get_iu(starget);
		if (i->f->get_qas)
			i->f->get_qas(starget);
		if (i->f->get_period)
			i->f->get_period(sdev->sdev_target);
		newperiod = spi_period(sdev->sdev_target);

		/* Here's the fallback sequence; first try turning off
		 * IU, then QAS (if we can control them), then finally
		 * fall down the periods */
		if (i->f->set_iu && spi_iu(starget)) {
			SPI_PRINTK(starget, KERN_ERR, "Domain Validation Disabing Information Units\n");
			DV_SET(iu, 0);
		} else if (i->f->set_qas && spi_qas(starget)) {
			SPI_PRINTK(starget, KERN_ERR, "Domain Validation Disabing Quick Arbitration and Selection\n");
			DV_SET(qas, 0);
		} else {
			newperiod = spi_period(starget);
			period = newperiod > period ? newperiod : period;
			if (period < 0x0d)
				period++;
@@ -693,14 +709,15 @@ spi_dv_retrain(struct scsi_request *sreq, u8 *buffer, u8 *ptr,

			if (unlikely(period > 0xff || period == prevperiod)) {
				/* Total failure; set to async and return */
			SPI_PRINTK(sdev->sdev_target, KERN_ERR, "Domain Validation Failure, dropping back to Asynchronous\n");
				SPI_PRINTK(starget, KERN_ERR, "Domain Validation Failure, dropping back to Asynchronous\n");
				DV_SET(offset, 0);
				return SPI_COMPARE_FAILURE;
			}
		SPI_PRINTK(sdev->sdev_target, KERN_ERR, "Domain Validation detected failure, dropping back\n");
			SPI_PRINTK(starget, KERN_ERR, "Domain Validation detected failure, dropping back\n");
			DV_SET(period, period);
			prevperiod = period;
		}
	}
	return retval;
}

@@ -768,23 +785,21 @@ spi_dv_device_internal(struct scsi_request *sreq, u8 *buffer)
	
	if (spi_dv_device_compare_inquiry(sreq, buffer, buffer, DV_LOOPS)
	    != SPI_COMPARE_SUCCESS) {
		SPI_PRINTK(sdev->sdev_target, KERN_ERR, "Domain Validation Initial Inquiry Failed\n");
		SPI_PRINTK(starget, KERN_ERR, "Domain Validation Initial Inquiry Failed\n");
		/* FIXME: should probably offline the device here? */
		return;
	}

	/* test width */
	if (i->f->set_width && spi_max_width(starget) && sdev->wdtr) {
		i->f->set_width(sdev->sdev_target, 1);

		printk("WIDTH IS %d\n", spi_max_width(starget));
		i->f->set_width(starget, 1);

		if (spi_dv_device_compare_inquiry(sreq, buffer,
						   buffer + len,
						   DV_LOOPS)
		    != SPI_COMPARE_SUCCESS) {
			SPI_PRINTK(sdev->sdev_target, KERN_ERR, "Wide Transfers Fail\n");
			i->f->set_width(sdev->sdev_target, 0);
			SPI_PRINTK(starget, KERN_ERR, "Wide Transfers Fail\n");
			i->f->set_width(starget, 0);
		}
	}

@@ -807,16 +822,30 @@ spi_dv_device_internal(struct scsi_request *sreq, u8 *buffer)
	/* now set up to the maximum */
	DV_SET(offset, spi_max_offset(starget));
	DV_SET(period, spi_min_period(starget));
	/* try QAS requests; this should be harmless to set if the
	 * target supports it */
	DV_SET(qas, 1);
	/* Also try IU transfers */
	DV_SET(iu, 1);
	if (spi_min_period(starget) < 9) {
		/* This u320 (or u640). Ignore the coupled parameters
		 * like DT and IU, but set the optional ones */
		DV_SET(rd_strm, 1);
		DV_SET(wr_flow, 1);
		DV_SET(rti, 1);
		if (spi_min_period(starget) == 8)
			DV_SET(pcomp_en, 1);
	}

	if (len == 0) {
		SPI_PRINTK(sdev->sdev_target, KERN_INFO, "Domain Validation skipping write tests\n");
		SPI_PRINTK(starget, KERN_INFO, "Domain Validation skipping write tests\n");
		spi_dv_retrain(sreq, buffer, buffer + len,
			       spi_dv_device_compare_inquiry);
		return;
	}

	if (len > SPI_MAX_ECHO_BUFFER_SIZE) {
		SPI_PRINTK(sdev->sdev_target, KERN_WARNING, "Echo buffer size %d is too big, trimming to %d\n", len, SPI_MAX_ECHO_BUFFER_SIZE);
		SPI_PRINTK(starget, KERN_WARNING, "Echo buffer size %d is too big, trimming to %d\n", len, SPI_MAX_ECHO_BUFFER_SIZE);
		len = SPI_MAX_ECHO_BUFFER_SIZE;
	}