[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: James Bottomley <James.Bottomley@SteelEye.com>
This commit is contained in:
parent
597487b9ba
commit
9a8bc9b84b
@ -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 spi_internal *i = to_spi_internal(sreq->sr_host->transportt);
|
||||||
struct scsi_device *sdev = sreq->sr_device;
|
struct scsi_device *sdev = sreq->sr_device;
|
||||||
|
struct scsi_target *starget = sdev->sdev_target;
|
||||||
int period = 0, prevperiod = 0;
|
int period = 0, prevperiod = 0;
|
||||||
enum spi_compare_returns retval;
|
enum spi_compare_returns retval;
|
||||||
|
|
||||||
@ -682,24 +683,40 @@ spi_dv_retrain(struct scsi_request *sreq, u8 *buffer, u8 *ptr,
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
/* OK, retrain, fallback */
|
/* 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)
|
if (i->f->get_period)
|
||||||
i->f->get_period(sdev->sdev_target);
|
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)) {
|
/* Here's the fallback sequence; first try turning off
|
||||||
/* Total failure; set to async and return */
|
* IU, then QAS (if we can control them), then finally
|
||||||
SPI_PRINTK(sdev->sdev_target, KERN_ERR, "Domain Validation Failure, dropping back to Asynchronous\n");
|
* fall down the periods */
|
||||||
DV_SET(offset, 0);
|
if (i->f->set_iu && spi_iu(starget)) {
|
||||||
return SPI_COMPARE_FAILURE;
|
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;
|
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)
|
if (spi_dv_device_compare_inquiry(sreq, buffer, buffer, DV_LOOPS)
|
||||||
!= SPI_COMPARE_SUCCESS) {
|
!= 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? */
|
/* FIXME: should probably offline the device here? */
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* test width */
|
/* test width */
|
||||||
if (i->f->set_width && spi_max_width(starget) && sdev->wdtr) {
|
if (i->f->set_width && spi_max_width(starget) && sdev->wdtr) {
|
||||||
i->f->set_width(sdev->sdev_target, 1);
|
i->f->set_width(starget, 1);
|
||||||
|
|
||||||
printk("WIDTH IS %d\n", spi_max_width(starget));
|
|
||||||
|
|
||||||
if (spi_dv_device_compare_inquiry(sreq, buffer,
|
if (spi_dv_device_compare_inquiry(sreq, buffer,
|
||||||
buffer + len,
|
buffer + len,
|
||||||
DV_LOOPS)
|
DV_LOOPS)
|
||||||
!= SPI_COMPARE_SUCCESS) {
|
!= SPI_COMPARE_SUCCESS) {
|
||||||
SPI_PRINTK(sdev->sdev_target, KERN_ERR, "Wide Transfers Fail\n");
|
SPI_PRINTK(starget, KERN_ERR, "Wide Transfers Fail\n");
|
||||||
i->f->set_width(sdev->sdev_target, 0);
|
i->f->set_width(starget, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -792,7 +807,7 @@ spi_dv_device_internal(struct scsi_request *sreq, u8 *buffer)
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
/* device can't handle synchronous */
|
/* device can't handle synchronous */
|
||||||
if(!sdev->ppr && !sdev->sdtr)
|
if (!sdev->ppr && !sdev->sdtr)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/* see if the device has an echo buffer. If it does we can
|
/* 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)
|
|||||||
/* now set up to the maximum */
|
/* now set up to the maximum */
|
||||||
DV_SET(offset, spi_max_offset(starget));
|
DV_SET(offset, spi_max_offset(starget));
|
||||||
DV_SET(period, spi_min_period(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) {
|
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_retrain(sreq, buffer, buffer + len,
|
||||||
spi_dv_device_compare_inquiry);
|
spi_dv_device_compare_inquiry);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (len > SPI_MAX_ECHO_BUFFER_SIZE) {
|
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;
|
len = SPI_MAX_ECHO_BUFFER_SIZE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user