Skip to content

Commit

Permalink
[SCSI] update spi transport class so that u320 Domain Validation works
Browse files Browse the repository at this point in the history
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: James Bottomley <James.Bottomley@SteelEye.com>
  • Loading branch information
James Bottomley authored and James Bottomley committed Jun 3, 2005
1 parent 597487b commit 9a8bc9b
Showing 1 changed file with 53 additions and 24 deletions.
77 changes: 53 additions & 24 deletions drivers/scsi/scsi_transport_spi.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -682,24 +683,40 @@ 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);
period = newperiod > period ? newperiod : period;
if (period < 0x0d)
period++;
else
period += period >> 1;

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");
DV_SET(offset, 0);
return SPI_COMPARE_FAILURE;

/* 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++;
else
period += period >> 1;

if (unlikely(period > 0xff || period == prevperiod)) {
/* Total failure; set to async and return */
SPI_PRINTK(starget, KERN_ERR, "Domain Validation Failure, dropping back to Asynchronous\n");
DV_SET(offset, 0);
return SPI_COMPARE_FAILURE;
}
SPI_PRINTK(starget, KERN_ERR, "Domain Validation detected failure, dropping back\n");
DV_SET(period, period);
prevperiod = period;
}
SPI_PRINTK(sdev->sdev_target, KERN_ERR, "Domain Validation detected failure, dropping back\n");
DV_SET(period, period);
prevperiod = period;
}
return retval;
}
Expand Down Expand Up @@ -768,31 +785,29 @@ 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);
}
}

if (!i->f->set_period)
return;

/* device can't handle synchronous */
if(!sdev->ppr && !sdev->sdtr)
if (!sdev->ppr && !sdev->sdtr)
return;

/* see if the device has an echo buffer. If it does we can
Expand All @@ -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;
}

Expand Down

0 comments on commit 9a8bc9b

Please sign in to comment.