Add support for the Intel 810 chipset (ICH type of chips)

Prober support for the VIA 82C686, I finally got the right datasheet.

Get rid of atapi_wait, merge it into ata_wait.

Avoid a couple of races by using asleep instead of tsleep.

Always use 16bit transfers on ISA systems.

Clear up the atapi_read/write functions.
This commit is contained in:
Søren Schmidt 2000-01-17 02:04:19 +00:00
parent 87be6e697a
commit 46a37dbac0
6 changed files with 157 additions and 124 deletions

View File

@ -133,6 +133,7 @@ ata_isaprobe(device_t dev)
if (res) {
isa_set_portsize(dev, res);
*(int *)device_get_softc(dev) = lun;
atadevices[lun]->flags |= ATA_USE_16BIT;
return 0;
}
return ENXIO;
@ -197,6 +198,12 @@ ata_pcimatch(device_t dev)
case 0x71998086:
return "Intel PIIX4 ATA-33 controller";
case 0x24118086:
return "Intel ICH ATA-66 controller";
case 0x24218086:
return "Intel ICH0 ATA-33 controller";
case 0x522910b9:
return "AcerLabs Aladdin ATA-33 controller";
@ -363,7 +370,18 @@ ata_pciattach(device_t dev)
/* set sector size */
pci_write_config(dev, 0x60, DEV_BSIZE, 2);
pci_write_config(dev, 0x68, DEV_BSIZE, 2);
/* prepare for ATA-66 on the 82C686 */
if (ata_find_dev(dev, 0x06861106))
pci_write_config(dev, 0x50,
pci_read_config(dev, 0x50, 4) | 0x070f070f, 4);
break;
case 0x00041103: /* HighPoint HPT366 controller */
printf("hpt366: cache_line_size=0x%02x latency_timer=0x%02x min_grant=0x%02x max_latency=0x%02x\n",
pci_read_config(dev, 0x0c, 1), pci_read_config(dev, 0x0d, 1),
pci_read_config(dev, 0x3e, 1), pci_read_config(dev, 0x3f, 1));
}
/* now probe the addresse found for "real" ATA/ATAPI hardware */
@ -809,30 +827,25 @@ ata_reinit(struct ata_softc *scp)
int32_t
ata_wait(struct ata_softc *scp, int32_t device, u_int8_t mask)
{
u_int8_t status;
u_int32_t timeout = 0;
DELAY(1);
while (timeout <= 5000000) { /* timeout 5 secs */
status = inb(scp->ioaddr + ATA_STATUS);
while (timeout < 5000000) { /* timeout 5 secs */
scp->status = inb(scp->ioaddr + ATA_STATUS);
/* if drive fails status, reselect the drive just to be sure */
if (status == 0xff) {
printf("ata%d: %s: no status, reselecting device\n",
if (scp->status == 0xff) {
printf("ata%d-%s: no status, reselecting device\n",
scp->lun, device?"slave":"master");
outb(scp->ioaddr + ATA_DRIVE, ATA_D_IBM | device);
DELAY(1);
status = inb(scp->ioaddr + ATA_STATUS);
}
if (status == 0xff)
return -1;
scp->status = status;
if (!(status & ATA_S_BUSY)) {
if (status & ATA_S_ERROR)
scp->error = inb(scp->ioaddr + ATA_ERROR);
if ((status & mask) == mask)
return (status & ATA_S_ERROR);
scp->status = inb(scp->ioaddr + ATA_STATUS);
}
/* are we done ? */
if (!(scp->status & ATA_S_BUSY))
break;
if (timeout > 1000) {
timeout += 1000;
DELAY(1000);
@ -841,9 +854,27 @@ ata_wait(struct ata_softc *scp, int32_t device, u_int8_t mask)
timeout += 10;
DELAY(10);
}
}
return -1;
}
}
if (scp->status & ATA_S_ERROR)
scp->error = inb(scp->ioaddr + ATA_ERROR);
if (timeout >= 5000000)
return -1;
if (!mask)
return (scp->status & ATA_S_ERROR);
/* Wait 50 msec for bits wanted. */
timeout = 5000;
while (timeout--) {
scp->status = inb(scp->ioaddr + ATA_STATUS);
if ((scp->status & mask) == mask) {
if (scp->status & ATA_S_ERROR)
scp->error = inb(scp->ioaddr + ATA_ERROR);
return (scp->status & ATA_S_ERROR);
}
DELAY (10);
}
return -1;
}
int32_t
ata_command(struct ata_softc *scp, int32_t device, u_int32_t command,
@ -876,8 +907,9 @@ ata_command(struct ata_softc *scp, int32_t device, u_int32_t command,
if (scp->active != ATA_IDLE)
printf("WARNING: WAIT_INTR active=%s\n", active2str(scp->active));
scp->active = ATA_WAIT_INTR;
asleep((caddr_t)scp, PRIBIO, "atacmd", 500);
outb(scp->ioaddr + ATA_CMD, command);
if (tsleep((caddr_t)scp, PRIBIO, "atacmd", 500)) {
if (await(PRIBIO, 500)) {
printf("ata_command: timeout waiting for interrupt\n");
scp->active = ATA_IDLE;
return -1;

View File

@ -148,6 +148,7 @@ struct ata_softc {
int32_t flags; /* controller flags */
#define ATA_DMA_ACTIVE 0x01
#define ATA_ATAPI_DMA_RO 0x02
#define ATA_USE_16BIT 0x04
int32_t devices; /* what is present */
#define ATA_ATA_MASTER 0x01

View File

@ -498,15 +498,15 @@ ad_transfer(struct ad_request *request)
printf("ad_transfer: timeout waiting for DRQ");
/* output the data */
#ifdef ATA_16BIT_ONLY
outsw(adp->controller->ioaddr + ATA_DATA,
(void *)((uintptr_t)request->data + request->donecount),
request->currentsize / sizeof(int16_t));
#else
outsl(adp->controller->ioaddr + ATA_DATA,
(void *)((uintptr_t)request->data + request->donecount),
request->currentsize / sizeof(int32_t));
#endif
if (adp->controller->flags & ATA_USE_16BIT)
outsw(adp->controller->ioaddr + ATA_DATA,
(void *)((uintptr_t)request->data + request->donecount),
request->currentsize / sizeof(int16_t));
else
outsl(adp->controller->ioaddr + ATA_DATA,
(void *)((uintptr_t)request->data + request->donecount),
request->currentsize / sizeof(int32_t));
request->bytecount -= request->currentsize;
}
@ -589,15 +589,15 @@ ad_interrupt(struct ad_request *request)
}
/* data ready, read in */
#ifdef ATA_16BIT_ONLY
insw(adp->controller->ioaddr + ATA_DATA,
(void *)((uintptr_t)request->data + request->donecount),
request->currentsize / sizeof(int16_t));
#else
insl(adp->controller->ioaddr + ATA_DATA,
(void *)((uintptr_t)request->data + request->donecount),
request->currentsize / sizeof(int32_t));
#endif
if (adp->controller->flags & ATA_USE_16BIT)
insw(adp->controller->ioaddr + ATA_DATA,
(void *)((uintptr_t)request->data + request->donecount),
request->currentsize / sizeof(int16_t));
else
insl(adp->controller->ioaddr + ATA_DATA,
(void *)((uintptr_t)request->data + request->donecount),
request->currentsize / sizeof(int32_t));
request->bytecount -= request->currentsize;
}

View File

@ -98,16 +98,20 @@ ata_dmainit(struct ata_softc *scp, int32_t device,
switch (scp->chiptype) {
case 0x71118086: /* Intel PIIX4 */
case 0x71998086: /* Intel PIIX4 */
case 0x71998086: /* Intel PIIX4e */
case 0x24118086: /* Intel ICH */
case 0x24218086: /* Intel ICH0 */
if (udmamode >= 2) {
int32_t mask48, new48;
error = ata_command(scp, device, ATA_C_SETFEATURES, 0, 0, 0,
ATA_UDMA2, ATA_C_F_SETXFER, ATA_WAIT_READY);
if (bootverbose)
printf("ata%d-%s: %s setting up UDMA2 mode on PIIX4 chip\n",
printf("ata%d-%s: %s setting up UDMA2 mode on %s chip\n",
scp->lun, (device == ATA_MASTER) ? "master" : "slave",
(error) ? "failed" : "success");
(error) ? "failed" : "success",
(scp->chiptype == 0x24118086) ? "ICH" :
(scp->chiptype == 0x24218086) ? "ICH0" :"PIIX4");
if (!error) {
mask48 = (1 << devno) + (3 << (16 + (devno << 2)));
new48 = (1 << devno) + (2 << (16 + (devno << 2)));
@ -143,10 +147,12 @@ ata_dmainit(struct ata_softc *scp, int32_t device,
error = ata_command(scp, device, ATA_C_SETFEATURES, 0, 0, 0,
ATA_WDMA2, ATA_C_F_SETXFER, ATA_WAIT_READY);
if (bootverbose)
printf("ata%d-%s: %s setting up WDMA2 mode on PIIX%s chip\n",
printf("ata%d-%s: %s setting up WDMA2 mode on %s chip\n",
scp->lun, (device == ATA_MASTER) ? "master" : "slave",
(error) ? "failed" : "success",
(scp->chiptype == 0x70108086) ? "3" : "4");
(scp->chiptype == 0x70108086) ? "PIIX3" :
(scp->chiptype == 0x24118086) ? "ICH" :
(scp->chiptype == 0x24218086) ? "ICH0" :"PIIX4");
if (!error) {
if (device == ATA_MASTER) {
mask40 = 0x0000330f;
@ -251,16 +257,44 @@ ata_dmainit(struct ata_softc *scp, int32_t device,
case 0x05711106: /* VIA 82C571, 82C586, 82C596 & 82C686 */
case 0x74091022: /* AMD 756 */
/* UDMA4 mode only on 82C686 and AMD 756 */
if ((udmamode >= 4 && ata_find_dev(scp->dev, 0x06861106)) ||
(udmamode >= 4 && scp->chiptype == 0x74091022)) {
error = ata_command(scp, device, ATA_C_SETFEATURES, 0, 0, 0,
/* UDMA modes on 82C686 */
if (ata_find_dev(scp->dev, 0x06861106)) {
if (udmamode >= 4) {
error = ata_command(scp, device, ATA_C_SETFEATURES, 0, 0, 0,
ATA_UDMA4, ATA_C_F_SETXFER, ATA_WAIT_READY);
if (bootverbose)
printf("ata%d-%s: %s setting up UDMA4 mode on VIA chip\n",
scp->lun, (device == ATA_MASTER) ? "master":"slave",
(error) ? "failed" : "success");
if (!error) {
pci_write_config(scp->dev, 0x53 - devno, 0xe8, 1);
scp->mode[(device == ATA_MASTER) ? 0 : 1] = ATA_UDMA4;
return 0;
}
}
if (udmamode >= 2) {
error = ata_command(scp, device, ATA_C_SETFEATURES, 0, 0, 0,
ATA_UDMA2, ATA_C_F_SETXFER, ATA_WAIT_READY);
if (bootverbose)
printf("ata%d-%s: %s setting up UDMA2 mode on VIA chip\n",
scp->lun, (device == ATA_MASTER) ? "master":"slave",
(error) ? "failed" : "success");
if (!error) {
pci_write_config(scp->dev, 0x53 - devno, 0xea, 1);
scp->mode[(device == ATA_MASTER) ? 0 : 1] = ATA_UDMA2;
return 0;
}
}
}
/* UDMA4 mode on AMD 756 */
if (udmamode >= 4 && scp->chiptype == 0x74091022) {
error = ata_command(scp, device, ATA_C_SETFEATURES, 0, 0, 0,
ATA_UDMA4, ATA_C_F_SETXFER, ATA_WAIT_READY);
if (bootverbose)
printf("ata%d-%s: %s setting up UDMA4 mode on %s chip\n",
printf("ata%d-%s: %s setting up UDMA4 mode on AMD chip\n",
scp->lun, (device == ATA_MASTER) ? "master":"slave",
(error) ? "failed" : "success",
(scp->chiptype == 0x74091022) ? "AMD" : "VIA");
(error) ? "failed" : "success");
if (!error) {
pci_write_config(scp->dev, 0x53 - devno, 0xc3, 1);
scp->mode[(device == ATA_MASTER) ? 0 : 1] = ATA_UDMA4;
@ -268,11 +302,10 @@ ata_dmainit(struct ata_softc *scp, int32_t device,
}
}
/* UDMA2 mode only on 82C586 > rev1, 82C596, 82C686, AMD 756 */
/* UDMA2 mode only on 82C586 > rev1, 82C596, AMD 756 */
if ((udmamode >= 2 && ata_find_dev(scp->dev, 0x05861106) &&
pci_read_config(scp->dev, 0x08, 1) >= 0x01) ||
(udmamode >= 2 && ata_find_dev(scp->dev, 0x05961106)) ||
(udmamode >= 2 && ata_find_dev(scp->dev, 0x06861106)) ||
(udmamode >= 2 && scp->chiptype == 0x74091022)) {
error = ata_command(scp, device, ATA_C_SETFEATURES, 0, 0, 0,
ATA_UDMA2, ATA_C_F_SETXFER, ATA_WAIT_READY);
@ -288,7 +321,6 @@ ata_dmainit(struct ata_softc *scp, int32_t device,
}
}
if (wdmamode >= 2 && apiomode >= 4) {
/* set WDMA2 mode timing */
error = ata_command(scp, device, ATA_C_SETFEATURES, 0, 0, 0,
ATA_WDMA2, ATA_C_F_SETXFER, ATA_WAIT_READY);
if (bootverbose)

View File

@ -56,7 +56,6 @@ static void atapi_timeout(struct atapi_request *request);
static int8_t *atapi_type(int32_t);
static int8_t *atapi_cmd2str(u_int8_t);
static int8_t *atapi_skey2str(u_int8_t);
static int32_t atapi_wait(struct atapi_softc *, u_int8_t);
static void atapi_init(void);
/* extern references */
@ -208,11 +207,11 @@ atapi_getparam(struct atapi_softc *atp)
if (ata_command(atp->controller, atp->unit, ATA_C_ATAPI_IDENTIFY,
0, 0, 0, 0, 0, ATA_WAIT_INTR))
return -1;
if (atapi_wait(atp, ATA_S_DRQ))
if (ata_wait(atp->controller, atp->unit, ATA_S_DRQ))
return -1;
insw(atp->controller->ioaddr + ATA_DATA, buffer,
sizeof(buffer)/sizeof(int16_t));
if (atapi_wait(atp, 0))
if (ata_wait(atp->controller, atp->unit, 0))
return -1;
if (!(atapi_parm = malloc(sizeof(struct atapi_params), M_ATAPI, M_NOWAIT)))
return -1;
@ -254,6 +253,10 @@ atapi_queue_cmd(struct atapi_softc *atp, int8_t *ccb, void *data,
/* append onto controller queue and try to start controller */
s = splbio();
/* if not using callbacks, prepare to sleep for this request */
if (!callback)
asleep((caddr_t)request, PRIBIO, "atprq", 0);
TAILQ_INSERT_TAIL(&atp->controller->atapi_queue, request, chain);
if (atp->controller->active == ATA_IDLE)
ata_start(atp->controller);
@ -265,7 +268,7 @@ atapi_queue_cmd(struct atapi_softc *atp, int8_t *ccb, void *data,
}
/* wait for request to complete */
tsleep((caddr_t)request, PRIBIO, "atprq", 0);
await(PRIBIO, 0);
splx(s);
error = request->error;
free(request, M_ATAPI);
@ -375,13 +378,16 @@ atapi_interrupt(struct atapi_request *request)
if (atp->flags & ATAPI_F_DMA_USED)
dma_stat = ata_dmadone(atp->controller);
if (atapi_wait(atp, 0) < 0) {
/* is this needed anymore ?? SOS XXX */
#if NOT_ANY_MORE
if (ata_wait(atp->controller, atp->unit, 0) < 0) {
printf("%s: timeout waiting for status", atp->devname);
atp->flags &= ~ATAPI_F_DMA_USED;
request->result = inb(atp->controller->ioaddr + ATA_ERROR) |
ATAPI_SK_RESERVED;
goto op_finished;
}
#endif
if (atp->flags & ATAPI_F_DMA_USED) {
atp->flags &= ~ATAPI_F_DMA_USED;
@ -552,64 +558,58 @@ static void
atapi_read(struct atapi_request *request, int32_t length)
{
int8_t **buffer = (int8_t **)&request->data;
int32_t size = min(request->bytecount, length);
int32_t resid;
if (request->ccb[0] == ATAPI_REQUEST_SENSE)
*buffer = (int8_t *)&request->sense;
if (request->device->controller->flags & ATA_USE_16BIT ||
(size % sizeof(int32_t)))
insw(request->device->controller->ioaddr + ATA_DATA,
(void *)((uintptr_t)*buffer), size / sizeof(int16_t));
else
insl(request->device->controller->ioaddr + ATA_DATA,
(void *)((uintptr_t)*buffer), size / sizeof(int32_t));
if (request->bytecount < length) {
printf("%s: read data overrun %d/%d\n",
request->device->devname, length, request->bytecount);
#ifdef ATA_16BIT_ONLY
insw(request->device->controller->ioaddr + ATA_DATA,
(void *)((uintptr_t)*buffer), request->bytecount/sizeof(int16_t));
#else
insl(request->device->controller->ioaddr + ATA_DATA,
(void *)((uintptr_t)*buffer), request->bytecount/sizeof(int32_t));
#endif
for (resid=request->bytecount; resid<length; resid+=sizeof(int16_t))
inw(request->device->controller->ioaddr + ATA_DATA);
*buffer += request->bytecount;
request->bytecount = 0;
}
else {
insw(request->device->controller->ioaddr + ATA_DATA,
(void *)((uintptr_t)*buffer), length / sizeof(int16_t));
*buffer += length;
request->bytecount -= length;
}
*buffer += size;
request->bytecount -= size;
}
static void
atapi_write(struct atapi_request *request, int32_t length)
{
int8_t **buffer = (int8_t **)&request->data;
int32_t size = min(request->bytecount, length);
int32_t resid;
if (request->ccb[0] == ATAPI_REQUEST_SENSE)
*buffer = (int8_t *)&request->sense;
if (request->device->controller->flags & ATA_USE_16BIT ||
(size % sizeof(int32_t)))
outsw(request->device->controller->ioaddr + ATA_DATA,
(void *)((uintptr_t)*buffer), size / sizeof(int16_t));
else
outsl(request->device->controller->ioaddr + ATA_DATA,
(void *)((uintptr_t)*buffer), size / sizeof(int32_t));
if (request->bytecount < length) {
printf("%s: write data underrun %d/%d\n",
request->device->devname, length, request->bytecount);
#ifdef ATA_16BIT_ONLY
outsw(request->device->controller->ioaddr + ATA_DATA,
(void *)((uintptr_t)*buffer), request->bytecount/sizeof(int16_t));
#else
outsl(request->device->controller->ioaddr + ATA_DATA,
(void *)((uintptr_t)*buffer), request->bytecount/sizeof(int32_t));
#endif
for (resid=request->bytecount; resid<length; resid+=sizeof(int16_t))
outw(request->device->controller->ioaddr + ATA_DATA, 0);
*buffer += request->bytecount;
request->bytecount = 0;
}
else {
outsw(request->device->controller->ioaddr + ATA_DATA,
(void *)((uintptr_t)*buffer), length / sizeof(int16_t));
*buffer += length;
request->bytecount -= length;
}
*buffer += size;
request->bytecount -= size;
}
static void
@ -731,41 +731,6 @@ atapi_skey2str(u_int8_t skey)
}
}
static int32_t
atapi_wait(struct atapi_softc *atp, u_int8_t mask)
{
u_int32_t timeout = 0;
DELAY(1);
while (timeout++ <= 500000) { /* timeout 5 secs */
atp->controller->status = inb(atp->controller->ioaddr + ATA_STATUS);
/* if drive fails status, reselect the drive just to be sure */
if (atp->controller->status == 0xff) {
outb(atp->controller->ioaddr + ATA_DRIVE, ATA_D_IBM | atp->unit);
DELAY(1);
atp->controller->status = inb(atp->controller->ioaddr + ATA_STATUS);
}
if (!(atp->controller->status & ATA_S_BUSY) &&
(atp->controller->status & ATA_S_READY))
break;
DELAY (10);
}
if (timeout <= 0)
return -1;
if (!mask)
return (atp->controller->status & ATA_S_ERROR);
/* Wait 50 msec for bits wanted. */
for (timeout=5000; timeout>0; --timeout) {
atp->controller->status = inb(atp->controller->ioaddr + ATA_STATUS);
if ((atp->controller->status & mask) == mask)
return (atp->controller->status & ATA_S_ERROR);
DELAY (10);
}
return -1;
}
static void
atapi_init(void)
{

View File

@ -966,10 +966,13 @@ acdioctl(dev_t dev, u_long cmd, caddr_t addr, int32_t flag, struct proc *p)
break;
case CDRIOCCLOSEDISK:
if (!(cdp->flags & F_WRITTEN) || !(cdp->flags & F_DISK_OPEN)) {
if (!(cdp->flags & F_DISK_OPEN)) {
error = EINVAL;
printf("acd%d: sequence error (nothing to close)\n", cdp->lun);
}
else if (!(cdp->flags & F_WRITTEN)) {
cdp->flags &= ~(F_DISK_OPEN | F_TRACK_OPEN);
}
else {
error = acd_close_disk(cdp);
cdp->flags &= ~(F_WRITTEN | F_DISK_OPEN | F_TRACK_OPEN);