1
0
mirror of https://git.FreeBSD.org/src.git synced 2025-02-01 17:00:36 +00:00

Better error handeling:

On UDMA CRC errors retry operation as it might be a fluke, if not fall
back to PIO mode on the failing drive. If you get alot of these your
cabeling is most likely not good enough.

On HARD error using DMA, retry once using PIO, if it succeds using PIO
fall back to PIO mode on the failing drive.
This commit is contained in:
Søren Schmidt 1999-11-29 12:24:51 +00:00
parent 8f04f6c729
commit 60c94e7628
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=53882
2 changed files with 58 additions and 30 deletions

View File

@ -90,7 +90,7 @@ static struct intr_config_hook *ad_attach_hook;
MALLOC_DEFINE(M_AD, "AD driver", "ATA disk driver");
/* defines */
#define AD_MAX_RETRIES 5
#define AD_MAX_RETRIES 3
static __inline int
apiomode(struct ata_params *ap)
@ -435,7 +435,7 @@ ad_transfer(struct ad_request *request)
request->timeout_handle.callout = NULL;
else
request->timeout_handle =
timeout((timeout_t*)ad_timeout, request, 3*hz);
timeout((timeout_t*)ad_timeout, request, 5*hz);
/* setup transfer parameters */
count = howmany(request->bytecount, DEV_BSIZE);
@ -464,6 +464,7 @@ ad_transfer(struct ad_request *request)
/* does this drive & transfer work with DMA ? */
request->flags &= ~AR_F_DMA_USED;
if ((adp->flags & AD_F_DMA_ENABLED) &&
!(request->flags & AR_F_FORCE_PIO) &&
!ata_dmasetup(adp->controller, adp->unit,
(void *)request->data, request->bytecount,
(request->flags & AR_F_READ))) {
@ -477,8 +478,8 @@ ad_transfer(struct ad_request *request)
else
cmd = request->flags & AR_F_READ ? ATA_C_READ : ATA_C_WRITE;
ata_command(adp->controller, adp->unit, cmd, cylinder, head,
sector, count, 0, ATA_IMMEDIATE);
ata_command(adp->controller, adp->unit, cmd,
cylinder, head, sector, count, 0, ATA_IMMEDIATE);
}
/* if this is a DMA transaction start it, return and wait for interrupt */
@ -503,9 +504,8 @@ ad_transfer(struct ad_request *request)
/* ready to write PIO data ? */
if (ata_wait(adp->controller, adp->unit,
ATA_S_READY | ATA_S_DSC | ATA_S_DRQ) < 0) {
(ATA_S_READY | ATA_S_DSC | ATA_S_DRQ)) < 0)
printf("ad_transfer: timeout waiting for DRQ");
}
/* output the data */
#ifdef ATA_16BIT_ONLY
@ -536,32 +536,51 @@ ad_interrupt(struct ad_request *request)
/* get drive status */
if (ata_wait(adp->controller, adp->unit, 0) < 0)
printf("ad_interrupt: timeout waiting for status");
if (adp->controller->status & (ATA_S_ERROR | ATA_S_CORR) ||
if (adp->controller->status & ATA_S_CORR)
printf("ad%d: soft error ECC corrected\n", adp->lun);
if ((adp->controller->status & ATA_S_ERROR) ||
(request->flags & AR_F_DMA_USED && dma_stat != ATA_BMSTAT_INTERRUPT)) {
oops:
if (adp->controller->status & ATA_S_ERROR) {
printf("ad%d: %s %s error blk# %d", adp->lun,
(adp->controller->error & ATA_E_ICRC) ? "UDMA CRC" : "HARD",
(request->flags & AR_F_READ) ? "READ" : "WRITE",
request->blockaddr + (request->donecount / DEV_BSIZE));
/* if this is a UDMA CRC error, reinject request */
if (adp->controller->error & ATA_E_ICRC &&
request->retries++ < AD_MAX_RETRIES) {
/* disarm timeout for this transfer */
untimeout((timeout_t *)ad_timeout, request,
request->timeout_handle);
TAILQ_INSERT_HEAD(&adp->controller->ata_queue, request, chain);
printf("ad%d: %s %s ERROR blk# %d", adp->lun,
(adp->controller->error & ATA_E_ICRC) ? "UDMA CRC" : "HARD",
(request->flags & AR_F_READ) ? "READ" : "WRITE",
request->blockaddr + (request->donecount / DEV_BSIZE));
/* if this is a UDMA CRC error, reinject request */
if (adp->controller->error & ATA_E_ICRC) {
untimeout((timeout_t *)ad_timeout, request,request->timeout_handle);
if (request->retries++ < AD_MAX_RETRIES)
printf(" retrying\n");
return ATA_OP_FINISHED;
}
else {
printf(" status=%02x error=%02x\n",
adp->controller->status, adp->controller->error);
request->flags |= AR_F_ERROR;
adp->flags &= ~AD_F_DMA_ENABLED;
printf(" falling back to PIO mode\n");
}
TAILQ_INSERT_HEAD(&adp->controller->ata_queue, request, chain);
return ATA_OP_FINISHED;
}
else if (adp->controller->status & ATA_S_CORR)
printf("ad%d: soft error ECC corrected\n", adp->lun);
/* if using DMA, try once again in PIO mode */
if (request->flags & AR_F_DMA_USED) {
untimeout((timeout_t *)ad_timeout, request,request->timeout_handle);
request->flags |= AR_F_FORCE_PIO;
TAILQ_INSERT_HEAD(&adp->controller->ata_queue, request, chain);
return ATA_OP_FINISHED;
}
request->flags |= AR_F_ERROR;
printf(" status=%02x error=%02x\n",
adp->controller->status, adp->controller->error);
}
/* if we arrived here with forced PIO mode, DMA doesn't work right */
if (request->flags & AR_F_FORCE_PIO) {
adp->flags &= ~AD_F_DMA_ENABLED;
printf("ad%d: DMA problem encountered, fallback to PIO mode\n",
adp->lun);
}
/* if this was a PIO read operation, get the data */
@ -574,7 +593,7 @@ ad_interrupt(struct ad_request *request)
printf("ad_interrupt: read interrupt arrived early");
if (ata_wait(adp->controller, adp->unit,
ATA_S_READY | ATA_S_DSC | ATA_S_DRQ) != 0){
(ATA_S_READY | ATA_S_DSC | ATA_S_DRQ)) != 0) {
printf("ad_interrupt: read error detected late");
goto oops;
}
@ -653,8 +672,16 @@ ad_timeout(struct ad_request *request)
adp->controller->lun,
(adp->unit == ATA_MASTER) ? "master" : "slave");
if (request->flags & AR_F_DMA_USED)
if (request->flags & AR_F_DMA_USED) {
ata_dmadone(adp->controller);
if (request->retries == AD_MAX_RETRIES) {
adp->flags &= ~AD_F_DMA_ENABLED;
printf("ata%d-%s: ad_timeout: trying fallback to PIO mode\n",
adp->controller->lun,
(adp->unit == ATA_MASTER) ? "master" : "slave");
request->retries = 0;
}
}
/* if retries still permit, reinject this request */
if (request->retries++ < AD_MAX_RETRIES)

View File

@ -163,6 +163,7 @@ struct ad_request {
#define AR_F_READ 0x0001
#define AR_F_ERROR 0x0002
#define AR_F_DMA_USED 0x0004
#define AR_F_FORCE_PIO 0x0008
int8_t *data; /* pointer to data buf */
struct buf *bp; /* associated buf ptr */