Index: head/sys/dev/ata/ata-all.c =================================================================== --- head/sys/dev/ata/ata-all.c (revision 84583) +++ head/sys/dev/ata/ata-all.c (revision 84584) @@ -1,1325 +1,1310 @@ /*- * Copyright (c) 1998,1999,2000,2001 Søren Schmidt * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer, * without modification, immediately at the beginning of the file. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * $FreeBSD$ */ #include "pci.h" #include "opt_ata.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef __alpha__ #include #endif #include #include #include /* device structures */ static d_ioctl_t ataioctl; static struct cdevsw ata_cdevsw = { /* open */ nullopen, /* close */ nullclose, /* read */ noread, /* write */ nowrite, /* ioctl */ ataioctl, /* poll */ nopoll, /* mmap */ nommap, /* strategy */ nostrategy, /* name */ "ata", /* maj */ 159, /* dump */ nodump, /* psize */ nopsize, /* flags */ 0, }; /* prototypes */ static void ata_boot_attach(void); static void ata_intr(void *); static int ata_getparam(struct ata_softc *, int, u_int8_t); static int ata_service(struct ata_softc *); -static char *active2str(int); static void bswap(int8_t *, int); static void btrim(int8_t *, int); static void bpack(int8_t *, int8_t *, int); static void ata_change_mode(struct ata_softc *, int, int); /* sysctl vars */ SYSCTL_NODE(_hw, OID_AUTO, ata, CTLFLAG_RD, 0, "ATA driver parameters"); /* global vars */ devclass_t ata_devclass; /* local vars */ static struct intr_config_hook *ata_delayed_attach = NULL; static MALLOC_DEFINE(M_ATA, "ATA generic", "ATA driver generic layer"); /* misc defines */ #define MASTER 0 #define SLAVE 1 int ata_probe(device_t dev) { struct ata_softc *scp; int rid; if (!dev) return ENXIO; scp = device_get_softc(dev); if (!scp) return ENXIO; if (scp->r_io || scp->r_altio || scp->r_irq) return EEXIST; /* initialize the softc basics */ scp->active = ATA_IDLE; scp->dev = dev; rid = ATA_IOADDR_RID; scp->r_io = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid, 0, ~0, ATA_IOSIZE, RF_ACTIVE); if (!scp->r_io) goto failure; rid = ATA_ALTADDR_RID; scp->r_altio = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid, 0, ~0, ATA_ALTIOSIZE, RF_ACTIVE); if (!scp->r_altio) goto failure; rid = ATA_BMADDR_RID; scp->r_bmio = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid, 0, ~0, ATA_BMIOSIZE, RF_ACTIVE); if (bootverbose) ata_printf(scp, -1, "iobase=0x%04x altiobase=0x%04x bmaddr=0x%04x\n", (int)rman_get_start(scp->r_io), (int)rman_get_start(scp->r_altio), (scp->r_bmio) ? (int)rman_get_start(scp->r_bmio) : 0); ata_reset(scp); TAILQ_INIT(&scp->ata_queue); TAILQ_INIT(&scp->atapi_queue); return 0; failure: if (scp->r_io) bus_release_resource(dev, SYS_RES_IOPORT, ATA_IOADDR_RID, scp->r_io); if (scp->r_altio) bus_release_resource(dev, SYS_RES_IOPORT, ATA_ALTADDR_RID,scp->r_altio); if (scp->r_bmio) bus_release_resource(dev, SYS_RES_IOPORT, ATA_BMADDR_RID, scp->r_bmio); if (bootverbose) ata_printf(scp, -1, "probe allocation failed\n"); return ENXIO; } int ata_attach(device_t dev) { struct ata_softc *scp; int error, rid; if (!dev) return ENXIO; scp = device_get_softc(dev); if (!scp) return ENXIO; rid = ATA_IRQ_RID; scp->r_irq = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, 0, ~0, 1, RF_SHAREABLE | RF_ACTIVE); if (!scp->r_irq) { ata_printf(scp, -1, "unable to allocate interrupt\n"); return ENXIO; } if ((error = bus_setup_intr(dev, scp->r_irq, INTR_TYPE_BIO|INTR_ENTROPY, ata_intr, scp, &scp->ih))) return error; /* * do not attach devices if we are in early boot, this is done later * when interrupts are enabled by a hook into the boot process. * otherwise attach what the probe has found in scp->devices. */ if (!ata_delayed_attach) { if (scp->devices & ATA_ATA_SLAVE) if (ata_getparam(scp, ATA_SLAVE, ATA_C_ATA_IDENTIFY)) scp->devices &= ~ATA_ATA_SLAVE; if (scp->devices & ATA_ATAPI_SLAVE) if (ata_getparam(scp, ATA_SLAVE, ATA_C_ATAPI_IDENTIFY)) scp->devices &= ~ATA_ATAPI_SLAVE; if (scp->devices & ATA_ATA_MASTER) if (ata_getparam(scp, ATA_MASTER, ATA_C_ATA_IDENTIFY)) scp->devices &= ~ATA_ATA_MASTER; if (scp->devices & ATA_ATAPI_MASTER) if (ata_getparam(scp, ATA_MASTER,ATA_C_ATAPI_IDENTIFY)) scp->devices &= ~ATA_ATAPI_MASTER; #ifdef DEV_ATADISK if (scp->devices & ATA_ATA_MASTER) ad_attach(scp, ATA_MASTER); if (scp->devices & ATA_ATA_SLAVE) ad_attach(scp, ATA_SLAVE); #endif #if defined(DEV_ATAPICD) || defined(DEV_ATAPIFD) || defined(DEV_ATAPIST) if (scp->devices & ATA_ATAPI_MASTER) atapi_attach(scp, ATA_MASTER); if (scp->devices & ATA_ATAPI_SLAVE) atapi_attach(scp, ATA_SLAVE); #endif } return 0; } int ata_detach(device_t dev) { struct ata_softc *scp; int s; if (!dev) return ENXIO; scp = device_get_softc(dev); if (!scp || !scp->devices) return ENXIO; /* make sure channel is not busy SOS XXX */ s = splbio(); while (!atomic_cmpset_int(&scp->active, ATA_IDLE, ATA_CONTROL)) tsleep((caddr_t)&s, PRIBIO, "atachm", hz/4); splx(s); /* disable interrupts on devices */ ATA_OUTB(scp->r_io, ATA_DRIVE, ATA_D_IBM | ATA_MASTER); ATA_OUTB(scp->r_altio, ATA_ALTSTAT, ATA_A_IDS | ATA_A_4BIT); ATA_OUTB(scp->r_io, ATA_DRIVE, ATA_D_IBM | ATA_SLAVE); ATA_OUTB(scp->r_altio, ATA_ALTSTAT, ATA_A_IDS | ATA_A_4BIT); #ifdef DEV_ATADISK if (scp->devices & ATA_ATA_MASTER && scp->dev_softc[MASTER]) ad_detach(scp->dev_softc[MASTER], 1); if (scp->devices & ATA_ATA_SLAVE && scp->dev_softc[SLAVE]) ad_detach(scp->dev_softc[SLAVE], 1); #endif #if defined(DEV_ATAPICD) || defined(DEV_ATAPIFD) || defined(DEV_ATAPIST) if (scp->devices & ATA_ATAPI_MASTER && scp->dev_softc[MASTER]) atapi_detach(scp->dev_softc[MASTER]); if (scp->devices & ATA_ATAPI_SLAVE && scp->dev_softc[SLAVE]) atapi_detach(scp->dev_softc[SLAVE]); #endif if (scp->dev_param[MASTER]) { free(scp->dev_param[MASTER], M_ATA); scp->dev_param[MASTER] = NULL; } if (scp->dev_param[SLAVE]) { free(scp->dev_param[SLAVE], M_ATA); scp->dev_param[SLAVE] = NULL; } scp->dev_softc[MASTER] = NULL; scp->dev_softc[SLAVE] = NULL; scp->mode[MASTER] = ATA_PIO; scp->mode[SLAVE] = ATA_PIO; scp->devices = 0; bus_teardown_intr(dev, scp->r_irq, scp->ih); bus_release_resource(dev, SYS_RES_IRQ, ATA_IRQ_RID, scp->r_irq); if (scp->r_bmio) bus_release_resource(dev, SYS_RES_IOPORT, ATA_BMADDR_RID, scp->r_bmio); bus_release_resource(dev, SYS_RES_IOPORT, ATA_ALTADDR_RID, scp->r_altio); bus_release_resource(dev, SYS_RES_IOPORT, ATA_IOADDR_RID, scp->r_io); scp->r_io = NULL; scp->r_altio = NULL; scp->r_bmio = NULL; scp->r_irq = NULL; scp->active = ATA_IDLE; return 0; } int ata_resume(device_t dev) { struct ata_softc *scp = device_get_softc(dev); ata_reinit(scp); return 0; } static int ataioctl(dev_t dev, u_long cmd, caddr_t addr, int32_t flag, struct thread *td) { struct ata_cmd *iocmd = (struct ata_cmd *)addr; device_t device; int error; if (cmd != IOCATA) return ENOTTY; if (iocmd->channel >= devclass_get_maxunit(ata_devclass)) return ENXIO; if (!(device = devclass_get_device(ata_devclass, iocmd->channel))) return ENODEV; switch (iocmd->cmd) { case ATAATTACH: { /* should enable channel HW on controller that can SOS XXX */ error = ata_probe(device); if (!error) error = ata_attach(device); return error; } case ATADETACH: { error = ata_detach(device); /* should disable channel HW on controller that can SOS XXX */ return error; } case ATAREINIT: { struct ata_softc *scp; int s; scp = device_get_softc(device); if (!scp) return ENODEV; /* make sure channel is not busy SOS XXX */ s = splbio(); while (!atomic_cmpset_int(&scp->active, ATA_IDLE, ATA_ACTIVE)) tsleep((caddr_t)&s, PRIBIO, "atachm", hz/4); error = ata_reinit(scp); splx(s); return error; } case ATAGMODE: { struct ata_softc *scp; scp = device_get_softc(device); if (!scp) return ENODEV; if (scp->dev_param[MASTER]) iocmd->u.mode.mode[MASTER] = scp->mode[MASTER]; else iocmd->u.mode.mode[MASTER] = -1; if (scp->dev_param[SLAVE]) iocmd->u.mode.mode[SLAVE] = scp->mode[SLAVE]; else iocmd->u.mode.mode[SLAVE] = -1; return 0; } case ATASMODE: { struct ata_softc *scp; scp = device_get_softc(device); if (!scp) return ENODEV; if (scp->dev_param[MASTER] && iocmd->u.mode.mode[MASTER] >= 0) { ata_change_mode(scp, ATA_MASTER, iocmd->u.mode.mode[MASTER]); iocmd->u.mode.mode[MASTER] = scp->mode[MASTER]; } else iocmd->u.mode.mode[MASTER] = -1; if (scp->dev_param[SLAVE] && iocmd->u.mode.mode[SLAVE] >= 0) { ata_change_mode(scp, ATA_SLAVE, iocmd->u.mode.mode[SLAVE]); iocmd->u.mode.mode[SLAVE] = scp->mode[SLAVE]; } else iocmd->u.mode.mode[SLAVE] = -1; return 0; } case ATAGPARM: { struct ata_softc *scp; scp = device_get_softc(device); if (!scp) return ENODEV; iocmd->u.param.type[MASTER] = scp->devices & (ATA_ATA_MASTER | ATA_ATAPI_MASTER); iocmd->u.param.type[SLAVE] = scp->devices & (ATA_ATA_SLAVE | ATA_ATAPI_SLAVE); if (scp->dev_name[MASTER]) strcpy(iocmd->u.param.name[MASTER], scp->dev_name[MASTER]); if (scp->dev_name[SLAVE]) strcpy(iocmd->u.param.name[SLAVE], scp->dev_name[SLAVE]); if (scp->dev_param[MASTER]) bcopy(scp->dev_param[MASTER], &iocmd->u.param.params[MASTER], sizeof(struct ata_params)); if (scp->dev_param[SLAVE]) bcopy(scp->dev_param[SLAVE], &iocmd->u.param.params[SLAVE], sizeof(struct ata_params)); return 0; } #if defined(DEV_ATAPICD) || defined(DEV_ATAPIFD) || defined(DEV_ATAPIST) case ATAPICMD: { struct ata_softc *scp; struct atapi_softc *atp; caddr_t buf; scp = device_get_softc(device); if (!scp) return ENODEV; if (!scp->dev_softc[iocmd->device] || !(scp->devices & (iocmd->device == 0 ? ATA_ATAPI_MASTER : ATA_ATAPI_SLAVE))) return ENODEV; if (!(buf = malloc(iocmd->u.atapi.count, M_ATA, M_NOWAIT))) return ENOMEM; atp = scp->dev_softc[iocmd->device]; if (iocmd->u.atapi.flags & ATAPI_CMD_WRITE) { error = copyin(iocmd->u.atapi.data, buf, iocmd->u.atapi.count); if (error) return error; } error = atapi_queue_cmd(atp, iocmd->u.atapi.ccb, buf, iocmd->u.atapi.count, (iocmd->u.atapi.flags == ATAPI_CMD_READ ? ATPR_F_READ : 0) | ATPR_F_QUIET, iocmd->u.atapi.timeout, NULL, NULL); if (error) { iocmd->u.atapi.error = error; bcopy(&atp->sense, iocmd->u.atapi.sense_data, sizeof(struct atapi_reqsense)); error = 0; } else if (iocmd->u.atapi.flags & ATAPI_CMD_READ) error = copyout(buf, iocmd->u.atapi.data, iocmd->u.atapi.count); free(buf, M_ATA); return error; } #endif } return ENOTTY; } static int ata_getparam(struct ata_softc *scp, int device, u_int8_t command) { struct ata_params *ata_parm; int retry = 0; /* select drive */ ATA_OUTB(scp->r_io, ATA_DRIVE, ATA_D_IBM | device); DELAY(1); /* enable interrupt */ ATA_OUTB(scp->r_altio, ATA_ALTSTAT, ATA_A_4BIT); DELAY(1); /* apparently some devices needs this repeated */ do { - if (ata_command(scp, device, command, 0, 0, 0, 0, 0, ATA_WAIT_INTR)) { + if (ata_command(scp, device, command, 0, 0, 0, ATA_WAIT_INTR)) { ata_printf(scp, device, "%s identify failed\n", command == ATA_C_ATAPI_IDENTIFY ? "ATAPI" : "ATA"); return -1; } if (retry++ > 4) { ata_printf(scp, device, "%s identify retries exceeded\n", command == ATA_C_ATAPI_IDENTIFY ? "ATAPI" : "ATA"); return -1; } } while (ata_wait(scp, device, ((command == ATA_C_ATAPI_IDENTIFY) ? ATA_S_DRQ : (ATA_S_READY | ATA_S_DSC | ATA_S_DRQ)))); ata_parm = malloc(sizeof(struct ata_params), M_ATA, M_NOWAIT); if (!ata_parm) { int i; for (i = 0; i < sizeof(struct ata_params)/sizeof(int16_t); i++) ATA_INW(scp->r_io, ATA_DATA); ata_printf(scp, device, "malloc for identify data failed\n"); return -1; } ATA_INSW(scp->r_io, ATA_DATA, (int16_t *)ata_parm, sizeof(struct ata_params)/sizeof(int16_t)); if (command == ATA_C_ATA_IDENTIFY || !((ata_parm->model[0] == 'N' && ata_parm->model[1] == 'E') || (ata_parm->model[0] == 'F' && ata_parm->model[1] == 'X'))) bswap(ata_parm->model, sizeof(ata_parm->model)); btrim(ata_parm->model, sizeof(ata_parm->model)); bpack(ata_parm->model, ata_parm->model, sizeof(ata_parm->model)); bswap(ata_parm->revision, sizeof(ata_parm->revision)); btrim(ata_parm->revision, sizeof(ata_parm->revision)); bpack(ata_parm->revision, ata_parm->revision, sizeof(ata_parm->revision)); scp->dev_param[ATA_DEV(device)] = ata_parm; return 0; } static void ata_boot_attach(void) { struct ata_softc *scp; int ctlr; /* * run through all ata devices and look for real ATA & ATAPI devices * using the hints we found in the early probe, this avoids some of * the delays probing of non-exsistent devices can cause. */ for (ctlr=0; ctlrdevices & ATA_ATA_SLAVE) if (ata_getparam(scp, ATA_SLAVE, ATA_C_ATA_IDENTIFY)) scp->devices &= ~ATA_ATA_SLAVE; if (scp->devices & ATA_ATAPI_SLAVE) if (ata_getparam(scp, ATA_SLAVE, ATA_C_ATAPI_IDENTIFY)) scp->devices &= ~ATA_ATAPI_SLAVE; if (scp->devices & ATA_ATA_MASTER) if (ata_getparam(scp, ATA_MASTER, ATA_C_ATA_IDENTIFY)) scp->devices &= ~ATA_ATA_MASTER; if (scp->devices & ATA_ATAPI_MASTER) if (ata_getparam(scp, ATA_MASTER, ATA_C_ATAPI_IDENTIFY)) scp->devices &= ~ATA_ATAPI_MASTER; } #ifdef DEV_ATADISK /* now we know whats there, do the real attach, first the ATA disks */ for (ctlr=0; ctlrdevices & ATA_ATA_MASTER) ad_attach(scp, ATA_MASTER); if (scp->devices & ATA_ATA_SLAVE) ad_attach(scp, ATA_SLAVE); } #endif #if defined(DEV_ATAPICD) || defined(DEV_ATAPIFD) || defined(DEV_ATAPIST) /* then the atapi devices */ for (ctlr=0; ctlrdevices & ATA_ATAPI_MASTER) atapi_attach(scp, ATA_MASTER); if (scp->devices & ATA_ATAPI_SLAVE) atapi_attach(scp, ATA_SLAVE); } #endif if (ata_delayed_attach) { config_intrhook_disestablish(ata_delayed_attach); free(ata_delayed_attach, M_ATA); ata_delayed_attach = NULL; } } static void ata_intr(void *data) { struct ata_softc *scp = (struct ata_softc *)data; /* * on PCI systems we might share an interrupt line with another * device or our twin ATA channel, so call scp->intr_func to figure * out if it is really an interrupt we should process here */ if (scp->intr_func && scp->intr_func(scp)) return; /* if drive is busy it didn't interrupt */ if (ATA_INB(scp->r_altio, ATA_ALTSTAT) & ATA_S_BUSY) { DELAY(100); if (!(ATA_INB(scp->r_altio, ATA_ALTSTAT) & ATA_S_DRQ)) return; } /* clear interrupt and get status */ scp->status = ATA_INB(scp->r_io, ATA_STATUS); if (scp->status & ATA_S_ERROR) scp->error = ATA_INB(scp->r_io, ATA_ERROR); /* find & call the responsible driver to process this interrupt */ switch (scp->active) { #ifdef DEV_ATADISK case ATA_ACTIVE_ATA: if (!scp->running || ad_interrupt(scp->running) == ATA_OP_CONTINUES) return; break; #endif #if defined(DEV_ATAPICD) || defined(DEV_ATAPIFD) || defined(DEV_ATAPIST) case ATA_ACTIVE_ATAPI: if (!scp->running || atapi_interrupt(scp->running) == ATA_OP_CONTINUES) return; break; #endif case ATA_WAIT_INTR: case ATA_WAIT_INTR | ATA_CONTROL: wakeup((caddr_t)scp); break; case ATA_WAIT_READY: case ATA_WAIT_READY | ATA_CONTROL: break; case ATA_IDLE: if (scp->flags & ATA_QUEUED) { scp->active = ATA_ACTIVE; /* XXX */ if (ata_service(scp) == ATA_OP_CONTINUES) return; } /* FALLTHROUGH */ default: #ifdef ATA_DEBUG { static int intr_count = 0; if (intr_count++ < 10) - ata_printf(scp, -1, "unwanted interrupt %d %sstatus = %02x\n", - intr_count, active2str(scp->active), scp->status); + ata_printf(scp, -1, + "unwanted interrupt #%d active=0x%x status=0x%02x\n", + intr_count, scp->active, scp->status); } #endif } scp->active &= ATA_CONTROL; if (scp->active & ATA_CONTROL) return; scp->running = NULL; ata_start(scp); return; } void ata_start(struct ata_softc *scp) { #ifdef DEV_ATADISK struct ad_request *ad_request; #endif #if defined(DEV_ATAPICD) || defined(DEV_ATAPIFD) || defined(DEV_ATAPIST) struct atapi_request *atapi_request; #endif if (!atomic_cmpset_int(&scp->active, ATA_IDLE, ATA_ACTIVE)) return; #ifdef DEV_ATADISK /* find & call the responsible driver if anything on the ATA queue */ if (TAILQ_EMPTY(&scp->ata_queue)) { if (scp->devices & (ATA_ATA_MASTER) && scp->dev_softc[MASTER]) ad_start((struct ad_softc *)scp->dev_softc[MASTER]); if (scp->devices & (ATA_ATA_SLAVE) && scp->dev_softc[SLAVE]) ad_start((struct ad_softc *)scp->dev_softc[SLAVE]); } if ((ad_request = TAILQ_FIRST(&scp->ata_queue))) { TAILQ_REMOVE(&scp->ata_queue, ad_request, chain); scp->active = ATA_ACTIVE_ATA; scp->running = ad_request; if (ad_transfer(ad_request) == ATA_OP_CONTINUES) return; } #endif #if defined(DEV_ATAPICD) || defined(DEV_ATAPIFD) || defined(DEV_ATAPIST) /* find & call the responsible driver if anything on the ATAPI queue */ if (TAILQ_EMPTY(&scp->atapi_queue)) { if (scp->devices & (ATA_ATAPI_MASTER) && scp->dev_softc[MASTER]) atapi_start((struct atapi_softc *)scp->dev_softc[MASTER]); if (scp->devices & (ATA_ATAPI_SLAVE) && scp->dev_softc[SLAVE]) atapi_start((struct atapi_softc *)scp->dev_softc[SLAVE]); } if ((atapi_request = TAILQ_FIRST(&scp->atapi_queue))) { TAILQ_REMOVE(&scp->atapi_queue, atapi_request, chain); scp->active = ATA_ACTIVE_ATAPI; scp->running = atapi_request; if (atapi_transfer(atapi_request) == ATA_OP_CONTINUES) return; } #endif scp->active = ATA_IDLE; } void ata_reset(struct ata_softc *scp) { u_int8_t lsb, msb, ostat0, ostat1; u_int8_t stat0 = ATA_S_BUSY, stat1 = ATA_S_BUSY; int mask = 0, timeout; /* do we have any signs of ATA/ATAPI HW being present ? */ ATA_OUTB(scp->r_io, ATA_DRIVE, ATA_D_IBM | ATA_MASTER); DELAY(10); ostat0 = ATA_INB(scp->r_io, ATA_STATUS); if ((ostat0 & 0xf8) != 0xf8 && ostat0 != 0xa5) mask |= 0x01; ATA_OUTB(scp->r_io, ATA_DRIVE, ATA_D_IBM | ATA_SLAVE); DELAY(10); ostat1 = ATA_INB(scp->r_io, ATA_STATUS); if ((ostat1 & 0xf8) != 0xf8 && ostat1 != 0xa5) mask |= 0x02; scp->devices = 0; if (!mask) return; /* in some setups we dont want to test for a slave */ if (scp->flags & ATA_NO_SLAVE) mask &= ~0x02; if (bootverbose) ata_printf(scp, -1, "mask=%02x ostat0=%02x ostat2=%02x\n", mask, ostat0, ostat1); /* reset channel */ ATA_OUTB(scp->r_io, ATA_DRIVE, ATA_D_IBM | ATA_MASTER); DELAY(10); ATA_OUTB(scp->r_altio, ATA_ALTSTAT, ATA_A_IDS | ATA_A_RESET); DELAY(10000); ATA_OUTB(scp->r_altio, ATA_ALTSTAT, ATA_A_IDS); DELAY(100000); ATA_INB(scp->r_io, ATA_ERROR); /* wait for BUSY to go inactive */ for (timeout = 0; timeout < 310000; timeout++) { if (stat0 & ATA_S_BUSY) { ATA_OUTB(scp->r_io, ATA_DRIVE, ATA_D_IBM | ATA_MASTER); DELAY(10); stat0 = ATA_INB(scp->r_io, ATA_STATUS); if (!(stat0 & ATA_S_BUSY)) { /* check for ATAPI signature while its still there */ lsb = ATA_INB(scp->r_io, ATA_CYL_LSB); msb = ATA_INB(scp->r_io, ATA_CYL_MSB); if (bootverbose) ata_printf(scp, ATA_MASTER, "ATAPI probe %02x %02x\n", lsb, msb); if (lsb == ATAPI_MAGIC_LSB && msb == ATAPI_MAGIC_MSB) scp->devices |= ATA_ATAPI_MASTER; } } if (stat1 & ATA_S_BUSY) { ATA_OUTB(scp->r_io, ATA_DRIVE, ATA_D_IBM | ATA_SLAVE); DELAY(10); stat1 = ATA_INB(scp->r_io, ATA_STATUS); if (!(stat1 & ATA_S_BUSY)) { /* check for ATAPI signature while its still there */ lsb = ATA_INB(scp->r_io, ATA_CYL_LSB); msb = ATA_INB(scp->r_io, ATA_CYL_MSB); if (bootverbose) ata_printf(scp, ATA_SLAVE, "ATAPI probe %02x %02x\n", lsb, msb); if (lsb == ATAPI_MAGIC_LSB && msb == ATAPI_MAGIC_MSB) scp->devices |= ATA_ATAPI_SLAVE; } } if (mask == 0x01) /* wait for master only */ if (!(stat0 & ATA_S_BUSY)) break; if (mask == 0x02) /* wait for slave only */ if (!(stat1 & ATA_S_BUSY)) break; if (mask == 0x03) /* wait for both master & slave */ if (!(stat0 & ATA_S_BUSY) && !(stat1 & ATA_S_BUSY)) break; DELAY(100); } DELAY(10); ATA_OUTB(scp->r_altio, ATA_ALTSTAT, ATA_A_4BIT); if (stat0 & ATA_S_BUSY) mask &= ~0x01; if (stat1 & ATA_S_BUSY) mask &= ~0x02; if (bootverbose) ata_printf(scp, -1, "mask=%02x stat0=%02x stat1=%02x\n", mask, stat0, stat1); if (!mask) return; if (mask & 0x01 && ostat0 != 0x00 && !(scp->devices & ATA_ATAPI_MASTER)) { ATA_OUTB(scp->r_io, ATA_DRIVE, ATA_D_IBM | ATA_MASTER); DELAY(10); ATA_OUTB(scp->r_io, ATA_ERROR, 0x58); ATA_OUTB(scp->r_io, ATA_CYL_LSB, 0xa5); lsb = ATA_INB(scp->r_io, ATA_ERROR); msb = ATA_INB(scp->r_io, ATA_CYL_LSB); if (bootverbose) ata_printf(scp, ATA_MASTER, "ATA probe %02x %02x\n", lsb, msb); if (lsb != 0x58 && msb == 0xa5) scp->devices |= ATA_ATA_MASTER; } if (mask & 0x02 && ostat1 != 0x00 && !(scp->devices & ATA_ATAPI_SLAVE)) { ATA_OUTB(scp->r_io, ATA_DRIVE, ATA_D_IBM | ATA_SLAVE); DELAY(10); ATA_OUTB(scp->r_io, ATA_ERROR, 0x58); ATA_OUTB(scp->r_io, ATA_CYL_LSB, 0xa5); lsb = ATA_INB(scp->r_io, ATA_ERROR); msb = ATA_INB(scp->r_io, ATA_CYL_LSB); if (bootverbose) ata_printf(scp, ATA_SLAVE, "ATA probe %02x %02x\n", lsb, msb); if (lsb != 0x58 && msb == 0xa5) scp->devices |= ATA_ATA_SLAVE; } if (bootverbose) ata_printf(scp, -1, "devices=%02x\n", scp->devices); } int ata_reinit(struct ata_softc *scp) { int devices, misdev, newdev; if (!scp->r_io || !scp->r_altio || !scp->r_irq) return ENXIO; scp->active = ATA_CONTROL; scp->running = NULL; devices = scp->devices; ata_printf(scp, -1, "resetting devices .. "); ata_reset(scp); if ((misdev = devices & ~scp->devices)) { if (misdev) printf("\n"); #ifdef DEV_ATADISK if (misdev & ATA_ATA_MASTER && scp->dev_softc[MASTER]) ad_detach(scp->dev_softc[MASTER], 0); if (misdev & ATA_ATA_SLAVE && scp->dev_softc[SLAVE]) ad_detach(scp->dev_softc[SLAVE], 0); #endif #if defined(DEV_ATAPICD) || defined(DEV_ATAPIFD) || defined(DEV_ATAPIST) if (misdev & ATA_ATAPI_MASTER && scp->dev_softc[MASTER]) atapi_detach(scp->dev_softc[MASTER]); if (misdev & ATA_ATAPI_SLAVE && scp->dev_softc[SLAVE]) atapi_detach(scp->dev_softc[SLAVE]); #endif if (misdev & ATA_ATA_MASTER || misdev & ATA_ATAPI_MASTER) { free(scp->dev_param[MASTER], M_ATA); scp->dev_param[MASTER] = NULL; } if (misdev & ATA_ATA_SLAVE || misdev & ATA_ATAPI_SLAVE) { free(scp->dev_param[SLAVE], M_ATA); scp->dev_param[SLAVE] = NULL; } } if ((newdev = ~devices & scp->devices)) { if (newdev & ATA_ATA_MASTER) if (ata_getparam(scp, ATA_MASTER, ATA_C_ATA_IDENTIFY)) newdev &= ~ATA_ATA_MASTER; if (newdev & ATA_ATA_SLAVE) if (ata_getparam(scp, ATA_SLAVE, ATA_C_ATA_IDENTIFY)) newdev &= ~ATA_ATA_SLAVE; if (newdev & ATA_ATAPI_MASTER) if (ata_getparam(scp, ATA_MASTER, ATA_C_ATAPI_IDENTIFY)) newdev &= ~ATA_ATAPI_MASTER; if (newdev & ATA_ATAPI_SLAVE) if (ata_getparam(scp, ATA_SLAVE, ATA_C_ATAPI_IDENTIFY)) newdev &= ~ATA_ATAPI_SLAVE; } if (!misdev && newdev) printf("\n"); #ifdef DEV_ATADISK if (newdev & ATA_ATA_MASTER && !scp->dev_softc[MASTER]) ad_attach(scp, ATA_MASTER); else if (scp->devices & ATA_ATA_MASTER && scp->dev_softc[MASTER]) ad_reinit((struct ad_softc *)scp->dev_softc[MASTER]); if (newdev & ATA_ATA_SLAVE && !scp->dev_softc[SLAVE]) ad_attach(scp, ATA_SLAVE); else if (scp->devices & (ATA_ATA_SLAVE) && scp->dev_softc[SLAVE]) ad_reinit((struct ad_softc *)scp->dev_softc[SLAVE]); #endif #if defined(DEV_ATAPICD) || defined(DEV_ATAPIFD) || defined(DEV_ATAPIST) if (newdev & ATA_ATAPI_MASTER && !scp->dev_softc[MASTER]) atapi_attach(scp, ATA_MASTER); else if (scp->devices & (ATA_ATAPI_MASTER) && scp->dev_softc[MASTER]) atapi_reinit((struct atapi_softc *)scp->dev_softc[MASTER]); if (newdev & ATA_ATAPI_SLAVE && !scp->dev_softc[SLAVE]) atapi_attach(scp, ATA_SLAVE); else if (scp->devices & (ATA_ATAPI_SLAVE) && scp->dev_softc[SLAVE]) atapi_reinit((struct atapi_softc *)scp->dev_softc[SLAVE]); #endif printf("done\n"); scp->active = ATA_IDLE; ata_start(scp); return 0; } static int ata_service(struct ata_softc *scp) { /* do we have a SERVICE request from the drive ? */ if ((scp->status & (ATA_S_SERVICE|ATA_S_ERROR|ATA_S_DRQ)) == ATA_S_SERVICE){ ATA_OUTB(scp->r_bmio, ATA_BMSTAT_PORT, ata_dmastatus(scp) | ATA_BMSTAT_INTERRUPT); #ifdef DEV_ATADISK if ((ATA_INB(scp->r_io, ATA_DRIVE) & ATA_SLAVE) == ATA_MASTER) { if ((scp->devices & ATA_ATA_MASTER) && scp->dev_softc[MASTER]) return ad_service((struct ad_softc *)scp->dev_softc[MASTER], 0); } else { if ((scp->devices & ATA_ATA_SLAVE) && scp->dev_softc[SLAVE]) return ad_service((struct ad_softc *)scp->dev_softc[SLAVE], 0); } #endif } return ATA_OP_FINISHED; } int ata_wait(struct ata_softc *scp, int device, u_int8_t mask) { int timeout = 0; DELAY(1); while (timeout < 5000000) { /* timeout 5 secs */ scp->status = ATA_INB(scp->r_io, ATA_STATUS); /* if drive fails status, reselect the drive just to be sure */ if (scp->status == 0xff) { ata_printf(scp, device, "no status, reselecting device\n"); ATA_OUTB(scp->r_io, ATA_DRIVE, ATA_D_IBM | device); DELAY(10); scp->status = ATA_INB(scp->r_io, ATA_STATUS); if (scp->status == 0xff) return -1; } /* are we done ? */ if (!(scp->status & ATA_S_BUSY)) break; if (timeout > 1000) { timeout += 1000; DELAY(1000); } else { timeout += 10; DELAY(10); } } if (scp->status & ATA_S_ERROR) scp->error = ATA_INB(scp->r_io, 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 = ATA_INB(scp->r_io, ATA_STATUS); if ((scp->status & mask) == mask) { if (scp->status & ATA_S_ERROR) scp->error = ATA_INB(scp->r_io, ATA_ERROR); return (scp->status & ATA_S_ERROR); } DELAY (10); } return -1; } int ata_command(struct ata_softc *scp, int device, u_int8_t command, - u_int16_t cylinder, u_int8_t head, u_int8_t sector, - u_int8_t count, u_int8_t feature, int flags) + u_int64_t lba, u_int16_t count, u_int8_t feature, int flags) { int error = 0; #ifdef ATA_DEBUG - ata_printf(scp, device, "ata_command: addr=%04x, cmd=%02x, " - "c=%d, h=%d, s=%d, count=%d, feature=%d, flags=%02x\n", - rman_get_start(scp->r_io), command, cylinder, head, sector, - count, feature, flags); - - /* sanity checks */ - switch(scp->active) { - case ATA_IDLE: - break; - - case ATA_CONTROL: - if (flags == ATA_WAIT_INTR || flags == ATA_WAIT_READY) - break; - goto out; - - case ATA_ACTIVE_ATA: - case ATA_ACTIVE_ATAPI: - if (flags == ATA_IMMEDIATE) - break; - - default: -out: - printf("ata_command called %s flags=%s cmd=%02x\n", - active2str(scp->active), active2str(flags), command); - break; - } + ata_printf(scp, device, "ata_command: addr=%04lx, cmd=%02x, " + "lba=%lld, count=%d, feature=%d, flags=%02x\n", + rman_get_start(scp->r_io), command, lba, count, feature, flags); #endif + /* select device */ + ATA_OUTB(scp->r_io, ATA_DRIVE, ATA_D_IBM | device); + /* disable interrupt from device */ if (scp->flags & ATA_QUEUED) ATA_OUTB(scp->r_altio, ATA_ALTSTAT, ATA_A_IDS | ATA_A_4BIT); - /* select device */ - ATA_OUTB(scp->r_io, ATA_DRIVE, ATA_D_IBM | device); - /* ready to issue command ? */ if (ata_wait(scp, device, 0) < 0) { ata_printf(scp, device, "timeout waiting to give command=%02x s=%02x e=%02x\n", command, scp->status, scp->error); return -1; } - ATA_OUTB(scp->r_io, ATA_FEATURE, feature); - ATA_OUTB(scp->r_io, ATA_COUNT, count); - ATA_OUTB(scp->r_io, ATA_SECTOR, sector); - ATA_OUTB(scp->r_io, ATA_CYL_MSB, cylinder >> 8); - ATA_OUTB(scp->r_io, ATA_CYL_LSB, cylinder); - ATA_OUTB(scp->r_io, ATA_DRIVE, ATA_D_IBM | device | head); + /* only use 48bit addressing if needed because of the overhead */ + if ((lba > 268435455 || count > 256) && + scp->dev_param[ATA_DEV(device)]->support.address48) { + ATA_OUTB(scp->r_io, ATA_FEATURE, (feature>>8) & 0xff); + ATA_OUTB(scp->r_io, ATA_FEATURE, feature); + ATA_OUTB(scp->r_io, ATA_COUNT, (count>>8) & 0xff); + ATA_OUTB(scp->r_io, ATA_COUNT, count & 0xff); + ATA_OUTB(scp->r_io, ATA_SECTOR, (lba>>24) & 0xff); + ATA_OUTB(scp->r_io, ATA_SECTOR, lba & 0xff); + ATA_OUTB(scp->r_io, ATA_CYL_LSB, (lba<<32) & 0xff); + ATA_OUTB(scp->r_io, ATA_CYL_LSB, (lba>>8) & 0xff); + ATA_OUTB(scp->r_io, ATA_CYL_MSB, (lba>>40) & 0xff); + ATA_OUTB(scp->r_io, ATA_CYL_MSB, (lba>>16) & 0xff); + ATA_OUTB(scp->r_io, ATA_DRIVE, ATA_D_LBA | device); - switch (flags) { + /* translate command into 48bit version */ + switch (command) { + case ATA_C_READ: + command = ATA_C_READ48; break; + case ATA_C_READ_MUL: + command = ATA_C_READ_MUL48; break; + case ATA_C_READ_DMA: + command = ATA_C_READ_DMA48; break; + case ATA_C_READ_DMA_QUEUED: + command = ATA_C_READ_DMA_QUEUED48; break; + case ATA_C_WRITE: + command = ATA_C_WRITE48; break; + case ATA_C_WRITE_MUL: + command = ATA_C_WRITE_MUL48; break; + case ATA_C_WRITE_DMA: + command = ATA_C_WRITE_DMA48; break; + case ATA_C_WRITE_DMA_QUEUED: + command = ATA_C_WRITE_DMA_QUEUED48; break; + case ATA_C_FLUSHCACHE: + command = ATA_C_FLUSHCACHE48; break; + default: + ata_printf(scp, device, "can't translate cmd to 48bit version\n"); + return -1; + } + } + else { + ATA_OUTB(scp->r_io, ATA_FEATURE, feature); + ATA_OUTB(scp->r_io, ATA_COUNT, count); + ATA_OUTB(scp->r_io, ATA_SECTOR, lba & 0xff); + ATA_OUTB(scp->r_io, ATA_CYL_LSB, (lba>>8) & 0xff); + ATA_OUTB(scp->r_io, ATA_CYL_MSB, (lba>>16) & 0xff); + if (flags & ATA_USE_CHS) + ATA_OUTB(scp->r_io, ATA_DRIVE, + ATA_D_IBM | device | ((lba>>24) & 0xf)); + else + ATA_OUTB(scp->r_io, ATA_DRIVE, + ATA_D_IBM | ATA_D_LBA | device | ((lba>>24) & 0xf)); + } + + switch (flags & ATA_WAIT_MASK) { + case ATA_IMMEDIATE: + ATA_OUTB(scp->r_io, ATA_CMD, command); + + /* enable interrupt */ + if (scp->flags & ATA_QUEUED) + ATA_OUTB(scp->r_altio, ATA_ALTSTAT, ATA_A_4BIT); + break; + case ATA_WAIT_INTR: scp->active |= ATA_WAIT_INTR; ATA_OUTB(scp->r_io, ATA_CMD, command); /* enable interrupt */ if (scp->flags & ATA_QUEUED) ATA_OUTB(scp->r_altio, ATA_ALTSTAT, ATA_A_4BIT); if (tsleep((caddr_t)scp, PRIBIO, "atacmd", 10 * hz) != 0) { ata_printf(scp, device, "ata_command: timeout waiting for intr\n"); scp->active &= ~ATA_WAIT_INTR; error = -1; } break; case ATA_WAIT_READY: scp->active |= ATA_WAIT_READY; ATA_OUTB(scp->r_io, ATA_CMD, command); if (ata_wait(scp, device, ATA_S_READY) < 0) { ata_printf(scp, device, "timeout waiting for command=%02x s=%02x e=%02x\n", command, scp->status, scp->error); error = -1; } scp->active &= ~ATA_WAIT_READY; break; - - case ATA_IMMEDIATE: - ATA_OUTB(scp->r_io, ATA_CMD, command); - break; - - default: - ata_printf(scp, device, "DANGER: illegal interrupt flag=%s\n", - active2str(flags)); } - /* enable interrupt */ - if (scp->flags & ATA_QUEUED) - ATA_OUTB(scp->r_altio, ATA_ALTSTAT, ATA_A_4BIT); return error; } void ata_set_name(struct ata_softc *scp, int device, char *name, int lun) { scp->dev_name[ATA_DEV(device)] = malloc(strlen(name) + 4, M_ATA, M_NOWAIT); if (scp->dev_name[ATA_DEV(device)]) sprintf(scp->dev_name[ATA_DEV(device)], "%s%d", name, lun); } void ata_free_name(struct ata_softc *scp, int device) { if (scp->dev_name[ATA_DEV(device)]) free(scp->dev_name[ATA_DEV(device)], M_ATA); scp->dev_name[ATA_DEV(device)] = NULL; } int ata_get_lun(u_int32_t *map) { int lun = ffs(~*map) - 1; *map |= (1 << lun); return lun; } int ata_test_lun(u_int32_t *map, int lun) { return (*map & (1 << lun)); } void ata_free_lun(u_int32_t *map, int lun) { *map &= ~(1 << lun); } int ata_printf(struct ata_softc *scp, int device, const char * fmt, ...) { va_list ap; int ret; if (device == -1) ret = printf("ata%d: ", device_get_unit(scp->dev)); else { if (scp->dev_name[ATA_DEV(device)]) ret = printf("%s: ", scp->dev_name[ATA_DEV(device)]); else ret = printf("ata%d-%s: ", device_get_unit(scp->dev), (device == ATA_MASTER) ? "master" : "slave"); } va_start(ap, fmt); ret += vprintf(fmt, ap); va_end(ap); return ret; } char * ata_mode2str(int mode) { switch (mode) { case ATA_PIO: return "BIOSPIO"; case ATA_PIO0: return "PIO0"; case ATA_PIO1: return "PIO1"; case ATA_PIO2: return "PIO2"; case ATA_PIO3: return "PIO3"; case ATA_PIO4: return "PIO4"; case ATA_WDMA2: return "WDMA2"; case ATA_UDMA2: return "UDMA33"; case ATA_UDMA4: return "UDMA66"; case ATA_UDMA5: return "UDMA100"; + case ATA_UDMA6: return "UDMA133"; case ATA_DMA: return "BIOSDMA"; default: return "???"; } } int -ata_pio2mode(int pio) -{ - switch (pio) { - default: - case 0: return ATA_PIO0; - case 1: return ATA_PIO1; - case 2: return ATA_PIO2; - case 3: return ATA_PIO3; - case 4: return ATA_PIO4; - } -} - -int ata_pmode(struct ata_params *ap) { if (ap->atavalid & ATA_FLAG_64_70) { if (ap->apiomodes & 2) return 4; if (ap->apiomodes & 1) return 3; } - if (ap->opiomode == 2) + if (ap->retired_piomode == 2) return 2; - if (ap->opiomode == 1) + if (ap->retired_piomode == 1) return 1; - if (ap->opiomode == 0) + if (ap->retired_piomode == 0) return 0; return -1; } int ata_wmode(struct ata_params *ap) { - if (ap->wdmamodes & 4) + if (ap->mwdmamodes & 0x04) return 2; - if (ap->wdmamodes & 2) + if (ap->mwdmamodes & 0x02) return 1; - if (ap->wdmamodes & 1) + if (ap->mwdmamodes & 0x01) return 0; return -1; } int ata_umode(struct ata_params *ap) { if (ap->atavalid & ATA_FLAG_88) { + if (ap->udmamodes & 0x40) + return 6; if (ap->udmamodes & 0x20) return 5; if (ap->udmamodes & 0x10) return 4; if (ap->udmamodes & 0x08) return 3; if (ap->udmamodes & 0x04) return 2; if (ap->udmamodes & 0x02) return 1; if (ap->udmamodes & 0x01) return 0; } return -1; -} - -static char * -active2str(int active) -{ - static char buf[64]; - - bzero(buf, sizeof(buf)); - if (active & ATA_IDLE) - strcat(buf, "ATA_IDLE "); - if (active & ATA_IMMEDIATE) - strcat(buf, "ATA_IMMEDIATE "); - if (active & ATA_WAIT_INTR) - strcat(buf, "ATA_WAIT_INTR "); - if (active & ATA_WAIT_READY) - strcat(buf, "ATA_WAIT_READY "); - if (active & ATA_ACTIVE) - strcat(buf, "ATA_ACTIVE "); - if (active & ATA_ACTIVE_ATA) - strcat(buf, "ATA_ACTIVE_ATA "); - if (active & ATA_ACTIVE_ATAPI) - strcat(buf, "ATA_ACTIVE_ATAPI "); - if (active & ATA_CONTROL) - strcat(buf, "ATA_CONTROL "); - return buf; } static void bswap(int8_t *buf, int len) { u_int16_t *ptr = (u_int16_t*)(buf + len); while (--ptr >= (u_int16_t*)buf) *ptr = ntohs(*ptr); } static void btrim(int8_t *buf, int len) { int8_t *ptr; for (ptr = buf; ptr < buf+len; ++ptr) if (!*ptr) *ptr = ' '; for (ptr = buf + len - 1; ptr >= buf && *ptr == ' '; --ptr) *ptr = 0; } static void bpack(int8_t *src, int8_t *dst, int len) { int i, j, blank; for (i = j = blank = 0 ; i < len; i++) { if (blank && src[i] == ' ') continue; if (blank && src[i] != ' ') { dst[j++] = src[i]; blank = 0; continue; } if (src[i] == ' ') { blank = 1; if (i == 0) continue; } dst[j++] = src[i]; } if (j < len) dst[j] = 0x00; } static void ata_change_mode(struct ata_softc *scp, int device, int mode) { int umode, wmode, pmode; int s = splbio(); while (!atomic_cmpset_int(&scp->active, ATA_IDLE, ATA_ACTIVE)) tsleep((caddr_t)&s, PRIBIO, "atachm", hz/4); umode = ata_umode(ATA_PARAM(scp, device)); wmode = ata_wmode(ATA_PARAM(scp, device)); pmode = ata_pmode(ATA_PARAM(scp, device)); switch (mode & ATA_DMA_MASK) { case ATA_UDMA: if ((mode & ATA_MODE_MASK) < umode) umode = mode & ATA_MODE_MASK; break; case ATA_WDMA: if ((mode & ATA_MODE_MASK) < wmode) wmode = mode & ATA_MODE_MASK; umode = -1; break; default: if (((mode & ATA_MODE_MASK) - ATA_PIO0) < pmode) pmode = (mode & ATA_MODE_MASK) - ATA_PIO0; umode = -1; wmode = -1; } ata_dmainit(scp, device, pmode, wmode, umode); scp->active = ATA_IDLE; ata_start(scp); splx(s); } static void ata_init(void) { /* register controlling device */ make_dev(&ata_cdevsw, 0, UID_ROOT, GID_OPERATOR, 0600, "ata"); /* register boot attach to be run when interrupts are enabled */ if (!(ata_delayed_attach = (struct intr_config_hook *) malloc(sizeof(struct intr_config_hook), M_TEMP, M_NOWAIT | M_ZERO))) { printf("ata: malloc of delayed attach hook failed\n"); return; } ata_delayed_attach->ich_func = (void*)ata_boot_attach; if (config_intrhook_establish(ata_delayed_attach) != 0) { printf("ata: config_intrhook_establish failed\n"); free(ata_delayed_attach, M_TEMP); } } SYSINIT(atadev, SI_SUB_DRIVERS, SI_ORDER_SECOND, ata_init, NULL) Index: head/sys/dev/ata/ata-all.h =================================================================== --- head/sys/dev/ata/ata-all.h (revision 84583) +++ head/sys/dev/ata/ata-all.h (revision 84584) @@ -1,271 +1,280 @@ /*- * Copyright (c) 1998,1999,2000,2001 Søren Schmidt * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer, * without modification, immediately at the beginning of the file. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * $FreeBSD$ */ /* ATA register defines */ #define ATA_DATA 0x00 /* data register */ #define ATA_ERROR 0x01 /* (R) error register */ #define ATA_E_NM 0x02 /* no media */ #define ATA_E_ABORT 0x04 /* command aborted */ #define ATA_E_MCR 0x08 /* media change request */ #define ATA_E_IDNF 0x10 /* ID not found */ #define ATA_E_MC 0x20 /* media changed */ #define ATA_E_UNC 0x40 /* uncorrectable data */ #define ATA_E_ICRC 0x80 /* UDMA crc error */ #define ATA_FEATURE 0x01 /* (W) feature register */ #define ATA_F_DMA 0x01 /* enable DMA */ #define ATA_F_OVL 0x02 /* enable overlap */ #define ATA_COUNT 0x02 /* (W) sector count */ #define ATA_IREASON 0x02 /* (R) interrupt reason */ #define ATA_I_CMD 0x01 /* cmd (1) | data (0) */ #define ATA_I_IN 0x02 /* read (1) | write (0) */ #define ATA_I_RELEASE 0x04 /* released bus (1) */ #define ATA_I_TAGMASK 0xf8 /* tag mask */ #define ATA_SECTOR 0x03 /* sector # */ #define ATA_CYL_LSB 0x04 /* cylinder# LSB */ #define ATA_CYL_MSB 0x05 /* cylinder# MSB */ #define ATA_DRIVE 0x06 /* Sector/Drive/Head register */ #define ATA_D_LBA 0x40 /* use LBA addressing */ #define ATA_D_IBM 0xa0 /* 512 byte sectors, ECC */ #define ATA_CMD 0x07 /* command register */ #define ATA_C_NOP 0x00 /* NOP command */ #define ATA_C_F_FLUSHQUEUE 0x00 /* flush queued cmd's */ #define ATA_C_F_AUTOPOLL 0x01 /* start autopoll function */ #define ATA_C_ATAPI_RESET 0x08 /* reset ATAPI device */ #define ATA_C_READ 0x20 /* read command */ +#define ATA_C_READ48 0x24 /* read command */ +#define ATA_C_READ_DMA48 0x25 /* read w/DMA command */ +#define ATA_C_READ_DMA_QUEUED48 0x26 /* read w/DMA QUEUED command */ +#define ATA_C_READ_MUL48 0x29 /* read multi command */ #define ATA_C_WRITE 0x30 /* write command */ +#define ATA_C_WRITE48 0x34 /* write command */ +#define ATA_C_WRITE_DMA48 0x35 /* write w/DMA command */ +#define ATA_C_WRITE_DMA_QUEUED48 0x36 /* write w/DMA QUEUED command */ +#define ATA_C_WRITE_MUL48 0x39 /* write multi command */ #define ATA_C_PACKET_CMD 0xa0 /* packet command */ #define ATA_C_ATAPI_IDENTIFY 0xa1 /* get ATAPI params*/ #define ATA_C_SERVICE 0xa2 /* service command */ #define ATA_C_READ_MUL 0xc4 /* read multi command */ #define ATA_C_WRITE_MUL 0xc5 /* write multi command */ #define ATA_C_SET_MULTI 0xc6 /* set multi size command */ #define ATA_C_READ_DMA_QUEUED 0xc7 /* read w/DMA QUEUED command */ #define ATA_C_READ_DMA 0xc8 /* read w/DMA command */ #define ATA_C_WRITE_DMA 0xca /* write w/DMA command */ #define ATA_C_WRITE_DMA_QUEUED 0xcc /* write w/DMA QUEUED command */ #define ATA_C_SLEEP 0xe6 /* sleep command */ #define ATA_C_FLUSHCACHE 0xe7 /* flush cache to disk */ +#define ATA_C_FLUSHCACHE48 0xea /* flush cache to disk */ #define ATA_C_ATA_IDENTIFY 0xec /* get ATA params */ #define ATA_C_SETFEATURES 0xef /* features command */ #define ATA_C_F_SETXFER 0x03 /* set transfer mode */ #define ATA_C_F_ENAB_WCACHE 0x02 /* enable write cache */ #define ATA_C_F_DIS_WCACHE 0x82 /* disable write cache */ #define ATA_C_F_ENAB_RCACHE 0xaa /* enable readahead cache */ #define ATA_C_F_DIS_RCACHE 0x55 /* disable readahead cache */ #define ATA_C_F_ENAB_RELIRQ 0x5d /* enable release interrupt */ #define ATA_C_F_DIS_RELIRQ 0xdd /* disable release interrupt */ #define ATA_C_F_ENAB_SRVIRQ 0x5e /* enable service interrupt */ #define ATA_C_F_DIS_SRVIRQ 0xde /* disable service interrupt */ #define ATA_STATUS 0x07 /* status register */ #define ATA_S_ERROR 0x01 /* error */ #define ATA_S_INDEX 0x02 /* index */ #define ATA_S_CORR 0x04 /* data corrected */ #define ATA_S_DRQ 0x08 /* data request */ #define ATA_S_DSC 0x10 /* drive seek completed */ #define ATA_S_SERVICE 0x10 /* drive needs service */ #define ATA_S_DWF 0x20 /* drive write fault */ #define ATA_S_DMA 0x20 /* DMA ready */ #define ATA_S_READY 0x40 /* drive ready */ #define ATA_S_BUSY 0x80 /* busy */ #define ATA_ALTSTAT 0x00 /* alternate status register */ #define ATA_ALTOFFSET 0x206 /* alternate registers offset */ #define ATA_PCCARD_ALTOFFSET 0x0e /* do for PCCARD devices */ #define ATA_A_IDS 0x02 /* disable interrupts */ #define ATA_A_RESET 0x04 /* RESET controller */ #define ATA_A_4BIT 0x08 /* 4 head bits */ /* misc defines */ #define ATA_PRIMARY 0x1f0 #define ATA_SECONDARY 0x170 #define ATA_MASTER 0x00 #define ATA_SLAVE 0x10 #define ATA_IOSIZE 0x08 #define ATA_ALTIOSIZE 0x01 #define ATA_BMIOSIZE 0x08 #define ATA_OP_FINISHED 0x00 #define ATA_OP_CONTINUES 0x01 #define ATA_DEV(device) ((device == ATA_MASTER) ? 0 : 1) #define ATA_PARAM(scp, device) (scp->dev_param[ATA_DEV(device)]) #define ATA_IOADDR_RID 0 #define ATA_ALTADDR_RID 1 #define ATA_BMADDR_RID 2 #define ATA_IRQ_RID 0 /* busmaster DMA related defines */ #define ATA_DMA_ENTRIES 256 #define ATA_DMA_EOT 0x80000000 #define ATA_BMCMD_PORT 0x00 -#define ATA_BMCMD_START_STOP 0x01 -#define ATA_BMCMD_WRITE_READ 0x08 +#define ATA_BMCMD_START_STOP 0x01 +#define ATA_BMCMD_WRITE_READ 0x08 #define ATA_BMDEVSPEC_0 0x01 #define ATA_BMSTAT_PORT 0x02 -#define ATA_BMSTAT_ACTIVE 0x01 -#define ATA_BMSTAT_ERROR 0x02 -#define ATA_BMSTAT_INTERRUPT 0x04 -#define ATA_BMSTAT_MASK 0x07 -#define ATA_BMSTAT_DMA_MASTER 0x20 -#define ATA_BMSTAT_DMA_SLAVE 0x40 -#define ATA_BMSTAT_DMA_SIMPLEX 0x80 +#define ATA_BMSTAT_ACTIVE 0x01 +#define ATA_BMSTAT_ERROR 0x02 +#define ATA_BMSTAT_INTERRUPT 0x04 +#define ATA_BMSTAT_MASK 0x07 +#define ATA_BMSTAT_DMA_MASTER 0x20 +#define ATA_BMSTAT_DMA_SLAVE 0x40 +#define ATA_BMSTAT_DMA_SIMPLEX 0x80 #define ATA_BMDEVSPEC_1 0x03 - #define ATA_BMDTP_PORT 0x04 /* structure for holding DMA address data */ struct ata_dmaentry { - u_int32_t base; - u_int32_t count; + u_int32_t base; + u_int32_t count; }; /* structure describing an ATA device */ struct ata_softc { struct device *dev; /* device handle */ int channel; /* channel on this controller */ struct resource *r_io; /* io addr resource handle */ struct resource *r_altio; /* altio addr resource handle */ struct resource *r_bmio; /* bmio addr resource handle */ struct resource *r_irq; /* interrupt of this channel */ void *ih; /* interrupt handle */ int (*intr_func)(struct ata_softc *); /* interrupt function */ u_int32_t chiptype; /* pciid of controller chip */ u_int32_t alignment; /* dma engine min alignment */ char *dev_name[2]; /* name of device */ struct ata_params *dev_param[2]; /* ptr to devices params */ void *dev_softc[2]; /* ptr to devices softc's */ int mode[2]; /* transfer mode for devices */ int flags; /* controller flags */ -#define ATA_DMA_ACTIVE 0x01 -#define ATA_ATAPI_DMA_RO 0x02 -#define ATA_USE_16BIT 0x04 -#define ATA_NO_SLAVE 0x08 -#define ATA_QUEUED 0x10 +#define ATA_NO_SLAVE 0x01 +#define ATA_USE_16BIT 0x02 +#define ATA_ATAPI_DMA_RO 0x04 +#define ATA_QUEUED 0x08 +#define ATA_DMA_ACTIVE 0x10 int devices; /* what is present */ #define ATA_ATA_MASTER 0x01 #define ATA_ATA_SLAVE 0x02 #define ATA_ATAPI_MASTER 0x04 #define ATA_ATAPI_SLAVE 0x08 u_int8_t status; /* last controller status */ u_int8_t error; /* last controller error */ int active; /* active processing request */ #define ATA_IDLE 0x0000 #define ATA_IMMEDIATE 0x0001 #define ATA_WAIT_INTR 0x0002 #define ATA_WAIT_READY 0x0004 -#define ATA_ACTIVE 0x0008 -#define ATA_ACTIVE_ATA 0x0010 -#define ATA_ACTIVE_ATAPI 0x0020 -#define ATA_CONTROL 0x0040 +#define ATA_WAIT_MASK 0x0007 +#define ATA_USE_CHS 0x0008 +#define ATA_ACTIVE 0x0010 +#define ATA_ACTIVE_ATA 0x0020 +#define ATA_ACTIVE_ATAPI 0x0040 +#define ATA_CONTROL 0x0080 TAILQ_HEAD(, ad_request) ata_queue; /* head of ATA queue */ TAILQ_HEAD(, atapi_request) atapi_queue; /* head of ATAPI queue */ void *running; /* currently running request */ }; /* externs */ extern devclass_t ata_devclass; /* public prototypes */ int ata_probe(device_t); int ata_attach(device_t); int ata_detach(device_t); int ata_resume(device_t); void ata_start(struct ata_softc *); void ata_reset(struct ata_softc *); int ata_reinit(struct ata_softc *); int ata_wait(struct ata_softc *, int, u_int8_t); -int ata_command(struct ata_softc *, int, u_int8_t, u_int16_t, u_int8_t, u_int8_t, u_int8_t, u_int8_t, int); +int ata_command(struct ata_softc *, int, u_int8_t, u_int64_t, u_int16_t, u_int8_t, int); int ata_printf(struct ata_softc *, int, const char *, ...) __printflike(3, 4); void ata_set_name(struct ata_softc *, int, char *, int); void ata_free_name(struct ata_softc *, int); int ata_get_lun(u_int32_t *); int ata_test_lun(u_int32_t *, int); void ata_free_lun(u_int32_t *, int); char *ata_mode2str(int); -int ata_pio2mode(int); int ata_pmode(struct ata_params *); int ata_wmode(struct ata_params *); int ata_umode(struct ata_params *); int ata_find_dev(device_t, u_int32_t, u_int32_t); void *ata_dmaalloc(struct ata_softc *, int); void ata_dmainit(struct ata_softc *, int, int, int, int); int ata_dmasetup(struct ata_softc *, int, struct ata_dmaentry *, caddr_t, int); void ata_dmastart(struct ata_softc *, int, struct ata_dmaentry *, int); int ata_dmastatus(struct ata_softc *); int ata_dmadone(struct ata_softc *); /* macros to hide busspace uglyness */ #define ATA_INB(res, offset) \ bus_space_read_1(rman_get_bustag((res)), \ rman_get_bushandle((res)), (offset)) #define ATA_INW(res, offset) \ bus_space_read_2(rman_get_bustag((res)), \ rman_get_bushandle((res)), (offset)) #define ATA_INL(res, offset) \ bus_space_read_4(rman_get_bustag((res)), \ rman_get_bushandle((res)), (offset)) #define ATA_INSW(res, offset, addr, count) \ bus_space_read_multi_2(rman_get_bustag((res)), \ rman_get_bushandle((res)), \ (offset), (addr), (count)) #define ATA_INSL(res, offset, addr, count) \ bus_space_read_multi_4(rman_get_bustag((res)), \ rman_get_bushandle((res)), \ (offset), (addr), (count)) #define ATA_OUTB(res, offset, value) \ bus_space_write_1(rman_get_bustag((res)), \ rman_get_bushandle((res)), (offset), (value)) #define ATA_OUTW(res, offset, value) \ bus_space_write_2(rman_get_bustag((res)), \ rman_get_bushandle((res)), (offset), (value)) #define ATA_OUTL(res, offset, value) \ bus_space_write_4(rman_get_bustag((res)), \ rman_get_bushandle((res)), (offset), (value)) #define ATA_OUTSW(res, offset, addr, count) \ bus_space_write_multi_2(rman_get_bustag((res)), \ rman_get_bushandle((res)), \ (offset), (addr), (count)) #define ATA_OUTSL(res, offset, addr, count) \ bus_space_write_multi_4(rman_get_bustag((res)), \ rman_get_bushandle((res)), \ (offset), (addr), (count)) Index: head/sys/dev/ata/ata-disk.c =================================================================== --- head/sys/dev/ata/ata-disk.c (revision 84583) +++ head/sys/dev/ata/ata-disk.c (revision 84584) @@ -1,997 +1,1001 @@ /*- * Copyright (c) 1998,1999,2000,2001 Søren Schmidt * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer, * without modification, immediately at the beginning of the file. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * $FreeBSD$ */ #include "opt_global.h" #include "opt_ata.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* device structures */ static d_open_t adopen; static d_close_t adclose; static d_strategy_t adstrategy; static d_dump_t addump; static struct cdevsw ad_cdevsw = { /* open */ adopen, /* close */ adclose, /* read */ physread, /* write */ physwrite, /* ioctl */ noioctl, /* poll */ nopoll, /* mmap */ nommap, /* strategy */ adstrategy, /* name */ "ad", /* maj */ 116, /* dump */ addump, /* psize */ nopsize, /* flags */ D_DISK, }; static struct cdevsw addisk_cdevsw; /* prototypes */ static void ad_invalidatequeue(struct ad_softc *, struct ad_request *); static int ad_tagsupported(struct ad_softc *); static void ad_timeout(struct ad_request *); static void ad_free(struct ad_request *); static int ad_version(u_int16_t); /* internal vars */ static u_int32_t adp_lun_map = 0; static MALLOC_DEFINE(M_AD, "AD driver", "ATA disk driver"); static int ata_dma = 1; static int ata_wc = 0; static int ata_tags = 0; TUNABLE_INT("hw.ata.ata_dma", &ata_dma); TUNABLE_INT("hw.ata.wc", &ata_wc); TUNABLE_INT("hw.ata.tags", &ata_tags); /* sysctl vars */ SYSCTL_DECL(_hw_ata); SYSCTL_INT(_hw_ata, OID_AUTO, ata_dma, CTLFLAG_RD, &ata_dma, 0, "ATA disk DMA mode control"); SYSCTL_INT(_hw_ata, OID_AUTO, wc, CTLFLAG_RD, &ata_wc, 0, "ATA disk write caching"); SYSCTL_INT(_hw_ata, OID_AUTO, tags, CTLFLAG_RD, &ata_tags, 0, "ATA disk tagged queuing support"); /* defines */ #define AD_MAX_RETRIES 3 #define AD_PARAM ATA_PARAM(adp->controller, adp->unit) /* experimental cache flush on BIO_ORDERED */ #undef ATA_FLUSHCACHE_ON void ad_attach(struct ata_softc *scp, int device) { struct ad_softc *adp; dev_t dev; - int secsperint; if (!(adp = malloc(sizeof(struct ad_softc), M_AD, M_NOWAIT | M_ZERO))) { ata_printf(scp, device, "failed to allocate driver storage\n"); return; } adp->controller = scp; adp->unit = device; #ifdef ATA_STATIC_ID adp->lun = (device_get_unit(scp->dev) << 1) + ATA_DEV(device); #else adp->lun = ata_get_lun(&adp_lun_map); #endif ata_set_name(scp, device, "ad", adp->lun); adp->heads = AD_PARAM->heads; adp->sectors = AD_PARAM->sectors; adp->total_secs = AD_PARAM->cylinders * adp->heads * adp->sectors; - if (AD_PARAM->cylinders == 16383 && adp->total_secs < AD_PARAM->lbasize) - adp->total_secs = AD_PARAM->lbasize; - - if (ad_version(AD_PARAM->versmajor) && - AD_PARAM->atavalid & ATA_FLAG_54_58 && AD_PARAM->lbasize) - adp->flags |= AD_F_LBA_ENABLED; + /* does this device need oldstyle CHS addressing */ + if (!ad_version(AD_PARAM->version_major) || + !(AD_PARAM->atavalid & ATA_FLAG_54_58) || !AD_PARAM->lba_size) + adp->flags |= AD_F_CHS_USED; + + /* use the 28bit LBA size if valid */ + if (AD_PARAM->cylinders == 16383 && adp->total_secs < AD_PARAM->lba_size) + adp->total_secs = AD_PARAM->lba_size; + + /* use the 48bit LBA size if valid */ + if (AD_PARAM->support.address48) + adp->total_secs = AD_PARAM->lba_size48; + /* use multiple sectors/interrupt if device supports it */ adp->transfersize = DEV_BSIZE; - if (ad_version(AD_PARAM->versmajor)) { - secsperint = max(1, min(AD_PARAM->nsecperint, 16)); + if (ad_version(AD_PARAM->version_major)) { + int secsperint = max(1, min(AD_PARAM->sectors_intr, 16)); + if (!ata_command(adp->controller, adp->unit, ATA_C_SET_MULTI, - 0, 0, 0, secsperint, 0, ATA_WAIT_INTR) && + 0, secsperint, 0, ATA_WAIT_INTR) && !ata_wait(adp->controller, adp->unit, 0)) adp->transfersize *= secsperint; } /* enable read cacheing if not default on device */ if (ata_command(adp->controller, adp->unit, ATA_C_SETFEATURES, - 0, 0, 0, 0, ATA_C_F_ENAB_RCACHE, ATA_WAIT_INTR)) + 0, 0, ATA_C_F_ENAB_RCACHE, ATA_WAIT_INTR)) ata_printf(scp, device, "enabling readahead cache failed\n"); /* enable write cacheing if allowed and not default on device */ if (ata_wc || ata_tags) { if (ata_command(adp->controller, adp->unit, ATA_C_SETFEATURES, - 0, 0, 0, 0, ATA_C_F_ENAB_WCACHE, ATA_WAIT_INTR)) + 0, 0, ATA_C_F_ENAB_WCACHE, ATA_WAIT_INTR)) ata_printf(scp, device, "enabling write cache failed\n"); } else { if (ata_command(adp->controller, adp->unit, ATA_C_SETFEATURES, - 0, 0, 0, 0, ATA_C_F_DIS_WCACHE, ATA_WAIT_INTR)) + 0, 0, ATA_C_F_DIS_WCACHE, ATA_WAIT_INTR)) ata_printf(scp, device, "disabling write cache failed\n"); } /* use DMA if allowed and if drive/controller supports it */ if (ata_dma) ata_dmainit(adp->controller, adp->unit, ata_pmode(AD_PARAM), ata_wmode(AD_PARAM), ata_umode(AD_PARAM)); else ata_dmainit(adp->controller, adp->unit, ata_pmode(AD_PARAM), -1, -1); /* use tagged queueing if allowed and supported */ if (ata_tags && ad_tagsupported(adp)) { adp->num_tags = AD_PARAM->queuelen; adp->flags |= AD_F_TAG_ENABLED; adp->controller->flags |= ATA_QUEUED; if (ata_command(adp->controller, adp->unit, ATA_C_SETFEATURES, - 0, 0, 0, 0, ATA_C_F_DIS_RELIRQ, ATA_WAIT_INTR)) + 0, 0, ATA_C_F_DIS_RELIRQ, ATA_WAIT_INTR)) ata_printf(scp, device, "disabling release interrupt failed\n"); if (ata_command(adp->controller, adp->unit, ATA_C_SETFEATURES, - 0, 0, 0, 0, ATA_C_F_DIS_SRVIRQ, ATA_WAIT_INTR)) + 0, 0, ATA_C_F_DIS_SRVIRQ, ATA_WAIT_INTR)) ata_printf(scp, device, "disabling service interrupt failed\n"); } devstat_add_entry(&adp->stats, "ad", adp->lun, DEV_BSIZE, DEVSTAT_NO_ORDERED_TAGS, DEVSTAT_TYPE_DIRECT | DEVSTAT_TYPE_IF_IDE, DEVSTAT_PRIORITY_DISK); dev = disk_create(adp->lun, &adp->disk, 0, &ad_cdevsw, &addisk_cdevsw); dev->si_drv1 = adp; dev->si_iosize_max = 256 * DEV_BSIZE; adp->dev = dev; bioq_init(&adp->queue); /* if this disk belongs to an ATA RAID dont print the probe */ if (!ar_probe(adp)) adp->flags |= AD_F_RAID_SUBDISK; else ad_print(adp, ""); /* construct the disklabel */ bzero(&adp->disk.d_label, sizeof(struct disklabel)); adp->disk.d_label.d_secsize = DEV_BSIZE; adp->disk.d_label.d_nsectors = adp->sectors; adp->disk.d_label.d_ntracks = adp->heads; adp->disk.d_label.d_ncylinders = adp->total_secs/(adp->heads*adp->sectors); adp->disk.d_label.d_secpercyl = adp->sectors * adp->heads; adp->disk.d_label.d_secperunit = adp->total_secs; /* store our softc signalling we are ready to go */ scp->dev_softc[ATA_DEV(device)] = adp; } void ad_detach(struct ad_softc *adp, int flush) { struct ad_request *request; struct bio *bp; adp->flags |= AD_F_DETACHING; if (adp->flags & AD_F_RAID_SUBDISK) printf("WARNING! detaching RAID subdisk, danger ahead\n"); ata_printf(adp->controller, adp->unit, "removed from configuration\n"); ad_invalidatequeue(adp, NULL); TAILQ_FOREACH(request, &adp->controller->ata_queue, chain) { if (request->device != adp) continue; TAILQ_REMOVE(&adp->controller->ata_queue, request, chain); biofinish(request->bp, NULL, ENXIO); ad_free(request); } while ((bp = bioq_first(&adp->queue))) { biofinish(bp, NULL, ENXIO); } disk_invalidate(&adp->disk); disk_destroy(adp->dev); devstat_remove_entry(&adp->stats); if (flush) { if (ata_command(adp->controller, adp->unit, ATA_C_FLUSHCACHE, - 0, 0, 0, 0, 0, ATA_WAIT_READY)) + 0, 0, 0, ATA_WAIT_READY)) ata_printf(adp->controller, adp->unit, "flushing cache on detach failed\n"); } ata_free_lun(&adp_lun_map, adp->lun); adp->controller->dev_softc[ATA_DEV(adp->unit)] = NULL; free(adp, M_AD); } static int adopen(dev_t dev, int flags, int fmt, struct thread *td) { struct ad_softc *adp = dev->si_drv1; if (adp->flags & AD_F_RAID_SUBDISK) return EBUSY; return 0; } static int adclose(dev_t dev, int flags, int fmt, struct thread *td) { struct ad_softc *adp = dev->si_drv1; if (ata_command(adp->controller, adp->unit, ATA_C_FLUSHCACHE, - 0, 0, 0, 0, 0, ATA_WAIT_READY)) + 0, 0, 0, ATA_WAIT_READY)) ata_printf(adp->controller, adp->unit, "flushing cache on close failed\n"); return 0; } static void adstrategy(struct bio *bp) { struct ad_softc *adp = bp->bio_dev->si_drv1; int s; if (adp->flags & AD_F_DETACHING) { biofinish(bp, NULL, ENXIO); return; } s = splbio(); bioqdisksort(&adp->queue, bp); ata_start(adp->controller); splx(s); } int addump(dev_t dev) { struct ad_softc *adp = dev->si_drv1; struct ad_request request; u_int count, blkno, secsize; vm_offset_t addr = 0; long blkcnt; int dumppages = MAXDUMPPGS; int error; int i; if ((error = disk_dumpcheck(dev, &count, &blkno, &secsize))) return error; if (!adp) return ENXIO; /* force PIO mode for dumps */ adp->controller->mode[ATA_DEV(adp->unit)] = ATA_PIO; ata_reinit(adp->controller); blkcnt = howmany(PAGE_SIZE, secsize); while (count > 0) { caddr_t va = NULL; DELAY(1000); if ((count / blkcnt) < dumppages) dumppages = count / blkcnt; for (i = 0; i < dumppages; ++i) { vm_offset_t a = addr + (i * PAGE_SIZE); if (is_physical_memory(a)) va = pmap_kenter_temporary(trunc_page(a), i); else va = pmap_kenter_temporary(trunc_page(0), i); } bzero(&request, sizeof(struct ad_request)); request.device = adp; request.blockaddr = blkno; request.bytecount = PAGE_SIZE * dumppages; request.data = va; while (request.bytecount > 0) { ad_transfer(&request); if (request.flags & ADR_F_ERROR) return EIO; request.donecount += request.currentsize; request.bytecount -= request.currentsize; DELAY(20); } if (dumpstatus(addr, (long)(count * DEV_BSIZE)) < 0) return EINTR; blkno += blkcnt * dumppages; count -= blkcnt * dumppages; addr += PAGE_SIZE * dumppages; } if (ata_wait(adp->controller, adp->unit, ATA_S_READY | ATA_S_DSC) < 0) ata_printf(adp->controller, adp->unit, "timeout waiting for final ready\n"); return 0; } void ad_start(struct ad_softc *adp) { struct bio *bp = bioq_first(&adp->queue); struct ad_request *request; int tag = 0; if (!bp) return; #ifdef ATA_FLUSHCACHE_ON /* * if BIO_ORDERED is set cache should be flushed, if there are * any outstanding requests, hold off and wait for them to finish */ if (adp->flags & AD_F_TAG_ENABLED && bp->bio_flags & BIO_ORDERED && adp->outstanding > 0) return; #endif /* if tagged queueing enabled get next free tag */ if (adp->flags & AD_F_TAG_ENABLED) { while (tag <= adp->num_tags && adp->tags[tag]) tag++; if (tag > adp->num_tags ) return; } if (!(request = malloc(sizeof(struct ad_request), M_AD, M_NOWAIT|M_ZERO))) { ata_printf(adp->controller, adp->unit, "out of memory in start\n"); return; } /* setup request */ request->device = adp; request->bp = bp; request->blockaddr = bp->bio_pblkno; request->bytecount = bp->bio_bcount; request->data = bp->bio_data; request->tag = tag; if (bp->bio_cmd == BIO_READ) request->flags |= ADR_F_READ; if (adp->controller->mode[ATA_DEV(adp->unit)] >= ATA_DMA) { if (!(request->dmatab = ata_dmaalloc(adp->controller, adp->unit))) adp->controller->mode[ATA_DEV(adp->unit)] = ATA_PIO; } /* insert in tag array */ adp->tags[tag] = request; /* remove from drive queue */ bioq_remove(&adp->queue, bp); /* link onto controller queue */ TAILQ_INSERT_TAIL(&adp->controller->ata_queue, request, chain); } int ad_transfer(struct ad_request *request) { struct ad_softc *adp; - u_int32_t blkno, secsprcyl; - u_int32_t cylinder, head, sector, count, cmd; + u_int64_t lba; + u_int32_t count, max_count; + u_int8_t cmd; + int flags = ATA_IMMEDIATE; /* get request params */ adp = request->device; /* calculate transfer details */ - blkno = request->blockaddr + (request->donecount / DEV_BSIZE); + lba = request->blockaddr + (request->donecount / DEV_BSIZE); if (request->donecount == 0) { /* start timeout for this transfer */ if (dumping) request->timeout_handle.callout = NULL; else request->timeout_handle = timeout((timeout_t*)ad_timeout, request, 10 * hz); - /* setup transfer parameters */ + /* setup transfer parameters !! 65536 for 48bit SOS XXX */ count = howmany(request->bytecount, DEV_BSIZE); - if (count > 256) { - count = 256; + max_count = AD_PARAM->support.address48 ? 65536 : 256; + if (count > max_count) { ata_printf(adp->controller, adp->unit, "count %d size transfers not supported\n", count); + count = max_count; } - if (adp->flags & AD_F_LBA_ENABLED) { - sector = (blkno >> 0) & 0xff; - cylinder = (blkno >> 8) & 0xffff; - head = ((blkno >> 24) & 0xf) | ATA_D_LBA; + if (adp->flags & AD_F_CHS_USED) { + int sector = (lba % adp->sectors) + 1; + int cylinder = lba / (adp->sectors * adp->heads); + int head = (lba % (adp->sectors * adp->heads)) / adp->sectors; + + lba = (sector&0xff) | ((cylinder&0xffff)<<8) | ((head&0xf)<<24); + flags |= ATA_USE_CHS; } - else { - secsprcyl = adp->sectors * adp->heads; - cylinder = blkno / secsprcyl; - head = (blkno % secsprcyl) / adp->sectors; - sector = (blkno % adp->sectors) + 1; - } /* setup first transfer length */ request->currentsize = min(request->bytecount, adp->transfersize); devstat_start_transaction(&adp->stats); /* does this drive & transfer work with DMA ? */ request->flags &= ~ADR_F_DMA_USED; if (adp->controller->mode[ATA_DEV(adp->unit)] >= ATA_DMA && !ata_dmasetup(adp->controller, adp->unit, request->dmatab, request->data, request->bytecount)) { request->flags |= ADR_F_DMA_USED; request->currentsize = request->bytecount; /* do we have tags enabled ? */ if (adp->flags & AD_F_TAG_ENABLED) { cmd = (request->flags & ADR_F_READ) ? ATA_C_READ_DMA_QUEUED : ATA_C_WRITE_DMA_QUEUED; - if (ata_command(adp->controller, adp->unit, cmd, - cylinder, head, sector, request->tag << 3, - count, ATA_IMMEDIATE)) { + if (ata_command(adp->controller, adp->unit, cmd, lba, + request->tag << 3, count, flags)) { ata_printf(adp->controller, adp->unit, "error executing command"); goto transfer_failed; } if (ata_wait(adp->controller, adp->unit, ATA_S_READY)) { ata_printf(adp->controller, adp->unit, "timeout waiting for READY\n"); goto transfer_failed; } adp->outstanding++; /* if ATA bus RELEASE check for SERVICE */ if (adp->flags & AD_F_TAG_ENABLED && - ATA_INB(adp->controller->r_io, ATA_IREASON) & ATA_I_RELEASE) { + ATA_INB(adp->controller->r_io, ATA_IREASON) & ATA_I_RELEASE) return ad_service(adp, 1); - } } else { cmd = (request->flags & ADR_F_READ) ? ATA_C_READ_DMA : ATA_C_WRITE_DMA; - if (ata_command(adp->controller, adp->unit, cmd, cylinder, - head, sector, count, 0, ATA_IMMEDIATE)) { + if (ata_command(adp->controller, adp->unit, + cmd, lba, count, 0, flags)) { ata_printf(adp->controller, adp->unit, "error executing command"); goto transfer_failed; } #if 0 /* * wait for data transfer phase * * well this should be here acording to specs, but * promise controllers doesn't like it, they lockup! * thats probably why tags doesn't work on the promise * as this is needed there... */ - if (ata_wait(adp->controller, adp->unit, - ATA_S_READY | ATA_S_DRQ)) { + if (ata_wait(adp->controller, adp->unit, + ATA_S_READY | ATA_S_DRQ)) { ata_printf(adp->controller, adp->unit, "timeout waiting for data phase\n"); goto transfer_failed; } #endif } /* start transfer, return and wait for interrupt */ ata_dmastart(adp->controller, adp->unit, request->dmatab, request->flags & ADR_F_READ); return ATA_OP_CONTINUES; } /* does this drive support multi sector transfers ? */ if (request->currentsize > DEV_BSIZE) cmd = request->flags&ADR_F_READ ? ATA_C_READ_MUL : ATA_C_WRITE_MUL; /* just plain old single sector transfer */ else cmd = request->flags&ADR_F_READ ? ATA_C_READ : ATA_C_WRITE; - if (ata_command(adp->controller, adp->unit, cmd, - cylinder, head, sector, count, 0, ATA_IMMEDIATE)) { + if (ata_command(adp->controller, adp->unit, cmd, lba, count, 0, flags)){ ata_printf(adp->controller, adp->unit, "error executing command"); goto transfer_failed; } } /* calculate this transfer length */ request->currentsize = min(request->bytecount, adp->transfersize); /* if this is a PIO read operation, return and wait for interrupt */ if (request->flags & ADR_F_READ) return ATA_OP_CONTINUES; /* ready to write PIO data ? */ if (ata_wait(adp->controller, adp->unit, (ATA_S_READY | ATA_S_DSC | ATA_S_DRQ)) < 0) { ata_printf(adp->controller, adp->unit, "timeout waiting for DRQ"); goto transfer_failed; } /* output the data */ if (adp->controller->flags & ATA_USE_16BIT) ATA_OUTSW(adp->controller->r_io, ATA_DATA, - (void *)((uintptr_t)request->data + request->donecount), - request->currentsize / sizeof(int16_t)); + (void *)((uintptr_t)request->data + request->donecount), + request->currentsize / sizeof(int16_t)); else ATA_OUTSL(adp->controller->r_io, ATA_DATA, - (void *)((uintptr_t)request->data + request->donecount), - request->currentsize / sizeof(int32_t)); + (void *)((uintptr_t)request->data + request->donecount), + request->currentsize / sizeof(int32_t)); return ATA_OP_CONTINUES; transfer_failed: untimeout((timeout_t *)ad_timeout, request, request->timeout_handle); ad_invalidatequeue(adp, request); printf(" - resetting\n"); /* if retries still permit, reinject this request */ if (request->retries++ < AD_MAX_RETRIES) TAILQ_INSERT_HEAD(&adp->controller->ata_queue, request, chain); else { /* retries all used up, return error */ request->bp->bio_error = EIO; request->bp->bio_flags |= BIO_ERROR; request->bp->bio_resid = request->bytecount; biofinish(request->bp, &adp->stats, 0); ad_free(request); } ata_reinit(adp->controller); return ATA_OP_CONTINUES; } int ad_interrupt(struct ad_request *request) { struct ad_softc *adp = request->device; int dma_stat = 0; #ifdef ATA_FLUSHCACHE_ON if (request->flags & ADR_F_FLUSHCACHE) goto finish; #endif /* finish DMA transfer */ if (request->flags & ADR_F_DMA_USED) dma_stat = ata_dmadone(adp->controller); /* do we have a corrected soft error ? */ if (adp->controller->status & ATA_S_CORR) diskerr(request->bp, "soft error (ECC corrected)", request->blockaddr + (request->donecount / DEV_BSIZE), &adp->disk.d_label); /* did any real errors happen ? */ if ((adp->controller->status & ATA_S_ERROR) || (request->flags & ADR_F_DMA_USED && dma_stat & ATA_BMSTAT_ERROR)) { adp->controller->error = ATA_INB(adp->controller->r_io, ATA_ERROR); diskerr(request->bp, (adp->controller->error & ATA_E_ICRC) ? "UDMA ICRC error" : "hard error", request->blockaddr + (request->donecount / DEV_BSIZE), &adp->disk.d_label); /* if this is a UDMA CRC error, reinject request */ if (request->flags & ADR_F_DMA_USED && adp->controller->error & ATA_E_ICRC) { untimeout((timeout_t *)ad_timeout, request,request->timeout_handle); ad_invalidatequeue(adp, request); if (request->retries++ < AD_MAX_RETRIES) printf(" retrying\n"); else { ata_dmainit(adp->controller, adp->unit, ata_pmode(AD_PARAM), -1, -1); printf(" falling back to PIO mode\n"); } TAILQ_INSERT_HEAD(&adp->controller->ata_queue, request, chain); return ATA_OP_FINISHED; } /* if using DMA, try once again in PIO mode */ if (request->flags & ADR_F_DMA_USED) { untimeout((timeout_t *)ad_timeout, request,request->timeout_handle); ad_invalidatequeue(adp, request); ata_dmainit(adp->controller, adp->unit, ata_pmode(AD_PARAM), -1, -1); request->flags |= ADR_F_FORCE_PIO; TAILQ_INSERT_HEAD(&adp->controller->ata_queue, request, chain); return ATA_OP_FINISHED; } request->flags |= ADR_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 & ADR_F_FORCE_PIO) ata_printf(adp->controller, adp->unit, "DMA problem fallback to PIO mode\n"); /* if this was a PIO read operation, get the data */ if (!(request->flags & ADR_F_DMA_USED) && (request->flags & (ADR_F_READ | ADR_F_ERROR)) == ADR_F_READ) { /* ready to receive data? */ if ((adp->controller->status & (ATA_S_READY | ATA_S_DSC | ATA_S_DRQ)) != (ATA_S_READY | ATA_S_DSC | ATA_S_DRQ)) ata_printf(adp->controller, adp->unit, "read interrupt arrived early"); if (ata_wait(adp->controller, adp->unit, (ATA_S_READY | ATA_S_DSC | ATA_S_DRQ)) != 0) { ata_printf(adp->controller, adp->unit, "read error detected (too) late"); request->flags |= ADR_F_ERROR; } else { /* data ready, read in */ if (adp->controller->flags & ATA_USE_16BIT) ATA_INSW(adp->controller->r_io, ATA_DATA, (void *)((uintptr_t)request->data + request->donecount), request->currentsize / sizeof(int16_t)); else ATA_INSL(adp->controller->r_io, ATA_DATA, (void *)((uintptr_t)request->data + request->donecount), request->currentsize / sizeof(int32_t)); } } /* finish up transfer */ if (request->flags & ADR_F_ERROR) { request->bp->bio_error = EIO; request->bp->bio_flags |= BIO_ERROR; } else { request->bytecount -= request->currentsize; request->donecount += request->currentsize; if (request->bytecount > 0) { ad_transfer(request); return ATA_OP_CONTINUES; } } /* disarm timeout for this transfer */ untimeout((timeout_t *)ad_timeout, request, request->timeout_handle); request->bp->bio_resid = request->bytecount; #ifdef ATA_FLUSHCACHE_ON if (request->bp->bio_flags & BIO_ORDERED) { request->flags |= ADR_F_FLUSHCACHE; if (ata_command(adp->controller, adp->unit, ATA_C_FLUSHCACHE, - 0, 0, 0, 0, 0, ATA_IMMEDIATE)) + 0, 0, 0, ATA_IMMEDIATE)) ata_printf(adp->controller, adp->unit, "flushing cache failed\n"); else return ATA_OP_CONTINUES; } finish: #endif biofinish(request->bp, &adp->stats, 0); ad_free(request); adp->outstanding--; /* check for SERVICE (tagged operations only) */ return ad_service(adp, 1); } int ad_service(struct ad_softc *adp, int change) { /* do we have to check the other device on this channel ? */ if (adp->controller->flags & ATA_QUEUED && change) { int device = adp->unit; if (adp->unit == ATA_MASTER) { if (adp->controller->devices & ATA_ATA_SLAVE && ((struct ad_softc *) (adp->controller->dev_softc[ATA_DEV(ATA_SLAVE)]))->flags & AD_F_TAG_ENABLED) device = ATA_SLAVE; } else { if (adp->controller->devices & ATA_ATA_MASTER && ((struct ad_softc *) (adp->controller->dev_softc[ATA_DEV(ATA_MASTER)]))->flags & AD_F_TAG_ENABLED) device = ATA_MASTER; } if (device != adp->unit && ((struct ad_softc *) (adp->controller->dev_softc[ATA_DEV(device)]))->outstanding > 0) { ATA_OUTB(adp->controller->r_io, ATA_DRIVE, ATA_D_IBM | device); adp = adp->controller->dev_softc[ATA_DEV(device)]; DELAY(1); } } adp->controller->status = ATA_INB(adp->controller->r_altio, ATA_ALTSTAT); /* do we have a SERVICE request from the drive ? */ if (adp->flags & AD_F_TAG_ENABLED && adp->outstanding > 0 && adp->controller->status & ATA_S_SERVICE) { struct ad_request *request; int tag; /* check for error */ if (adp->controller->status & ATA_S_ERROR) { ata_printf(adp->controller, adp->unit, "Oops! controller says s=0x%02x e=0x%02x\n", adp->controller->status, adp->controller->error); ad_invalidatequeue(adp, NULL); return ATA_OP_FINISHED; } /* issue SERVICE cmd */ if (ata_command(adp->controller, adp->unit, ATA_C_SERVICE, - 0, 0, 0, 0, 0, ATA_IMMEDIATE)) { + 0, 0, 0, ATA_IMMEDIATE)) { ata_printf(adp->controller, adp->unit, "problem executing SERVICE cmd\n"); ad_invalidatequeue(adp, NULL); return ATA_OP_FINISHED; } /* setup the transfer environment when ready */ if (ata_wait(adp->controller, adp->unit, ATA_S_READY)) { ata_printf(adp->controller, adp->unit, "problem issueing SERVICE tag=%d s=0x%02x e=0x%02x\n", ATA_INB(adp->controller->r_io, ATA_COUNT) >> 3, adp->controller->status, adp->controller->error); ad_invalidatequeue(adp, NULL); return ATA_OP_FINISHED; } tag = ATA_INB(adp->controller->r_io, ATA_COUNT) >> 3; if (!(request = adp->tags[tag])) { ata_printf(adp->controller, adp->unit, "no request for tag=%d\n", tag); ad_invalidatequeue(adp, NULL); return ATA_OP_FINISHED; } adp->controller->active = ATA_ACTIVE_ATA; adp->controller->running = request; request->serv++; /* start DMA transfer when ready */ if (ata_wait(adp->controller, adp->unit, ATA_S_READY | ATA_S_DRQ)) { ata_printf(adp->controller, adp->unit, "timeout waiting for data phase s=%02x e=%02x\n", adp->controller->status, adp->controller->error); ad_invalidatequeue(adp, NULL); return ATA_OP_FINISHED; } ata_dmastart(adp->controller, adp->unit, request->dmatab, request->flags & ADR_F_READ); return ATA_OP_CONTINUES; } return ATA_OP_FINISHED; } static void ad_free(struct ad_request *request) { int s = splbio(); if (request->dmatab) free(request->dmatab, M_DEVBUF); request->device->tags[request->tag] = NULL; free(request, M_AD); splx(s); } static void ad_invalidatequeue(struct ad_softc *adp, struct ad_request *request) { /* if tags used invalidate all other tagged transfers */ if (adp->flags & AD_F_TAG_ENABLED) { struct ad_request *tmpreq; int tag; ata_printf(adp->controller, adp->unit,"invalidating queued requests\n"); for (tag = 0; tag <= adp->num_tags; tag++) { tmpreq = adp->tags[tag]; adp->tags[tag] = NULL; if (tmpreq == request || tmpreq == NULL) continue; untimeout((timeout_t *)ad_timeout, tmpreq, tmpreq->timeout_handle); TAILQ_INSERT_HEAD(&adp->controller->ata_queue, tmpreq, chain); } if (ata_command(adp->controller, adp->unit, ATA_C_NOP, - 0, 0, 0, 0, ATA_C_F_FLUSHQUEUE, ATA_WAIT_READY)) + 0, 0, ATA_C_F_FLUSHQUEUE, ATA_WAIT_READY)) ata_printf(adp->controller, adp->unit, "flush queue failed\n"); adp->outstanding = 0; } } static int ad_tagsupported(struct ad_softc *adp) { const char *drives[] = {"IBM-DPTA", "IBM-DTLA", NULL}; int i = 0; switch (adp->controller->chiptype) { case 0x4d33105a: /* Promises before TX2 doesn't work with tagged queuing */ case 0x4d38105a: case 0x0d30105a: case 0x4d30105a: return 0; } /* check that drive does DMA, has tags enabled, and is one we know works */ if (adp->controller->mode[ATA_DEV(adp->unit)] >= ATA_DMA && - AD_PARAM->supqueued && AD_PARAM->enabqueued) { + AD_PARAM->support.queued && AD_PARAM->enabled.queued) { while (drives[i] != NULL) { if (!strncmp(AD_PARAM->model, drives[i], strlen(drives[i]))) return 1; i++; } /* * check IBM's new obscure way of naming drives * we want "IC" (IBM CORP) and "AT" or "AV" (ATA interface) * but doesn't care about the other info (size, capacity etc) */ if (!strncmp(AD_PARAM->model, "IC", 2) && (!strncmp(AD_PARAM->model + 8, "AT", 2) || !strncmp(AD_PARAM->model + 8, "AV", 2))) return 1; } return 0; } static void ad_timeout(struct ad_request *request) { struct ad_softc *adp = request->device; int s = splbio(); adp->controller->running = NULL; ata_printf(adp->controller, adp->unit, "%s command timeout tag=%d serv=%d - resetting\n", (request->flags & ADR_F_READ) ? "READ" : "WRITE", request->tag, request->serv); if (request->flags & ADR_F_DMA_USED) { ata_dmadone(adp->controller); ad_invalidatequeue(adp, request); if (request->retries == AD_MAX_RETRIES) { ata_dmainit(adp->controller, adp->unit, ata_pmode(AD_PARAM), -1, -1); ata_printf(adp->controller, adp->unit, "trying fallback to PIO mode\n"); request->retries = 0; } } /* if retries still permit, reinject this request */ if (request->retries++ < AD_MAX_RETRIES) { TAILQ_INSERT_HEAD(&adp->controller->ata_queue, request, chain); } else { /* retries all used up, return error */ request->bp->bio_error = EIO; request->bp->bio_flags |= BIO_ERROR; biofinish(request->bp, &adp->stats, 0); ad_free(request); } ata_reinit(adp->controller); splx(s); } void ad_reinit(struct ad_softc *adp) { /* reinit disk parameters */ ad_invalidatequeue(adp, NULL); - ata_command(adp->controller, adp->unit, ATA_C_SET_MULTI, 0, 0, 0, + ata_command(adp->controller, adp->unit, ATA_C_SET_MULTI, 0, adp->transfersize / DEV_BSIZE, 0, ATA_WAIT_INTR); 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 ata_dmainit(adp->controller, adp->unit, ata_pmode(AD_PARAM), -1, -1); } void ad_print(struct ad_softc *adp, char *prepend) { if (prepend) printf("%s", prepend); if (bootverbose) { ata_printf(adp->controller, adp->unit, "<%.40s/%.8s> ATA-%d disk at ata%d-%s\n", AD_PARAM->model, AD_PARAM->revision, - ad_version(AD_PARAM->versmajor), + ad_version(AD_PARAM->version_major), device_get_unit(adp->controller->dev), (adp->unit == ATA_MASTER) ? "master" : "slave"); if (prepend) printf("%s", prepend); ata_printf(adp->controller, adp->unit, - "%luMB (%u sectors), %u C, %u H, %u S, %u B\n", + "%lluMB (%llu sectors), %llu C, %u H, %u S, %u B\n", adp->total_secs / ((1024L*1024L)/DEV_BSIZE), adp->total_secs, adp->total_secs / (adp->heads * adp->sectors), adp->heads, adp->sectors, DEV_BSIZE); if (prepend) printf("%s", prepend); ata_printf(adp->controller, adp->unit, "%d secs/int, %d depth queue, %s%s\n", adp->transfersize / DEV_BSIZE, adp->num_tags + 1, (adp->flags & AD_F_TAG_ENABLED) ? "tagged " : "", ata_mode2str(adp->controller->mode[ATA_DEV(adp->unit)])); if (prepend) printf("%s", prepend); ata_printf(adp->controller, adp->unit, "piomode=%d dmamode=%d udmamode=%d cblid=%d\n", ata_pmode(AD_PARAM), ata_wmode(AD_PARAM), - ata_umode(AD_PARAM), AD_PARAM->cblid); + ata_umode(AD_PARAM), AD_PARAM->hwres_cblid); } else ata_printf(adp->controller, adp->unit, - "%luMB <%.40s> [%d/%d/%d] at ata%d-%s %s%s\n", + "%lluMB <%.40s> [%lld/%d/%d] at ata%d-%s %s%s\n", adp->total_secs / ((1024L * 1024L) / DEV_BSIZE), AD_PARAM->model, adp->total_secs / (adp->heads*adp->sectors), adp->heads, adp->sectors, device_get_unit(adp->controller->dev), (adp->unit == ATA_MASTER) ? "master" : "slave", (adp->flags & AD_F_TAG_ENABLED) ? "tagged " : "", ata_mode2str(adp->controller->mode[ATA_DEV(adp->unit)])); } static int ad_version(u_int16_t version) { int bit; if (version == 0xffff) return 0; for (bit = 15; bit >= 0; bit--) if (version & (1< * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer, * without modification, immediately at the beginning of the file. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * $FreeBSD$ */ /* structure describing an ATA disk request */ struct ad_request { struct ad_softc *device; /* ptr to parent device */ u_int32_t blockaddr; /* block number */ u_int32_t bytecount; /* bytes to transfer */ u_int32_t donecount; /* bytes transferred */ u_int32_t currentsize; /* size of current transfer */ struct callout_handle timeout_handle; /* handle for untimeout */ int retries; /* retry count */ int flags; #define ADR_F_READ 0x0001 #define ADR_F_ERROR 0x0002 #define ADR_F_DMA_USED 0x0004 #define ADR_F_QUEUED 0x0008 #define ADR_F_FORCE_PIO 0x0010 #define ADR_F_FLUSHCACHE 0x0020 caddr_t data; /* pointer to data buf */ struct bio *bp; /* associated bio ptr */ u_int8_t tag; /* tag ID of this request */ int serv; /* request had service */ struct ata_dmaentry *dmatab; /* DMA transfer table */ TAILQ_ENTRY(ad_request) chain; /* list management */ }; /* structure describing an ATA disk */ struct ad_softc { struct ata_softc *controller; /* ptr to parent ctrl */ int unit; /* ATA_MASTER or ATA_SLAVE */ int lun; /* logical unit number */ - u_int32_t total_secs; /* total # of sectors (LBA) */ + u_int64_t total_secs; /* total # of sectors (LBA) */ u_int8_t heads; u_int8_t sectors; u_int32_t transfersize; /* size of each transfer */ int num_tags; /* number of tags supported */ int flags; /* drive flags */ #define AD_F_LABELLING 0x0001 #define AD_F_DETACHING 0x0002 -#define AD_F_LBA_ENABLED 0x0004 +#define AD_F_CHS_USED 0x0004 #define AD_F_32B_ENABLED 0x0008 #define AD_F_TAG_ENABLED 0x0010 #define AD_F_RAID_SUBDISK 0x0020 struct ad_request *tags[32]; /* tag array of requests */ int outstanding; /* tags not serviced yet */ struct bio_queue_head queue; /* head of request queue */ struct devstat stats; /* devstat entry */ struct disk disk; /* disklabel/slice stuff */ dev_t dev; /* device place holder */ }; void ad_attach(struct ata_softc *, int); void ad_detach(struct ad_softc *, int); void ad_start(struct ad_softc *); int ad_transfer(struct ad_request *); int ad_interrupt(struct ad_request *); int ad_service(struct ad_softc *, int); void ad_reinit(struct ad_softc *); void ad_print(struct ad_softc *, char *); Index: head/sys/dev/ata/ata-dma.c =================================================================== --- head/sys/dev/ata/ata-dma.c (revision 84583) +++ head/sys/dev/ata/ata-dma.c (revision 84584) @@ -1,1169 +1,1169 @@ /*- * Copyright (c) 1998,1999,2000,2001 Søren Schmidt * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer, * without modification, immediately at the beginning of the file. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * $FreeBSD$ */ #include "pci.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* prototypes */ static void cyrix_timing(struct ata_softc *, int, int); static void promise_timing(struct ata_softc *, int, int); static void hpt_timing(struct ata_softc *, int, int); /* misc defines */ #ifdef __alpha__ #undef vtophys #define vtophys(va) alpha_XXX_dmamap((vm_offset_t)va) #endif #define ATAPI_DEVICE(scp, device) \ ((device == ATA_MASTER && scp->devices & ATA_ATAPI_MASTER) || \ (device == ATA_SLAVE && scp->devices & ATA_ATAPI_SLAVE)) void * ata_dmaalloc(struct ata_softc *scp, int device) { void *dmatab; if ((dmatab = malloc(PAGE_SIZE, M_DEVBUF, M_NOWAIT))) { if (((uintptr_t)dmatab >> PAGE_SHIFT) ^ (((uintptr_t)dmatab + PAGE_SIZE - 1) >> PAGE_SHIFT)) { ata_printf(scp, device, "dmatab crosses page boundary, no DMA\n"); free(dmatab, M_DEVBUF); dmatab = NULL; } } return dmatab; } void ata_dmainit(struct ata_softc *scp, int device, int apiomode, int wdmamode, int udmamode) { device_t parent = device_get_parent(scp->dev); int devno = (scp->channel << 1) + ATA_DEV(device); int error; /* set our most pessimistic default mode */ scp->mode[ATA_DEV(device)] = ATA_PIO; if (!scp->r_bmio) return; /* if simplex controller, only allow DMA on primary channel */ if (scp->channel == 1) { ATA_OUTB(scp->r_bmio, ATA_BMSTAT_PORT, ATA_INB(scp->r_bmio, ATA_BMSTAT_PORT) & (ATA_BMSTAT_DMA_MASTER | ATA_BMSTAT_DMA_SLAVE)); if (ATA_INB(scp->r_bmio, ATA_BMSTAT_PORT) & ATA_BMSTAT_DMA_SIMPLEX) { ata_printf(scp, device, "simplex device, DMA on primary only\n"); return; } } /* DMA engine address alignment is usually 1 word (2 bytes) */ scp->alignment = 0x1; - if (udmamode > 2 && !ATA_PARAM(scp, device)->cblid) { + if (udmamode > 2 && !ATA_PARAM(scp, device)->hwres_cblid) { ata_printf(scp, device, "DMA limited to UDMA33, non-ATA66 compliant cable\n"); udmamode = 2; } switch (scp->chiptype) { case 0x244a8086: /* Intel ICH2 mobile */ case 0x244b8086: /* Intel ICH2 */ if (udmamode >= 5) { int32_t mask48, new48; int16_t word54; word54 = pci_read_config(parent, 0x54, 2); if (word54 & (0x10 << devno)) { - error = ata_command(scp, device, ATA_C_SETFEATURES, 0, 0, 0, + error = ata_command(scp, device, ATA_C_SETFEATURES, 0, ATA_UDMA5, ATA_C_F_SETXFER,ATA_WAIT_READY); if (bootverbose) ata_printf(scp, device, "%s setting UDMA5 on Intel chip\n", (error) ? "failed" : "success"); if (!error) { mask48 = (1 << devno) + (3 << (16 + (devno << 2))); new48 = (1 << devno) + (1 << (16 + (devno << 2))); pci_write_config(parent, 0x48, (pci_read_config(parent, 0x48, 4) & ~mask48) | new48, 4); pci_write_config(parent, 0x54, word54 | (0x1000<mode[ATA_DEV(device)] = ATA_UDMA5; return; } } } /* make sure eventual ATA100 mode from the BIOS is disabled */ pci_write_config(parent, 0x54, pci_read_config(parent, 0x54, 2) & ~(0x1000<= 4) { int32_t mask48, new48; int16_t word54; word54 = pci_read_config(parent, 0x54, 2); if (word54 & (0x10 << devno)) { - error = ata_command(scp, device, ATA_C_SETFEATURES, 0, 0, 0, + error = ata_command(scp, device, ATA_C_SETFEATURES, 0, ATA_UDMA4, ATA_C_F_SETXFER,ATA_WAIT_READY); if (bootverbose) ata_printf(scp, device, "%s setting UDMA4 on Intel chip\n", (error) ? "failed" : "success"); if (!error) { mask48 = (1 << devno) + (3 << (16 + (devno << 2))); new48 = (1 << devno) + (2 << (16 + (devno << 2))); pci_write_config(parent, 0x48, (pci_read_config(parent, 0x48, 4) & ~mask48) | new48, 4); pci_write_config(parent, 0x54, word54 | (1 << devno), 2); scp->mode[ATA_DEV(device)] = ATA_UDMA4; return; } } } /* make sure eventual ATA66 mode from the BIOS is disabled */ pci_write_config(parent, 0x54, pci_read_config(parent, 0x54, 2) & ~(1 << devno), 2); /* FALLTHROUGH */ case 0x71118086: /* Intel PIIX4 */ case 0x71998086: /* Intel PIIX4e */ case 0x24218086: /* Intel ICH0 */ if (udmamode >= 2) { int32_t mask48, new48; - error = ata_command(scp, device, ATA_C_SETFEATURES, 0, 0, 0, + error = ata_command(scp, device, ATA_C_SETFEATURES, 0, ATA_UDMA2, ATA_C_F_SETXFER, ATA_WAIT_READY); if (bootverbose) ata_printf(scp, device, "%s setting UDMA2 on Intel chip\n", (error) ? "failed" : "success"); if (!error) { mask48 = (1 << devno) + (3 << (16 + (devno << 2))); new48 = (1 << devno) + (2 << (16 + (devno << 2))); pci_write_config(parent, 0x48, (pci_read_config(parent, 0x48, 4) & ~mask48) | new48, 4); scp->mode[ATA_DEV(device)] = ATA_UDMA2; return; } } /* make sure eventual ATA33 mode from the BIOS is disabled */ pci_write_config(parent, 0x48, pci_read_config(parent, 0x48, 4) & ~(1 << devno), 4); /* FALLTHROUGH */ case 0x70108086: /* Intel PIIX3 */ if (wdmamode >= 2 && apiomode >= 4) { int32_t mask40, new40, mask44, new44; /* if SITRE not set doit for both channels */ if (!((pci_read_config(parent,0x40,4)>>(scp->channel<<8))&0x4000)) { new40 = pci_read_config(parent, 0x40, 4); new44 = pci_read_config(parent, 0x44, 4); if (!(new40 & 0x00004000)) { new44 &= ~0x0000000f; new44 |= ((new40&0x00003000)>>10)|((new40&0x00000300)>>8); } if (!(new40 & 0x40000000)) { new44 &= ~0x000000f0; new44 |= ((new40&0x30000000)>>22)|((new40&0x03000000)>>20); } new40 |= 0x40004000; pci_write_config(parent, 0x40, new40, 4); pci_write_config(parent, 0x44, new44, 4); } - error = ata_command(scp, device, ATA_C_SETFEATURES, 0, 0, 0, + error = ata_command(scp, device, ATA_C_SETFEATURES, 0, ATA_WDMA2, ATA_C_F_SETXFER, ATA_WAIT_READY); if (bootverbose) ata_printf(scp, device, "%s setting WDMA2 on Intel chip\n", (error) ? "failed" : "success"); if (!error) { if (device == ATA_MASTER) { mask40 = 0x0000330f; new40 = 0x00002307; mask44 = 0; new44 = 0; } else { mask40 = 0x000000f0; new40 = 0x00000070; mask44 = 0x0000000f; new44 = 0x0000000b; } if (scp->channel) { mask40 <<= 16; new40 <<= 16; mask44 <<= 4; new44 <<= 4; } pci_write_config(parent, 0x40, (pci_read_config(parent, 0x40, 4) & ~mask40)| new40, 4); pci_write_config(parent, 0x44, (pci_read_config(parent, 0x44, 4) & ~mask44)| new44, 4); scp->mode[ATA_DEV(device)] = ATA_WDMA2; return; } } /* we could set PIO mode timings, but we assume the BIOS did that */ break; case 0x12308086: /* Intel PIIX */ if (wdmamode >= 2 && apiomode >= 4) { int32_t word40; word40 = pci_read_config(parent, 0x40, 4); word40 >>= scp->channel * 16; /* Check for timing config usable for DMA on controller */ if (!((word40 & 0x3300) == 0x2300 && ((word40 >> (device == ATA_MASTER ? 0 : 4)) & 1) == 1)) break; - error = ata_command(scp, device, ATA_C_SETFEATURES, 0, 0, 0, + error = ata_command(scp, device, ATA_C_SETFEATURES, 0, ATA_WDMA2, ATA_C_F_SETXFER, ATA_WAIT_READY); if (bootverbose) ata_printf(scp, device, "%s setting WDMA2 on Intel chip\n", (error) ? "failed" : "success"); if (!error) { scp->mode[ATA_DEV(device)] = ATA_WDMA2; return; } } break; case 0x522910b9: /* AcerLabs Aladdin IV/V */ /* the older Aladdin doesn't support ATAPI DMA on both master & slave */ if (pci_get_revid(parent) < 0xC2 && scp->devices & ATA_ATAPI_MASTER && scp->devices & ATA_ATAPI_SLAVE) { ata_printf(scp, device, "Aladdin: two atapi devices on this channel, no DMA\n"); break; } if (udmamode >= 5 && pci_get_revid(parent) >= 0xC4) { - error = ata_command(scp, device, ATA_C_SETFEATURES, 0, 0, 0, + error = ata_command(scp, device, ATA_C_SETFEATURES, 0, ATA_UDMA5, ATA_C_F_SETXFER, ATA_WAIT_READY); if (bootverbose) ata_printf(scp, device, "%s setting UDMA5 on Acer chip\n", (error) ? "failed" : "success"); if (!error) { int32_t word54 = pci_read_config(parent, 0x54, 4); pci_write_config(parent, 0x4b, pci_read_config(parent, 0x4b, 1) | 0x01, 1); word54 &= ~(0x000f000f << (devno << 2)); word54 |= (0x000f0005 << (devno << 2)); pci_write_config(parent, 0x54, word54, 4); pci_write_config(parent, 0x53, pci_read_config(parent, 0x53, 1) | 0x03, 1); scp->mode[ATA_DEV(device)] = ATA_UDMA5; return; } } if (udmamode >= 4 && pci_get_revid(parent) >= 0xC2) { - error = ata_command(scp, device, ATA_C_SETFEATURES, 0, 0, 0, + error = ata_command(scp, device, ATA_C_SETFEATURES, 0, ATA_UDMA4, ATA_C_F_SETXFER, ATA_WAIT_READY); if (bootverbose) ata_printf(scp, device, "%s setting UDMA4 on Acer chip\n", (error) ? "failed" : "success"); if (!error) { int32_t word54 = pci_read_config(parent, 0x54, 4); pci_write_config(parent, 0x4b, pci_read_config(parent, 0x4b, 1) | 0x01, 1); word54 &= ~(0x000f000f << (devno << 2)); word54 |= (0x00080005 << (devno << 2)); pci_write_config(parent, 0x54, word54, 4); pci_write_config(parent, 0x53, pci_read_config(parent, 0x53, 1) | 0x03, 1); scp->mode[ATA_DEV(device)] = ATA_UDMA4; return; } } if (udmamode >= 2 && pci_get_revid(parent) >= 0x20) { - error = ata_command(scp, device, ATA_C_SETFEATURES, 0, 0, 0, + error = ata_command(scp, device, ATA_C_SETFEATURES, 0, ATA_UDMA2, ATA_C_F_SETXFER, ATA_WAIT_READY); if (bootverbose) ata_printf(scp, device, "%s setting UDMA2 on Acer chip\n", (error) ? "failed" : "success"); if (!error) { int32_t word54 = pci_read_config(parent, 0x54, 4); word54 &= ~(0x000f000f << (devno << 2)); word54 |= (0x000a0005 << (devno << 2)); pci_write_config(parent, 0x54, word54, 4); pci_write_config(parent, 0x53, pci_read_config(parent, 0x53, 1) | 0x03, 1); scp->flags |= ATA_ATAPI_DMA_RO; scp->mode[ATA_DEV(device)] = ATA_UDMA2; return; } } /* make sure eventual UDMA mode from the BIOS is disabled */ pci_write_config(parent, 0x56, pci_read_config(parent, 0x56, 2) & ~(0x0008 << (devno << 2)), 2); if (wdmamode >= 2 && apiomode >= 4) { - error = ata_command(scp, device, ATA_C_SETFEATURES, 0, 0, 0, + error = ata_command(scp, device, ATA_C_SETFEATURES, 0, ATA_WDMA2, ATA_C_F_SETXFER, ATA_WAIT_READY); if (bootverbose) ata_printf(scp, device, "%s setting WDMA2 on Acer chip\n", (error) ? "failed" : "success"); if (!error) { pci_write_config(parent, 0x53, pci_read_config(parent, 0x53, 1) | 0x03, 1); scp->flags |= ATA_ATAPI_DMA_RO; scp->mode[ATA_DEV(device)] = ATA_WDMA2; return; } } pci_write_config(parent, 0x53, (pci_read_config(parent, 0x53, 1) & ~0x01) | 0x02, 1); /* we could set PIO mode timings, but we assume the BIOS did that */ break; case 0x74111022: /* AMD 766 */ if (udmamode >= 5) { - error = ata_command(scp, device, ATA_C_SETFEATURES, 0, 0, 0, + error = ata_command(scp, device, ATA_C_SETFEATURES, 0, ATA_UDMA5, ATA_C_F_SETXFER, ATA_WAIT_READY); if (bootverbose) ata_printf(scp, device, "%s setting UDMA5 on AMD chip\n", (error) ? "failed" : "success"); if (!error) { pci_write_config(parent, 0x53 - devno, 0xc6, 1); scp->mode[ATA_DEV(device)] = ATA_UDMA5; return; } } /* FALLTHROUGH */ case 0x74091022: /* AMD 756 */ if (udmamode >= 4) { - error = ata_command(scp, device, ATA_C_SETFEATURES, 0, 0, 0, + error = ata_command(scp, device, ATA_C_SETFEATURES, 0, ATA_UDMA4, ATA_C_F_SETXFER, ATA_WAIT_READY); if (bootverbose) ata_printf(scp, device, "%s setting UDMA4 on AMD chip\n", (error) ? "failed" : "success"); if (!error) { pci_write_config(parent, 0x53 - devno, 0xc5, 1); scp->mode[ATA_DEV(device)] = ATA_UDMA4; return; } } goto via_82c586; case 0x05711106: /* VIA 82C571, 82C586, 82C596, 82C686 */ if (ata_find_dev(parent, 0x06861106, 0x40) || ata_find_dev(parent, 0x30741106, 0)) { /* 82C686b */ if (udmamode >= 5) { - error = ata_command(scp, device, ATA_C_SETFEATURES, 0, 0, 0, + error = ata_command(scp, device, ATA_C_SETFEATURES, 0, ATA_UDMA5, ATA_C_F_SETXFER, ATA_WAIT_READY); if (bootverbose) ata_printf(scp, device, "%s setting UDMA5 on VIA chip\n", (error) ? "failed" : "success"); if (!error) { pci_write_config(parent, 0x53 - devno, 0xf0, 1); scp->mode[ATA_DEV(device)] = ATA_UDMA5; return; } } if (udmamode >= 4) { - error = ata_command(scp, device, ATA_C_SETFEATURES, 0, 0, 0, + error = ata_command(scp, device, ATA_C_SETFEATURES, 0, ATA_UDMA4, ATA_C_F_SETXFER, ATA_WAIT_READY); if (bootverbose) ata_printf(scp, device, "%s setting UDMA4 on VIA chip\n", (error) ? "failed" : "success"); if (!error) { pci_write_config(parent, 0x53 - devno, 0xf1, 1); scp->mode[ATA_DEV(device)] = ATA_UDMA4; return; } } if (udmamode >= 2) { - error = ata_command(scp, device, ATA_C_SETFEATURES, 0, 0, 0, + error = ata_command(scp, device, ATA_C_SETFEATURES, 0, ATA_UDMA2, ATA_C_F_SETXFER, ATA_WAIT_READY); if (bootverbose) ata_printf(scp, device, "%s setting UDMA2 on VIA chip\n", (error) ? "failed" : "success"); if (!error) { pci_write_config(parent, 0x53 - devno, 0xf4, 1); scp->mode[ATA_DEV(device)] = ATA_UDMA2; return; } } } else if (ata_find_dev(parent, 0x06861106, 0) || /* 82C686a */ ata_find_dev(parent, 0x05961106, 0x12)) { /* 82C596b */ if (udmamode >= 4) { - error = ata_command(scp, device, ATA_C_SETFEATURES, 0, 0, 0, + error = ata_command(scp, device, ATA_C_SETFEATURES, 0, ATA_UDMA4, ATA_C_F_SETXFER, ATA_WAIT_READY); if (bootverbose) ata_printf(scp, device, "%s setting UDMA4 on VIA chip\n", (error) ? "failed" : "success"); if (!error) { pci_write_config(parent, 0x53 - devno, 0xe8, 1); scp->mode[ATA_DEV(device)] = ATA_UDMA4; return; } } if (udmamode >= 2) { - error = ata_command(scp, device, ATA_C_SETFEATURES, 0, 0, 0, + error = ata_command(scp, device, ATA_C_SETFEATURES, 0, ATA_UDMA2, ATA_C_F_SETXFER, ATA_WAIT_READY); if (bootverbose) ata_printf(scp, device, "%s setting UDMA2 on VIA chip\n", (error) ? "failed" : "success"); if (!error) { pci_write_config(parent, 0x53 - devno, 0xea, 1); scp->mode[ATA_DEV(device)] = ATA_UDMA2; return; } } } else if (ata_find_dev(parent, 0x05961106, 0) || /* 82C596a */ ata_find_dev(parent, 0x05861106, 0x03)) { /* 82C586b */ via_82c586: if (udmamode >= 2) { - error = ata_command(scp, device, ATA_C_SETFEATURES, 0, 0, 0, + error = ata_command(scp, device, ATA_C_SETFEATURES, 0, ATA_UDMA2, ATA_C_F_SETXFER, ATA_WAIT_READY); if (bootverbose) ata_printf(scp, device, "%s setting UDMA2 on %s chip\n", (error) ? "failed" : "success", ((scp->chiptype == 0x74091022) || (scp->chiptype == 0x74111022)) ? "AMD" : "VIA"); if (!error) { pci_write_config(parent, 0x53 - devno, 0xc0, 1); scp->mode[ATA_DEV(device)] = ATA_UDMA2; return; } } } if (wdmamode >= 2 && apiomode >= 4) { - error = ata_command(scp, device, ATA_C_SETFEATURES, 0, 0, 0, + error = ata_command(scp, device, ATA_C_SETFEATURES, 0, ATA_WDMA2, ATA_C_F_SETXFER, ATA_WAIT_READY); if (bootverbose) ata_printf(scp, device, "%s setting WDMA2 on %s chip\n", (error) ? "failed" : "success", (scp->chiptype == 0x74091022) ? "AMD" : "VIA"); if (!error) { pci_write_config(parent, 0x53 - devno, 0x0b, 1); pci_write_config(parent, 0x4b - devno, 0x31, 1); scp->mode[ATA_DEV(device)] = ATA_WDMA2; return; } } /* we could set PIO mode timings, but we assume the BIOS did that */ break; case 0x55131039: /* SiS 5591 */ if (udmamode >= 2 && pci_get_revid(parent) > 0xc1) { - error = ata_command(scp, device, ATA_C_SETFEATURES, 0, 0, 0, + error = ata_command(scp, device, ATA_C_SETFEATURES, 0, ATA_UDMA2, ATA_C_F_SETXFER, ATA_WAIT_READY); if (bootverbose) ata_printf(scp, device, "%s setting UDMA2 on SiS chip\n", (error) ? "failed" : "success"); if (!error) { pci_write_config(parent, 0x40 + (devno << 1), 0xa301, 2); scp->mode[ATA_DEV(device)] = ATA_UDMA2; return; } } if (wdmamode >=2 && apiomode >= 4) { - error = ata_command(scp, device, ATA_C_SETFEATURES, 0, 0, 0, + error = ata_command(scp, device, ATA_C_SETFEATURES, 0, ATA_WDMA2, ATA_C_F_SETXFER, ATA_WAIT_READY); if (bootverbose) ata_printf(scp, device, "%s setting WDMA2 on SiS chip\n", (error) ? "failed" : "success"); if (!error) { pci_write_config(parent, 0x40 + (devno << 1), 0x0301, 2); scp->mode[ATA_DEV(device)] = ATA_WDMA2; return; } } /* we could set PIO mode timings, but we assume the BIOS did that */ break; case 0x06491095: /* CMD 649 ATA100 controller */ if (udmamode >= 5) { u_int8_t umode; - error = ata_command(scp, device, ATA_C_SETFEATURES, 0, 0, 0, + error = ata_command(scp, device, ATA_C_SETFEATURES, 0, ATA_UDMA5, ATA_C_F_SETXFER, ATA_WAIT_READY); if (bootverbose) ata_printf(scp, device, "%s setting UDMA5 on CMD chip\n", (error) ? "failed" : "success"); if (!error) { umode = pci_read_config(parent, scp->channel ? 0x7b : 0x73, 1); umode &= ~(device == ATA_MASTER ? 0x35 : 0xca); umode |= (device == ATA_MASTER ? 0x05 : 0x0a); pci_write_config(parent, scp->channel ? 0x7b : 0x73, umode, 1); scp->mode[ATA_DEV(device)] = ATA_UDMA5; return; } } /* FALLTHROUGH */ case 0x06481095: /* CMD 648 ATA66 controller */ if (udmamode >= 4) { u_int8_t umode; - error = ata_command(scp, device, ATA_C_SETFEATURES, 0, 0, 0, + error = ata_command(scp, device, ATA_C_SETFEATURES, 0, ATA_UDMA4, ATA_C_F_SETXFER, ATA_WAIT_READY); if (bootverbose) ata_printf(scp, device, "%s setting UDMA4 on CMD chip\n", (error) ? "failed" : "success"); if (!error) { umode = pci_read_config(parent, scp->channel ? 0x7b : 0x73, 1); umode &= ~(device == ATA_MASTER ? 0x35 : 0xca); umode |= (device == ATA_MASTER ? 0x15 : 0x4a); pci_write_config(parent, scp->channel ? 0x7b : 0x73, umode, 1); scp->mode[ATA_DEV(device)] = ATA_UDMA4; return; } } if (udmamode >= 2) { u_int8_t umode; - error = ata_command(scp, device, ATA_C_SETFEATURES, 0, 0, 0, + error = ata_command(scp, device, ATA_C_SETFEATURES, 0, ATA_UDMA2, ATA_C_F_SETXFER, ATA_WAIT_READY); if (bootverbose) ata_printf(scp, device, "%s setting UDMA2 on CMD chip\n", (error) ? "failed" : "success"); if (!error) { umode = pci_read_config(parent, scp->channel ? 0x7b : 0x73, 1); umode &= ~(device == ATA_MASTER ? 0x35 : 0xca); umode |= (device == ATA_MASTER ? 0x11 : 0x42); pci_write_config(parent, scp->channel ? 0x7b : 0x73, umode, 1); scp->mode[ATA_DEV(device)] = ATA_UDMA2; return; } } /* make sure eventual UDMA mode from the BIOS is disabled */ pci_write_config(parent, scp->channel ? 0x7b : 0x73, pci_read_config(parent, scp->channel ? 0x7b : 0x73, 1)& ~(device == ATA_MASTER ? 0x35 : 0xca), 1); /* FALLTHROUGH */ case 0x06461095: /* CMD 646 ATA controller */ if (wdmamode >= 2 && apiomode >= 4) { - error = ata_command(scp, device, ATA_C_SETFEATURES, 0, 0, 0, + error = ata_command(scp, device, ATA_C_SETFEATURES, 0, ATA_WDMA2, ATA_C_F_SETXFER, ATA_WAIT_READY); if (bootverbose) ata_printf(scp, device, "%s setting WDMA2 on CMD chip\n", error ? "failed" : "success"); if (!error) { int32_t offset = (devno < 3) ? (devno << 1) : 7; pci_write_config(parent, 0x54 + offset, 0x3f, 1); scp->mode[ATA_DEV(device)] = ATA_WDMA2; return; } } /* we could set PIO mode timings, but we assume the BIOS did that */ break; case 0xc6931080: /* Cypress 82c693 ATA controller */ if (wdmamode >= 2 && apiomode >= 4) { - error = ata_command(scp, device, ATA_C_SETFEATURES, 0, 0, 0, + error = ata_command(scp, device, ATA_C_SETFEATURES, 0, ATA_WDMA2, ATA_C_F_SETXFER, ATA_WAIT_READY); if (bootverbose) ata_printf(scp, device, "%s setting WDMA2 on Cypress chip\n", error ? "failed" : "success"); if (!error) { pci_write_config(scp->dev, scp->channel ? 0x4e:0x4c, 0x2020, 2); scp->mode[ATA_DEV(device)] = ATA_WDMA2; return; } } /* we could set PIO mode timings, but we assume the BIOS did that */ break; case 0x01021078: /* Cyrix 5530 ATA33 controller */ scp->alignment = 0xf; /* DMA engine requires 16 byte alignment */ if (udmamode >= 2) { - error = ata_command(scp, device, ATA_C_SETFEATURES, 0, 0, 0, + error = ata_command(scp, device, ATA_C_SETFEATURES, 0, ATA_UDMA2, ATA_C_F_SETXFER, ATA_WAIT_READY); if (bootverbose) ata_printf(scp, device, "%s setting UDMA2 on Cyrix chip\n", (error) ? "failed" : "success"); if (!error) { cyrix_timing(scp, devno, ATA_UDMA2); scp->mode[ATA_DEV(device)] = ATA_UDMA2; return; } } if (wdmamode >= 2 && apiomode >= 4) { - error = ata_command(scp, device, ATA_C_SETFEATURES, 0, 0, 0, + error = ata_command(scp, device, ATA_C_SETFEATURES, 0, ATA_WDMA2, ATA_C_F_SETXFER, ATA_WAIT_READY); if (bootverbose) ata_printf(scp, device, "%s setting WDMA2 on Cyrix chip\n", (error) ? "failed" : "success"); if (!error) { cyrix_timing(scp, devno, ATA_WDMA2); scp->mode[ATA_DEV(device)] = ATA_WDMA2; return; } } - error = ata_command(scp, device, ATA_C_SETFEATURES, 0, 0, 0, - ata_pio2mode(apiomode), ATA_C_F_SETXFER, + error = ata_command(scp, device, ATA_C_SETFEATURES, 0, + ATA_PIO0 + apiomode, ATA_C_F_SETXFER, ATA_WAIT_READY); if (bootverbose) ata_printf(scp, device, "%s setting %s on Cyrix chip\n", (error) ? "failed" : "success", - ata_mode2str(ata_pio2mode(apiomode))); - cyrix_timing(scp, devno, ata_pio2mode(apiomode)); - scp->mode[ATA_DEV(device)] = ata_pio2mode(apiomode); + ata_mode2str(ATA_PIO0 + apiomode)); + cyrix_timing(scp, devno, ATA_PIO0 + apiomode); + scp->mode[ATA_DEV(device)] = ATA_PIO0 + apiomode; return; case 0x02111166: /* ServerWorks ROSB4 ATA33 controller */ if (udmamode >= 2) { - error = ata_command(scp, device, ATA_C_SETFEATURES, 0, 0, 0, + error = ata_command(scp, device, ATA_C_SETFEATURES, 0, ATA_UDMA2, ATA_C_F_SETXFER, ATA_WAIT_READY); if (bootverbose) ata_printf(scp, device, "%s setting UDMA2 on ServerWorks chip\n", (error) ? "failed" : "success"); if (!error) { u_int16_t reg56; pci_write_config(parent, 0x54, pci_read_config(parent, 0x54, 1) | (0x01 << devno), 1); reg56 = pci_read_config(parent, 0x56, 2); reg56 &= ~(0xf << (devno * 4)); reg56 |= (0x2 << (devno * 4)); pci_write_config(parent, 0x56, reg56, 2); scp->mode[ATA_DEV(device)] = ATA_UDMA2; return; } } if (wdmamode >= 2 && apiomode >= 4) { - error = ata_command(scp, device, ATA_C_SETFEATURES, 0, 0, 0, + error = ata_command(scp, device, ATA_C_SETFEATURES, 0, ATA_WDMA2, ATA_C_F_SETXFER, ATA_WAIT_READY); if (bootverbose) ata_printf(scp, device, "%s setting WDMA2 on ServerWorks chip\n", (error) ? "failed" : "success"); if (!error) { int offset = (scp->channel * 2) + (device == ATA_MASTER); int word44 = pci_read_config(parent, 0x44, 4); pci_write_config(parent, 0x54, pci_read_config(parent, 0x54, 1) & ~(0x01 << devno), 1); word44 &= ~(0xff << (offset << 8)); word44 |= (0x20 << (offset << 8)); pci_write_config(parent, 0x44, 0x20, 4); scp->mode[ATA_DEV(device)] = ATA_WDMA2; return; } } /* we could set PIO mode timings, but we assume the BIOS did that */ break; case 0x4d68105a: /* Promise TX2 ATA100 controllers */ case 0x6268105a: /* Promise TX2v2 ATA100 controllers */ ATA_OUTB(scp->r_bmio, ATA_BMDEVSPEC_0, 0x0b); if (udmamode >= 4 && !(ATA_INB(scp->r_bmio, ATA_BMDEVSPEC_1) & 0x04)) { - error = ata_command(scp, device, ATA_C_SETFEATURES, 0, 0, 0, + error = ata_command(scp, device, ATA_C_SETFEATURES, 0, ATA_UDMA + max(udmamode, 5), ATA_C_F_SETXFER, ATA_WAIT_READY); if (bootverbose) ata_printf(scp, device, "%s setting %s on Promise chip\n", (error) ? "failed" : "success", ata_mode2str(ATA_UDMA + max(udmamode, 5))); if (!error) { scp->mode[ATA_DEV(device)] = ATA_UDMA + (max(udmamode, 5)); return; } } if (udmamode >= 2) { - error = ata_command(scp, device, ATA_C_SETFEATURES, 0, 0, 0, + error = ata_command(scp, device, ATA_C_SETFEATURES, 0, ATA_UDMA2, ATA_C_F_SETXFER, ATA_WAIT_READY); if (bootverbose) ata_printf(scp, device, "%s setting %s on Promise chip\n", (error) ? "failed" : "success", "UDMA2"); if (!error) { scp->mode[ATA_DEV(device)] = ATA_UDMA2; return; } } if (wdmamode >= 2 && apiomode >= 4) { - error = ata_command(scp, device, ATA_C_SETFEATURES, 0, 0, 0, + error = ata_command(scp, device, ATA_C_SETFEATURES, 0, ATA_WDMA2, ATA_C_F_SETXFER, ATA_WAIT_READY); if (bootverbose) ata_printf(scp, device, "%s setting %s on Promise chip\n", (error) ? "failed" : "success", "WDMA2"); if (!error) { scp->mode[ATA_DEV(device)] = ATA_WDMA2; return; } } break; case 0x4d30105a: /* Promise Ultra/FastTrak 100 controllers */ case 0x0d30105a: /* Promise OEM ATA100 controllers */ if (!ATAPI_DEVICE(scp, device) && udmamode >= 5 && !(pci_read_config(parent, 0x50, 2)&(scp->channel ? 1<<11 : 1<<10))){ - error = ata_command(scp, device, ATA_C_SETFEATURES, 0, 0, 0, + error = ata_command(scp, device, ATA_C_SETFEATURES, 0, ATA_UDMA5, ATA_C_F_SETXFER, ATA_WAIT_READY); if (bootverbose) ata_printf(scp, device, "%s setting UDMA5 on Promise chip\n", (error) ? "failed" : "success"); if (!error) { promise_timing(scp, devno, ATA_UDMA5); scp->mode[ATA_DEV(device)] = ATA_UDMA5; return; } } /* FALLTHROUGH */ case 0x4d38105a: /* Promise Ultra/FastTrak 66 controllers */ if (!ATAPI_DEVICE(scp, device) && udmamode >= 4 && !(pci_read_config(parent, 0x50, 2)&(scp->channel ? 1<<11 : 1<<10))){ - error = ata_command(scp, device, ATA_C_SETFEATURES, 0, 0, 0, + error = ata_command(scp, device, ATA_C_SETFEATURES, 0, ATA_UDMA4, ATA_C_F_SETXFER, ATA_WAIT_READY); if (bootverbose) ata_printf(scp, device, "%s setting UDMA4 on Promise chip\n", (error) ? "failed" : "success"); if (!error) { promise_timing(scp, devno, ATA_UDMA4); scp->mode[ATA_DEV(device)] = ATA_UDMA4; return; } } /* FALLTHROUGH */ case 0x4d33105a: /* Promise Ultra/FastTrak 33 controllers */ if (!ATAPI_DEVICE(scp, device) && udmamode >= 2) { - error = ata_command(scp, device, ATA_C_SETFEATURES, 0, 0, 0, + error = ata_command(scp, device, ATA_C_SETFEATURES, 0, ATA_UDMA2, ATA_C_F_SETXFER, ATA_WAIT_READY); if (bootverbose) ata_printf(scp, device, "%s setting UDMA2 on Promise chip\n", (error) ? "failed" : "success"); if (!error) { promise_timing(scp, devno, ATA_UDMA2); scp->mode[ATA_DEV(device)] = ATA_UDMA2; return; } } if (!ATAPI_DEVICE(scp, device) && wdmamode >= 2 && apiomode >= 4) { - error = ata_command(scp, device, ATA_C_SETFEATURES, 0, 0, 0, + error = ata_command(scp, device, ATA_C_SETFEATURES, 0, ATA_WDMA2, ATA_C_F_SETXFER, ATA_WAIT_READY); if (bootverbose) ata_printf(scp, device, "%s setting WDMA2 on Promise chip\n", (error) ? "failed" : "success"); if (!error) { promise_timing(scp, devno, ATA_WDMA2); scp->mode[ATA_DEV(device)] = ATA_WDMA2; return; } } - error = ata_command(scp, device, ATA_C_SETFEATURES, 0, 0, 0, - ata_pio2mode(apiomode), + error = ata_command(scp, device, ATA_C_SETFEATURES, 0, + ATA_PIO0 + apiomode, ATA_C_F_SETXFER, ATA_WAIT_READY); if (bootverbose) ata_printf(scp, device, "%s setting PIO%d on Promise chip\n", (error) ? "failed" : "success", (apiomode >= 0) ? apiomode : 0); - promise_timing(scp, devno, ata_pio2mode(apiomode)); - scp->mode[ATA_DEV(device)] = ata_pio2mode(apiomode); + promise_timing(scp, devno, ATA_PIO0 + apiomode); + scp->mode[ATA_DEV(device)] = ATA_PIO0 + apiomode; return; case 0x00041103: /* HighPoint HPT366/368/370 controllers */ if (!ATAPI_DEVICE(scp, device) && udmamode >=5 && pci_get_revid(parent) >= 0x03 && !(pci_read_config(parent, 0x5a, 1) & (scp->channel ? 0x01:0x02))) { - error = ata_command(scp, device, ATA_C_SETFEATURES, 0, 0, 0, + error = ata_command(scp, device, ATA_C_SETFEATURES, 0, ATA_UDMA5, ATA_C_F_SETXFER, ATA_WAIT_READY); if (bootverbose) ata_printf(scp, device, "%s setting UDMA5 on HighPoint chip\n", (error) ? "failed" : "success"); if (!error) { hpt_timing(scp, devno, ATA_UDMA5); scp->mode[ATA_DEV(device)] = ATA_UDMA5; return; } } if (!ATAPI_DEVICE(scp, device) && udmamode >=4 && !(pci_read_config(parent, 0x5a, 1) & (scp->channel ? 0x01:0x02))) { - error = ata_command(scp, device, ATA_C_SETFEATURES, 0, 0, 0, + error = ata_command(scp, device, ATA_C_SETFEATURES, 0, ATA_UDMA4, ATA_C_F_SETXFER, ATA_WAIT_READY); if (bootverbose) ata_printf(scp, device, "%s setting UDMA4 on HighPoint chip\n", (error) ? "failed" : "success"); if (!error) { hpt_timing(scp, devno, ATA_UDMA4); scp->mode[ATA_DEV(device)] = ATA_UDMA4; return; } } if (!ATAPI_DEVICE(scp, device) && udmamode >= 2) { - error = ata_command(scp, device, ATA_C_SETFEATURES, 0, 0, 0, + error = ata_command(scp, device, ATA_C_SETFEATURES, 0, ATA_UDMA2, ATA_C_F_SETXFER, ATA_WAIT_READY); if (bootverbose) ata_printf(scp, device, "%s setting UDMA2 on HighPoint chip\n", (error) ? "failed" : "success"); if (!error) { hpt_timing(scp, devno, ATA_UDMA2); scp->mode[ATA_DEV(device)] = ATA_UDMA2; return; } } if (!ATAPI_DEVICE(scp, device) && wdmamode >= 2 && apiomode >= 4) { - error = ata_command(scp, device, ATA_C_SETFEATURES, 0, 0, 0, + error = ata_command(scp, device, ATA_C_SETFEATURES, 0, ATA_WDMA2, ATA_C_F_SETXFER, ATA_WAIT_READY); if (bootverbose) ata_printf(scp, device, "%s setting WDMA2 on HighPoint chip\n", (error) ? "failed" : "success"); if (!error) { hpt_timing(scp, devno, ATA_WDMA2); scp->mode[ATA_DEV(device)] = ATA_WDMA2; return; } } - error = ata_command(scp, device, ATA_C_SETFEATURES, 0, 0, 0, - ata_pio2mode(apiomode), + error = ata_command(scp, device, ATA_C_SETFEATURES, 0, + ATA_PIO0 + apiomode, ATA_C_F_SETXFER, ATA_WAIT_READY); if (bootverbose) ata_printf(scp, device, "%s setting PIO%d on HighPoint chip\n", (error) ? "failed" : "success", (apiomode >= 0) ? apiomode : 0); - hpt_timing(scp, devno, ata_pio2mode(apiomode)); - scp->mode[ATA_DEV(device)] = ata_pio2mode(apiomode); + hpt_timing(scp, devno, ATA_PIO0 + apiomode); + scp->mode[ATA_DEV(device)] = ATA_PIO0 + apiomode; return; default: /* unknown controller chip */ /* better not try generic DMA on ATAPI devices it almost never works */ if ((device == ATA_MASTER && scp->devices & ATA_ATAPI_MASTER) || (device == ATA_SLAVE && scp->devices & ATA_ATAPI_SLAVE)) break; /* if controller says its setup for DMA take the easy way out */ /* the downside is we dont know what DMA mode we are in */ if ((udmamode >= 0 || wdmamode > 1) && (ATA_INB(scp->r_bmio, ATA_BMSTAT_PORT) & ((device==ATA_MASTER) ? ATA_BMSTAT_DMA_MASTER : ATA_BMSTAT_DMA_SLAVE))) { scp->mode[ATA_DEV(device)] = ATA_DMA; return; } /* well, we have no support for this, but try anyways */ if ((wdmamode >= 2 && apiomode >= 4) && scp->r_bmio) { - error = ata_command(scp, device, ATA_C_SETFEATURES, 0, 0, 0, + error = ata_command(scp, device, ATA_C_SETFEATURES, 0, ATA_WDMA2, ATA_C_F_SETXFER, ATA_WAIT_READY); if (bootverbose) ata_printf(scp, device, "%s setting WDMA2 on generic chip\n", (error) ? "failed" : "success"); if (!error) { scp->mode[ATA_DEV(device)] = ATA_WDMA2; return; } } } - error = ata_command(scp, device, ATA_C_SETFEATURES, 0, 0, 0, - ata_pio2mode(apiomode), ATA_C_F_SETXFER,ATA_WAIT_READY); + error = ata_command(scp, device, ATA_C_SETFEATURES, 0, ATA_PIO0 + apiomode, + ATA_C_F_SETXFER,ATA_WAIT_READY); if (bootverbose) ata_printf(scp, device, "%s setting PIO%d on generic chip\n", (error) ? "failed" : "success", apiomode < 0 ? 0 : apiomode); if (!error) - scp->mode[ATA_DEV(device)] = ata_pio2mode(apiomode); + scp->mode[ATA_DEV(device)] = ATA_PIO0 + apiomode; else { if (bootverbose) ata_printf(scp, device, "using PIO mode set by BIOS\n"); scp->mode[ATA_DEV(device)] = ATA_PIO; } } int ata_dmasetup(struct ata_softc *scp, int device, struct ata_dmaentry *dmatab, caddr_t data, int32_t count) { u_int32_t dma_count, dma_base; int i = 0; if (((uintptr_t)data & scp->alignment) || (count & scp->alignment)) { ata_printf(scp, device, "non aligned DMA transfer attempted\n"); return -1; } if (!count) { ata_printf(scp, device, "zero length DMA transfer attempted\n"); return -1; } dma_base = vtophys(data); dma_count = min(count, (PAGE_SIZE - ((uintptr_t)data & PAGE_MASK))); data += dma_count; count -= dma_count; while (count) { dmatab[i].base = dma_base; dmatab[i].count = (dma_count & 0xffff); i++; if (i >= ATA_DMA_ENTRIES) { ata_printf(scp, device, "too many segments in DMA table\n"); return -1; } dma_base = vtophys(data); dma_count = min(count, PAGE_SIZE); data += min(count, PAGE_SIZE); count -= min(count, PAGE_SIZE); } dmatab[i].base = dma_base; dmatab[i].count = (dma_count & 0xffff) | ATA_DMA_EOT; return 0; } void ata_dmastart(struct ata_softc *scp, int device, struct ata_dmaentry *dmatab, int dir) { scp->flags |= ATA_DMA_ACTIVE; ATA_OUTL(scp->r_bmio, ATA_BMDTP_PORT, vtophys(dmatab)); ATA_OUTB(scp->r_bmio, ATA_BMCMD_PORT, dir ? ATA_BMCMD_WRITE_READ : 0); ATA_OUTB(scp->r_bmio, ATA_BMSTAT_PORT, (ATA_INB(scp->r_bmio, ATA_BMSTAT_PORT) | (ATA_BMSTAT_INTERRUPT | ATA_BMSTAT_ERROR))); ATA_OUTB(scp->r_bmio, ATA_BMCMD_PORT, ATA_INB(scp->r_bmio, ATA_BMCMD_PORT) | ATA_BMCMD_START_STOP); } int ata_dmadone(struct ata_softc *scp) { int error; ATA_OUTB(scp->r_bmio, ATA_BMCMD_PORT, ATA_INB(scp->r_bmio, ATA_BMCMD_PORT) & ~ATA_BMCMD_START_STOP); scp->flags &= ~ATA_DMA_ACTIVE; error = ATA_INB(scp->r_bmio, ATA_BMSTAT_PORT); ATA_OUTB(scp->r_bmio, ATA_BMSTAT_PORT, error | ATA_BMSTAT_INTERRUPT | ATA_BMSTAT_ERROR); return error & ATA_BMSTAT_MASK; } int ata_dmastatus(struct ata_softc *scp) { return ATA_INB(scp->r_bmio, ATA_BMSTAT_PORT) & ATA_BMSTAT_MASK; } static void cyrix_timing(struct ata_softc *scp, int devno, int mode) { u_int32_t reg20 = 0x0000e132; u_int32_t reg24 = 0x00017771; switch (mode) { case ATA_PIO0: reg20 = 0x0000e132; break; case ATA_PIO1: reg20 = 0x00018121; break; case ATA_PIO2: reg20 = 0x00024020; break; case ATA_PIO3: reg20 = 0x00032010; break; case ATA_PIO4: reg20 = 0x00040010; break; case ATA_WDMA2: reg24 = 0x00002020; break; case ATA_UDMA2: reg24 = 0x00911030; break; } ATA_OUTL(scp->r_bmio, (devno << 3) + 0x20, reg20); ATA_OUTL(scp->r_bmio, (devno << 3) + 0x24, reg24); } static void promise_timing(struct ata_softc *scp, int devno, int mode) { u_int32_t timing = 0; struct promise_timing { u_int8_t pa:4; u_int8_t prefetch:1; u_int8_t iordy:1; u_int8_t errdy:1; u_int8_t syncin:1; u_int8_t pb:5; u_int8_t mb:3; u_int8_t mc:4; u_int8_t dmaw:1; u_int8_t dmar:1; u_int8_t iordyp:1; u_int8_t dmarqp:1; u_int8_t reserved:8; } *t = (struct promise_timing*)&timing; t->iordy = 1; t->iordyp = 1; if (mode >= ATA_DMA) { t->prefetch = 1; t->errdy = 1; t->syncin = 1; } switch (scp->chiptype) { case 0x4d33105a: /* Promise Ultra/Fasttrak 33 */ switch (mode) { default: case ATA_PIO0: t->pa = 9; t->pb = 19; t->mb = 7; t->mc = 15; break; case ATA_PIO1: t->pa = 5; t->pb = 12; t->mb = 7; t->mc = 15; break; case ATA_PIO2: t->pa = 3; t->pb = 8; t->mb = 7; t->mc = 15; break; case ATA_PIO3: t->pa = 2; t->pb = 6; t->mb = 7; t->mc = 15; break; case ATA_PIO4: t->pa = 1; t->pb = 4; t->mb = 7; t->mc = 15; break; case ATA_WDMA2: t->pa = 3; t->pb = 7; t->mb = 3; t->mc = 3; break; case ATA_UDMA2: t->pa = 3; t->pb = 7; t->mb = 1; t->mc = 1; break; } break; case 0x4d38105a: /* Promise Ultra/Fasttrak 66 */ case 0x4d30105a: /* Promise Ultra/Fasttrak 100 */ case 0x0d30105a: /* Promise OEM ATA 100 */ switch (mode) { default: case ATA_PIO0: t->pa = 15; t->pb = 31; t->mb = 7; t->mc = 15; break; case ATA_PIO1: t->pa = 10; t->pb = 24; t->mb = 7; t->mc = 15; break; case ATA_PIO2: t->pa = 6; t->pb = 16; t->mb = 7; t->mc = 15; break; case ATA_PIO3: t->pa = 4; t->pb = 12; t->mb = 7; t->mc = 15; break; case ATA_PIO4: t->pa = 2; t->pb = 8; t->mb = 7; t->mc = 15; break; case ATA_WDMA2: t->pa = 6; t->pb = 14; t->mb = 6; t->mc = 6; break; case ATA_UDMA2: t->pa = 6; t->pb = 14; t->mb = 2; t->mc = 2; break; case ATA_UDMA4: t->pa = 3; t->pb = 7; t->mb = 1; t->mc = 1; break; case ATA_UDMA5: t->pa = 3; t->pb = 7; t->mb = 1; t->mc = 1; break; } break; } pci_write_config(device_get_parent(scp->dev), 0x60 + (devno<<2), timing, 4); } static void hpt_timing(struct ata_softc *scp, int devno, int mode) { device_t parent = device_get_parent(scp->dev); u_int32_t timing; if (pci_get_revid(parent) >= 0x03) { /* HPT370 */ switch (mode) { case ATA_PIO0: timing = 0x06914e57; break; case ATA_PIO1: timing = 0x06914e43; break; case ATA_PIO2: timing = 0x06514e33; break; case ATA_PIO3: timing = 0x06514e22; break; case ATA_PIO4: timing = 0x06514e21; break; case ATA_WDMA2: timing = 0x26514e21; break; case ATA_UDMA2: timing = 0x16494e31; break; case ATA_UDMA4: timing = 0x16454e31; break; case ATA_UDMA5: timing = 0x16454e31; break; default: timing = 0x06514e57; } pci_write_config(parent, 0x40 + (devno << 2) , timing, 4); pci_write_config(parent, 0x5b, 0x22, 1); } else { /* HPT36[68] */ switch (pci_read_config(parent, 0x41 + (devno << 2), 1)) { case 0x85: /* 25Mhz */ switch (mode) { case ATA_PIO0: timing = 0xc0d08585; break; case ATA_PIO1: timing = 0xc0d08572; break; case ATA_PIO2: timing = 0xc0ca8542; break; case ATA_PIO3: timing = 0xc0ca8532; break; case ATA_PIO4: timing = 0xc0ca8521; break; case ATA_WDMA2: timing = 0xa0ca8521; break; case ATA_UDMA2: timing = 0x90cf8521; break; case ATA_UDMA4: timing = 0x90c98521; break; default: timing = 0x01208585; } break; default: case 0xa7: /* 33MHz */ switch (mode) { case ATA_PIO0: timing = 0xc0d0a7aa; break; case ATA_PIO1: timing = 0xc0d0a7a3; break; case ATA_PIO2: timing = 0xc0d0a753; break; case ATA_PIO3: timing = 0xc0c8a742; break; case ATA_PIO4: timing = 0xc0c8a731; break; case ATA_WDMA2: timing = 0xa0c8a731; break; case ATA_UDMA2: timing = 0x90caa731; break; case ATA_UDMA4: timing = 0x90c9a731; break; default: timing = 0x0120a7a7; } break; case 0xd9: /* 40Mhz */ switch (mode) { case ATA_PIO0: timing = 0xc018d9d9; break; case ATA_PIO1: timing = 0xc010d9c7; break; case ATA_PIO2: timing = 0xc010d997; break; case ATA_PIO3: timing = 0xc010d974; break; case ATA_PIO4: timing = 0xc008d963; break; case ATA_WDMA2: timing = 0xa008d943; break; case ATA_UDMA2: timing = 0x900bd943; break; case ATA_UDMA4: timing = 0x900fd943; break; default: timing = 0x0120d9d9; } } pci_write_config(parent, 0x40 + (devno << 2), (timing & ~0x80000000),4); } } Index: head/sys/dev/ata/ata-raid.c =================================================================== --- head/sys/dev/ata/ata-raid.c (revision 84583) +++ head/sys/dev/ata/ata-raid.c (revision 84584) @@ -1,566 +1,565 @@ /*- * Copyright (c) 2000,2001 Søren Schmidt * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer, * without modification, immediately at the beginning of the file. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * $FreeBSD$ */ #include "opt_global.h" #include "opt_ata.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* device structures */ static d_open_t aropen; static d_strategy_t arstrategy; static struct cdevsw ar_cdevsw = { /* open */ aropen, /* close */ nullclose, /* read */ physread, /* write */ physwrite, /* ioctl */ noioctl, /* poll */ nopoll, /* mmap */ nommap, /* strategy */ arstrategy, /* name */ "ar", /* maj */ 157, /* dump */ nodump, /* psize */ nopsize, /* flags */ D_DISK, }; static struct cdevsw ardisk_cdevsw; /* prototypes */ static void ar_attach(struct ar_softc *); static void ar_done(struct bio *); static int ar_highpoint_conf(struct ad_softc *, struct ar_softc **); static int ar_promise_conf(struct ad_softc *, struct ar_softc **); static int ar_read(struct ad_softc *, u_int32_t, int, char *); /* internal vars */ static int ar_init = 0; static struct ar_softc *ar_table[16]; static MALLOC_DEFINE(M_AR, "AR driver", "ATA RAID driver"); int ar_probe(struct ad_softc *adp) { if (!ar_init) { bzero(&ar_table, sizeof(ar_table)); ar_init = 1; } switch(adp->controller->chiptype) { case 0x4d33105a: case 0x4d38105a: case 0x4d30105a: case 0x0d30105a: case 0x4d68105a: case 0x6268105a: return (ar_promise_conf(adp, ar_table)); case 0x00041103: return (ar_highpoint_conf(adp, ar_table)); } return 1; } static void ar_attach(struct ar_softc *raid) { dev_t dev; int i; printf("ar%d: %luMB lun, raid->total_secs / ((1024L * 1024L) / DEV_BSIZE)); switch (raid->flags & (AR_F_RAID_0 | AR_F_RAID_1 | AR_F_SPAN)) { case AR_F_RAID_0: printf("RAID0 "); break; case AR_F_RAID_1: printf("RAID1 "); break; case AR_F_SPAN: printf("SPAN "); break; case (AR_F_RAID_0 | AR_F_RAID_1): printf("RAID0+1 "); break; default: printf("unknown array 0x%x ", raid->flags); return; } printf("array> [%d/%d/%d] subdisks:\n", raid->cylinders, raid->heads, raid->sectors); for (i = 0; i < raid->num_subdisks; i++) ad_print(raid->subdisk[i], " "); for (i = 0; i < raid->num_mirrordisks; i++) ad_print(raid->mirrordisk[i], " "); dev = disk_create(raid->lun, &raid->disk, 0, &ar_cdevsw, &ardisk_cdevsw); dev->si_drv1 = raid; dev->si_iosize_max = 256 * DEV_BSIZE; raid->dev = dev; } static int aropen(dev_t dev, int flags, int fmt, struct thread *td) { struct ar_softc *rdp = dev->si_drv1; struct disklabel *dl; dl = &rdp->disk.d_label; bzero(dl, sizeof *dl); dl->d_secsize = DEV_BSIZE; dl->d_nsectors = rdp->sectors; dl->d_ntracks = rdp->heads; dl->d_ncylinders = rdp->cylinders; dl->d_secpercyl = rdp->sectors * rdp->heads; dl->d_secperunit = rdp->total_secs; return 0; } static void arstrategy(struct bio *bp) { struct ar_softc *rdp = bp->bio_dev->si_drv1; int lba, count, chunk; caddr_t data; bp->bio_resid = bp->bio_bcount; lba = bp->bio_pblkno; data = bp->bio_data; for (count = howmany(bp->bio_bcount, DEV_BSIZE); count > 0; count -= chunk, lba += chunk, data += (chunk * DEV_BSIZE)) { struct ar_buf *buf1, *buf2; int plba; buf1 = malloc(sizeof(struct ar_buf), M_AR, M_NOWAIT | M_ZERO); if (rdp->flags & AR_F_SPAN) { plba = lba; while (plba >= (rdp->subdisk[buf1->drive]->total_secs-rdp->reserved) && buf1->drive < rdp->num_subdisks) plba-=(rdp->subdisk[buf1->drive++]->total_secs-rdp->reserved); buf1->bp.bio_pblkno = plba; chunk = min(rdp->subdisk[buf1->drive]->total_secs - rdp->reserved - plba, count); } else if (rdp->flags & AR_F_RAID_0) { plba = lba / rdp->interleave; chunk = lba % rdp->interleave; if (plba == rdp->total_secs / rdp->interleave) { int lastblksize = (rdp->total_secs-(plba*rdp->interleave))/rdp->num_subdisks; buf1->drive = chunk / lastblksize; buf1->bp.bio_pblkno = ((plba / rdp->num_subdisks) * rdp->interleave) + chunk % lastblksize; chunk = min(count, lastblksize); } else { buf1->drive = plba % rdp->num_subdisks; buf1->bp.bio_pblkno = ((plba / rdp->num_subdisks) * rdp->interleave) + chunk; chunk = min(count, rdp->interleave - chunk); } } else { buf1->bp.bio_pblkno = lba; buf1->drive = 0; chunk = count; } if (buf1->drive > 0) buf1->bp.bio_pblkno += rdp->offset; buf1->bp.bio_caller1 = (void *)rdp; buf1->bp.bio_bcount = chunk * DEV_BSIZE; buf1->bp.bio_data = data; buf1->bp.bio_cmd = bp->bio_cmd; buf1->bp.bio_flags = bp->bio_flags; buf1->bp.bio_done = ar_done; buf1->org = bp; /* simpleminded load balancing on RAID1 arrays */ if (rdp->flags & AR_F_RAID_1 && bp->bio_cmd == BIO_READ) { if (buf1->bp.bio_pblkno < (rdp->last_lba[buf1->drive][rdp->last_disk] - 100) || buf1->bp.bio_pblkno > (rdp->last_lba[buf1->drive][rdp->last_disk] + 100)) { rdp->last_disk = 1 - rdp->last_disk; rdp->last_lba[buf1->drive][rdp->last_disk] = buf1->bp.bio_pblkno; } if (rdp->last_disk) buf1->bp.bio_dev = rdp->mirrordisk[buf1->drive]->dev; else buf1->bp.bio_dev = rdp->subdisk[buf1->drive]->dev; } else buf1->bp.bio_dev = rdp->subdisk[buf1->drive]->dev; if (rdp->flags & AR_F_RAID_1 && bp->bio_cmd == BIO_WRITE) { buf2 = malloc(sizeof(struct ar_buf), M_AR, M_NOWAIT); bcopy(buf1, buf2, sizeof(struct ar_buf)); buf2->bp.bio_dev = rdp->mirrordisk[buf1->drive]->dev; buf2->mirror = buf1; buf1->mirror = buf2; buf2->bp.bio_dev->si_disk->d_devsw->d_strategy((struct bio *)buf2); } buf1->bp.bio_dev->si_disk->d_devsw->d_strategy((struct bio *)buf1); } } static void ar_done(struct bio *bp) { struct ar_softc *rdp = (struct ar_softc *)bp->bio_caller1; struct ar_buf *buf = (struct ar_buf *)bp; int s; s = splbio(); if (bp->bio_flags & BIO_ERROR) { if (bp->bio_cmd == BIO_WRITE || buf->done || !(rdp->flags&AR_F_RAID_1)){ buf->org->bio_flags |= BIO_ERROR; buf->org->bio_error = bp->bio_error; } printf("ar%d: subdisk error\n", rdp->lun); } if (rdp->flags & AR_F_RAID_1) { if (bp->bio_cmd == BIO_WRITE) { if (!buf->done) { buf->mirror->done = 1; goto done; } } else { if (!buf->done && bp->bio_flags & BIO_ERROR) { /* read error on this disk, try mirror */ buf->done = 1; buf->bp.bio_dev = rdp->mirrordisk[buf->drive]->dev; buf->bp.bio_dev->si_disk->d_devsw->d_strategy((struct bio*)buf); return; } } } buf->org->bio_resid -= bp->bio_bcount; if (buf->org->bio_resid == 0) biodone(buf->org); done: free(buf, M_AR); splx(s); } /* read the RAID info from a disk on a HighPoint controller */ static int ar_highpoint_conf(struct ad_softc *adp, struct ar_softc **raidp) { struct highpoint_raid_conf *info; struct ar_softc *raid; int array, error = 1; if (!(info = (struct highpoint_raid_conf *) malloc(sizeof(struct highpoint_raid_conf), M_AR, M_NOWAIT | M_ZERO))) return error; if (ar_read(adp, 0x09, DEV_BSIZE, (char *)info)) { if (bootverbose) printf("HighPoint read conf failed\n"); goto highpoint_out; } /* check if this is a HighPoint RAID struct */ if (info->magic != HPT_MAGIC_OK) { if (bootverbose) printf("HighPoint check1 failed\n"); goto highpoint_out; } /* now convert HighPoint config info into our generic form */ for (array = 0; array < 8; array++) { if (!raidp[array]) { raidp[array] = (struct ar_softc*)malloc(sizeof(struct ar_softc),M_AR, M_NOWAIT | M_ZERO); if (!raidp[array]) { printf("ar: failed to allocate raid config storage\n"); goto highpoint_out; } } raid = raidp[array]; switch (info->type) { case HPT_T_RAID_0: /* check the order byte to determine what this really is */ switch (info->order & (HPT_O_MIRROR | HPT_O_STRIPE)) { case HPT_O_MIRROR: goto hpt_mirror; case HPT_O_STRIPE: if (raid->magic_0 && raid->magic_0 != info->magic_0) continue; raid->magic_0 = info->magic_0; raid->flags |= (AR_F_RAID_0 | AR_F_RAID_1); raid->interleave = 1 << info->raid0_shift; raid->subdisk[info->disk_number] = adp; raid->num_subdisks++; if ((raid->num_subdisks + raid->num_mirrordisks) == (info->raid_disks * 2)) raid->flags |= AR_F_CONF_DONE; break; case (HPT_O_MIRROR | HPT_O_STRIPE): if (raid->magic_1 && raid->magic_1 != info->magic_0) continue; raid->magic_1 = info->magic_0; raid->flags |= (AR_F_RAID_0 | AR_F_RAID_1); raid->mirrordisk[info->disk_number] = adp; raid->num_mirrordisks++; if ((raid->num_subdisks + raid->num_mirrordisks) == (info->raid_disks * 2)) raid->flags |= AR_F_CONF_DONE; break; default: if (raid->magic_0 && raid->magic_0 != info->magic_0) continue; raid->magic_0 = info->magic_0; raid->flags |= AR_F_RAID_0; raid->interleave = 1 << info->raid0_shift; raid->subdisk[info->disk_number] = adp; raid->num_subdisks++; if (raid->num_subdisks == info->raid_disks) raid->flags |= AR_F_CONF_DONE; } break; case HPT_T_RAID_1: hpt_mirror: if (raid->magic_0 && raid->magic_0 != info->magic_0) continue; raid->magic_0 = info->magic_0; raid->flags |= AR_F_RAID_1; if (info->disk_number == 0 && raid->num_subdisks == 0) { raid->subdisk[raid->num_subdisks] = adp; raid->num_subdisks = 1; } if (info->disk_number != 0 && raid->num_mirrordisks == 0) { raid->mirrordisk[raid->num_mirrordisks] = adp; raid->num_mirrordisks = 1; } if ((raid->num_subdisks + raid->num_mirrordisks) == (info->raid_disks * 2)) raid->flags |= AR_F_CONF_DONE; break; case HPT_T_SPAN: if (raid->magic_0 && raid->magic_0 != info->magic_0) continue; raid->magic_0 = info->magic_0; raid->flags |= AR_F_SPAN; raid->subdisk[info->disk_number] = adp; raid->num_subdisks++; if (raid->num_subdisks == info->raid_disks) raid->flags |= AR_F_CONF_DONE; break; default: printf("HighPoint unknown RAID type 0x%02x\n", info->type); } /* do we have a complete array to attach to ? */ if (raid->flags & AR_F_CONF_DONE) { raid->lun = array; raid->heads = 255; raid->sectors = 63; raid->cylinders = (info->total_secs - 9) / (63 * 255); raid->total_secs = info->total_secs - (9 * raid->num_subdisks); raid->offset = 10; raid->reserved = 10; ar_attach(raid); } error = 0; } highpoint_out: free(info, M_AR); return error; } /* read the RAID info from a disk on a Promise Fasttrak controller */ static int ar_promise_conf(struct ad_softc *adp, struct ar_softc **raidp) { struct promise_raid_conf *info; struct ar_softc *raid; u_int32_t lba, magic; u_int32_t cksum, *ckptr; int count, disk_number, array, error = 1; if (!(info = (struct promise_raid_conf *) malloc(sizeof(struct promise_raid_conf), M_AR, M_NOWAIT | M_ZERO))) return error; lba = ((adp->total_secs / (adp->heads * adp->sectors)) * adp->heads * adp->sectors) - adp->sectors; if (ar_read(adp, lba, 4 * DEV_BSIZE, (char *)info)) { if (bootverbose) printf("Promise read conf failed\n"); goto promise_out; } /* check if this is a Promise RAID struct */ if (strncmp(info->promise_id, PR_MAGIC, sizeof(PR_MAGIC))) { if (bootverbose) printf("Promise check1 failed\n"); goto promise_out; } /* check if the checksum is OK */ for (cksum = 0, ckptr = (int32_t *)info, count = 0; count < 511; count++) cksum += *ckptr++; if (cksum != *ckptr) { if (bootverbose) printf("Promise check2 failed\n"); goto promise_out; } /* now convert Promise config info into our generic form */ if ((info->raid.flags != PR_F_READY) || (((info->raid.status & (PR_S_DEFINED|PR_S_ONLINE)) != (PR_S_DEFINED|PR_S_ONLINE)))) { if (bootverbose) printf("Promise check3 failed\n"); goto promise_out; } magic = (adp->controller->chiptype >> 16) | info->raid.array_number << 16; array = info->raid.array_number; if (raidp[array]) { if (magic != raidp[array]->magic_0) { if (bootverbose) printf("Promise check4 failed\n"); goto promise_out; } } else { if (!(raidp[array] = (struct ar_softc *) malloc(sizeof(struct ar_softc), M_AR, M_NOWAIT))) { printf("ar: failed to allocate raid config storage\n"); goto promise_out; } else bzero(raidp[array], sizeof(struct ar_softc)); } raid = raidp[array]; raid->magic_0 = magic; switch (info->raid.type) { case PR_T_STRIPE: raid->flags |= AR_F_RAID_0; raid->interleave = 1 << info->raid.raid0_shift; break; case PR_T_MIRROR: raid->flags |= AR_F_RAID_1; break; case PR_T_SPAN: raid->flags |= AR_F_SPAN; break; default: printf("Promise unknown RAID type 0x%02x\n", info->raid.type); goto promise_out; } /* find out where this disk is in the defined array */ disk_number = info->raid.disk_number; if (disk_number < info->raid.raid0_disks) { raid->subdisk[disk_number] = adp; raid->num_subdisks++; if (raid->num_subdisks > 1 && !(raid->flags & AR_F_SPAN)) { raid->flags |= AR_F_RAID_0; raid->interleave = 1 << info->raid.raid0_shift; } } else { raid->mirrordisk[disk_number - info->raid.raid0_disks] = adp; raid->num_mirrordisks++; } /* do we have a complete array to attach to ? */ if (raid->num_subdisks + raid->num_mirrordisks == info->raid.total_disks) { raid->flags |= AR_F_CONF_DONE; raid->lun = array; raid->heads = info->raid.heads + 1; raid->sectors = info->raid.sectors; raid->cylinders = info->raid.cylinders + 1; raid->total_secs = info->raid.total_secs; raid->offset = 0; raid->reserved = 63; ar_attach(raid); } error = 0; promise_out: free(info, M_AR); return error; } int ar_read(struct ad_softc *adp, u_int32_t lba, int count, char *data) { if (ata_command(adp->controller, adp->unit | ATA_D_LBA, - (count > DEV_BSIZE) ? ATA_C_READ_MUL : ATA_C_READ, - (lba >> 8) & 0xffff, (lba >> 24) & 0xff, lba & 0xff, - count / DEV_BSIZE, 0, ATA_WAIT_INTR)) { + (count > DEV_BSIZE) ? ATA_C_READ_MUL : ATA_C_READ, + lba, count / DEV_BSIZE, 0, ATA_WAIT_INTR)) { ata_printf(adp->controller, adp->unit, "RAID read config failed\n"); return 1; } if (ata_wait(adp->controller, adp->unit, ATA_S_READY|ATA_S_DSC|ATA_S_DRQ)) { ata_printf(adp->controller, adp->unit, "RAID read config timeout\n"); return 1; } ATA_INSW(adp->controller->r_io, ATA_DATA, (int16_t *)data, count/sizeof(int16_t)); ATA_INB(adp->controller->r_io, ATA_STATUS); return 0; } Index: head/sys/dev/ata/atapi-all.c =================================================================== --- head/sys/dev/ata/atapi-all.c (revision 84583) +++ head/sys/dev/ata/atapi-all.c (revision 84584) @@ -1,756 +1,756 @@ /*- * Copyright (c) 1998,1999,2000,2001 Søren Schmidt * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer, * without modification, immediately at the beginning of the file. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * $FreeBSD$ */ #include "opt_global.h" #include "opt_ata.h" #include #include #include #include #include #include #include #include #include #include #include #include /* prototypes */ static void atapi_read(struct atapi_request *, int); static void atapi_write(struct atapi_request *, int); static void atapi_finish(struct atapi_request *); static void atapi_timeout(struct atapi_request *); static char *atapi_type(int); static char *atapi_cmd2str(u_int8_t); static char *atapi_skey2str(u_int8_t); /* internal vars */ static MALLOC_DEFINE(M_ATAPI, "ATAPI generic", "ATAPI driver generic layer"); static int atapi_dma = 0; TUNABLE_INT("hw.ata.atapi_dma", &atapi_dma); /* systcl vars */ SYSCTL_DECL(_hw_ata); SYSCTL_INT(_hw_ata, OID_AUTO, atapi_dma, CTLFLAG_RD, &atapi_dma, 0, "ATAPI device DMA mode control"); /* defines */ #define ATAPI_MAX_RETRIES 3 #define ATP_PARAM ATA_PARAM(atp->controller, atp->unit) void atapi_attach(struct ata_softc *scp, int device) { struct atapi_softc *atp; if (!(atp = malloc(sizeof(struct atapi_softc), M_ATAPI, M_NOWAIT|M_ZERO))) { ata_printf(scp, device, "failed to allocate driver storage\n"); return; } atp->controller = scp; atp->unit = device; if (bootverbose) ata_printf(scp, device, "piomode=%d dmamode=%d udmamode=%d dmaflag=%d\n", ata_pmode(ATP_PARAM), ata_wmode(ATP_PARAM), - ata_umode(ATP_PARAM), ATP_PARAM->dmaflag); + ata_umode(ATP_PARAM), ATP_PARAM->support_dma); - if (atapi_dma && !(ATP_PARAM->drqtype == ATAPI_DRQT_INTR)){ + if (atapi_dma && !(ATP_PARAM->drq_type == ATAPI_DRQT_INTR)) { ata_dmainit(atp->controller, atp->unit, (ata_pmode(ATP_PARAM) < 0) ? - (ATP_PARAM->dmaflag ? 4 : 0) : ata_pmode(ATP_PARAM), + (ATP_PARAM->support_dma ? 4 : 0) : ata_pmode(ATP_PARAM), (ata_wmode(ATP_PARAM) < 0) ? - (ATP_PARAM->dmaflag ? 2 : 0) : ata_wmode(ATP_PARAM), + (ATP_PARAM->support_dma ? 2 : 0) : ata_wmode(ATP_PARAM), ata_umode(ATP_PARAM)); } else ata_dmainit(atp->controller, atp->unit, ata_pmode(ATP_PARAM) < 0 ? 0 : ata_pmode(ATP_PARAM), -1,-1); - switch (ATP_PARAM->device_type) { + switch (ATP_PARAM->type) { #ifdef DEV_ATAPICD case ATAPI_TYPE_CDROM: if (acdattach(atp)) goto notfound; break; #endif #ifdef DEV_ATAPIFD case ATAPI_TYPE_DIRECT: if (afdattach(atp)) goto notfound; break; #endif #ifdef DEV_ATAPIST case ATAPI_TYPE_TAPE: if (astattach(atp)) goto notfound; break; #endif notfound: default: ata_printf(scp, device, "<%.40s/%.8s> %s device - NO DRIVER!\n", ATP_PARAM->model, ATP_PARAM->revision, - atapi_type(ATP_PARAM->device_type)); + atapi_type(ATP_PARAM->type)); free(atp, M_ATAPI); atp = NULL; } /* store our softc signalling we are ready to go */ scp->dev_softc[ATA_DEV(device)] = atp; } void atapi_detach(struct atapi_softc *atp) { struct atapi_request *request; atp->flags |= ATAPI_F_DETACHING; ata_printf(atp->controller, atp->unit, "removed from configuration\n"); - switch (ATP_PARAM->device_type) { + switch (ATP_PARAM->type) { #ifdef DEV_ATAPICD case ATAPI_TYPE_CDROM: acddetach(atp); break; #endif #ifdef DEV_ATAPIFD case ATAPI_TYPE_DIRECT: afddetach(atp); break; #endif #ifdef DEV_ATAPIST case ATAPI_TYPE_TAPE: astdetach(atp); break; #endif default: return; } TAILQ_FOREACH(request, &atp->controller->atapi_queue, chain) { if (request->device != atp) continue; TAILQ_REMOVE(&atp->controller->atapi_queue, request, chain); if (request->driver) { struct bio *bp = (struct bio *) request->driver; biofinish(bp, NULL, ENXIO); } if (request->dmatab) free(request->dmatab, M_DEVBUF); free(request, M_ATAPI); } atp->controller->dev_softc[ATA_DEV(atp->unit)] = NULL; free(atp, M_ATAPI); } int atapi_queue_cmd(struct atapi_softc *atp, int8_t *ccb, caddr_t data, int count, int flags, int timeout, atapi_callback_t callback, void *driver) { struct atapi_request *request; int error, s; if (!(request = malloc(sizeof(struct atapi_request), M_ATAPI, M_NOWAIT | M_ZERO))) return ENOMEM; request->device = atp; request->data = data; request->bytecount = count; request->flags = flags; request->timeout = timeout * hz; - request->ccbsize = (ATP_PARAM->cmdsize) ? 16 : 12; + request->ccbsize = (ATP_PARAM->packet_size) ? 16 : 12; bcopy(ccb, request->ccb, request->ccbsize); if (callback) { request->callback = callback; request->driver = driver; } if (atp->controller->mode[ATA_DEV(atp->unit)] >= ATA_DMA) { if (!(request->dmatab = ata_dmaalloc(atp->controller, atp->unit))) atp->controller->mode[ATA_DEV(atp->unit)] = ATA_PIO; } s = splbio(); /* append onto controller queue and try to start controller */ #ifdef ATAPI_DEBUG ata_printf(atp->controller, atp->unit, "queueing %s ", atapi_cmd2str(request->ccb[0])); atapi_dump("ccb = ", &request->ccb[0], sizeof(request->ccb)); #endif if (flags & ATPR_F_AT_HEAD) TAILQ_INSERT_HEAD(&atp->controller->atapi_queue, request, chain); else TAILQ_INSERT_TAIL(&atp->controller->atapi_queue, request, chain); ata_start(atp->controller); /* if callback used, then just return, gets called from interrupt context */ if (callback) { splx(s); return 0; } /* wait for request to complete */ tsleep((caddr_t)request, PRIBIO, "atprq", 0); splx(s); error = request->error; if (error) atp->sense = request->sense; if (request->dmatab) free(request->dmatab, M_DEVBUF); free(request, M_ATAPI); return error; } void atapi_start(struct atapi_softc *atp) { - switch (ATP_PARAM->device_type) { + switch (ATP_PARAM->type) { #ifdef DEV_ATAPICD case ATAPI_TYPE_CDROM: acd_start(atp); break; #endif #ifdef DEV_ATAPIFD case ATAPI_TYPE_DIRECT: afd_start(atp); break; #endif #ifdef DEV_ATAPIST case ATAPI_TYPE_TAPE: ast_start(atp); break; #endif default: return; } } int atapi_transfer(struct atapi_request *request) { struct atapi_softc *atp = request->device; int timout; u_int8_t reason; #ifdef ATAPI_DEBUG ata_printf(atp->controller, atp->unit, "starting %s ", atapi_cmd2str(request->ccb[0])); atapi_dump("ccb = ", &request->ccb[0], sizeof(request->ccb)); #endif /* is this just a POLL DSC command ? */ if (request->ccb[0] == ATAPI_POLL_DSC) { ATA_OUTB(atp->controller->r_io, ATA_DRIVE, ATA_D_IBM | atp->unit); DELAY(10); if (ATA_INB(atp->controller->r_altio, ATA_ALTSTAT) & ATA_S_DSC) request->error = 0; else request->error = EBUSY; atapi_finish(request); return ATA_OP_FINISHED; } /* start timeout for this command */ request->timeout_handle = timeout((timeout_t *)atapi_timeout, request, request->timeout); if (!(request->flags & ATPR_F_INTERNAL)) atp->cmd = request->ccb[0]; /* if DMA enabled setup DMA hardware */ request->flags &= ~ATPR_F_DMA_USED; 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 || request->ccb[0] == ATAPI_WRITE_BIG) && !(atp->controller->flags & ATA_ATAPI_DMA_RO))) && !ata_dmasetup(atp->controller, atp->unit, request->dmatab, (void *)request->data, request->bytecount)) { request->flags |= ATPR_F_DMA_USED; } /* start ATAPI operation */ if (ata_command(atp->controller, atp->unit, ATA_C_PACKET_CMD, - request->bytecount, 0, 0, 0, + request->bytecount, 0, (request->flags & ATPR_F_DMA_USED) ? ATA_F_DMA : 0, ATA_IMMEDIATE)) ata_printf(atp->controller, atp->unit, "failure to send ATAPI packet command\n"); if (request->flags & ATPR_F_DMA_USED) ata_dmastart(atp->controller, atp->unit, request->dmatab, request->flags & ATPR_F_READ); /* command interrupt device ? just return */ - if (ATP_PARAM->drqtype == ATAPI_DRQT_INTR) + if (ATP_PARAM->drq_type == ATAPI_DRQT_INTR) return ATA_OP_CONTINUES; /* ready to write ATAPI command */ timout = 5000; /* might be less for fast devices */ while (timout--) { reason = ATA_INB(atp->controller->r_io, ATA_IREASON); atp->controller->status = ATA_INB(atp->controller->r_io, ATA_STATUS); if (((reason & (ATA_I_CMD | ATA_I_IN)) | (atp->controller->status&(ATA_S_DRQ|ATA_S_BUSY)))==ATAPI_P_CMDOUT) break; DELAY(20); } if (timout <= 0) { ata_printf(atp->controller, atp->unit, "failure to execute ATAPI packet command\n"); untimeout((timeout_t *)atapi_timeout, request, request->timeout_handle); request->error = EIO; atapi_finish(request); return ATA_OP_FINISHED; } /* this seems to be needed for some (slow) devices */ DELAY(10); /* send actual command */ ATA_OUTSW(atp->controller->r_io, ATA_DATA, (int16_t *)request->ccb, request->ccbsize / sizeof(int16_t)); return ATA_OP_CONTINUES; } int atapi_interrupt(struct atapi_request *request) { struct atapi_softc *atp = request->device; int reason, dma_stat = 0; reason = (ATA_INB(atp->controller->r_io, ATA_IREASON)&(ATA_I_CMD|ATA_I_IN))| (atp->controller->status & ATA_S_DRQ); if (reason == ATAPI_P_CMDOUT) { if (!(atp->controller->status & ATA_S_DRQ)) { ata_printf(atp->controller, atp->unit, "command interrupt without DRQ\n"); untimeout((timeout_t *)atapi_timeout, request, request->timeout_handle); request->error = EIO; atapi_finish(request); return ATA_OP_FINISHED; } ATA_OUTSW(atp->controller->r_io, ATA_DATA, (int16_t *)request->ccb, request->ccbsize / sizeof(int16_t)); return ATA_OP_CONTINUES; } if (request->flags & ATPR_F_DMA_USED) { dma_stat = ata_dmadone(atp->controller); if ((atp->controller->status & (ATA_S_ERROR | ATA_S_DWF)) || dma_stat & ATA_BMSTAT_ERROR) { request->result = ATA_INB(atp->controller->r_io, ATA_ERROR); } else { request->result = 0; request->donecount = request->bytecount; request->bytecount = 0; } } else { int length = ATA_INB(atp->controller->r_io, ATA_CYL_LSB) | ATA_INB(atp->controller->r_io, ATA_CYL_MSB) << 8; switch (reason) { case ATAPI_P_WRITE: if (request->flags & ATPR_F_READ) { request->result = ATA_INB(atp->controller->r_io, ATA_ERROR); ata_printf(atp->controller, atp->unit, "%s trying to write on read buffer\n", atapi_cmd2str(atp->cmd)); break; } atapi_write(request, length); return ATA_OP_CONTINUES; case ATAPI_P_READ: if (!(request->flags & ATPR_F_READ)) { request->result = ATA_INB(atp->controller->r_io, ATA_ERROR); ata_printf(atp->controller, atp->unit, "%s trying to read on write buffer\n", atapi_cmd2str(atp->cmd)); break; } atapi_read(request, length); return ATA_OP_CONTINUES; case ATAPI_P_DONEDRQ: ata_printf(atp->controller, atp->unit, "%s DONEDRQ\n", atapi_cmd2str(atp->cmd)); if (request->flags & ATPR_F_READ) atapi_read(request, length); else atapi_write(request, length); /* FALLTHROUGH */ case ATAPI_P_ABORT: case ATAPI_P_DONE: if (atp->controller->status & (ATA_S_ERROR | ATA_S_DWF)) request->result = ATA_INB(atp->controller->r_io, ATA_ERROR); else if (!(request->flags & ATPR_F_INTERNAL)) request->result = 0; break; default: ata_printf(atp->controller, atp->unit, "unknown transfer phase %d\n", reason); } } untimeout((timeout_t *)atapi_timeout, request, request->timeout_handle); /* check for error, if valid sense key, queue a request sense cmd */ if ((request->result & ATAPI_SK_MASK) && request->ccb[0] != ATAPI_REQUEST_SENSE) { bzero(request->ccb, request->ccbsize); request->ccb[0] = ATAPI_REQUEST_SENSE; request->ccb[4] = sizeof(struct atapi_reqsense); request->bytecount = sizeof(struct atapi_reqsense); request->flags &= ATPR_F_QUIET; request->flags |= ATPR_F_READ | ATPR_F_INTERNAL; TAILQ_INSERT_HEAD(&atp->controller->atapi_queue, request, chain); } else { if (request->result) { switch ((request->result & ATAPI_SK_MASK)) { case ATAPI_SK_NO_SENSE: request->error = 0; break; case ATAPI_SK_RECOVERED_ERROR: ata_printf(atp->controller, atp->unit, "%s - recovered error\n", atapi_cmd2str(atp->cmd)); request->error = 0; break; case ATAPI_SK_NOT_READY: request->error = EBUSY; break; case ATAPI_SK_UNIT_ATTENTION: atp->flags |= ATAPI_F_MEDIA_CHANGED; request->error = EIO; break; default: request->error = EIO; if (request->flags & ATPR_F_QUIET) break; ata_printf(atp->controller, atp->unit, "%s - %s asc=0x%02x ascq=0x%02x ", atapi_cmd2str(atp->cmd), atapi_skey2str(request->sense.sense_key), request->sense.asc, request->sense.ascq); if (request->sense.sksv) printf("sks=0x%02x 0x%02x 0x%02x ", request->sense.sk_specific, request->sense.sk_specific1, request->sense.sk_specific2); printf("error=0x%02x\n", request->result & ATAPI_E_MASK); } } else request->error = 0; atapi_finish(request); } return ATA_OP_FINISHED; } void atapi_reinit(struct atapi_softc *atp) { /* reinit device parameters */ if (atp->controller->mode[ATA_DEV(atp->unit)] >= ATA_DMA) ata_dmainit(atp->controller, atp->unit, (ata_pmode(ATP_PARAM) < 0) ? - (ATP_PARAM->dmaflag ? 4 : 0) : ata_pmode(ATP_PARAM), + (ATP_PARAM->support_dma ? 4 : 0) : ata_pmode(ATP_PARAM), (ata_wmode(ATP_PARAM) < 0) ? - (ATP_PARAM->dmaflag ? 2 : 0) : ata_wmode(ATP_PARAM), + (ATP_PARAM->support_dma ? 2 : 0) : ata_wmode(ATP_PARAM), ata_umode(ATP_PARAM)); else ata_dmainit(atp->controller, atp->unit, ata_pmode(ATP_PARAM)<0 ? 0 : ata_pmode(ATP_PARAM), -1, -1); } int atapi_test_ready(struct atapi_softc *atp) { int8_t ccb[16] = { ATAPI_TEST_UNIT_READY, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; return atapi_queue_cmd(atp, ccb, NULL, 0, 0, 30, NULL, NULL); } int atapi_wait_dsc(struct atapi_softc *atp, int timeout) { int error = 0; int8_t ccb[16] = { ATAPI_POLL_DSC, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; timeout *= hz; while (timeout > 0) { error = atapi_queue_cmd(atp, ccb, NULL, 0, 0, 0, NULL, NULL); if (error != EBUSY) break; tsleep((caddr_t)&error, PRIBIO, "atpwt", hz / 2); timeout -= (hz / 2); } return error; } void atapi_dump(char *label, void *data, int len) { u_int8_t *p = data; printf("%s %02x", label, *p++); while (--len > 0) printf ("-%02x", *p++); printf("\n"); } static void atapi_read(struct atapi_request *request, int length) { int8_t **buffer = (int8_t **)&request->data; int size = min(request->bytecount, length); struct ata_softc *scp = request->device->controller; int resid; if (request->flags & ATPR_F_INTERNAL) *buffer = (int8_t *)&request->sense; if (scp->flags & ATA_USE_16BIT || (size % sizeof(int32_t))) ATA_INSW(scp->r_io, ATA_DATA, (void *)((uintptr_t)*buffer), size / sizeof(int16_t)); else ATA_INSL(scp->r_io, ATA_DATA, (void *)((uintptr_t)*buffer), size / sizeof(int32_t)); if (request->bytecount < length) { ata_printf(scp, request->device->unit, "read data overrun %d/%d\n", length, request->bytecount); for (resid=request->bytecount; residr_io, ATA_DATA); } *buffer += size; request->bytecount -= size; request->donecount += size; } static void atapi_write(struct atapi_request *request, int length) { int8_t **buffer = (int8_t **)&request->data; int size = min(request->bytecount, length); struct ata_softc *scp = request->device->controller; int resid; if (request->flags & ATPR_F_INTERNAL) *buffer = (int8_t *)&request->sense; if (scp->flags & ATA_USE_16BIT || (size % sizeof(int32_t))) ATA_OUTSW(scp->r_io, ATA_DATA, (void *)((uintptr_t)*buffer), size / sizeof(int16_t)); else ATA_OUTSL(scp->r_io, ATA_DATA, (void *)((uintptr_t)*buffer), size / sizeof(int32_t)); if (request->bytecount < length) { ata_printf(scp, request->device->unit, "write data underrun %d/%d\n", length, request->bytecount); for (resid=request->bytecount; residr_io, ATA_DATA, 0); } *buffer += size; request->bytecount -= size; request->donecount += size; } static void atapi_finish(struct atapi_request *request) { #ifdef ATAPI_DEBUG ata_printf(request->device->controller, request->device->unit, "finished %s%s\n", request->callback ? "callback " : "", atapi_cmd2str(request->ccb[0])); #endif if (request->callback) { if (!((request->callback)(request))) { if (request->dmatab) free(request->dmatab, M_DEVBUF); free(request, M_ATAPI); } } else wakeup((caddr_t)request); } static void atapi_timeout(struct atapi_request *request) { struct atapi_softc *atp = request->device; int s = splbio(); atp->controller->running = NULL; ata_printf(atp->controller, atp->unit, "%s command timeout - resetting\n", atapi_cmd2str(request->ccb[0])); if (request->flags & ATPR_F_DMA_USED) { ata_dmadone(atp->controller); if (request->retries == ATAPI_MAX_RETRIES) { ata_dmainit(atp->controller, atp->unit, (ata_pmode(ATP_PARAM)<0)?0:ata_pmode(ATP_PARAM),-1,-1); ata_printf(atp->controller, atp->unit, "trying fallback to PIO mode\n"); request->retries = 0; } } /* if retries still permit, reinject this request */ if (request->retries++ < ATAPI_MAX_RETRIES) TAILQ_INSERT_HEAD(&atp->controller->atapi_queue, request, chain); else { /* retries all used up, return error */ request->error = EIO; wakeup((caddr_t)request); } ata_reinit(atp->controller); splx(s); } static char * atapi_type(int type) { switch (type) { case ATAPI_TYPE_CDROM: return "CDROM"; case ATAPI_TYPE_DIRECT: return "floppy"; case ATAPI_TYPE_TAPE: return "tape"; case ATAPI_TYPE_OPTICAL: return "optical"; default: return "Unknown"; } } static char * atapi_cmd2str(u_int8_t cmd) { switch (cmd) { case 0x00: return ("TEST_UNIT_READY"); case 0x01: return ("REZERO"); case 0x03: return ("REQUEST_SENSE"); case 0x04: return ("FORMAT_UNIT"); case 0x08: return ("READ"); case 0x0a: return ("WRITE"); case 0x10: return ("WEOF"); case 0x11: return ("SPACE"); case 0x15: return ("MODE_SELECT"); case 0x19: return ("ERASE"); case 0x1a: return ("MODE_SENSE"); case 0x1b: return ("START_STOP"); case 0x1e: return ("PREVENT_ALLOW"); case 0x25: return ("READ_CAPACITY"); case 0x28: return ("READ_BIG"); case 0x2a: return ("WRITE_BIG"); case 0x2b: return ("LOCATE"); case 0x34: return ("READ_POSITION"); case 0x35: return ("SYNCHRONIZE_CACHE"); case 0x3b: return ("WRITE_BUFFER"); case 0x3c: return ("READ_BUFFER"); case 0x42: return ("READ_SUBCHANNEL"); case 0x43: return ("READ_TOC"); case 0x45: return ("PLAY_10"); case 0x47: return ("PLAY_MSF"); case 0x48: return ("PLAY_TRACK"); case 0x4b: return ("PAUSE"); case 0x51: return ("READ_DISK_INFO"); case 0x52: return ("READ_TRACK_INFO"); case 0x53: return ("RESERVE_TRACK"); case 0x54: return ("SEND_OPC_INFO"); case 0x55: return ("MODE_SELECT_BIG"); case 0x58: return ("REPAIR_TRACK"); case 0x59: return ("READ_MASTER_CUE"); case 0x5a: return ("MODE_SENSE_BIG"); case 0x5b: return ("CLOSE_TRACK/SESSION"); case 0x5c: return ("READ_BUFFER_CAPACITY"); case 0x5d: return ("SEND_CUE_SHEET"); case 0xa1: return ("BLANK_CMD"); case 0xa3: return ("SEND_KEY"); case 0xa4: return ("REPORT_KEY"); case 0xa5: return ("PLAY_12"); case 0xa6: return ("LOAD_UNLOAD"); case 0xad: return ("READ_DVD_STRUCTURE"); case 0xb4: return ("PLAY_CD"); case 0xbb: return ("SET_SPEED"); case 0xbd: return ("MECH_STATUS"); case 0xbe: return ("READ_CD"); case 0xff: return ("POLL_DSC"); default: { static char buffer[16]; sprintf(buffer, "unknown CMD (0x%02x)", cmd); return buffer; } } } static char * atapi_skey2str(u_int8_t skey) { switch (skey) { case 0x00: return ("NO SENSE"); case 0x01: return ("RECOVERED ERROR"); case 0x02: return ("NOT READY"); case 0x03: return ("MEDIUM ERROR"); case 0x04: return ("HARDWARE ERROR"); case 0x05: return ("ILLEGAL REQUEST"); case 0x06: return ("UNIT ATTENTION"); case 0x07: return ("DATA PROTECT"); case 0x08: return ("BLANK CHECK"); case 0x09: return ("VENDOR SPECIFIC"); case 0x0a: return ("COPY ABORTED"); case 0x0b: return ("ABORTED COMMAND"); case 0x0c: return ("EQUAL"); case 0x0d: return ("VOLUME OVERFLOW"); case 0x0e: return ("MISCOMPARE"); case 0x0f: return ("RESERVED"); default: return("UNKNOWN"); } } Index: head/sys/sys/ata.h =================================================================== --- head/sys/sys/ata.h (revision 84583) +++ head/sys/sys/ata.h (revision 84584) @@ -1,223 +1,264 @@ /*- * Copyright (c) 2000,2001 Søren Schmidt * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer, * without modification, immediately at the beginning of the file. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * $FreeBSD$ */ #ifndef _SYS_ATA_H_ #define _SYS_ATA_H_ #include /* ATA/ATAPI device parameter information */ struct ata_params { - u_int8_t cmdsize :2; /* packet command size */ +/*000*/ u_int16_t packet_size :2; /* packet command size */ #define ATAPI_PSIZE_12 0 /* 12 bytes */ #define ATAPI_PSIZE_16 1 /* 16 bytes */ - u_int8_t :3; - u_int8_t drqtype :2; /* DRQ type */ + u_int16_t incomplete :1; + u_int16_t :2; + u_int16_t drq_type :2; /* DRQ type */ #define ATAPI_DRQT_MPROC 0 /* cpu 3 ms delay */ #define ATAPI_DRQT_INTR 1 /* intr 10 ms delay */ #define ATAPI_DRQT_ACCEL 2 /* accel 50 us delay */ - u_int8_t removable :1; /* device is removable */ - u_int8_t device_type :5; /* device type */ + u_int16_t removable :1; /* device is removable */ + u_int16_t type :5; /* device type */ #define ATAPI_TYPE_DIRECT 0 /* disk/floppy */ #define ATAPI_TYPE_TAPE 1 /* streaming tape */ #define ATAPI_TYPE_CDROM 5 /* CD-ROM device */ #define ATAPI_TYPE_OPTICAL 7 /* optical disk */ - u_int8_t :1; - u_int8_t proto :2; /* command protocol */ -#define ATAPI_PROTO_ATAPI 2 + u_int16_t :2; + u_int16_t cmd_protocol :1; /* command protocol */ +#define ATA_PROTO_ATA 0 +#define ATA_PROTO_ATAPI 1 - u_int16_t cylinders; /* number of cylinders */ - u_int16_t reserved2; - u_int16_t heads; /* # heads */ - u_int16_t unfbytespertrk; /* # unformatted bytes/track */ - u_int16_t unfbytes; /* # unformatted bytes/sector */ - u_int16_t sectors; /* # sectors/track */ - u_int16_t vendorunique0[3]; - u_int8_t serial[20]; /* serial number */ - u_int16_t buffertype; /* buffer type */ -#define ATA_BT_SINGLEPORTSECTOR 1 /* 1 port, 1 sector buffer */ -#define ATA_BT_DUALPORTMULTI 2 /* 2 port, mult sector buffer */ -#define ATA_BT_DUALPORTMULTICACHE 3 /* above plus track cache */ +/*001*/ u_int16_t cylinders; /* # of cylinders */ + u_int16_t reserved2; +/*003*/ u_int16_t heads; /* # heads */ + u_int16_t obsolete4; + u_int16_t obsolete5; +/*006*/ u_int16_t sectors; /* # sectors/track */ +/*007*/ u_int16_t vendor7[3]; +/*010*/ u_int8_t serial[20]; /* serial number */ + u_int16_t retired20; + u_int16_t retired21; + u_int16_t obsolete22; +/*023*/ u_int8_t revision[8]; /* firmware revision */ +/*027*/ u_int8_t model[40]; /* model name */ +/*047*/ u_int16_t sectors_intr:8; /* sectors per interrupt */ + u_int16_t :8; - u_int16_t buffersize; /* buf size, 512-byte units */ - u_int16_t necc; /* ecc bytes appended */ - u_int8_t revision[8]; /* firmware revision */ - u_int8_t model[40]; /* model name */ - u_int8_t nsecperint; /* sectors per interrupt */ - u_int8_t vendorunique1; - u_int16_t usedmovsd; /* double word read/write? */ +/*048*/ u_int16_t usedmovsd; /* double word read/write? */ +/*049*/ u_int16_t retired49:8; + u_int16_t support_dma :1; /* DMA supported */ + u_int16_t support_lba :1; /* LBA supported */ + u_int16_t disable_iordy :1; /* IORDY may be disabled */ + u_int16_t support_iordy :1; /* IORDY supported */ + u_int16_t softreset :1; /* needs softreset when busy */ + u_int16_t stdby_ovlap :1; /* standby/overlap supported */ + u_int16_t support_queueing:1; /* supports queuing overlap */ + u_int16_t support_idma :1; /* interleaved DMA supported */ - u_int8_t vendorcap; /* vendor capabilities */ - u_int8_t dmaflag :1; /* DMA supported - always 1 */ - u_int8_t lbaflag :1; /* LBA supported - always 1 */ - u_int8_t iordydis :1; /* IORDY may be disabled */ - u_int8_t iordyflag :1; /* IORDY supported */ - u_int8_t softreset :1; /* needs softreset when busy */ - u_int8_t stdby_ovlap :1; /* standby/overlap supported */ - u_int8_t queueing :1; /* supports queuing overlap */ - u_int8_t idmaflag :1; /* interleaved DMA supported */ - u_int16_t capvalidate; /* validation for above */ +/*050*/ u_int16_t device_stdby_min:1; + u_int16_t :13; + u_int16_t capability_one:1; + u_int16_t capability_zero:1; - u_int8_t vendorunique3; - u_int8_t opiomode; /* PIO modes 0-2 */ - u_int8_t vendorunique4; - u_int8_t odmamode; /* old DMA modes, not ATA-3 */ - - u_int16_t atavalid; /* fields valid */ +/*051*/ u_int16_t vendor51:8; + u_int16_t retired_piomode:8; /* PIO modes 0-2 */ +/*052*/ u_int16_t vendor52:8; + u_int16_t retired_dmamode:8; /* DMA modes, not ATA-3 */ +/*053*/ u_int16_t atavalid; /* fields valid */ #define ATA_FLAG_54_58 1 /* words 54-58 valid */ #define ATA_FLAG_64_70 2 /* words 64-70 valid */ #define ATA_FLAG_88 4 /* word 88 valid */ - u_int16_t currcyls; - u_int16_t currheads; - u_int16_t currsectors; - u_int16_t currsize0; - u_int16_t currsize1; - u_int8_t currmultsect; - u_int8_t multsectvalid; - u_int32_t lbasize; + u_int16_t obsolete54[5]; +/*059*/ u_int16_t multi_count:8; + u_int16_t multi_valid:1; + u_int16_t :7; - u_int16_t sdmamodes; /* singleword DMA modes */ - u_int16_t wdmamodes; /* multiword DMA modes */ - u_int16_t apiomodes; /* advanced PIO modes */ +/*060*/ u_int32_t lba_size; + u_int16_t obsolete62; +/*063*/ u_int16_t mwdmamodes; /* multiword DMA modes */ +/*064*/ u_int16_t apiomodes; /* advanced PIO modes */ - u_int16_t mwdmamin; /* min. M/W DMA time/word ns */ - u_int16_t mwdmarec; /* rec. M/W DMA time ns */ - u_int16_t pioblind; /* min. PIO cycle w/o flow */ - u_int16_t pioiordy; /* min. PIO cycle IORDY flow */ +/*065*/ u_int16_t mwdmamin; /* min. M/W DMA time/word ns */ +/*066*/ u_int16_t mwdmarec; /* rec. M/W DMA time ns */ +/*067*/ u_int16_t pioblind; /* min. PIO cycle w/o flow */ +/*068*/ u_int16_t pioiordy; /* min. PIO cycle IORDY flow */ + u_int16_t reserved69; + u_int16_t reserved70; +/*071*/ u_int16_t rlsovlap; /* rel time (us) for overlap */ +/*072*/ u_int16_t rlsservice; /* rel time (us) for service */ + u_int16_t reserved73; + u_int16_t reserved74; - u_int16_t reserved69; - u_int16_t reserved70; - u_int16_t rlsovlap; /* rel time (us) for overlap */ - u_int16_t rlsservice; /* rel time (us) for service */ - u_int16_t reserved73; - u_int16_t reserved74; - u_int16_t queuelen:5; - u_int16_t :11; - u_int16_t reserved76; - u_int16_t reserved77; - u_int16_t reserved78; - u_int16_t reserved79; - u_int16_t versmajor; - u_int16_t versminor; - u_int16_t featsupp1; /* 82 */ - u_int16_t supmicrocode:1; - u_int16_t supqueued:1; - u_int16_t supcfa:1; - u_int16_t supapm:1; - u_int16_t suprmsn:1; - u_int16_t :11; - u_int16_t featsupp3; /* 84 */ - u_int16_t featenab1; /* 85 */ - u_int16_t enabmicrocode:1; - u_int16_t enabqueued:1; - u_int16_t enabcfa:1; - u_int16_t enabapm:1; - u_int16_t enabrmsn:1; - u_int16_t :11; - u_int16_t featenab3; /* 87 */ - u_int16_t udmamodes; /* UltraDMA modes */ - u_int16_t erasetime; - u_int16_t enherasetime; - u_int16_t apmlevel; - u_int16_t masterpasswdrev; - u_int16_t masterhwres :8; - u_int16_t slavehwres :5; - u_int16_t cblid :1; - u_int16_t reserved93_1415 :2; - u_int16_t reserved94[32]; - u_int16_t rmvstat; - u_int16_t securstat; - u_int16_t reserved129[30]; - u_int16_t cfapwrmode; - u_int16_t reserved160[85]; - u_int16_t integrity; - u_int16_t reserved246[10]; +/*075*/ u_int16_t queuelen:5; + u_int16_t :11; + + u_int16_t reserved76; + u_int16_t reserved77; + u_int16_t reserved78; + u_int16_t reserved79; +/*080*/ u_int16_t version_major; +/*081*/ u_int16_t version_minor; + struct { +/*082/085*/ u_int16_t smart:1; + u_int16_t security:1; + u_int16_t removable:1; + u_int16_t power_mngt:1; + u_int16_t packet:1; + u_int16_t write_cache:1; + u_int16_t look_ahead:1; + u_int16_t release_irq:1; + u_int16_t service_irq:1; + u_int16_t reset:1; + u_int16_t protected:1; + u_int16_t :1; + u_int16_t write_buffer:1; + u_int16_t read_buffer:1; + u_int16_t nop:1; + u_int16_t :1; + +/*083/086*/ u_int16_t microcode:1; + u_int16_t queued:1; + u_int16_t cfa:1; + u_int16_t apm:1; + u_int16_t notify:1; + u_int16_t standby:1; + u_int16_t spinup:1; + u_int16_t :1; + u_int16_t max_security:1; + u_int16_t auto_acoustic:1; + u_int16_t address48:1; + u_int16_t config_overlay:1; + u_int16_t flush_cache:1; + u_int16_t flush_cache48:1; + u_int16_t support_one:1; + u_int16_t support_zero:1; + +/*084/087*/ u_int16_t smart_error_log:1; + u_int16_t smart_self_test:1; + u_int16_t media_serial_no:1; + u_int16_t media_card_pass:1; + u_int16_t streaming:1; + u_int16_t logging:1; + u_int16_t :8; + u_int16_t extended_one:1; + u_int16_t extended_zero:1; + } support, enabled; + +/*088*/ u_int16_t udmamodes; /* UltraDMA modes */ +/*089*/ u_int16_t erase_time; +/*090*/ u_int16_t enhanced_erase_time; +/*091*/ u_int16_t apm_value; +/*092*/ u_int16_t master_passwd_revision; + +/*093*/ u_int16_t hwres_master :8; + u_int16_t hwres_slave :5; + u_int16_t hwres_cblid :1; + u_int16_t hwres_valid:2; + +/*094*/ u_int16_t current_acoustic:8; + u_int16_t vendor_acoustic:8; + +/*095*/ u_int16_t stream_min_req_size; +/*096*/ u_int16_t stream_transfer_time; +/*097*/ u_int16_t stream_access_latency; +/*098*/ u_int32_t stream_granularity; +/*100*/ u_int64_t lba_size48; + u_int16_t reserved104[23]; +/*127*/ u_int16_t removable_status; +/*128*/ u_int16_t security_status; + u_int16_t reserved129[31]; +/*160*/ u_int16_t cfa_powermode1; + u_int16_t reserved161[14]; +/*176*/ u_int16_t media_serial[30]; + u_int16_t reserved206[49]; +/*255*/ u_int16_t integrity; }; #define ATA_MODE_MASK 0x0f #define ATA_DMA_MASK 0xf0 #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_WDMA 0x20 #define ATA_WDMA2 0x22 #define ATA_UDMA 0x40 #define ATA_UDMA2 0x42 #define ATA_UDMA4 0x44 #define ATA_UDMA5 0x45 +#define ATA_UDMA6 0x46 struct ata_cmd { int channel; int device; int cmd; #define ATAGPARM 1 #define ATAGMODE 2 #define ATASMODE 3 #define ATAREINIT 4 #define ATAATTACH 5 #define ATADETACH 6 #define ATAPICMD 7 union { struct { int mode[2]; } mode; struct { int type[2]; char name[2][32]; struct ata_params params[2]; } param; struct { char ccb[16]; caddr_t data; int count; int flags; #define ATAPI_CMD_CTRL 0x00 #define ATAPI_CMD_READ 0x01 #define ATAPI_CMD_WRITE 0x02 int timeout; int error; char sense_data[18]; } atapi; } u; }; #define IOCATA _IOWR('a', 1, struct ata_cmd) #endif /* _SYS_ATA_H_ */