diff options
-rw-r--r-- | sys/dev/ata/ata-all.c | 72 | ||||
-rw-r--r-- | sys/dev/ata/ata-all.h | 10 | ||||
-rw-r--r-- | sys/dev/ata/ata-disk.c | 22 | ||||
-rw-r--r-- | sys/dev/ata/ata-disk.h | 3 | ||||
-rw-r--r-- | sys/dev/ata/ata-dma.c | 27 | ||||
-rw-r--r-- | sys/dev/ata/atapi-all.c | 3 | ||||
-rw-r--r-- | sys/dev/ata/atapi-all.h | 7 |
7 files changed, 101 insertions, 43 deletions
diff --git a/sys/dev/ata/ata-all.c b/sys/dev/ata/ata-all.c index a1abee5..f1d534e 100644 --- a/sys/dev/ata/ata-all.c +++ b/sys/dev/ata/ata-all.c @@ -47,6 +47,7 @@ #include <sys/buf.h> #include <sys/malloc.h> #include <sys/devicestat.h> +#include <sys/sysctl.h> #include <machine/stdarg.h> #include <vm/vm.h> #include <vm/pmap.h> @@ -784,7 +785,6 @@ ataintr(void *data) intr_count, scp->status); } #endif - /* return; SOS XXX */ } scp->active = ATA_IDLE; scp->running = NULL; @@ -799,6 +799,7 @@ ata_start(struct ata_softc *scp) if (scp->active != ATA_IDLE) return; + scp->active = ATA_ACTIVE; #if NATADISK > 0 /* find & call the responsible driver if anything on the ATA queue */ @@ -853,6 +854,7 @@ ata_start(struct ata_softc *scp) return; } #endif + scp->active = ATA_IDLE; } void @@ -1062,6 +1064,7 @@ int8_t * ata_mode2str(int32_t mode) { switch (mode) { + case ATA_PIO: return "BIOSPIO"; case ATA_PIO0: return "PIO0"; case ATA_PIO1: return "PIO1"; case ATA_PIO2: return "PIO2"; @@ -1070,7 +1073,7 @@ ata_mode2str(int32_t mode) case ATA_WDMA2: return "WDMA2"; case ATA_UDMA2: return "UDMA33"; case ATA_UDMA4: return "UDMA66"; - case ATA_DMA: return "DMA"; + case ATA_DMA: return "BIOSDMA"; default: return "???"; } } @@ -1205,3 +1208,68 @@ ata_printf(struct ata_softc *scp, int32_t device, const char * fmt, ...) va_end(ap); return ret; } + +static char ata_conf[1024]; + +static void +ata_change_mode(struct ata_softc *scp, int32_t device, int32_t mode) +{ + int32_t s = splbio(); + + while (scp->active != ATA_IDLE) + tsleep((caddr_t)&s, PRIBIO, "atachm", hz/4); + scp->active = ATA_REINITING; + ata_dmainit(scp, device, ata_pmode(ATA_PARAM(scp, device)), + mode < ATA_DMA ? -1 : ata_wmode(ATA_PARAM(scp, device)), + mode < ATA_DMA ? -1 : ata_umode(ATA_PARAM(scp, device))); + scp->active = ATA_IDLE; + ata_start(scp); + splx(s); +} + +static int +sysctl_hw_ata SYSCTL_HANDLER_ARGS +{ + int error, i; + + /* readout internal state */ + bzero(ata_conf, sizeof(ata_conf)); + for (i = 0; i < (atanlun << 1); i++) { + if (!atadevices[i >> 1] || !atadevices[ i >> 1]->dev_softc[i & 1]) + strcat(ata_conf, "---,"); + else if (atadevices[i >> 1]->mode[i & 1] >= ATA_DMA) + strcat(ata_conf, "dma,"); + else + strcat(ata_conf, "pio,"); + } + error = sysctl_handle_string(oidp, ata_conf, sizeof(ata_conf), req); + if (error == 0 && req->newptr != NULL) { + char *ptr = ata_conf; + + /* update internal state */ + i = 0; + while (*ptr) { + if (!strncmp(ptr, "pio", 3) || !strncmp(ptr, "PIO", 3)) { + if (atadevices[i >> 1]->dev_softc[i & 1] && + atadevices[i >>1 ]->mode[i & 1] >= ATA_DMA) + ata_change_mode(atadevices[i >> 1], + (i & 1) ? ATA_SLAVE : ATA_MASTER, ATA_PIO); + } + else if (!strncmp(ptr, "dma", 3) || !strncmp(ptr, "DMA", 3)) { + if (atadevices[i >> 1]->dev_softc[i & 1] && + atadevices[i >> 1]->mode[i & 1] < ATA_DMA) + ata_change_mode(atadevices[i >> 1], + (i & 1) ? ATA_SLAVE : ATA_MASTER, ATA_DMA); + } + else if (strncmp(ptr, "---", 3)) + break; + ptr+=3; + if (*ptr++ != ',' || ++i > (atanlun << 1)) + break; + } + } + return error; +} + +SYSCTL_PROC(_hw, OID_AUTO, atamodes, CTLTYPE_STRING | CTLFLAG_RW, + 0, sizeof(ata_conf), sysctl_hw_ata, "A", ""); diff --git a/sys/dev/ata/ata-all.h b/sys/dev/ata/ata-all.h index 66de7f1..ff6c640 100644 --- a/sys/dev/ata/ata-all.h +++ b/sys/dev/ata/ata-all.h @@ -260,15 +260,16 @@ struct ata_softc { void *dev_softc[2]; /* ptr to devices softc's */ struct ata_dmaentry *dmatab[2]; /* DMA transfer tables */ int32_t mode[2]; /* transfer mode for devices */ +#define ATA_PIO 0x00 #define ATA_PIO0 0x08 #define ATA_PIO1 0x09 #define ATA_PIO2 0x0a #define ATA_PIO3 0x0b #define ATA_PIO4 0x0c +#define ATA_DMA 0x10 #define ATA_WDMA2 0x22 #define ATA_UDMA2 0x42 #define ATA_UDMA4 0x44 -#define ATA_DMA 0xff int32_t flags; /* controller flags */ #define ATA_DMA_ACTIVE 0x01 @@ -288,9 +289,10 @@ struct ata_softc { #define ATA_IMMEDIATE 0x1 #define ATA_WAIT_INTR 0x2 #define ATA_WAIT_READY 0x3 -#define ATA_ACTIVE_ATA 0x4 -#define ATA_ACTIVE_ATAPI 0x5 -#define ATA_REINITING 0x6 +#define ATA_ACTIVE 0x4 +#define ATA_ACTIVE_ATA 0x5 +#define ATA_ACTIVE_ATAPI 0x6 +#define ATA_REINITING 0x7 TAILQ_HEAD(, ad_request) ata_queue; /* head of ATA queue */ TAILQ_HEAD(, atapi_request) atapi_queue; /* head of ATAPI queue */ diff --git a/sys/dev/ata/ata-disk.c b/sys/dev/ata/ata-disk.c index c21be76..f7d596c 100644 --- a/sys/dev/ata/ata-disk.c +++ b/sys/dev/ata/ata-disk.c @@ -152,9 +152,8 @@ ad_attach(struct ata_softc *scp, int32_t device) printf("ad%d: enabling write cache failed\n", adp->lun); /* use DMA if drive & controller supports it */ - if (!ata_dmainit(adp->controller, adp->unit, ata_pmode(AD_PARAM), - ata_wmode(AD_PARAM), ata_umode(AD_PARAM))) - adp->flags |= AD_F_DMA_ENABLED; + ata_dmainit(adp->controller, adp->unit, ata_pmode(AD_PARAM), + ata_wmode(AD_PARAM), ata_umode(AD_PARAM)); /* use tagged queueing if supported (not yet) */ if ((adp->num_tags = (AD_PARAM->queuelen & 0x1f) + 1)) @@ -257,8 +256,9 @@ addump(dev_t dev) if (!adp) return ENXIO; + /* force PIO mode for dumps */ + adp->controller->mode[ATA_DEV(adp->unit)] = ATA_PIO; ata_reinit(adp->controller); - adp->flags &= ~AD_F_DMA_ENABLED; while (count > 0) { DELAY(1000); @@ -386,7 +386,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) && + if ((adp->controller->mode[ATA_DEV(adp->unit)] >= ATA_DMA) && !ata_dmasetup(adp->controller, adp->unit, (void *)request->data, request->bytecount, (request->flags & AR_F_READ))) { @@ -394,23 +394,26 @@ ad_transfer(struct ad_request *request) cmd = request->flags & AR_F_READ ? ATA_C_READ_DMA : ATA_C_WRITE_DMA; request->currentsize = request->bytecount; } + /* does this drive support multi sector transfers ? */ else if (request->currentsize > DEV_BSIZE) cmd = request->flags & AR_F_READ?ATA_C_READ_MULTI:ATA_C_WRITE_MULTI; + /* just plain old single sector transfer */ else cmd = request->flags & AR_F_READ ? ATA_C_READ : ATA_C_WRITE; if (ata_command(adp->controller, adp->unit, cmd, - cylinder, head, sector, count, 0, ATA_IMMEDIATE)) + cylinder, head, sector, count, 0, ATA_IMMEDIATE)) { printf("ad%d: wouldn't take transfer command\n", adp->lun); + return; + } /* if this is a DMA transfer, start it, return and wait for interrupt */ if (request->flags & AR_F_DMA_USED) { ata_dmastart(adp->controller); return; } - } /* calculate this transfer length */ @@ -473,7 +476,6 @@ oops: else { ata_dmainit(adp->controller, adp->unit, ata_pmode(AD_PARAM), -1, -1); - adp->flags &= ~AD_F_DMA_ENABLED; printf(" falling back to PIO mode\n"); } TAILQ_INSERT_HEAD(&adp->controller->ata_queue, request, chain); @@ -485,7 +487,6 @@ oops: untimeout((timeout_t *)ad_timeout, request,request->timeout_handle); ata_dmainit(adp->controller, adp->unit, ata_pmode(AD_PARAM), -1,-1); request->flags |= AR_F_FORCE_PIO; - adp->flags &= ~AD_F_DMA_ENABLED; TAILQ_INSERT_HEAD(&adp->controller->ata_queue, request, chain); return ATA_OP_FINISHED; } @@ -558,7 +559,7 @@ ad_reinit(struct ad_softc *adp) /* reinit disk parameters */ ata_command(adp->controller, adp->unit, ATA_C_SET_MULTI, 0, 0, 0, adp->transfersize / DEV_BSIZE, 0, ATA_WAIT_READY); - if (adp->flags & AD_F_DMA_ENABLED) + if (adp->controller->mode[ATA_DEV(adp->unit)] >= ATA_DMA) ata_dmainit(adp->controller, adp->unit, ata_pmode(AD_PARAM), ata_wmode(AD_PARAM), ata_umode(AD_PARAM)); else @@ -578,7 +579,6 @@ ad_timeout(struct ad_request *request) ata_dmadone(adp->controller); if (request->retries == AD_MAX_RETRIES) { ata_dmainit(adp->controller, adp->unit, ata_pmode(AD_PARAM), -1,-1); - adp->flags &= ~AD_F_DMA_ENABLED; printf("ad%d: ad_timeout: trying fallback to PIO mode\n", adp->lun); request->retries = 0; } diff --git a/sys/dev/ata/ata-disk.h b/sys/dev/ata/ata-disk.h index 63fb4c7..eadfeb12 100644 --- a/sys/dev/ata/ata-disk.h +++ b/sys/dev/ata/ata-disk.h @@ -42,8 +42,7 @@ struct ad_softc { #define AD_F_LABELLING 0x0001 #define AD_F_LBA_ENABLED 0x0002 #define AD_F_32B_ENABLED 0x0004 -#define AD_F_DMA_ENABLED 0x0008 -#define AD_F_TAG_ENABLED 0x0010 +#define AD_F_TAG_ENABLED 0x0008 struct buf_queue_head queue; /* head of request queue */ struct devstat stats; /* devstat entry */ diff --git a/sys/dev/ata/ata-dma.c b/sys/dev/ata/ata-dma.c index 82a1afb..56de719 100644 --- a/sys/dev/ata/ata-dma.c +++ b/sys/dev/ata/ata-dma.c @@ -260,7 +260,8 @@ ata_dmainit(struct ata_softc *scp, int32_t device, error = ata_command(scp, device, ATA_C_SETFEATURES, 0, 0, 0, ATA_UDMA4, ATA_C_F_SETXFER, ATA_WAIT_READY); if (bootverbose) - ata_printf(scp, device, "%s setting up UDMA4 mode on VIA chip\n", + ata_printf(scp, device, + "%s setting up UDMA4 mode on VIA chip\n", (error) ? "failed" : "success"); if (!error) { pci_write_config(scp->dev, 0x53 - devno, 0xe8, 1); @@ -418,11 +419,9 @@ ata_dmainit(struct ata_softc *scp, int32_t device, "%s setting up PIO%d mode on Promise chip\n", (error) ? "failed" : "success", (apiomode >= 0) ? apiomode : 0); - if (!error) { - promise_timing(scp, devno, ata_pio2mode(apiomode)); - return 0; - } - break; + promise_timing(scp, devno, ata_pio2mode(apiomode)); + scp->mode[ATA_DEV(device)] = ata_pio2mode(apiomode); + return -1; case 0x00041103: /* HighPoint HPT366 controller */ /* no ATAPI devices for now */ @@ -476,11 +475,9 @@ ata_dmainit(struct ata_softc *scp, int32_t device, ata_printf(scp, device, "%s setting up PIO%d mode on HPT366 chip\n", (error) ? "failed" : "success", (apiomode >= 0) ? apiomode : 0); - if (!error) { - hpt366_timing(scp, devno, ata_pio2mode(apiomode)); - return 0; - } - break; + hpt366_timing(scp, devno, ata_pio2mode(apiomode)); + scp->mode[ATA_DEV(device)] = ata_pio2mode(apiomode); + return -1; default: /* unknown controller chip */ /* better not try generic DMA on ATAPI devices it almost never works */ @@ -490,11 +487,6 @@ ata_dmainit(struct ata_softc *scp, int32_t device, /* well, we have no support for this, but try anyways */ if ((wdmamode >= 2 && apiomode >= 4) && scp->bmaddr) { -#if MAYBE_NOT - && (inb(scp->bmaddr + ATA_BMSTAT_PORT) & - ((device == ATA_MASTER) ? - ATA_BMSTAT_DMA_MASTER : ATA_BMSTAT_DMA_SLAVE))) { -#endif error = ata_command(scp, device, ATA_C_SETFEATURES, 0, 0, 0, ATA_WDMA2, ATA_C_F_SETXFER, ATA_WAIT_READY); if (bootverbose) @@ -512,8 +504,7 @@ ata_dmainit(struct ata_softc *scp, int32_t device, if (bootverbose) ata_printf(scp, device, "%s setting up PIO%d mode on generic chip\n", (error) ? "failed" : "success",(apiomode>=0) ? apiomode : 0); - if (!error) - scp->mode[ATA_DEV(device)] = ata_pio2mode(apiomode); + scp->mode[ATA_DEV(device)] = ata_pio2mode(apiomode); return -1; } diff --git a/sys/dev/ata/atapi-all.c b/sys/dev/ata/atapi-all.c index fecbe3a..2f37f2c 100644 --- a/sys/dev/ata/atapi-all.c +++ b/sys/dev/ata/atapi-all.c @@ -93,7 +93,6 @@ atapi_attach(struct ata_softc *scp, int32_t device) (ata_wmode(ATP_PARAM) < 0) ? (ATP_PARAM->dmaflag ? 2 : 0) : ata_wmode(ATP_PARAM), ata_umode(ATP_PARAM))) - atp->flags |= ATAPI_F_DMA_ENABLED; } else #endif @@ -208,7 +207,7 @@ atapi_transfer(struct atapi_request *request) atp->flags &= ~ATAPI_F_DSC_USED; /* if DMA enabled setup DMA hardware */ - if ((atp->flags & ATAPI_F_DMA_ENABLED) && + if ((atp->controller->mode[ATA_DEV(atp->unit)] >= ATA_DMA) && (request->ccb[0] == ATAPI_READ || request->ccb[0] == ATAPI_READ_BIG || ((request->ccb[0] == ATAPI_WRITE || diff --git a/sys/dev/ata/atapi-all.h b/sys/dev/ata/atapi-all.h index 36e84b6..26cf7ad 100644 --- a/sys/dev/ata/atapi-all.h +++ b/sys/dev/ata/atapi-all.h @@ -139,10 +139,9 @@ struct atapi_softc { int8_t *devname; /* this devices name */ int8_t cmd; /* last cmd executed */ u_int32_t flags; /* drive flags */ -#define ATAPI_F_DMA_ENABLED 0x0001 -#define ATAPI_F_DMA_USED 0x0002 -#define ATAPI_F_DSC_USED 0x0004 -#define ATAPI_F_MEDIA_CHANGED 0x0008 +#define ATAPI_F_DMA_USED 0x0001 +#define ATAPI_F_DSC_USED 0x0002 +#define ATAPI_F_MEDIA_CHANGED 0x0004 }; |