diff options
Diffstat (limited to 'sys/dev/ata/ata-all.c')
-rw-r--r-- | sys/dev/ata/ata-all.c | 1581 |
1 files changed, 447 insertions, 1134 deletions
diff --git a/sys/dev/ata/ata-all.c b/sys/dev/ata/ata-all.c index cb77622..8d0923a 100644 --- a/sys/dev/ata/ata-all.c +++ b/sys/dev/ata/ata-all.c @@ -33,12 +33,14 @@ #include <sys/systm.h> #include <sys/ata.h> #include <sys/kernel.h> +#include <sys/endian.h> #include <sys/conf.h> -#include <sys/module.h> #include <sys/bus.h> #include <sys/bio.h> #include <sys/malloc.h> +#include <sys/mutex.h> #include <sys/sysctl.h> +#include <sys/taskqueue.h> #include <machine/stdarg.h> #include <machine/resource.h> #include <machine/bus.h> @@ -50,33 +52,35 @@ #include <dev/ata/ata-all.h> #include <dev/ata/ata-disk.h> #include <dev/ata/ata-raid.h> -#include <dev/ata/atapi-all.h> /* device structures */ -static d_ioctl_t ataioctl; +static d_ioctl_t ata_ioctl; static struct cdevsw ata_cdevsw = { .d_open = nullopen, .d_close = nullclose, - .d_ioctl = ataioctl, + .d_ioctl = ata_ioctl, .d_name = "ata", .d_maj = 159, }; /* prototypes */ +static void ata_shutdown(void *arg, int howto); +static int ata_getparam(struct ata_device *atadev, u_int8_t command); +static void ata_identify_devices(struct ata_channel *ch); static void ata_boot_attach(void); -static void ata_intr(void *); -static int ata_getparam(struct ata_device *, u_int8_t); -static int ata_service(struct ata_channel *); -static void ata_flush(struct ata_device *); -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_device *, int); -static u_int8_t ata_enclosure_sensor(struct ata_device *, int, u_int8_t, u_int8_t); -static int ata_enclosure_status(struct ata_device *, int *, int *, int *, int *); +static void bswap(int8_t *buf, int len); +static void btrim(int8_t *buf, int len); +static void bpack(int8_t *src, int8_t *dst, int len); +static void ata_init(void); /* sysctl vars */ SYSCTL_NODE(_hw, OID_AUTO, ata, CTLFLAG_RD, 0, "ATA driver parameters"); +TUNABLE_INT("hw.ata.ata_dma", &ata_dma); +TUNABLE_INT("hw.ata.wc", &ata_wc); +TUNABLE_INT("hw.ata.atapi_dma", &atapi_dma); +int ata_dma = 1; +int ata_wc = 1; +int atapi_dma = 0; /* global vars */ struct intr_config_hook *ata_delayed_attach = NULL; @@ -85,10 +89,9 @@ devclass_t ata_devclass; /* local vars */ static MALLOC_DEFINE(M_ATA, "ATA generic", "ATA driver generic layer"); -/* misc defines */ -#define DEV_ATAPIALL defined(DEV_ATAPICD) || defined(DEV_ATAPIFD) || \ - defined(DEV_ATAPIST) || defined(DEV_ATAPICAM) - +/* + * newbus device interface related functions + */ int ata_probe(device_t dev) { @@ -101,20 +104,22 @@ ata_probe(device_t dev) return EEXIST; /* initialize the softc basics */ - ch->active = ATA_IDLE; - ch->dev = dev; + ata_generic_hw(ch); ch->device[MASTER].channel = ch; ch->device[MASTER].unit = ATA_MASTER; ch->device[MASTER].mode = ATA_PIO; ch->device[SLAVE].channel = ch; ch->device[SLAVE].unit = ATA_SLAVE; ch->device[SLAVE].mode = ATA_PIO; + ch->dev = dev; + ch->state = ATA_IDLE; + bzero(&ch->queue_mtx, sizeof(struct mtx)); + mtx_init(&ch->queue_mtx, "ATA queue lock", MTX_DEF, 0); TAILQ_INIT(&ch->ata_queue); - TAILQ_INIT(&ch->atapi_queue); /* initialise device(s) on this channel */ ch->locking(ch, ATA_LF_LOCK); - ata_reset(ch); + ch->hw.reset(ch); ch->locking(ch, ATA_LF_UNLOCK); return 0; } @@ -135,8 +140,8 @@ ata_attach(device_t dev) ata_printf(ch, -1, "unable to allocate interrupt\n"); return ENXIO; } - if ((error = bus_setup_intr(dev, ch->r_irq, INTR_TYPE_BIO | INTR_ENTROPY, - ata_intr, ch, &ch->ih))) { + if ((error = bus_setup_intr(dev, ch->r_irq, ATA_INTR_FLAGS, + ch->hw.interrupt, ch, &ch->ih))) { ata_printf(ch, -1, "unable to setup interrupt\n"); return error; } @@ -144,42 +149,19 @@ ata_attach(device_t dev) if (ch->dma) ch->dma->alloc(ch); - /* - * 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 ch->devices. - */ - if (!ata_delayed_attach) { - ch->locking(ch, ATA_LF_LOCK); - if (ch->devices & ATA_ATA_SLAVE) - if (ata_getparam(&ch->device[SLAVE], ATA_C_ATA_IDENTIFY)) - ch->devices &= ~ATA_ATA_SLAVE; - if (ch->devices & ATA_ATAPI_SLAVE) - if (ata_getparam(&ch->device[SLAVE], ATA_C_ATAPI_IDENTIFY)) - ch->devices &= ~ATA_ATAPI_SLAVE; - if (ch->devices & ATA_ATA_MASTER) - if (ata_getparam(&ch->device[MASTER], ATA_C_ATA_IDENTIFY)) - ch->devices &= ~ATA_ATA_MASTER; - if (ch->devices & ATA_ATAPI_MASTER) - if (ata_getparam(&ch->device[MASTER], ATA_C_ATAPI_IDENTIFY)) - ch->devices &= ~ATA_ATAPI_MASTER; -#ifdef DEV_ATADISK - if (ch->devices & ATA_ATA_MASTER) - ad_attach(&ch->device[MASTER]); - if (ch->devices & ATA_ATA_SLAVE) - ad_attach(&ch->device[SLAVE]); -#endif -#if DEV_ATAPIALL - if (ch->devices & ATA_ATAPI_MASTER) - atapi_attach(&ch->device[MASTER]); - if (ch->devices & ATA_ATAPI_SLAVE) - atapi_attach(&ch->device[SLAVE]); -#endif + /* do not attach devices if we are in early boot */ + if (ata_delayed_attach) + return 0; + + ata_identify_devices(ch); + + if (ch->device[MASTER].attach) + ch->device[MASTER].attach(&ch->device[MASTER]); + if (ch->device[SLAVE].attach) + ch->device[SLAVE].attach(&ch->device[SLAVE]); #ifdef DEV_ATAPICAM - atapi_cam_attach_bus(ch); + atapi_cam_attach_bus(ch); #endif - ch->locking(ch, ATA_LF_UNLOCK); - } return 0; } @@ -187,56 +169,97 @@ int ata_detach(device_t dev) { struct ata_channel *ch; - int s; + struct ata_request *request; if (!dev || !(ch = device_get_softc(dev)) || !ch->r_irq) return ENXIO; - /* make sure channel is not busy */ - ch->locking(ch, ATA_LF_LOCK); - ATA_SLEEPLOCK_CH(ch, ATA_CONTROL); - - s = splbio(); -#ifdef DEV_ATADISK - if (ch->devices & ATA_ATA_MASTER && ch->device[MASTER].driver) - ad_detach(&ch->device[MASTER]); - if (ch->devices & ATA_ATA_SLAVE && ch->device[SLAVE].driver) - ad_detach(&ch->device[SLAVE]); -#endif -#if DEV_ATAPIALL - if (ch->devices & ATA_ATAPI_MASTER && ch->device[MASTER].driver) - atapi_detach(&ch->device[MASTER]); - if (ch->devices & ATA_ATAPI_SLAVE && ch->device[SLAVE].driver) - atapi_detach(&ch->device[SLAVE]); -#endif + /* detach devices on this channel */ + if (ch->device[MASTER].detach) + ch->device[MASTER].detach(&ch->device[MASTER]); + if (ch->device[SLAVE].detach) + ch->device[SLAVE].detach(&ch->device[SLAVE]); #ifdef DEV_ATAPICAM atapi_cam_detach_bus(ch); #endif - splx(s); + + /* fail outstanding requests on this channel */ + mtx_lock(&ch->queue_mtx); + while ((request = TAILQ_FIRST(&ch->ata_queue))) { + TAILQ_REMOVE(&ch->ata_queue, request, chain); + request->status = ATA_S_ERROR; + mtx_unlock(&ch->queue_mtx); + ata_finish(request); + mtx_lock(&ch->queue_mtx); + } + mtx_unlock(&ch->queue_mtx); if (ch->device[MASTER].param) { - ata_flush(&ch->device[MASTER]); + ata_controlcmd(&ch->device[MASTER], ATA_FLUSHCACHE, 0, 0, 0); free(ch->device[MASTER].param, M_ATA); ch->device[MASTER].param = NULL; } if (ch->device[SLAVE].param) { - ata_flush(&ch->device[SLAVE]); + ata_controlcmd(&ch->device[SLAVE], ATA_FLUSHCACHE, 0, 0, 0); free(ch->device[SLAVE].param, M_ATA); ch->device[SLAVE].param = NULL; } - ch->device[MASTER].driver = NULL; - ch->device[SLAVE].driver = NULL; ch->device[MASTER].mode = ATA_PIO; ch->device[SLAVE].mode = ATA_PIO; ch->devices = 0; + if (ch->dma) ch->dma->free(ch); bus_teardown_intr(dev, ch->r_irq, ch->ih); bus_release_resource(dev, SYS_RES_IRQ, ATA_IRQ_RID, ch->r_irq); ch->r_irq = NULL; + return 0; +} + +int +ata_reinit(struct ata_channel *ch) +{ + int devices, misdev, newdev; + + if (!ch->r_irq) + return ENXIO; + + /* reset the HW */ + ata_printf(ch, -1, "resetting devices ..\n"); + ATA_FORCELOCK_CH(ch, ATA_CONTROL); + ch->running = NULL; + devices = ch->devices; + ch->hw.reset(ch); ATA_UNLOCK_CH(ch); - ch->locking(ch, ATA_LF_UNLOCK); + + /* detach what left the channel during reset */ + if ((misdev = devices & ~ch->devices)) { + if ((misdev & (ATA_ATA_MASTER | ATA_ATAPI_MASTER)) && + ch->device[MASTER].detach) + ch->device[MASTER].detach(&ch->device[MASTER]); + if ((misdev & (ATA_ATA_SLAVE | ATA_ATAPI_SLAVE)) && + ch->device[SLAVE].detach) + ch->device[SLAVE].detach(&ch->device[SLAVE]); + } + + /* identify whats present on this channel now */ + ata_identify_devices(ch); + + /* attach new devices that appeared during reset */ + if ((newdev = ~devices & ch->devices)) { + if ((newdev & (ATA_ATA_MASTER | ATA_ATAPI_MASTER)) && + ch->device[MASTER].attach) + ch->device[MASTER].attach(&ch->device[MASTER]); + if ((newdev & (ATA_ATA_SLAVE | ATA_ATAPI_SLAVE)) && + ch->device[SLAVE].attach) + ch->device[SLAVE].attach(&ch->device[SLAVE]); + } +#ifdef DEV_ATAPICAM + atapi_cam_reinit_bus(ch); +#endif + + printf("done\n"); return 0; } @@ -265,1094 +288,428 @@ ata_resume(device_t dev) ch->locking(ch, ATA_LF_LOCK); error = ata_reinit(ch); ch->locking(ch, ATA_LF_UNLOCK); + ata_start(ch); return error; } -static int -ataioctl(dev_t dev, u_long cmd, caddr_t addr, int32_t flag, struct thread *td) +static void +ata_shutdown(void *arg, int howto) { - struct ata_cmd *iocmd = (struct ata_cmd *)addr; struct ata_channel *ch; - device_t device = devclass_get_device(ata_devclass, iocmd->channel); - int error; + int ctlr; - if (cmd != IOCATA) - return ENOTTY; - - if (iocmd->cmd == ATAGMAXCHANNEL) { - iocmd->u.maxchan = devclass_get_maxunit(ata_devclass); - return 0; + /* flush cache on all devices */ + for (ctlr = 0; ctlr < devclass_get_maxunit(ata_devclass); ctlr++) { + if (!(ch = devclass_get_softc(ata_devclass, ctlr))) + continue; + if (ch->device[MASTER].param) + ata_controlcmd(&ch->device[MASTER], ATA_FLUSHCACHE, 0, 0, 0); + if (ch->device[SLAVE].param) + ata_controlcmd(&ch->device[SLAVE], ATA_FLUSHCACHE, 0, 0, 0); } +} - if (iocmd->channel < -1 || iocmd->device < -1 || iocmd->device > SLAVE) - return ENXIO; +/* + * device related interfaces + */ +static int +ata_ioctl(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 = devclass_get_device(ata_devclass, iocmd->channel); + struct ata_channel *ch; + struct ata_device *atadev; + struct ata_request *request; + caddr_t buf; + int error = ENOTTY; + DROP_GIANT(); 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: - if (!device || !(ch = device_get_softc(device))) - return ENXIO; - ch->locking(ch, ATA_LF_LOCK); - ATA_SLEEPLOCK_CH(ch, ATA_ACTIVE); - error = ata_reinit(ch); - ch->locking(ch, ATA_LF_UNLOCK); - return error; - - case ATAGMODE: - if (!device || !(ch = device_get_softc(device))) - return ENXIO; - - if ((iocmd->device == MASTER || iocmd->device == -1) && - ch->device[MASTER].driver) - iocmd->u.mode.mode[MASTER] = ch->device[MASTER].mode; - else - iocmd->u.mode.mode[MASTER] = -1; - - if ((iocmd->device == SLAVE || iocmd->device == -1) && - ch->device[SLAVE].param) - iocmd->u.mode.mode[SLAVE] = ch->device[SLAVE].mode; - else - iocmd->u.mode.mode[SLAVE] = -1; - return 0; - - case ATASMODE: - if (!device || !(ch = device_get_softc(device))) - return ENXIO; - - ch->locking(ch, ATA_LF_LOCK); - if ((iocmd->device == MASTER || iocmd->device == -1) && - iocmd->u.mode.mode[MASTER] >= 0 && ch->device[MASTER].param) { - ata_change_mode(&ch->device[MASTER],iocmd->u.mode.mode[MASTER]); - iocmd->u.mode.mode[MASTER] = ch->device[MASTER].mode; - } - else - iocmd->u.mode.mode[MASTER] = -1; - - if ((iocmd->device == SLAVE || iocmd->device == -1) && - iocmd->u.mode.mode[SLAVE] >= 0 && ch->device[SLAVE].param) { - ata_change_mode(&ch->device[SLAVE], iocmd->u.mode.mode[SLAVE]); - iocmd->u.mode.mode[SLAVE] = ch->device[SLAVE].mode; - } - else - iocmd->u.mode.mode[SLAVE] = -1; - ch->locking(ch, ATA_LF_UNLOCK); - return 0; - - case ATAGPARM: - if (!device || !(ch = device_get_softc(device))) - return ENXIO; - - iocmd->u.param.type[MASTER] = - ch->devices & (ATA_ATA_MASTER | ATA_ATAPI_MASTER); - iocmd->u.param.type[SLAVE] = - ch->devices & (ATA_ATA_SLAVE | ATA_ATAPI_SLAVE); - - if (ch->device[MASTER].name) - strcpy(iocmd->u.param.name[MASTER], ch->device[MASTER].name); - if (ch->device[SLAVE].name) - strcpy(iocmd->u.param.name[SLAVE], ch->device[SLAVE].name); - - if (ch->device[MASTER].param) - bcopy(ch->device[MASTER].param, &iocmd->u.param.params[MASTER], - sizeof(struct ata_params)); - if (ch->device[SLAVE].param) - bcopy(ch->device[SLAVE].param, &iocmd->u.param.params[SLAVE], - sizeof(struct ata_params)); - return 0; - - case ATAENCSTAT: { - struct ata_device *atadev; - - if (!device || !(ch = device_get_softc(device))) - return ENXIO; - - if (iocmd->device == SLAVE) - atadev = &ch->device[SLAVE]; - else - atadev = &ch->device[MASTER]; + case ATAGMAXCHANNEL: + iocmd->u.maxchan = devclass_get_maxunit(ata_devclass); + error = 0; + break; - return ata_enclosure_status(atadev, - &iocmd->u.enclosure.fan, - &iocmd->u.enclosure.temp, - &iocmd->u.enclosure.v05, - &iocmd->u.enclosure.v12); + case ATAGPARM: + if (!device || !(ch = device_get_softc(device))) { + error = ENXIO; + break; } + iocmd->u.param.type[MASTER] = + ch->devices & (ATA_ATA_MASTER | ATA_ATAPI_MASTER); + iocmd->u.param.type[SLAVE] = + ch->devices & (ATA_ATA_SLAVE | ATA_ATAPI_SLAVE); + if (ch->device[MASTER].name) + strcpy(iocmd->u.param.name[MASTER], ch->device[MASTER].name); + if (ch->device[SLAVE].name) + strcpy(iocmd->u.param.name[SLAVE], ch->device[SLAVE].name); + if (ch->device[MASTER].param) + bcopy(ch->device[MASTER].param, &iocmd->u.param.params[MASTER], + sizeof(struct ata_params)); + if (ch->device[SLAVE].param) + bcopy(ch->device[SLAVE].param, &iocmd->u.param.params[SLAVE], + sizeof(struct ata_params)); + error = 0; + break; -#ifdef DEV_ATADISK - case ATARAIDREBUILD: - return ata_raid_rebuild(iocmd->channel); - - case ATARAIDCREATE: - return ata_raid_create(&iocmd->u.raid_setup); - - case ATARAIDDELETE: - return ata_raid_delete(iocmd->channel); + case ATAGMODE: + if (!device || !(ch = device_get_softc(device))) { + error = ENXIO; + break; + } + iocmd->u.mode.mode[MASTER] = ch->device[MASTER].mode; + iocmd->u.mode.mode[SLAVE] = ch->device[SLAVE].mode; + error = 0; + break; - case ATARAIDADDSPARE: - return ata_raid_addspare(iocmd->channel, iocmd->u.raid_spare.disk); + case ATASMODE: + if (!device || !(ch = device_get_softc(device))) { + error = ENXIO; + break; + } + if (iocmd->u.mode.mode[MASTER] >= 0 && ch->device[MASTER].param) + ch->device[MASTER].setmode(&ch->device[MASTER], + iocmd->u.mode.mode[MASTER]); + iocmd->u.mode.mode[MASTER] = ch->device[MASTER].mode; + if (iocmd->u.mode.mode[SLAVE] >= 0 && ch->device[SLAVE].param) + ch->device[SLAVE].setmode(&ch->device[SLAVE], + iocmd->u.mode.mode[SLAVE]); + iocmd->u.mode.mode[SLAVE] = ch->device[SLAVE].mode; + error = 0; + break; - case ATARAIDSTATUS: - return ata_raid_status(iocmd->channel, &iocmd->u.raid_status); -#endif -#if DEV_ATAPIALL - case ATAPICMD: { - struct ata_device *atadev; - caddr_t buf; - - if (!device || !(ch = device_get_softc(device))) - return ENXIO; - - if (!(atadev = &ch->device[iocmd->device]) || - !(ch->devices & (iocmd->device == MASTER ? - ATA_ATAPI_MASTER : ATA_ATAPI_SLAVE))) - return ENODEV; - - if (!(buf = malloc(iocmd->u.atapi.count, M_ATA, M_NOWAIT))) - return ENOMEM; - - if (iocmd->u.atapi.flags & ATAPI_CMD_WRITE) { - error = copyin(iocmd->u.atapi.data, buf, iocmd->u.atapi.count); - if (error) { - free(buf, M_ATA); - return error; - } - } - error = atapi_queue_cmd(atadev, 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); + case ATAREQUEST: + if (!device || !(ch = device_get_softc(device))) { + error = ENXIO; + break; + } + if (!(atadev = &ch->device[iocmd->device])) { + error = ENODEV; + break; + } + if (!(buf = malloc(iocmd->u.request.count, M_ATA, M_NOWAIT))) { + error = ENOMEM; + break; + } + if (!(request = ata_alloc_request())) { + error = ENOMEM; + free(buf, M_ATA); + break; + } + if (iocmd->u.request.flags & ATA_CMD_WRITE) { + error = copyin(iocmd->u.request.data, buf, iocmd->u.request.count); if (error) { - iocmd->u.atapi.error = error; - bcopy(&atadev->result, iocmd->u.atapi.sense_data, - sizeof(struct atapi_reqsense)); - error = 0; + free(buf, M_ATA); + ata_free_request(request); + break; } - 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 - default: - break; - } - return ENOTTY; -} - -static int -ata_getparam(struct ata_device *atadev, u_int8_t command) -{ - struct ata_params *ata_parm; - int retry = 0; - - if (!(ata_parm = malloc(sizeof(struct ata_params), M_ATA, M_NOWAIT))) { - ata_prtdev(atadev, "malloc for identify data failed\n"); - return -1; - } + + request->device = atadev; - /* apparently some devices needs this repeated */ - do { - if (ata_command(atadev, command, 0, 0, 0, - dumping ? ATA_WAIT_READY : ATA_WAIT_INTR)) { - ata_prtdev(atadev, "%s identify failed\n", - command == ATA_C_ATAPI_IDENTIFY ? "ATAPI" : "ATA"); - free(ata_parm, M_ATA); - return -1; + if (iocmd->u.request.flags & ATA_CMD_ATAPI) { + request->flags = ATA_R_ATAPI; + bcopy(iocmd->u.request.u.atapi.ccb, request->u.atapi.ccb, 16); } - if (retry++ > 4) { - ata_prtdev(atadev, "%s identify retries exceeded\n", - command == ATA_C_ATAPI_IDENTIFY ? "ATAPI" : "ATA"); - free(ata_parm, M_ATA); - return -1; + else { + request->u.ata.command = iocmd->u.request.u.ata.command; + request->u.ata.feature = iocmd->u.request.u.ata.feature; + request->u.ata.lba = iocmd->u.request.u.ata.lba; + request->u.ata.count = iocmd->u.request.u.ata.count; } - } while (ata_wait(atadev, ((command == ATA_C_ATAPI_IDENTIFY) ? - ATA_S_DRQ : (ATA_S_READY|ATA_S_DSC|ATA_S_DRQ)))); - ATA_IDX_INSW(atadev->channel, 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') || - (ata_parm->model[0] == 'P' && ata_parm->model[1] == 'i'))) - 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)); - bswap(ata_parm->serial, sizeof(ata_parm->serial)); - btrim(ata_parm->serial, sizeof(ata_parm->serial)); - bpack(ata_parm->serial, ata_parm->serial, sizeof(ata_parm->serial)); - atadev->param = ata_parm; - return 0; -} -static void -ata_boot_attach(void) -{ - struct ata_channel *ch; - int ctlr; + request->timeout = iocmd->u.request.timeout; + request->data = buf; + request->bytecount = iocmd->u.request.count; + request->transfersize = request->bytecount; - /* - * 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; ctlr<devclass_get_maxunit(ata_devclass); ctlr++) { - if (!(ch = devclass_get_softc(ata_devclass, ctlr))) - continue; - ch->locking(ch, ATA_LF_LOCK); - if (ch->devices & ATA_ATA_SLAVE) - if (ata_getparam(&ch->device[SLAVE], ATA_C_ATA_IDENTIFY)) - ch->devices &= ~ATA_ATA_SLAVE; - if (ch->devices & ATA_ATAPI_SLAVE) - if (ata_getparam(&ch->device[SLAVE], ATA_C_ATAPI_IDENTIFY)) - ch->devices &= ~ATA_ATAPI_SLAVE; - if (ch->devices & ATA_ATA_MASTER) - if (ata_getparam(&ch->device[MASTER], ATA_C_ATA_IDENTIFY)) - ch->devices &= ~ATA_ATA_MASTER; - if (ch->devices & ATA_ATAPI_MASTER) - if (ata_getparam(&ch->device[MASTER], ATA_C_ATAPI_IDENTIFY)) - ch->devices &= ~ATA_ATAPI_MASTER; - ch->locking(ch, ATA_LF_UNLOCK); - } -#ifdef DEV_ATADISK - /* now we know whats there, do the real attach, first the ATA disks */ - for (ctlr=0; ctlr<devclass_get_maxunit(ata_devclass); ctlr++) { - if (!(ch = devclass_get_softc(ata_devclass, ctlr))) - continue; - ch->locking(ch, ATA_LF_LOCK); - if (ch->devices & ATA_ATA_MASTER) - ad_attach(&ch->device[MASTER]); - if (ch->devices & ATA_ATA_SLAVE) - ad_attach(&ch->device[SLAVE]); - ch->locking(ch, ATA_LF_UNLOCK); - } -#endif - /* then the atapi devices */ - for (ctlr=0; ctlr<devclass_get_maxunit(ata_devclass); ctlr++) { - if (!(ch = devclass_get_softc(ata_devclass, ctlr))) - continue; - ch->locking(ch, ATA_LF_LOCK); -#if DEV_ATAPIALL - if (ch->devices & ATA_ATAPI_MASTER) - atapi_attach(&ch->device[MASTER]); - if (ch->devices & ATA_ATAPI_SLAVE) - atapi_attach(&ch->device[SLAVE]); -#endif -#ifdef DEV_ATAPICAM - atapi_cam_attach_bus(ch); -#endif - ch->locking(ch, ATA_LF_UNLOCK); - } - if (ata_delayed_attach) { - config_intrhook_disestablish(ata_delayed_attach); - free(ata_delayed_attach, M_TEMP); - ata_delayed_attach = NULL; - } -#ifdef DEV_ATADISK - ata_raid_attach(); -#endif -} + if (iocmd->u.request.flags & ATA_CMD_CONTROL) + request->flags |= ATA_R_CONTROL; + if (iocmd->u.request.flags & ATA_CMD_READ) + request->flags |= ATA_R_READ; + if (iocmd->u.request.flags & ATA_CMD_WRITE) + request->flags |= ATA_R_WRITE; -static void -ata_intr(void *data) -{ - struct ata_channel *ch = (struct ata_channel *)data; + ata_queue_request(request); - /* if device is busy it didn't interrupt */ - if (ATA_IDX_INB(ch, ATA_ALTSTAT) & ATA_S_BUSY) { - DELAY(100); - if (!(ATA_IDX_INB(ch, ATA_ALTSTAT) & ATA_S_DRQ)) - return; - } + if (request->error) + iocmd->u.request.error = request->error; + else { + if (iocmd->u.request.flags & ATA_CMD_READ) + error = copyout(buf, + iocmd->u.request.data, iocmd->u.request.count); + else + error = 0; + } + free(buf, M_ATA); + ata_free_request(request); + break; - /* clear interrupt and get status */ - ch->status = ATA_IDX_INB(ch, ATA_STATUS); + case ATAREINIT: + if (!device || !(ch = device_get_softc(device))) + return ENXIO; + error = ata_reinit(ch); + ata_start(ch); + break; - if (ch->status & ATA_S_ERROR) - ch->error = ATA_IDX_INB(ch, ATA_ERROR); + case ATAATTACH: + if (!device) { + error = ENXIO; + break; + } + /* SOS should enable channel HW on controller XXX */ + error = ata_probe(device); + if (!error) + error = ata_attach(device); + break; - /* find & call the responsible driver to process this interrupt */ - switch (ch->active) { -#ifdef DEV_ATADISK - case ATA_ACTIVE_ATA: - if (!ch->running || ad_interrupt(ch->running) == ATA_OP_CONTINUES) - return; + case ATADETACH: + if (!device) { + error = ENXIO; + break; + } + error = ata_detach(device); + /* SOS should disable channel HW on controller XXX */ break; -#endif -#if DEV_ATAPIALL - case ATA_ACTIVE_ATAPI: - if (!ch->running || atapi_interrupt(ch->running) == ATA_OP_CONTINUES) - return; + + +#ifdef DEV_ATARAID + case ATARAIDCREATE: + error = ata_raid_create(&iocmd->u.raid_setup); + break; + + case ATARAIDDELETE: + error = ata_raid_delete(iocmd->channel); + break; + + case ATARAIDSTATUS: + error = ata_raid_status(iocmd->channel, &iocmd->u.raid_status); + break; + + case ATARAIDADDSPARE: + error = ata_raid_addspare(iocmd->channel, iocmd->u.raid_spare.disk); + break; + + case ATARAIDREBUILD: + error = ata_raid_rebuild(iocmd->channel); break; #endif - default: - if (ch->active & ATA_WAIT_INTR) - wakeup(ch); } - - if (ch->active & ATA_CONTROL) { - ATA_FORCELOCK_CH(ch, ATA_CONTROL); - return; - } - - if (ch->active & ATA_WAIT_INTR) { - ATA_UNLOCK_CH(ch); - return; - } - - if ((ch->flags & ATA_QUEUED) && - ATA_IDX_INB(ch, ATA_ALTSTAT) & ATA_S_SERVICE) { - ATA_FORCELOCK_CH(ch, ATA_ACTIVE); - if (ata_service(ch) == ATA_OP_CONTINUES) - return; - } - ch->running = NULL; - ATA_UNLOCK_CH(ch); - ch->locking(ch, ATA_LF_UNLOCK); - ata_start(ch); - return; + PICKUP_GIANT(); + return error; } -void -ata_start(struct ata_channel *ch) +/* + * device probe functions + */ +static int +ata_getparam(struct ata_device *atadev, u_int8_t command) { -#ifdef DEV_ATADISK - struct ad_request *ad_request; -#endif -#if DEV_ATAPIALL - struct atapi_request *atapi_request; -#endif - int s; + struct ata_params *atacap; + struct ata_request *request; + int error = ENOMEM; - ch->locking(ch, ATA_LF_LOCK); - if (!ATA_LOCK_CH(ch, ATA_ACTIVE)) - return; - - s = splbio(); -#ifdef DEV_ATADISK - /* find & call the responsible driver if anything on the ATA queue */ - if (TAILQ_EMPTY(&ch->ata_queue)) { - if (ch->devices & (ATA_ATA_MASTER) && ch->device[MASTER].driver) - ad_start(&ch->device[MASTER]); - if (ch->devices & (ATA_ATA_SLAVE) && ch->device[SLAVE].driver) - ad_start(&ch->device[SLAVE]); - } - if ((ad_request = TAILQ_FIRST(&ch->ata_queue))) { - TAILQ_REMOVE(&ch->ata_queue, ad_request, chain); - ch->active = ATA_ACTIVE_ATA; - ch->running = ad_request; - if (ad_transfer(ad_request) == ATA_OP_CONTINUES) { - splx(s); - return; + if (atadev->param) + atacap = atadev->param; + else + atacap = malloc(sizeof(struct ata_params), M_ATA, M_NOWAIT); + if (atacap) { + request = ata_alloc_request(); + if (request) { + request->device = atadev; + request->u.ata.command = command; + request->flags = ATA_R_READ; + request->data = (caddr_t)atacap; + request->timeout = 2; + request->retries = 2; + request->bytecount = sizeof(struct ata_params); + request->transfersize = DEV_BSIZE; + ata_queue_request(request); + error = request->result; + ata_free_request(request); } - } + if (error) { + atadev->param = NULL; + free(atacap, M_ATA); + } + else { +#if BYTE_ORDER == BIG_ENDIAN + int16_t *ptr; + for (ptr = (int16_t *)atacap; + ptr < (int16_t *)atacap + sizeof(struct ata_params)/2; ptr++) { + *ptr = bswap16(*ptr); + } #endif -#if DEV_ATAPIALL - /* find & call the responsible driver if anything on the ATAPI queue */ - if (TAILQ_EMPTY(&ch->atapi_queue)) { - if (ch->devices & (ATA_ATAPI_MASTER) && ch->device[MASTER].driver) - atapi_start(&ch->device[MASTER]); - if (ch->devices & (ATA_ATAPI_SLAVE) && ch->device[SLAVE].driver) - atapi_start(&ch->device[SLAVE]); - } - if ((atapi_request = TAILQ_FIRST(&ch->atapi_queue))) { - TAILQ_REMOVE(&ch->atapi_queue, atapi_request, chain); - ch->active = ATA_ACTIVE_ATAPI; - ch->running = atapi_request; - if (atapi_transfer(atapi_request) == ATA_OP_CONTINUES) { - splx(s); - return; + if (!((atacap->model[0] == 'N' && atacap->model[1] == 'E') || + (atacap->model[0] == 'F' && atacap->model[1] == 'X') || + (atacap->model[0] == 'P' && atacap->model[1] == 'i'))) + bswap(atacap->model, sizeof(atacap->model)); + btrim(atacap->model, sizeof(atacap->model)); + bpack(atacap->model, atacap->model, sizeof(atacap->model)); + bswap(atacap->revision, sizeof(atacap->revision)); + btrim(atacap->revision, sizeof(atacap->revision)); + bpack(atacap->revision, atacap->revision, sizeof(atacap->revision)); + bswap(atacap->serial, sizeof(atacap->serial)); + btrim(atacap->serial, sizeof(atacap->serial)); + bpack(atacap->serial, atacap->serial, sizeof(atacap->serial)); + atadev->param = atacap; + if (bootverbose) + ata_prtdev(atadev, + "pio=0x%02x wdma=0x%02x udma=0x%02x cable=%spin\n", + ata_pmode(atacap), ata_wmode(atacap), + ata_umode(atacap), + (atacap->hwres & ATA_CABLE_ID) ? "80":"40"); } } -#endif - ATA_UNLOCK_CH(ch); - ch->locking(ch, ATA_LF_UNLOCK); - splx(s); + return error; } -void -ata_reset(struct ata_channel *ch) +static void +ata_identify_devices(struct ata_channel *ch) { - u_int8_t lsb, msb, ostat0, ostat1; - u_int8_t stat0 = 0, stat1 = 0; - int mask = 0, timeout; - - /* do we have any signs of ATA/ATAPI HW being present ? */ - ATA_IDX_OUTB(ch, ATA_DRIVE, ATA_D_IBM | ATA_MASTER); - DELAY(10); - ostat0 = ATA_IDX_INB(ch, ATA_STATUS); - if ((ostat0 & 0xf8) != 0xf8 && ostat0 != 0xa5) { - stat0 = ATA_S_BUSY; - mask |= 0x01; - } - ATA_IDX_OUTB(ch, ATA_DRIVE, ATA_D_IBM | ATA_SLAVE); - DELAY(10); - ostat1 = ATA_IDX_INB(ch, ATA_STATUS); - if ((ostat1 & 0xf8) != 0xf8 && ostat1 != 0xa5) { - stat1 = ATA_S_BUSY; - mask |= 0x02; - } - - ch->devices = 0; - if (!mask) - return; - - /* in some setups we dont want to test for a slave */ - if (ch->flags & ATA_NO_SLAVE) { - stat1 = 0x0; - mask &= ~0x02; + if (ch->devices & ATA_ATA_SLAVE) { + if (ata_getparam(&ch->device[SLAVE], ATA_ATA_IDENTIFY)) + ch->devices &= ~ATA_ATA_SLAVE; +#ifdef DEV_ATADISK + else + ch->device[SLAVE].attach = ad_attach; +#endif } - - if (bootverbose) - ata_printf(ch, -1, "pre reset mask=%02x ostat0=%02x ostat2=%02x\n", - mask, ostat0, ostat1); - - /* reset channel */ - ATA_IDX_OUTB(ch, ATA_DRIVE, ATA_D_IBM | ATA_MASTER); - DELAY(10); - ATA_IDX_OUTB(ch, ATA_ALTSTAT, ATA_A_IDS | ATA_A_RESET); - DELAY(10000); - ATA_IDX_OUTB(ch, ATA_ALTSTAT, ATA_A_IDS); - DELAY(100000); - ATA_IDX_INB(ch, ATA_ERROR); - - /* wait for BUSY to go inactive */ - for (timeout = 0; timeout < 310000; timeout++) { - if (stat0 & ATA_S_BUSY) { - ATA_IDX_OUTB(ch, ATA_DRIVE, ATA_D_IBM | ATA_MASTER); - DELAY(10); - - /* check for ATAPI signature while its still there */ - lsb = ATA_IDX_INB(ch, ATA_CYL_LSB); - msb = ATA_IDX_INB(ch, ATA_CYL_MSB); - stat0 = ATA_IDX_INB(ch, ATA_STATUS); - if (!(stat0 & ATA_S_BUSY)) { - if (bootverbose) - ata_printf(ch, ATA_MASTER, "ATAPI %02x %02x\n", lsb, msb); - if (lsb == ATAPI_MAGIC_LSB && msb == ATAPI_MAGIC_MSB) - ch->devices |= ATA_ATAPI_MASTER; - } - } - if (stat1 & ATA_S_BUSY) { - ATA_IDX_OUTB(ch, ATA_DRIVE, ATA_D_IBM | ATA_SLAVE); - DELAY(10); - - /* check for ATAPI signature while its still there */ - lsb = ATA_IDX_INB(ch, ATA_CYL_LSB); - msb = ATA_IDX_INB(ch, ATA_CYL_MSB); - stat1 = ATA_IDX_INB(ch, ATA_STATUS); - if (!(stat1 & ATA_S_BUSY)) { - if (bootverbose) - ata_printf(ch, ATA_SLAVE, "ATAPI %02x %02x\n", lsb, msb); - if (lsb == ATAPI_MAGIC_LSB && msb == ATAPI_MAGIC_MSB) - ch->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)) + if (ch->devices & ATA_ATAPI_SLAVE) { + if (ata_getparam(&ch->device[SLAVE], ATA_ATAPI_IDENTIFY)) + ch->devices &= ~ATA_ATAPI_SLAVE; + else { + switch (ch->device[SLAVE].param->config & ATA_ATAPI_TYPE_MASK) { +#ifdef DEV_ATAPICD + case ATA_ATAPI_TYPE_CDROM: + ch->device[SLAVE].attach = acd_attach; break; - if (mask == 0x03) /* wait for both master & slave */ - if (!(stat0 & ATA_S_BUSY) && !(stat1 & ATA_S_BUSY)) +#endif +#ifdef DEV_ATAPIFD + case ATA_ATAPI_TYPE_DIRECT: + ch->device[SLAVE].attach = afd_attach; break; - DELAY(100); - } - DELAY(10); - ATA_IDX_OUTB(ch, ATA_ALTSTAT, ATA_A_4BIT); - - if (stat0 & ATA_S_BUSY) - mask &= ~0x01; - if (stat1 & ATA_S_BUSY) - mask &= ~0x02; - if (bootverbose) - ata_printf(ch, -1, "after reset mask=%02x stat0=%02x stat1=%02x\n", - mask, stat0, stat1); - if (!mask) - return; - - if (mask & 0x01 && ostat0 != 0x00 && !(ch->devices & ATA_ATAPI_MASTER)) { - ATA_IDX_OUTB(ch, ATA_DRIVE, ATA_D_IBM | ATA_MASTER); - DELAY(10); - ATA_IDX_OUTB(ch, ATA_ERROR, 0x58); - ATA_IDX_OUTB(ch, ATA_CYL_LSB, 0xa5); - lsb = ATA_IDX_INB(ch, ATA_ERROR); - msb = ATA_IDX_INB(ch, ATA_CYL_LSB); - if (bootverbose) - ata_printf(ch, ATA_MASTER, "ATA %02x %02x\n", lsb, msb); - if (lsb != 0x58 && msb == 0xa5) - ch->devices |= ATA_ATA_MASTER; - } - if (mask & 0x02 && ostat1 != 0x00 && !(ch->devices & ATA_ATAPI_SLAVE)) { - ATA_IDX_OUTB(ch, ATA_DRIVE, ATA_D_IBM | ATA_SLAVE); - DELAY(10); - ATA_IDX_OUTB(ch, ATA_ERROR, 0x58); - ATA_IDX_OUTB(ch, ATA_CYL_LSB, 0xa5); - lsb = ATA_IDX_INB(ch, ATA_ERROR); - msb = ATA_IDX_INB(ch, ATA_CYL_LSB); - if (bootverbose) - ata_printf(ch, ATA_SLAVE, "ATA %02x %02x\n", lsb, msb); - if (lsb != 0x58 && msb == 0xa5) - ch->devices |= ATA_ATA_SLAVE; - } - if (bootverbose) - ata_printf(ch, -1, "devices=%02x\n", ch->devices); -} - -int -ata_reinit(struct ata_channel *ch) -{ - int devices, misdev, newdev; - - - if (!ch->r_irq) - return ENXIO; - - ATA_FORCELOCK_CH(ch, ATA_CONTROL); - ch->running = NULL; - devices = ch->devices; - ata_printf(ch, -1, "resetting devices ..\n"); - ata_reset(ch); - - if ((misdev = devices & ~ch->devices)) { -#ifdef DEV_ATADISK - if (misdev & ATA_ATA_MASTER && ch->device[MASTER].driver) - ad_detach(&ch->device[MASTER]); - if (misdev & ATA_ATA_SLAVE && ch->device[SLAVE].driver) - ad_detach(&ch->device[SLAVE]); #endif -#if DEV_ATAPIALL - if (misdev & ATA_ATAPI_MASTER && ch->device[MASTER].driver) - atapi_detach(&ch->device[MASTER]); - if (misdev & ATA_ATAPI_SLAVE && ch->device[SLAVE].driver) - atapi_detach(&ch->device[SLAVE]); +#ifdef DEV_ATAPIST + case ATA_ATAPI_TYPE_TAPE: + ch->device[SLAVE].attach = ast_attach; + break; #endif - if (misdev & ATA_ATA_MASTER || misdev & ATA_ATAPI_MASTER) { - if (ch->device[MASTER].param) - free(ch->device[MASTER].param, M_ATA); - ch->device[MASTER].param = NULL; - } - if (misdev & ATA_ATA_SLAVE || misdev & ATA_ATAPI_SLAVE) { - if (ch->device[SLAVE].param) - free(ch->device[SLAVE].param, M_ATA); - ch->device[SLAVE].param = NULL; + } } } - if ((newdev = ~devices & ch->devices)) { - if (newdev & ATA_ATA_MASTER) - if (ata_getparam(&ch->device[MASTER], ATA_C_ATA_IDENTIFY)) - ch->devices &= ~ATA_ATA_MASTER; - if (newdev & ATA_ATA_SLAVE) - if (ata_getparam(&ch->device[SLAVE], ATA_C_ATA_IDENTIFY)) - ch->devices &= ~ATA_ATA_SLAVE; - if (newdev & ATA_ATAPI_MASTER) - if (ata_getparam(&ch->device[MASTER], ATA_C_ATAPI_IDENTIFY)) - ch->devices &= ~ATA_ATAPI_MASTER; - if (newdev & ATA_ATAPI_SLAVE) - if (ata_getparam(&ch->device[SLAVE], ATA_C_ATAPI_IDENTIFY)) - ch->devices &= ~ATA_ATAPI_SLAVE; - } - newdev = ~devices & ch->devices; + if (ch->devices & ATA_ATA_MASTER) { + if (ata_getparam(&ch->device[MASTER], ATA_ATA_IDENTIFY)) + ch->devices &= ~ATA_ATA_MASTER; #ifdef DEV_ATADISK - if (newdev & ATA_ATA_SLAVE && !ch->device[SLAVE].driver) { - ATA_UNLOCK_CH(ch); - ad_attach(&ch->device[SLAVE]); - ATA_SLEEPLOCK_CH(ch, ATA_CONTROL); - } - else if (ch->devices & (ATA_ATA_SLAVE) && ch->device[SLAVE].driver) { - ata_getparam(&ch->device[SLAVE], ATA_C_ATA_IDENTIFY); - ad_reinit(&ch->device[SLAVE]); - } - if (newdev & ATA_ATA_MASTER && !ch->device[MASTER].driver) { - ATA_UNLOCK_CH(ch); - ad_attach(&ch->device[MASTER]); - ATA_SLEEPLOCK_CH(ch, ATA_CONTROL); - } - else if (ch->devices & ATA_ATA_MASTER && ch->device[MASTER].driver) { - ata_getparam(&ch->device[MASTER], ATA_C_ATA_IDENTIFY); - ad_reinit(&ch->device[MASTER]); - } + else + ch->device[MASTER].attach = ad_attach; #endif -#if DEV_ATAPIALL - if (newdev & ATA_ATAPI_SLAVE && !ch->device[SLAVE].driver) { - ATA_UNLOCK_CH(ch); - atapi_attach(&ch->device[SLAVE]); - ATA_SLEEPLOCK_CH(ch, ATA_CONTROL); - } - else if (ch->devices & (ATA_ATAPI_SLAVE) && ch->device[SLAVE].driver) { - ata_getparam(&ch->device[SLAVE], ATA_C_ATAPI_IDENTIFY); - atapi_reinit(&ch->device[SLAVE]); - } - if (newdev & ATA_ATAPI_MASTER && !ch->device[MASTER].driver) { - ATA_UNLOCK_CH(ch); - atapi_attach(&ch->device[MASTER]); - ATA_SLEEPLOCK_CH(ch, ATA_CONTROL); - } - else if (ch->devices & (ATA_ATAPI_MASTER) && ch->device[MASTER].driver) { - ata_getparam(&ch->device[MASTER], ATA_C_ATAPI_IDENTIFY); - atapi_reinit(&ch->device[MASTER]); } + if (ch->devices & ATA_ATAPI_MASTER) { + if (ata_getparam(&ch->device[MASTER], ATA_ATAPI_IDENTIFY)) + ch->devices &= ~ATA_ATAPI_MASTER; + else { + switch (ch->device[MASTER].param->config & ATA_ATAPI_TYPE_MASK) { +#ifdef DEV_ATAPICD + case ATA_ATAPI_TYPE_CDROM: + ch->device[MASTER].attach = acd_attach; + break; #endif -#ifdef DEV_ATAPICAM - atapi_cam_reinit_bus(ch); +#ifdef DEV_ATAPIFD + case ATA_ATAPI_TYPE_DIRECT: + ch->device[MASTER].attach = afd_attach; + break; #endif - printf("done\n"); - ATA_UNLOCK_CH(ch); - ata_start(ch); - return 0; -} - -static int -ata_service(struct ata_channel *ch) -{ - /* do we have a SERVICE request from the drive ? */ - if ((ch->status & (ATA_S_SERVICE|ATA_S_ERROR|ATA_S_DRQ)) == ATA_S_SERVICE) { -#if 0 /* XXX */ - ATA_IDX_OUTB(ch->r_bmio, ATA_BMSTAT_PORT, - ch->dma->status(ch) | ATA_BMSTAT_INTERRUPT); +#ifdef DEV_ATAPIST + case ATA_ATAPI_TYPE_TAPE: + ch->device[MASTER].attach = ast_attach; + break; #endif -#ifdef DEV_ATADISK - if ((ATA_IDX_INB(ch, ATA_DRIVE) & ATA_SLAVE) == ATA_MASTER) { - if ((ch->devices & ATA_ATA_MASTER) && ch->device[MASTER].driver) - return ad_service((struct ad_softc *) - ch->device[MASTER].driver, 0); - } - else { - if ((ch->devices & ATA_ATA_SLAVE) && ch->device[SLAVE].driver) - return ad_service((struct ad_softc *) - ch->device[SLAVE].driver, 0); + } } -#endif } - return ATA_OP_FINISHED; } -static void -ata_flush(struct ata_device *atadev) -{ - if (ata_command(atadev, ATA_C_FLUSHCACHE, 0, 0, 0, ATA_WAIT_READY)) - ata_prtdev(atadev, "flushing device failed\n"); -} - -static void -ata_shutdown(void *arg, int howto) +static void +ata_boot_attach(void) { struct ata_channel *ch; int ctlr; - /* flush cache on all devices */ - for (ctlr = 0; ctlr < devclass_get_maxunit(ata_devclass); 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; ctlr<devclass_get_maxunit(ata_devclass); ctlr++) { if (!(ch = devclass_get_softc(ata_devclass, ctlr))) continue; - ch->locking(ch, ATA_LF_LOCK); - if (ch->device[MASTER].param) - ata_flush(&ch->device[MASTER]); - if (ch->device[SLAVE].param) - ata_flush(&ch->device[SLAVE]); - ch->locking(ch, ATA_LF_UNLOCK); - } -} - -int -ata_wait(struct ata_device *atadev, u_int8_t mask) -{ - int timeout = 0; - - DELAY(1); - while (timeout < 5000000) { /* timeout 5 secs */ - atadev->channel->status = ATA_IDX_INB(atadev->channel, ATA_STATUS); - - /* if drive fails status, reselect the drive just to be sure */ - if (atadev->channel->status == 0xff) { - ata_prtdev(atadev, "no status, reselecting device\n"); - ATA_IDX_OUTB(atadev->channel, ATA_DRIVE, ATA_D_IBM|atadev->unit); - DELAY(10); - atadev->channel->status = ATA_IDX_INB(atadev->channel, ATA_STATUS); - if (atadev->channel->status == 0xff) - return -1; - } - - /* are we done ? */ - if (!(atadev->channel->status & ATA_S_BUSY)) - break; - - if (timeout > 1000) { - timeout += 1000; - DELAY(1000); - } - else { - timeout += 10; - DELAY(10); - } - } - if (atadev->channel->status & ATA_S_ERROR) - atadev->channel->error = ATA_IDX_INB(atadev->channel, ATA_ERROR); - if (timeout >= 5000000) - return -1; - if (!mask) - return (atadev->channel->status & ATA_S_ERROR); - - /* Wait 50 msec for bits wanted. */ - timeout = 5000; - while (timeout--) { - atadev->channel->status = ATA_IDX_INB(atadev->channel, ATA_STATUS); - if ((atadev->channel->status & mask) == mask) { - if (atadev->channel->status & ATA_S_ERROR) - atadev->channel->error=ATA_IDX_INB(atadev->channel, ATA_ERROR); - return (atadev->channel->status & ATA_S_ERROR); - } - DELAY (10); - } - return -1; -} - -int -ata_command(struct ata_device *atadev, u_int8_t command, - u_int64_t lba, u_int16_t count, u_int16_t feature, int flags) -{ - int error = 0; -#ifdef ATA_DEBUG - ata_prtdev(atadev, "ata_command: addr=%04lx, cmd=%02x, " - "lba=%jd, count=%d, feature=%d, flags=%02x\n", - rman_get_start(atadev->channel->r_io[ATA_DATA].res), - command, (intmax_t)lba, count, feature, flags); + ata_identify_devices(ch); + if (ch->device[MASTER].attach) + ch->device[MASTER].attach(&ch->device[MASTER]); + if (ch->device[SLAVE].attach) + ch->device[SLAVE].attach(&ch->device[SLAVE]); +#ifdef DEV_ATAPICAM + atapi_cam_attach_bus(ch); #endif - - /* select device */ - ATA_IDX_OUTB(atadev->channel, ATA_DRIVE, ATA_D_IBM | atadev->unit); - - /* disable interrupt from device */ - if (atadev->channel->flags & ATA_QUEUED) - ATA_IDX_OUTB(atadev->channel, ATA_ALTSTAT, ATA_A_IDS | ATA_A_4BIT); - - /* ready to issue command ? */ - if (ata_wait(atadev, 0) < 0) { - ata_prtdev(atadev, "timeout sending command=%02x s=%02x e=%02x\n", - command, atadev->channel->status, atadev->channel->error); - return -1; } - - /* only use 48bit addressing if needed because of the overhead */ - if ((lba > 268435455 || count > 256) && atadev->param && - atadev->param->support.address48) { - ATA_IDX_OUTB(atadev->channel, ATA_FEATURE, (feature>>8) & 0xff); - ATA_IDX_OUTB(atadev->channel, ATA_FEATURE, feature); - ATA_IDX_OUTB(atadev->channel, ATA_COUNT, (count>>8) & 0xff); - ATA_IDX_OUTB(atadev->channel, ATA_COUNT, count & 0xff); - ATA_IDX_OUTB(atadev->channel, ATA_SECTOR, (lba>>24) & 0xff); - ATA_IDX_OUTB(atadev->channel, ATA_SECTOR, lba & 0xff); - ATA_IDX_OUTB(atadev->channel, ATA_CYL_LSB, (lba>>32) & 0xff); - ATA_IDX_OUTB(atadev->channel, ATA_CYL_LSB, (lba>>8) & 0xff); - ATA_IDX_OUTB(atadev->channel, ATA_CYL_MSB, (lba>>40) & 0xff); - ATA_IDX_OUTB(atadev->channel, ATA_CYL_MSB, (lba>>16) & 0xff); - ATA_IDX_OUTB(atadev->channel, ATA_DRIVE, ATA_D_LBA | atadev->unit); - - /* 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_prtdev(atadev, "can't translate cmd to 48bit version\n"); - return -1; - } - atadev->channel->flags |= ATA_48BIT_ACTIVE; - } - else { - ATA_IDX_OUTB(atadev->channel, ATA_FEATURE, feature); - ATA_IDX_OUTB(atadev->channel, ATA_COUNT, count); - ATA_IDX_OUTB(atadev->channel, ATA_SECTOR, lba & 0xff); - ATA_IDX_OUTB(atadev->channel, ATA_CYL_LSB, (lba>>8) & 0xff); - ATA_IDX_OUTB(atadev->channel, ATA_CYL_MSB, (lba>>16) & 0xff); - if (atadev->flags & ATA_D_USE_CHS) - ATA_IDX_OUTB(atadev->channel, ATA_DRIVE, - ATA_D_IBM | atadev->unit | ((lba>>24) & 0xf)); - else - ATA_IDX_OUTB(atadev->channel, ATA_DRIVE, - ATA_D_IBM | ATA_D_LBA | atadev->unit | ((lba>>24) &0xf)); - atadev->channel->flags &= ~ATA_48BIT_ACTIVE; - } - - switch (flags & ATA_WAIT_MASK) { - case ATA_IMMEDIATE: - ATA_IDX_OUTB(atadev->channel, ATA_CMD, command); - - /* enable interrupt */ - if (atadev->channel->flags & ATA_QUEUED) - ATA_IDX_OUTB(atadev->channel, ATA_ALTSTAT, ATA_A_4BIT); - break; - - case ATA_WAIT_INTR: - atadev->channel->active |= ATA_WAIT_INTR; - ATA_IDX_OUTB(atadev->channel, ATA_CMD, command); - - /* enable interrupt */ - if (atadev->channel->flags & ATA_QUEUED) - ATA_IDX_OUTB(atadev->channel, ATA_ALTSTAT, ATA_A_4BIT); - - if (tsleep(atadev->channel, PRIBIO, "atacmd", 10 * hz)) { - ata_prtdev(atadev, "timeout waiting for interrupt\n"); - atadev->channel->active &= ~ATA_WAIT_INTR; - error = -1; - } - break; - - case ATA_WAIT_READY: - atadev->channel->active |= ATA_WAIT_READY; - ATA_IDX_OUTB(atadev->channel, ATA_CMD, command); - if (ata_wait(atadev, ATA_S_READY) < 0) { - ata_prtdev(atadev, "timeout waiting for cmd=%02x s=%02x e=%02x\n", - command, atadev->channel->status,atadev->channel->error); - error = -1; - } - atadev->channel->active &= ~ATA_WAIT_READY; - break; +#ifdef DEV_ATARAID + ata_raid_attach(); +#endif + if (ata_delayed_attach) { + config_intrhook_disestablish(ata_delayed_attach); + free(ata_delayed_attach, M_TEMP); + ata_delayed_attach = NULL; } - return error; -} - -static void -ata_enclosure_start(struct ata_device *atadev) -{ - ATA_IDX_INB(atadev->channel, ATA_DRIVE); - DELAY(1); - ATA_IDX_INB(atadev->channel, ATA_DRIVE); - DELAY(1); - ATA_IDX_INB(atadev->channel, ATA_CMD); - DELAY(1); - ATA_IDX_OUTB(atadev->channel, ATA_DRIVE, ATA_D_IBM | atadev->unit); - DELAY(1); - ATA_IDX_OUTB(atadev->channel, ATA_DRIVE, ATA_D_IBM | atadev->unit); - DELAY(1); - ATA_IDX_OUTB(atadev->channel, ATA_DRIVE, ATA_D_IBM | atadev->unit); - DELAY(1); - ATA_IDX_INB(atadev->channel, ATA_COUNT); - DELAY(1); - ATA_IDX_INB(atadev->channel, ATA_DRIVE); - DELAY(1); -} - -static void -ata_enclosure_end(struct ata_device *atadev) -{ - ATA_IDX_OUTB(atadev->channel, ATA_DRIVE, ATA_D_IBM | atadev->unit); - DELAY(1); } +/* + * misc support functions + */ static void -ata_enclosure_chip_start(struct ata_device *atadev) +bswap(int8_t *buf, int len) { - ATA_IDX_OUTB(atadev->channel, ATA_SECTOR, 0x0b); - ATA_IDX_OUTB(atadev->channel, ATA_SECTOR, 0x0a); - DELAY(25); - ATA_IDX_OUTB(atadev->channel, ATA_SECTOR, 0x08); + u_int16_t *ptr = (u_int16_t*)(buf + len); + + while (--ptr >= (u_int16_t*)buf) + *ptr = ntohs(*ptr); } static void -ata_enclosure_chip_end(struct ata_device *atadev) -{ - ATA_IDX_OUTB(atadev->channel, ATA_SECTOR, 0x08); - DELAY(64); - ATA_IDX_OUTB(atadev->channel, ATA_SECTOR, 0x0a); - DELAY(25); - ATA_IDX_OUTB(atadev->channel, ATA_SECTOR, 0x0b); - DELAY(64); -} +btrim(int8_t *buf, int len) +{ + int8_t *ptr; -static u_int8_t -ata_enclosure_chip_rdbit(struct ata_device *atadev) -{ - u_int8_t val; - - ATA_IDX_OUTB(atadev->channel, ATA_SECTOR, 0); - DELAY(64); - ATA_IDX_OUTB(atadev->channel, ATA_SECTOR, 0x02); - DELAY(25); - val = ATA_IDX_INB(atadev->channel, ATA_SECTOR) & 0x01; - DELAY(38); - return val; + for (ptr = buf; ptr < buf+len; ++ptr) + if (!*ptr) + *ptr = ' '; + for (ptr = buf + len - 1; ptr >= buf && *ptr == ' '; --ptr) + *ptr = 0; } static void -ata_enclosure_chip_wrbit(struct ata_device *atadev, u_int8_t data) -{ - ATA_IDX_OUTB(atadev->channel, ATA_SECTOR, 0x08 | (data & 0x01)); - DELAY(64); - ATA_IDX_OUTB(atadev->channel, ATA_SECTOR, 0x08 | 0x02 | (data & 0x01)); - DELAY(64); -} - -static u_int8_t -ata_enclosure_chip_rw(struct ata_device *atadev, int rw, u_int8_t val) -{ - int i; - - if (rw) { - for (i = 0; i < 8; i++) - ata_enclosure_chip_wrbit(atadev, (val & (0x80 >> i)) ? 1 : 0); - } - else { - for (i = 0; i < 8; i++) - val = (val << 1) | ata_enclosure_chip_rdbit(atadev); - } - ata_enclosure_chip_wrbit(atadev, 0); - return val; -} - -static u_int8_t -ata_enclosure_sensor(struct ata_device *atadev, - int rw, u_int8_t idx, u_int8_t data) +bpack(int8_t *src, int8_t *dst, int len) { - ata_enclosure_start(atadev); - ata_enclosure_chip_start(atadev); - ata_enclosure_chip_rw(atadev, 1, 0x5a); - ata_enclosure_chip_rw(atadev, 1, idx); - if (rw) { - ata_enclosure_chip_rw(atadev, 1, data); - } - else { - ata_enclosure_chip_end(atadev); - ata_enclosure_chip_start(atadev); - ata_enclosure_chip_rw(atadev, 1, 0x5b); - data = ata_enclosure_chip_rw(atadev, 0, 0); - } - ata_enclosure_chip_end(atadev); - ata_enclosure_end(atadev); - return data; -} + int i, j, blank; -static int -ata_enclosure_status(struct ata_device *atadev, - int *fan, int *temp, int *v05, int *v12) -{ - u_int8_t id1, id2, cnt, div; - int error = ENXIO; - - if (atadev->flags & ATA_D_ENC_PRESENT) { - atadev->channel->locking(atadev->channel, ATA_LF_LOCK); - ATA_SLEEPLOCK_CH(atadev->channel, ATA_CONTROL); - ata_enclosure_sensor(atadev, 1, 0x4e, 0); - id1 = ata_enclosure_sensor(atadev, 0, 0x4f, 0); - ata_enclosure_sensor(atadev, 1, 0x4e, 0x80); - id2 = ata_enclosure_sensor(atadev, 0, 0x4f, 0); - if (id1 == 0xa3 && id2 == 0x5c) { - div = 1 << (((ata_enclosure_sensor(atadev, 0, 0x5d, 0)&0x20)>>3)+ - ((ata_enclosure_sensor(atadev, 0, 0x47, 0)&0x30)>>4)+1); - cnt = ata_enclosure_sensor(atadev, 0, 0x28, 0); - if (cnt == 0xff) - *fan = 0; - else - *fan = 1350000 / cnt / div; - ata_enclosure_sensor(atadev, 1, 0x4e, 0x01); - *temp = (ata_enclosure_sensor(atadev, 0, 0x50, 0) * 10) + - (ata_enclosure_sensor(atadev, 0, 0x50, 0) & 0x80 ? 5 : 0); - *v05 = ata_enclosure_sensor(atadev, 0, 0x23, 0) * 27; - *v12 = ata_enclosure_sensor(atadev, 0, 0x24, 0) * 61; - error = 0; + for (i = j = blank = 0 ; i < len; i++) { + if (blank && src[i] == ' ') continue; + if (blank && src[i] != ' ') { + dst[j++] = src[i]; + blank = 0; + continue; } - ATA_UNLOCK_CH(atadev->channel); - atadev->channel->locking(atadev->channel, ATA_LF_UNLOCK); - } - return error; -} - -void -ata_enclosure_print(struct ata_device *atadev) -{ - u_int8_t id, st; - int fan, temp, v05, v12; - - atadev->channel->locking(atadev->channel, ATA_LF_LOCK); - ATA_SLEEPLOCK_CH(atadev->channel, ATA_CONTROL); - ata_enclosure_start(atadev); - id = ATA_IDX_INB(atadev->channel, ATA_DRIVE); - DELAY(1); - st = ATA_IDX_INB(atadev->channel, ATA_COUNT); - DELAY(1); - ata_enclosure_end(atadev); - ATA_UNLOCK_CH(atadev->channel); - atadev->channel->locking(atadev->channel, ATA_LF_UNLOCK); - - switch (id & 0x93) { - case 0x00: - ata_prtdev(atadev, "Universal enclosure"); - break; - case 0x01: - ata_prtdev(atadev, "FastSwap enclosure"); - break; - case 0x10: - case 0x11: - ata_prtdev(atadev, "SuperSwap enclosure"); - break; - default: - atadev->flags &= ~ATA_D_ENC_PRESENT; - return; - } - atadev->flags |= ATA_D_ENC_PRESENT; - - ata_enclosure_leds(atadev, ATA_LED_GREEN); - if (ata_enclosure_status(atadev, &fan, &temp, &v05, &v12)) - printf(" detected\n"); - else - printf(" [FAN:%drpm TEMP:%d.%01dC %d.%03dV %d.%03dV]\n", - fan, temp/10, temp%10, v05/1000, v05%1000, v12/1000, v12%1000); -} - -void -ata_enclosure_leds(struct ata_device *atadev, u_int8_t color) -{ - if (atadev->flags & ATA_D_ENC_PRESENT) { - u_int8_t reg; - - ata_enclosure_start(atadev); - reg = ATA_IDX_INB(atadev->channel, ATA_COUNT); - DELAY(1); - ATA_IDX_OUTB(atadev->channel, ATA_COUNT, - (color & ATA_LED_MASK) | (reg & ~ATA_LED_MASK)); - DELAY(1); - ata_enclosure_end(atadev); + if (src[i] == ' ') { + blank = 1; + if (i == 0) + continue; + } + dst[j++] = src[i]; } -} - -static void -ata_change_mode(struct ata_device *atadev, int mode) -{ - ATA_SLEEPLOCK_CH(atadev->channel, ATA_ACTIVE); - atadev->setmode(atadev, mode); - ATA_UNLOCK_CH(atadev->channel); - ata_start(atadev->channel); + if (j < len) + dst[j] = 0x00; } int @@ -1465,13 +822,13 @@ ata_pmode(struct ata_params *ap) if (ap->apiomodes & 0x01) return ATA_PIO3; } - if (ap->retired_piomode == 2) + if ((ap->retired_piomode & ATA_RETIRED_PIO_MASK) == 2) return ATA_PIO2; - if (ap->retired_piomode == 1) + if ((ap->retired_piomode & ATA_RETIRED_PIO_MASK) == 1) return ATA_PIO1; - if (ap->retired_piomode == 0) + if ((ap->retired_piomode & ATA_RETIRED_PIO_MASK) == 0) return ATA_PIO0; - if (ap->support_dma) + if (ap->capabilities1 & ATA_SUPPORT_DMA) return ATA_PIO4; return ATA_PIO0; } @@ -1485,7 +842,7 @@ ata_wmode(struct ata_params *ap) return ATA_WDMA1; if (ap->mwdmamodes & 0x01) return ATA_WDMA0; - if (ap->support_dma) + if (ap->capabilities1 & ATA_SUPPORT_DMA) return ATA_WDMA2; return -1; } @@ -1531,50 +888,6 @@ ata_limit_mode(struct ata_device *atadev, int mode, int maxmode) } 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_init(void) { /* register controlling device */ |