diff options
Diffstat (limited to 'sys')
29 files changed, 3563 insertions, 3934 deletions
diff --git a/sys/conf/NOTES b/sys/conf/NOTES index 6ab503633aad..05fcfe972876 100644 --- a/sys/conf/NOTES +++ b/sys/conf/NOTES @@ -2352,14 +2352,10 @@ options KSTACK_MAX_PAGES=32 # Maximum pages to give the kernel stack # Yet more undocumented options for linting. options AAC_DEBUG -options ACD_DEBUG options ACPI_MAX_THREADS=1 #!options ACPI_NO_SEMAPHORES # Broken: ##options ASR_MEASURE_PERFORMANCE -options AST_DEBUG -options ATAPI_DEBUG -options ATA_DEBUG # BKTR_ALLOC_PAGES has no effect except to cause warnings, and # BROOKTREE_ALLOC_PAGES hasn't actually been superseded by it, since the # driver still mostly spells this option BROOKTREE_ALLOC_PAGES. diff --git a/sys/conf/files b/sys/conf/files index abda8dc81c57..ab7788d3240a 100644 --- a/sys/conf/files +++ b/sys/conf/files @@ -302,6 +302,8 @@ dev/an/if_an_pccard.c optional an pccard dev/an/if_an_pci.c optional an pci dev/asr/asr.c optional asr pci dev/ata/ata-all.c optional ata +dev/ata/ata-queue.c optional ata +dev/ata/ata-lowlevel.c optional ata dev/ata/ata-isa.c optional ata isa dev/ata/ata-cbus.c optional ata pc98 dev/ata/ata-card.c optional ata card @@ -310,11 +312,7 @@ dev/ata/ata-pci.c optional ata pci dev/ata/ata-chipset.c optional ata pci dev/ata/ata-dma.c optional ata pci dev/ata/ata-disk.c optional atadisk -dev/ata/ata-raid.c optional atadisk -dev/ata/atapi-all.c optional atapicd -dev/ata/atapi-all.c optional atapifd -dev/ata/atapi-all.c optional atapist -dev/ata/atapi-all.c optional atapicam +dev/ata/ata-raid.c optional ataraid dev/ata/atapi-cd.c optional atapicd dev/ata/atapi-fd.c optional atapifd dev/ata/atapi-tape.c optional atapist diff --git a/sys/conf/options b/sys/conf/options index 3a1ed5e18477..29fc4755b43f 100644 --- a/sys/conf/options +++ b/sys/conf/options @@ -297,13 +297,10 @@ ISP_TARGET_MODE opt_isp.h ISP_FW_CRASH_DUMP opt_isp.h # Options used in the 'ata' ATA/ATAPI driver -ACD_DEBUG opt_ata.h -AST_DEBUG opt_ata.h -ATAPI_DEBUG opt_ata.h -ATA_DEBUG opt_ata.h ATA_STATIC_ID opt_ata.h ATA_NOPCI opt_ata.h DEV_ATADISK opt_ata.h +DEV_ATARAID opt_ata.h DEV_ATAPICD opt_ata.h DEV_ATAPIST opt_ata.h DEV_ATAPIFD opt_ata.h diff --git a/sys/dev/ata/ata-all.c b/sys/dev/ata/ata-all.c index cb7762260092..8d0923a11ab7 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 */ diff --git a/sys/dev/ata/ata-all.h b/sys/dev/ata/ata-all.h index 44cb042e2b82..99ec220eddb9 100644 --- a/sys/dev/ata/ata-all.h +++ b/sys/dev/ata/ata-all.h @@ -30,7 +30,9 @@ /* ATA register defines */ #define ATA_DATA 0x00 /* data register */ + #define ATA_ERROR 0x01 /* (R) error register */ +#define ATA_E_ILI 0x01 /* illegal length */ #define ATA_E_NM 0x02 /* no media */ #define ATA_E_ABORT 0x04 /* command aborted */ #define ATA_E_MCR 0x08 /* media change request */ @@ -38,6 +40,24 @@ #define ATA_E_MC 0x20 /* media changed */ #define ATA_E_UNC 0x40 /* uncorrectable data */ #define ATA_E_ICRC 0x80 /* UDMA crc error */ +#define ATA_E_MASK 0x0f /* error mask */ +#define ATA_SK_MASK 0xf0 /* sense key mask */ +#define ATA_SK_NO_SENSE 0x00 /* no specific sense key info */ +#define ATA_SK_RECOVERED_ERROR 0x10 /* command OK, data recovered */ +#define ATA_SK_NOT_READY 0x20 /* no access to drive */ +#define ATA_SK_MEDIUM_ERROR 0x30 /* non-recovered data error */ +#define ATA_SK_HARDWARE_ERROR 0x40 /* non-recoverable HW failure */ +#define ATA_SK_ILLEGAL_REQUEST 0x50 /* invalid command param(s) */ +#define ATA_SK_UNIT_ATTENTION 0x60 /* media changed */ +#define ATA_SK_DATA_PROTECT 0x70 /* write protect */ +#define ATA_SK_BLANK_CHECK 0x80 /* blank check */ +#define ATA_SK_VENDOR_SPECIFIC 0x90 /* vendor specific skey */ +#define ATA_SK_COPY_ABORTED 0xa0 /* copy aborted */ +#define ATA_SK_ABORTED_COMMAND 0xb0 /* command aborted, try again */ +#define ATA_SK_EQUAL 0xc0 /* equal */ +#define ATA_SK_VOLUME_OVERFLOW 0xd0 /* volume overflow */ +#define ATA_SK_MISCOMPARE 0xe0 /* data dont match the medium */ +#define ATA_SK_RESERVED 0xf0 #define ATA_FEATURE 0x01 /* (W) feature register */ #define ATA_F_DMA 0x01 /* enable DMA */ @@ -58,44 +78,6 @@ #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 */ @@ -117,6 +99,16 @@ #define ATA_A_RESET 0x04 /* RESET controller */ #define ATA_A_4BIT 0x08 /* 4 head bits */ +/* ATAPI misc defines */ +#define ATAPI_MAGIC_LSB 0x14 +#define ATAPI_MAGIC_MSB 0xeb +#define ATAPI_P_READ (ATA_S_DRQ | ATA_I_IN) +#define ATAPI_P_WRITE (ATA_S_DRQ) +#define ATAPI_P_CMDOUT (ATA_S_DRQ | ATA_I_CMD) +#define ATAPI_P_DONEDRQ (ATA_S_DRQ | ATA_I_CMD | ATA_I_IN) +#define ATAPI_P_DONE (ATA_I_CMD | ATA_I_IN) +#define ATAPI_P_ABORT 0 + /* misc defines */ #define ATA_PRIMARY 0x1f0 #define ATA_SECONDARY 0x170 @@ -126,8 +118,6 @@ #define ATA_ALTIOSIZE 0x01 #define ATA_BMIOSIZE 0x08 #define ATA_PC98_BANKIOSIZE 0x01 -#define ATA_OP_FINISHED 0x00 -#define ATA_OP_CONTINUES 0x01 #define ATA_IOADDR_RID 0 #define ATA_ALTADDR_RID 1 #define ATA_BMADDR_RID 0x20 @@ -163,22 +153,72 @@ #define ATA_IDX_DATA 0x0f #define ATA_MAX_RES 0x10 -/* structure for holding DMA address data */ -struct ata_dmaentry { - u_int32_t base; - u_int32_t count; -}; +#define ATA_INTR_FLAGS (INTR_MPSAFE|INTR_TYPE_BIO|INTR_ENTROPY) +#define ATA_OP_CONTINUES 0 +#define ATA_OP_FINISHED 1 + +struct ata_request { + struct ata_device *device; /* ptr to device softc */ + void *driver; /* driver specific */ + + union { + struct { + u_int8_t command; /* command reg */ + u_int8_t feature; /* feature reg */ + u_int64_t lba; /* lba reg */ + u_int16_t count; /* count reg */ + } ata; + struct { + u_int8_t ccb[16]; /* ATAPI command block */ + } atapi; + } u; + + u_int8_t status; /* ATA status */ + u_int8_t error; /* ATA error */ + u_int8_t dmastat; /* DMA status */ + + u_int32_t bytecount; /* bytes to transfer */ + u_int32_t transfersize; /* bytes pr transfer */ + u_int32_t donecount; /* bytes transferred */ + caddr_t data; /* pointer to data buf */ + int flags; +#define ATA_R_DONE 0x0001 +#define ATA_R_CONTROL 0x0002 +#define ATA_R_READ 0x0004 +#define ATA_R_WRITE 0x0008 + +#define ATA_R_ATAPI 0x0010 +#define ATA_R_QUIET 0x0020 +#define ATA_R_DMA 0x0040 + +#define ATA_R_ORDERED 0x0100 +#define ATA_R_AT_HEAD 0x0200 +#define ATA_R_REQUEUE 0x0400 +#define ATA_R_SKIPSTART 0x0800 + + void (*callback)(struct ata_request *); + int retries; /* retry count */ + int timeout; /* timeout for this cmd */ + struct callout_handle timeout_handle; /* handle for untimeout */ + int result; /* result error code */ + struct task task; /* task management */ + TAILQ_ENTRY(ata_request) sequence; /* sequence management */ + TAILQ_ENTRY(ata_request) chain; /* list management */ +}; /* structure describing an ATA/ATAPI device */ struct ata_device { struct ata_channel *channel; int unit; /* unit number */ -#define ATA_MASTER 0x00 -#define ATA_SLAVE 0x10 +#define ATA_MASTER 0x00 +#define ATA_SLAVE 0x10 char *name; /* device name */ struct ata_params *param; /* ata param structure */ - void *driver; /* ptr to driver for device */ + void *softc; /* ptr to softc for device */ + void (*attach)(struct ata_device *); + void (*detach)(struct ata_device *); + void (*start)(struct ata_device *); int flags; #define ATA_D_USE_CHS 0x0001 #define ATA_D_DETACHING 0x0002 @@ -186,13 +226,18 @@ struct ata_device { #define ATA_D_ENC_PRESENT 0x0008 int cmd; /* last cmd executed */ - void *result; /* misc data */ int mode; /* transfermode */ void (*setmode)(struct ata_device *, int); }; +/* structure for holding DMA address data */ +struct ata_dmaentry { + u_int32_t base; + u_int32_t count; +}; + /* structure holding DMA related information */ -struct ata_dma_data { +struct ata_dma { bus_dma_tag_t dmatag; /* parent DMA tag */ bus_dma_tag_t cdmatag; /* control DMA tag */ bus_dmamap_t cdmamap; /* control DMA map */ @@ -200,7 +245,8 @@ struct ata_dma_data { bus_dmamap_t ddmamap; /* data DMA map */ struct ata_dmaentry *dmatab; /* DMA transfer table */ bus_addr_t mdmatab; /* bus address of dmatab */ - u_int32_t alignment; /* DMA engine alignment */ + u_int32_t alignment; /* DMA engine alignment */ + u_int32_t max_iosize; /* DMA engine max IO size */ int flags; #define ATA_DMA_ACTIVE 0x01 /* DMA transfer in progress */ #define ATA_DMA_READ 0x02 /* transaction is a read */ @@ -212,6 +258,13 @@ struct ata_dma_data { int (*stop)(struct ata_channel *); }; +/* structure holding lowlevel functions */ +struct ata_lowlevel { + void (*reset)(struct ata_channel *); + int (*transaction)(struct ata_request *); + void (*interrupt)(void *); +}; + /* structure holding resources for an ATA channel */ struct ata_resource { struct resource *res; @@ -225,15 +278,14 @@ struct ata_channel { struct ata_resource r_io[ATA_MAX_RES];/* I/O resources */ struct resource *r_irq; /* interrupt of this channel */ void *ih; /* interrupt handle */ - struct ata_dma_data *dma; /* DMA data / functions */ - u_int32_t chiptype; /* controller chip PCI id */ + struct ata_lowlevel hw; /* lowlevel HW functions */ + struct ata_dma *dma; /* DMA data / functions */ int flags; /* channel flags */ #define ATA_NO_SLAVE 0x01 #define ATA_USE_16BIT 0x02 #define ATA_USE_PC98GEOM 0x04 #define ATA_ATAPI_DMA_RO 0x08 -#define ATA_QUEUED 0x10 -#define ATA_48BIT_ACTIVE 0x20 +#define ATA_48BIT_ACTIVE 0x10 struct ata_device device[2]; /* devices on this channel */ #define MASTER 0x00 @@ -245,28 +297,42 @@ struct ata_channel { #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; /* ATA channel state control */ + int state; /* ATA channel state control */ #define ATA_IDLE 0x0000 -#define ATA_IMMEDIATE 0x0001 -#define ATA_WAIT_INTR 0x0002 -#define ATA_WAIT_READY 0x0004 -#define ATA_WAIT_MASK 0x0007 -#define ATA_ACTIVE 0x0010 -#define ATA_ACTIVE_ATA 0x0020 -#define ATA_ACTIVE_ATAPI 0x0040 -#define ATA_CONTROL 0x0080 +#define ATA_ACTIVE 0x0001 +#define ATA_CONTROL 0x0002 void (*locking)(struct ata_channel *, int); #define ATA_LF_LOCK 0x0001 #define ATA_LF_UNLOCK 0x0002 - TAILQ_HEAD(, ad_request) ata_queue; /* head of ATA queue */ - TAILQ_HEAD(, atapi_request) atapi_queue; /* head of ATAPI queue */ + struct mtx queue_mtx; + TAILQ_HEAD(, ata_request) ata_queue; /* head of ATA queue */ void *running; /* currently running request */ }; +/* ATAPI request sense structure */ +struct atapi_sense { + u_int8_t error_code :7; /* current or deferred errors */ + u_int8_t valid :1; /* follows ATAPI spec */ + u_int8_t segment; /* Segment number */ + u_int8_t sense_key :4; /* sense key */ + u_int8_t reserved2_4 :1; /* reserved */ + u_int8_t ili :1; /* incorrect length indicator */ + u_int8_t eom :1; /* end of medium */ + u_int8_t filemark :1; /* filemark */ + u_int32_t cmd_info __packed; /* cmd information */ + u_int8_t sense_length; /* additional sense len (n-7) */ + u_int32_t cmd_specific_info __packed; /* additional cmd spec info */ + u_int8_t asc; /* additional sense code */ + u_int8_t ascq; /* additional sense code qual */ + u_int8_t replaceable_unit_code; /* replaceable unit code */ + u_int8_t sk_specific :7; /* sense key specific */ + u_int8_t sksv :1; /* sense key specific info OK */ + u_int8_t sk_specific1; /* sense key specific */ + u_int8_t sk_specific2; /* sense key specific */ +}; + /* disk bay/enclosure related */ #define ATA_LED_OFF 0x00 #define ATA_LED_RED 0x01 @@ -277,20 +343,15 @@ struct ata_channel { /* externs */ extern devclass_t ata_devclass; extern struct intr_config_hook *ata_delayed_attach; +extern int ata_dma, ata_wc, atapi_dma; /* public prototypes */ +/* ata-all.c: */ int ata_probe(device_t); int ata_attach(device_t); int ata_detach(device_t); int ata_suspend(device_t); int ata_resume(device_t); -void ata_start(struct ata_channel *); -void ata_reset(struct ata_channel *); -int ata_reinit(struct ata_channel *); -int ata_wait(struct ata_device *, u_int8_t); -int ata_command(struct ata_device *, u_int8_t, u_int64_t, u_int16_t, u_int16_t, int); -void ata_enclosure_leds(struct ata_device *, u_int8_t); -void ata_enclosure_print(struct ata_device *); int ata_printf(struct ata_channel *, int, const char *, ...) __printflike(3, 4); int ata_prtdev(struct ata_device *, const char *, ...) __printflike(2, 3); void ata_set_name(struct ata_device *, char *, int); @@ -299,22 +360,45 @@ 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_pmode(struct ata_params *); -int ata_wmode(struct ata_params *); -int ata_umode(struct ata_params *); -int ata_limit_mode(struct ata_device *, int, int); +int ata_pmode(struct ata_params *ap); +int ata_wmode(struct ata_params *ap); +int ata_umode(struct ata_params *ap); +int ata_limit_mode(struct ata_device *atadev, int mode, int maxmode); + +/* ata-queue.c: */ +int ata_reinit(struct ata_channel *ch); +void ata_start(struct ata_channel *ch); +struct ata_request *ata_alloc_request(void); +void ata_free_request(struct ata_request *request); +int ata_controlcmd(struct ata_device *atadev, u_int8_t command, u_int16_t feature, u_int64_t lba, u_int16_t count); +int ata_atapicmd(struct ata_device *atadev, u_int8_t *ccb, caddr_t data, int count, int flags, int timeout); +void ata_queue_request(struct ata_request *request); +void ata_finish(struct ata_request *request); +char *ata_cmd2str(struct ata_request *request); + +/* ata-lowlevel.c: */ +void ata_generic_hw(struct ata_channel *ch); + +/* subdrivers */ +void ad_attach(struct ata_device *); +void acd_attach(struct ata_device *); +void afd_attach(struct ata_device *); +void ast_attach(struct ata_device *); +void atapi_cam_attach_bus(struct ata_channel *); +void atapi_cam_detach_bus(struct ata_channel *); +void atapi_cam_reinit_bus(struct ata_channel *); /* macros for locking a channel */ #define ATA_LOCK_CH(ch, value) \ - atomic_cmpset_acq_int(&(ch)->active, ATA_IDLE, (value)) + atomic_cmpset_acq_int(&(ch)->state, ATA_IDLE, (value)) #define ATA_SLEEPLOCK_CH(ch, value) \ - while (!atomic_cmpset_acq_int(&(ch)->active, ATA_IDLE, (value))) \ + while (!atomic_cmpset_acq_int(&(ch)->state, ATA_IDLE, (value))) \ tsleep((caddr_t)&(ch), PRIBIO, "atalck", 1); -#define ATA_FORCELOCK_CH(ch, value) atomic_store_rel_int(&(ch)->active, (value)) +#define ATA_FORCELOCK_CH(ch, value) atomic_store_rel_int(&(ch)->state, (value)) -#define ATA_UNLOCK_CH(ch) atomic_store_rel_int(&(ch)->active, ATA_IDLE) +#define ATA_UNLOCK_CH(ch) atomic_store_rel_int(&(ch)->state, ATA_IDLE) /* macros to hide busspace uglyness */ #define ATA_INB(res, offset) \ diff --git a/sys/dev/ata/ata-card.c b/sys/dev/ata/ata-card.c index 1f4ba3a91fb1..198992af68f9 100644 --- a/sys/dev/ata/ata-card.c +++ b/sys/dev/ata/ata-card.c @@ -35,6 +35,7 @@ #include <sys/module.h> #include <sys/bus.h> #include <sys/malloc.h> +#include <sys/taskqueue.h> #include <machine/stdarg.h> #include <machine/resource.h> #include <machine/bus.h> @@ -45,8 +46,6 @@ #include <dev/pccard/pccarddevs.h> static const struct pccard_product ata_pccard_products[] = { - /* NetBSD has a few others that need to migrate into pccarddevs */ - /* XXX */ PCMCIA_CARD(FREECOM, PCCARDIDE, 0), PCMCIA_CARD(EXP, EXPMULTIMEDIA, 0), PCMCIA_CARD(IODATA, CBIDE2, 0), @@ -72,7 +71,7 @@ ata_pccard_match(device_t dev) if (fcn == PCCARD_FUNCTION_DISK) return (0); - /* Match other devices here, primarily cdrom/dvd rom */ + /* match other devices here, primarily cdrom/dvd rom */ if ((pp = pccard_product_lookup(dev, ata_pccard_products, sizeof(ata_pccard_products[0]), NULL)) != NULL) { if (pp->pp_name) diff --git a/sys/dev/ata/ata-cbus.c b/sys/dev/ata/ata-cbus.c index 0bca3ab19b75..ae4411d7376a 100644 --- a/sys/dev/ata/ata-cbus.c +++ b/sys/dev/ata/ata-cbus.c @@ -35,6 +35,7 @@ #include <sys/ata.h> #include <sys/bus.h> #include <sys/malloc.h> +#include <sys/taskqueue.h> #include <machine/resource.h> #include <machine/bus.h> #include <sys/rman.h> diff --git a/sys/dev/ata/ata-chipset.c b/sys/dev/ata/ata-chipset.c index add97eacd93a..ac96d825d2f0 100644 --- a/sys/dev/ata/ata-chipset.c +++ b/sys/dev/ata/ata-chipset.c @@ -35,6 +35,7 @@ #include <sys/ata.h> #include <sys/bus.h> #include <sys/malloc.h> +#include <sys/taskqueue.h> #include <machine/stdarg.h> #include <machine/resource.h> #include <machine/bus.h> @@ -74,6 +75,8 @@ static int ata_highpoint_check_80pin(struct ata_device *, int); static int ata_intel_chipinit(device_t); static void ata_intel_old_setmode(struct ata_device *, int); static void ata_intel_new_setmode(struct ata_device *, int); +static int ata_national_chipinit(device_t); +static void ata_national_setmode(struct ata_device *, int); static int ata_nvidia_chipinit(device_t); static int ata_via_chipinit(device_t); static void ata_via_family_setmode(struct ata_device *, int); @@ -100,12 +103,12 @@ static void ata_sii_setmode(struct ata_device *, int); static void ata_cmd_setmode(struct ata_device *, int); static int ata_sis_chipinit(device_t); static void ata_sis_setmode(struct ata_device *, int); -static int ata_mode2idx(int); static int ata_check_80pin(struct ata_device *, int); static struct ata_chip_id *ata_find_chip(device_t, struct ata_chip_id *, int); static struct ata_chip_id *ata_match_chip(device_t, struct ata_chip_id *); -static int ata_default_interrupt(device_t); -static void ata_pci_serialize(struct ata_channel *, int); +static int ata_setup_interrupt(device_t); +static void ata_serialize(struct ata_channel *, int); +static int ata_mode2idx(int); /* generic or unknown ATA chipset init code */ int @@ -123,7 +126,7 @@ ata_generic_chipinit(device_t dev) { struct ata_pci_controller *ctlr = device_get_softc(dev); - if (ata_default_interrupt(dev)) + if (ata_setup_interrupt(dev)) return ENXIO; ctlr->setmode = ata_generic_setmode; return 0; @@ -155,11 +158,9 @@ ata_generic_intr(void *data) static void ata_generic_setmode(struct ata_device *atadev, int mode) { - if (mode >= ATA_DMA) - atadev->mode = ATA_DMA; - else - atadev->mode = ATA_PIO; - return; + mode = ata_check_80pin(atadev, mode); + if (!ata_controlcmd(atadev, ATA_SETFEATURES, ATA_SF_SETXFER, 0, mode)) + atadev->mode = mode; } /* @@ -200,14 +201,14 @@ ata_acard_chipinit(device_t dev) device_printf(dev, "unable to map interrupt\n"); return ENXIO; } - if ((bus_setup_intr(dev, ctlr->r_irq, INTR_TYPE_BIO | INTR_ENTROPY, + if ((bus_setup_intr(dev, ctlr->r_irq, ATA_INTR_FLAGS, ata_acard_intr, ctlr, &ctlr->handle))) { device_printf(dev, "unable to setup interrupt\n"); return ENXIO; } if (ctlr->chip->cfg1 == ATPOLD) { ctlr->setmode = ata_acard_850_setmode; - ctlr->locking = ata_pci_serialize; + ctlr->locking = ata_serialize; } else ctlr->setmode = ata_acard_86X_setmode; @@ -254,11 +255,10 @@ ata_acard_850_setmode(struct ata_device *atadev, int mode) /* XXX missing WDMA0+1 + PIO modes */ if (mode >= ATA_WDMA2) { - error = ata_command(atadev, ATA_C_SETFEATURES, 0, - mode, ATA_C_F_SETXFER, ATA_WAIT_READY); + error = ata_controlcmd(atadev, ATA_SETFEATURES, ATA_SF_SETXFER, 0,mode); if (bootverbose) - ata_prtdev(atadev, "%s setting %s on %s chip\n", - (error) ? "failed" : "success", + ata_prtdev(atadev, "%ssetting %s on %s chip\n", + (error) ? "FAILURE " : "", ata_mode2str(mode), ctlr->chip->text); if (!error) { u_int8_t reg54 = pci_read_config(parent, 0x54, 1); @@ -292,11 +292,10 @@ ata_acard_86X_setmode(struct ata_device *atadev, int mode) /* XXX missing WDMA0+1 + PIO modes */ if (mode >= ATA_WDMA2) { - error = ata_command(atadev, ATA_C_SETFEATURES, 0, - mode, ATA_C_F_SETXFER, ATA_WAIT_READY); + error = ata_controlcmd(atadev, ATA_SETFEATURES, ATA_SF_SETXFER, 0,mode); if (bootverbose) - ata_prtdev(atadev, "%s setting %s on %s chip\n", - (error) ? "failed" : "success", + ata_prtdev(atadev, "%ssetting %s on %s chip\n", + (error) ? "FAILURE " : "", ata_mode2str(mode), ctlr->chip->text); if (!error) { u_int16_t reg44 = pci_read_config(parent, 0x44, 2); @@ -345,7 +344,7 @@ ata_ali_chipinit(device_t dev) { struct ata_pci_controller *ctlr = device_get_softc(dev); - if (ata_default_interrupt(dev)) + if (ata_setup_interrupt(dev)) return ENXIO; /* deactivate the ATAPI FIFO and enable ATAPI UDMA */ @@ -390,11 +389,11 @@ ata_ali_setmode(struct ata_device *atadev, int mode) } } - error = ata_command(atadev, ATA_C_SETFEATURES, 0, mode, - ATA_C_F_SETXFER, ATA_WAIT_READY); + error = ata_controlcmd(atadev, ATA_SETFEATURES, ATA_SF_SETXFER, 0, mode); + if (bootverbose) - ata_prtdev(atadev, "%s setting %s on %s chip\n", - (error) ? "failed" : "success", + ata_prtdev(atadev, "%ssetting %s on %s chip\n", + (error) ? "FAILURE " : "", ata_mode2str(mode), ctlr->chip->text); if (!error) { if (mode >= ATA_UDMA0) { @@ -452,7 +451,7 @@ ata_amd_chipinit(device_t dev) { struct ata_pci_controller *ctlr = device_get_softc(dev); - if (ata_default_interrupt(dev)) + if (ata_setup_interrupt(dev)) return ENXIO; /* set prefetch, postwrite */ @@ -486,7 +485,7 @@ ata_cyrix_chipinit(device_t dev) { struct ata_pci_controller *ctlr = device_get_softc(dev); - if (ata_default_interrupt(dev)) + if (ata_setup_interrupt(dev)) return ENXIO; if (ctlr->r_io1) @@ -510,11 +509,11 @@ ata_cyrix_setmode(struct ata_device *atadev, int mode) mode = ata_limit_mode(atadev, mode, ATA_UDMA2); atadev->channel->dma->alignment = 16; - error = ata_command(atadev, ATA_C_SETFEATURES, 0, mode, - ATA_C_F_SETXFER, ATA_WAIT_READY); + error = ata_controlcmd(atadev, ATA_SETFEATURES, ATA_SF_SETXFER, 0, mode); + if (bootverbose) - ata_prtdev(atadev, "%s setting %s on Cyrix chip\n", - (error) ? "failed" : "success", ata_mode2str(mode)); + ata_prtdev(atadev, "%ssetting %s on Cyrix chip\n", + (error) ? "FAILURE " : "", ata_mode2str(mode)); if (!error) { if (mode >= ATA_UDMA0) { ATA_OUTL(ch->r_io[ATA_BMCMD_PORT].res, @@ -562,7 +561,7 @@ ata_cypress_chipinit(device_t dev) { struct ata_pci_controller *ctlr = device_get_softc(dev); - if (ata_default_interrupt(dev)) + if (ata_setup_interrupt(dev)) return ENXIO; ctlr->setmode = ata_cypress_setmode; @@ -579,11 +578,10 @@ ata_cypress_setmode(struct ata_device *atadev, int mode) /* XXX missing WDMA0+1 + PIO modes */ if (mode == ATA_WDMA2) { - error = ata_command(atadev, ATA_C_SETFEATURES, 0, mode, - ATA_C_F_SETXFER, ATA_WAIT_READY); + error = ata_controlcmd(atadev, ATA_SETFEATURES, ATA_SF_SETXFER, 0,mode); if (bootverbose) - ata_prtdev(atadev, "%s setting WDMA2 on Cypress chip\n", - error ? "failed" : "success"); + ata_prtdev(atadev, "%ssetting WDMA2 on Cypress chip\n", + error ? "FAILURE " : ""); if (!error) { pci_write_config(parent, atadev->channel->unit?0x4e:0x4c,0x2020,2); atadev->mode = mode; @@ -641,7 +639,7 @@ ata_highpoint_chipinit(device_t dev) device_printf(dev, "unable to map interrupt\n"); return ENXIO; } - if ((bus_setup_intr(dev, ctlr->r_irq, INTR_TYPE_BIO | INTR_ENTROPY, + if ((bus_setup_intr(dev, ctlr->r_irq, ATA_INTR_FLAGS, ata_highpoint_intr, ctlr, &ctlr->handle))) { device_printf(dev, "unable to setup interrupt\n"); return ENXIO; @@ -724,11 +722,11 @@ ata_highpoint_setmode(struct ata_device *atadev, int mode) mode = ata_highpoint_check_80pin(atadev, mode); - error = ata_command(atadev, ATA_C_SETFEATURES, 0, mode, - ATA_C_F_SETXFER, ATA_WAIT_READY); + error = ata_controlcmd(atadev, ATA_SETFEATURES, ATA_SF_SETXFER, 0, mode); + if (bootverbose) - ata_prtdev(atadev, "%s setting %s on HighPoint chip\n", - (error) ? "failed" : "success", ata_mode2str(mode)); + ata_prtdev(atadev, "%ssetting %s on HighPoint chip\n", + (error) ? "FAILURE " : "", ata_mode2str(mode)); if (!error) pci_write_config(parent, 0x40 + (devno << 2), timings33[ata_mode2idx(mode)][ctlr->chip->cfg1], 4); @@ -805,7 +803,7 @@ ata_intel_chipinit(device_t dev) { struct ata_pci_controller *ctlr = device_get_softc(dev); - if (ata_default_interrupt(dev)) + if (ata_setup_interrupt(dev)) return ENXIO; if (ctlr->chip->chipid == ATA_I82371FB) @@ -845,11 +843,11 @@ ata_intel_new_setmode(struct ata_device *atadev, int mode) mode = ATA_UDMA2; } - error = ata_command(atadev, ATA_C_SETFEATURES, 0, mode, - ATA_C_F_SETXFER, ATA_WAIT_READY); + error = ata_controlcmd(atadev, ATA_SETFEATURES, ATA_SF_SETXFER, 0, mode); + if (bootverbose) - ata_prtdev(atadev, "%s setting %s on %s chip\n", - (error) ? "failed" : "success", + ata_prtdev(atadev, "%ssetting %s on %s chip\n", + (error) ? "FAILURE " : "", ata_mode2str(mode), ctlr->chip->text); if (error) return; @@ -899,6 +897,92 @@ ata_intel_new_setmode(struct ata_device *atadev, int mode) } /* + * National chipset support functions + */ +int +ata_national_ident(device_t dev) +{ + struct ata_pci_controller *ctlr = device_get_softc(dev); + + /* this chip is a clone of the Cyrix chip, bugs and all */ + if (pci_get_devid(dev) == ATA_SC1100) { + device_set_desc(dev, "National Geode SC1100 ATA33 controller"); + ctlr->chipinit = ata_national_chipinit; + return 0; + } + return ENXIO; +} + +static device_t nat_host = NULL; + +static int +ata_national_chipinit(device_t dev) +{ + struct ata_pci_controller *ctlr = device_get_softc(dev); + device_t *children; + int nchildren, i; + + if (ata_setup_interrupt(dev)) + return ENXIO; + + /* locate the ISA part in the southbridge and enable UDMA33 */ + if (!device_get_children(device_get_parent(dev), &children,&nchildren)){ + for (i = 0; i < nchildren; i++) { + if (pci_get_devid(children[i]) == 0x0510100b) { + nat_host = children[i]; + break; + } + } + free(children, M_TEMP); + } + ctlr->setmode = ata_national_setmode; + return 0; +} + +static void +ata_national_setmode(struct ata_device *atadev, int mode) +{ + device_t parent = device_get_parent(atadev->channel->dev); + int devno = (atadev->channel->unit << 1) + ATA_DEV(atadev->unit); + u_int32_t piotiming[] = + { 0x9172d132, 0x21717121, 0x00803020, 0x20102010, 0x00100010, + 0x00803020, 0x20102010, 0x00100010, + 0x00100010, 0x00100010, 0x00100010 }; + u_int32_t dmatiming[] = { 0x80077771, 0x80012121, 0x80002020 }; + u_int32_t udmatiming[] = { 0x80921250, 0x80911140, 0x80911030 }; + int error; + + atadev->channel->dma->alignment = 4; + atadev->channel->dma->max_iosize = 63 * 1024; + + mode = ata_limit_mode(atadev, mode, ATA_UDMA2); + + error = ata_controlcmd(atadev, ATA_SETFEATURES, ATA_SF_SETXFER, 0, mode); + + if (bootverbose) + ata_prtdev(atadev, "%s setting %s on National chip\n", + (error) ? "failed" : "success", ata_mode2str(mode)); + if (!error) { + if (mode >= ATA_UDMA0) { + pci_write_config(parent, 0x44 + (devno << 3), + udmatiming[mode & ATA_MODE_MASK], 4); + } + else if (mode >= ATA_WDMA0) { + pci_write_config(parent, 0x44 + (devno << 3), + dmatiming[mode & ATA_MODE_MASK], 4); + } + else { + pci_write_config(parent, 0x44 + (devno << 3), + pci_read_config(parent, 0x44 + (devno << 3), 4) | + 0x80000000, 4); + } + pci_write_config(parent, 0x40 + (devno << 3), + piotiming[ata_mode2idx(mode)], 4); + atadev->mode = mode; + } +} + +/* * nVidia chipset support functions */ int @@ -927,7 +1011,7 @@ ata_nvidia_chipinit(device_t dev) { struct ata_pci_controller *ctlr = device_get_softc(dev); - if (ata_default_interrupt(dev)) + if (ata_setup_interrupt(dev)) return ENXIO; /* set prefetch, postwrite */ @@ -954,25 +1038,25 @@ ata_promise_ident(device_t dev) { ATA_PDC20263, 0, PRNEW, 0x00, ATA_UDMA4, "Promise PDC20263" }, { ATA_PDC20265, 0, PRNEW, 0x00, ATA_UDMA5, "Promise PDC20265" }, { ATA_PDC20267, 0, PRNEW, 0x00, ATA_UDMA5, "Promise PDC20267" }, - { ATA_PDC20268, 0, PRTX, PRTX4, ATA_UDMA5, "Promise PDC20268" }, - { ATA_PDC20269, 0, PRTX, 0x00, ATA_UDMA6, "Promise PDC20269" }, - { ATA_PDC20270, 0, PRTX, PRTX4, ATA_UDMA5, "Promise PDC20270" }, - { ATA_PDC20271, 0, PRTX, 0x00, ATA_UDMA6, "Promise PDC20271" }, - { ATA_PDC20275, 0, PRTX, 0x00, ATA_UDMA6, "Promise PDC20275" }, - { ATA_PDC20276, 0, PRTX, PRSX6K, ATA_UDMA6, "Promise PDC20276" }, - { ATA_PDC20277, 0, PRTX, 0x00, ATA_UDMA6, "Promise PDC20277" }, - { ATA_PDC20318, 0, PRMIO, PRSATA, ATA_SA150, "Promise PDC20318" }, - { ATA_PDC20319, 0, PRMIO, PRSATA, ATA_SA150, "Promise PDC20319" }, - { ATA_PDC20371, 0, PRMIO, PRSATA, ATA_SA150, "Promise PDC20371" }, - { ATA_PDC20375, 0, PRMIO, PRSATA, ATA_SA150, "Promise PDC20375" }, - { ATA_PDC20376, 0, PRMIO, PRSATA, ATA_SA150, "Promise PDC20376" }, - { ATA_PDC20377, 0, PRMIO, PRSATA, ATA_SA150, "Promise PDC20377" }, - { ATA_PDC20378, 0, PRMIO, PRSATA, ATA_SA150, "Promise PDC20378" }, - { ATA_PDC20379, 0, PRMIO, PRSATA, ATA_SA150, "Promise PDC20379" }, - { ATA_PDC20617, 0, PRMIO, PRDUAL, ATA_UDMA6, "Promise PDC20617" }, - { ATA_PDC20618, 0, PRMIO, PRDUAL, ATA_UDMA6, "Promise PDC20618" }, - { ATA_PDC20619, 0, PRMIO, PRDUAL, ATA_UDMA6, "Promise PDC20619" }, - { ATA_PDC20620, 0, PRMIO, PRDUAL, ATA_UDMA6, "Promise PDC20620" }, + { ATA_PDC20268, 0, PRTX, PRTX4, ATA_UDMA5, "Promise PDC20268" }, + { ATA_PDC20269, 0, PRTX, 0x00, ATA_UDMA6, "Promise PDC20269" }, + { ATA_PDC20270, 0, PRTX, PRTX4, ATA_UDMA5, "Promise PDC20270" }, + { ATA_PDC20271, 0, PRTX, 0x00, ATA_UDMA6, "Promise PDC20271" }, + { ATA_PDC20275, 0, PRTX, 0x00, ATA_UDMA6, "Promise PDC20275" }, + { ATA_PDC20276, 0, PRTX, PRSX6K, ATA_UDMA6, "Promise PDC20276" }, + { ATA_PDC20277, 0, PRTX, 0x00, ATA_UDMA6, "Promise PDC20277" }, + { ATA_PDC20318, 0, PRMIO, PRSATA, ATA_SA150, "Promise PDC20318" }, + { ATA_PDC20319, 0, PRMIO, PRSATA, ATA_SA150, "Promise PDC20319" }, + { ATA_PDC20371, 0, PRMIO, PRSATA, ATA_SA150, "Promise PDC20371" }, + { ATA_PDC20375, 0, PRMIO, PRSATA, ATA_SA150, "Promise PDC20375" }, + { ATA_PDC20376, 0, PRMIO, PRSATA, ATA_SA150, "Promise PDC20376" }, + { ATA_PDC20377, 0, PRMIO, PRSATA, ATA_SA150, "Promise PDC20377" }, + { ATA_PDC20378, 0, PRMIO, PRSATA, ATA_SA150, "Promise PDC20378" }, + { ATA_PDC20379, 0, PRMIO, PRSATA, ATA_SA150, "Promise PDC20379" }, + { ATA_PDC20617, 0, PRMIO, PRDUAL, ATA_UDMA6, "Promise PDC20617" }, + { ATA_PDC20618, 0, PRMIO, PRDUAL, ATA_UDMA6, "Promise PDC20618" }, + { ATA_PDC20619, 0, PRMIO, PRDUAL, ATA_UDMA6, "Promise PDC20619" }, + { ATA_PDC20620, 0, PRMIO, PRDUAL, ATA_UDMA6, "Promise PDC20620" }, { 0, 0, 0, 0, 0, 0}}; char buffer[64]; uintptr_t devid = 0; @@ -1039,7 +1123,7 @@ ata_promise_chipinit(device_t dev) /* enable burst mode */ ATA_OUTB(ctlr->r_io1, 0x1f, ATA_INB(ctlr->r_io1, 0x1f) | 0x01); - if ((bus_setup_intr(dev, ctlr->r_irq, INTR_TYPE_BIO | INTR_ENTROPY, + if ((bus_setup_intr(dev, ctlr->r_irq, ATA_INTR_FLAGS, ata_promise_old_intr, ctlr, &ctlr->handle))) { device_printf(dev, "unable to setup interrupt\n"); return ENXIO; @@ -1047,7 +1131,7 @@ ata_promise_chipinit(device_t dev) break; case PRTX: - if ((bus_setup_intr(dev, ctlr->r_irq, INTR_TYPE_BIO | INTR_ENTROPY, + if ((bus_setup_intr(dev, ctlr->r_irq, ATA_INTR_FLAGS, ata_promise_tx2_intr, ctlr, &ctlr->handle))) { device_printf(dev, "unable to setup interrupt\n"); return ENXIO; @@ -1074,7 +1158,7 @@ ata_promise_chipinit(device_t dev) else ctlr->channels = 4; - if ((bus_setup_intr(dev, ctlr->r_irq, INTR_TYPE_BIO | INTR_ENTROPY, + if ((bus_setup_intr(dev, ctlr->r_irq, ATA_INTR_FLAGS, ata_promise_mio_intr, ctlr, &ctlr->handle))) { device_printf(dev, "unable to setup interrupt\n"); return ENXIO; @@ -1109,7 +1193,7 @@ ata_promise_mio_allocate(device_t dev, struct ata_channel *ch) (ATA_IDX_INL(ch, ATA_BMCMD_PORT) & ~0x00000f8f) | ch->unit); ATA_IDX_OUTL(ch, ATA_BMDEVSPEC_0, 0x00000001); - ch->flags |= ATA_NO_SLAVE; + ch->flags |= (ATA_NO_SLAVE | ATA_USE_16BIT); ctlr->dmainit(ch); return 0; } @@ -1171,13 +1255,13 @@ ata_promise_mio_intr(void *data) struct ata_pci_controller *ctlr = data; struct ata_channel *ch; u_int32_t irq_vector; - int unit; + int unit; irq_vector = ATA_INL(ctlr->r_io2, 0x0040); for (unit = 0; unit < ctlr->channels; unit++) { if (irq_vector & (1 << unit)) { if ((ch = ctlr->interrupt[unit].argument)) { - ctlr->interrupt[unit].function(ch); + ctlr->interrupt[unit].function(ch); ATA_IDX_OUTL(ch, ATA_BMDEVSPEC_0, 0x00000001); } } @@ -1235,7 +1319,7 @@ ata_promise_setmode(struct ata_device *atadev, int mode) break; case PRMIO: - if (mode > ATA_UDMA2 && + if (mode > ATA_UDMA2 && (ATA_IDX_INL(atadev->channel, ATA_BMCTL_PORT) & 0x01000000)) { ata_prtdev(atadev, "DMA limited to UDMA33, non-ATA66 cable or device\n"); @@ -1244,16 +1328,15 @@ ata_promise_setmode(struct ata_device *atadev, int mode) break; } - error = ata_command(atadev, ATA_C_SETFEATURES, 0, mode, - ATA_C_F_SETXFER, ATA_WAIT_READY); + error = ata_controlcmd(atadev, ATA_SETFEATURES, ATA_SF_SETXFER, 0, mode); + if (bootverbose) - ata_prtdev(atadev, "%s setting %s on %s chip\n", - (error) ? "failed" : "success", + ata_prtdev(atadev, "%ssetting %s on %s chip\n", + (error) ? "FAILURE " : "", ata_mode2str(mode), ctlr->chip->text); if (!error) { if (ctlr->chip->cfg1 < PRTX) - pci_write_config(device_get_parent(atadev->channel->dev), - 0x60 + (devno << 2), + pci_write_config(parent, 0x60 + (devno << 2), timings33[ctlr->chip->cfg1][ata_mode2idx(mode)],4); atadev->mode = mode; } @@ -1290,12 +1373,11 @@ ata_promise_new_dmastart(struct ata_channel *ch, ATA_OUTL(ctlr->r_io1, 0x20, (dir ? 0x05000000 : 0x06000000) | (count >> 1)); } - ATA_IDX_OUTL(ch, ATA_BMDTP_PORT, ch->dma->mdmatab); - ATA_IDX_OUTB(ch, ATA_BMCMD_PORT, dir ? ATA_BMCMD_WRITE_READ : 0); ATA_IDX_OUTB(ch, ATA_BMSTAT_PORT, (ATA_IDX_INB(ch, ATA_BMSTAT_PORT) | (ATA_BMSTAT_INTERRUPT | ATA_BMSTAT_ERROR))); + ATA_IDX_OUTL(ch, ATA_BMDTP_PORT, ch->dma->mdmatab); ATA_IDX_OUTB(ch, ATA_BMCMD_PORT, - ATA_IDX_INB(ch, ATA_BMCMD_PORT) | ATA_BMCMD_START_STOP); + (dir ? ATA_BMCMD_WRITE_READ : 0) | ATA_BMCMD_START_STOP); return error; } @@ -1388,17 +1470,31 @@ ata_serverworks_chipinit(device_t dev) { struct ata_pci_controller *ctlr = device_get_softc(dev); - if (ata_default_interrupt(dev)) + if (ata_setup_interrupt(dev)) return ENXIO; - if (ctlr->chip->cfg1 > SWKS33) + if (ctlr->chip->cfg1 == SWKS33) { + device_t *children; + int nchildren, i; + + /* locate the ISA part in the southbridge and enable UDMA33 */ + if (!device_get_children(device_get_parent(dev), &children,&nchildren)){ + for (i = 0; i < nchildren; i++) { + if (pci_get_devid(children[i]) == ATA_ROSB4_ISA) { + pci_write_config(children[i], 0x64, + (pci_read_config(children[i], 0x64, 4) & + ~0x00002000) | 0x00004000, 4); + break; + } + } + free(children, M_TEMP); + } + } + else { pci_write_config(dev, 0x5a, (pci_read_config(dev, 0x5a, 1) & ~0x40) | (ctlr->chip->cfg1 == SWKS100) ? 0x03 : 0x02, 1); - else - pci_write_config(dev, 0x64, - (pci_read_config(dev, 0x64, 4) & ~0x00002000) | - 0x00004000, 4); + } ctlr->setmode = ata_serverworks_setmode; return 0; } @@ -1411,35 +1507,50 @@ ata_serverworks_setmode(struct ata_device *atadev, int mode) int devno = (atadev->channel->unit << 1) + ATA_DEV(atadev->unit); int offset = devno ^ 0x01; int error; - u_int8_t timings[] = { 0x5d, 0x47, 0x34, 0x22, 0x20, 0x34, 0x22, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20 }; + u_int8_t piotimings[] = { 0x5d, 0x47, 0x34, 0x22, 0x20, 0x34, 0x22, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20 }; + u_int8_t dmatimings[] = { 0x77, 0x21, 0x20 }; mode = ata_limit_mode(atadev, mode, ctlr->chip->max_dma); mode = ata_check_80pin(atadev, mode); - error = ata_command(atadev, ATA_C_SETFEATURES, 0, mode, - ATA_C_F_SETXFER, ATA_WAIT_READY); + error = ata_controlcmd(atadev, ATA_SETFEATURES, ATA_SF_SETXFER, 0, mode); + if (bootverbose) - ata_prtdev(atadev, "%s setting %s on %s chip\n", - (error) ? "failed" : "success", + ata_prtdev(atadev, "%ssetting %s on %s chip\n", + (error) ? "FAILURE " : "", ata_mode2str(mode), ctlr->chip->text); if (!error) { if (mode >= ATA_UDMA0) { - pci_write_config(parent, 0x54, pci_read_config(parent, 0x54, 1) | - (0x01 << devno), 1); pci_write_config(parent, 0x56, (pci_read_config(parent, 0x56, 2) & ~(0xf << (devno << 2))) | ((mode & ATA_MODE_MASK) << (devno << 2)), 2); + + pci_write_config(parent, 0x54, pci_read_config(parent, 0x54, 1) | + (0x01 << devno), 1); + pci_write_config(parent, 0x44, + (pci_read_config(parent, 0x44, 4) & + ~(0xff << (offset << 8))) | + (dmatimings[2] << (offset << 8)), 4); + } + else if (mode >= ATA_WDMA0) { + pci_write_config(parent, 0x54, pci_read_config(parent, 0x54, 1) & + ~(0x01 << devno), 1); + pci_write_config(parent, 0x44, + (pci_read_config(parent, 0x44, 4) & + ~(0xff << (offset << 8))) | + (dmatimings[mode & ATA_MODE_MASK]<<(offset<<8)),4); } else - pci_write_config(parent, 0x54, pci_read_config(parent, 0x54, 1) | + pci_write_config(parent, 0x54, pci_read_config(parent, 0x54, 1) & ~(0x01 << devno), 1); - pci_write_config(parent, 0x44, - (pci_read_config(parent, 0x44, 4) & + + pci_write_config(parent, 0x40, + (pci_read_config(parent, 0x40, 4) & ~(0xff << (offset << 8))) | - (timings[ata_mode2idx(mode)] << (offset << 8)), 4); + (piotimings[ata_mode2idx(mode)] << (offset << 8)), 4); atadev->mode = mode; } } @@ -1453,12 +1564,12 @@ ata_sii_ident(device_t dev) struct ata_pci_controller *ctlr = device_get_softc(dev); struct ata_chip_id *idx; static struct ata_chip_id ids[] = - {{ ATA_SII3112, 0x00, SIIMEMIO, 0, ATA_SA150, "SiI 3112" }, + {{ ATA_SII3112, 0x00, SIIMEMIO, 0, ATA_SA150, "SiI 3112" }, { ATA_SII0680, 0x00, SIIMEMIO, SIISETCLK, ATA_UDMA6, "SiI 0680" }, - { ATA_CMD649, 0x00, 0, SIIINTR, ATA_UDMA5, "CMD 649" }, - { ATA_CMD648, 0x00, 0, SIIINTR, ATA_UDMA4, "CMD 648" }, - { ATA_CMD646, 0x07, 0, 0, ATA_UDMA2, "CMD 646U2" }, - { ATA_CMD646, 0x00, 0, 0, ATA_WDMA2, "CMD 646" }, + { ATA_CMD649, 0x00, 0, SIIINTR, ATA_UDMA5, "CMD 649" }, + { ATA_CMD648, 0x00, 0, SIIINTR, ATA_UDMA4, "CMD 648" }, + { ATA_CMD646, 0x07, 0, 0, ATA_UDMA2, "CMD 646U2" }, + { ATA_CMD646, 0x00, 0, 0, ATA_WDMA2, "CMD 646" }, { 0, 0, 0, 0, 0, 0}}; char buffer[64]; @@ -1485,7 +1596,7 @@ ata_sii_chipinit(device_t dev) } if (ctlr->chip->cfg1 == SIIMEMIO) { - if ((bus_setup_intr(dev, ctlr->r_irq, INTR_TYPE_BIO | INTR_ENTROPY, + if ((bus_setup_intr(dev, ctlr->r_irq, ATA_INTR_FLAGS, ata_sii_intr, ctlr, &ctlr->handle))) { device_printf(dev, "unable to setup interrupt\n"); return ENXIO; @@ -1507,7 +1618,7 @@ ata_sii_chipinit(device_t dev) ctlr->setmode = ata_sii_setmode; } else { - if ((bus_setup_intr(dev, ctlr->r_irq, INTR_TYPE_BIO | INTR_ENTROPY, + if ((bus_setup_intr(dev, ctlr->r_irq, ATA_INTR_FLAGS, ctlr->chip->cfg2 & SIIINTR ? ata_cmd_intr : ata_generic_intr, ctlr, &ctlr->handle))) { @@ -1523,7 +1634,7 @@ ata_sii_chipinit(device_t dev) /* enable interrupt as BIOS might not */ pci_write_config(dev, 0x71, 0x01, 1); - ctlr->setmode = ata_cmd_setmode; + ctlr->setmode = ata_cmd_setmode; } return 0; } @@ -1586,18 +1697,18 @@ ata_cmd_intr(void *data) { struct ata_pci_controller *ctlr = data; struct ata_channel *ch; - u_int8_t dmastat; + u_int8_t dmastat, reg71; int unit; /* implement this as a toggle instead to balance load XXX */ for (unit = 0; unit < 2; unit++) { if (!(ch = ctlr->interrupt[unit].argument)) continue; - if (!(pci_read_config(device_get_parent(ch->dev), 0x71, 1) & + if (!((reg71 = pci_read_config(device_get_parent(ch->dev), 0x71, 1)) & (ch->unit ? 0x08 : 0x04))) continue; pci_write_config(device_get_parent(ch->dev), 0x71, - (ch->unit ? 0x08 : 0x04), 1); + reg71 & ~(ch->unit ? 0x04 : 0x08), 1); if (ch->dma->flags & ATA_DMA_ACTIVE) { if (!((dmastat = (ATA_IDX_INB(ch, ATA_BMSTAT_PORT) & ATA_BMSTAT_MASK)) & ATA_BMSTAT_INTERRUPT)) @@ -1617,24 +1728,34 @@ ata_sii_setmode(struct ata_device *atadev, int mode) int rego = (atadev->channel->unit << 4) + (ATA_DEV(atadev->unit) << 1); int mreg = atadev->channel->unit ? 0x84 : 0x80; int mask = 0x03 << (ATA_DEV(atadev->unit) << 2); - int mval = pci_read_config(parent, mreg, 1) & ~mask; + int mval; int error; mode = ata_limit_mode(atadev, mode, ctlr->chip->max_dma); - if (ctlr->chip->max_dma < ATA_SA150) + if (ctlr->chip->max_dma < ATA_UDMA2) { mode = ata_check_80pin(atadev, mode); + } + else if (ctlr->chip->max_dma < ATA_SA150 && mode > ATA_UDMA2 && + (pci_read_config(parent, 0x79, 1) & + (atadev->channel->unit ? 0x02 : 0x01))) { + ata_prtdev(atadev, + "DMA limited to UDMA33, non-ATA66 cable or device\n"); + mode = ATA_UDMA2; + } + + error = ata_controlcmd(atadev, ATA_SETFEATURES, ATA_SF_SETXFER, 0, mode); - error = ata_command(atadev, ATA_C_SETFEATURES, 0, mode, - ATA_C_F_SETXFER, ATA_WAIT_READY); if (bootverbose) - ata_prtdev(atadev, "%s setting %s on %s chip\n", - (error) ? "failed" : "success", + ata_prtdev(atadev, "%ssetting %s on %s chip\n", + (error) ? "FAILURE " : "", ata_mode2str(mode), ctlr->chip->text); if (error) return; + mval = pci_read_config(parent, mreg, 1) & ~mask; + if (ctlr->chip->max_dma < ATA_SA150) { if (mode >= ATA_UDMA0) { u_int8_t udmatimings[] = { 0xf, 0xb, 0x7, 0x5, 0x3, 0x2, 0x1 }; @@ -1680,11 +1801,11 @@ ata_cmd_setmode(struct ata_device *atadev, int mode) mode = ata_check_80pin(atadev, mode); - error = ata_command(atadev, ATA_C_SETFEATURES, 0, mode, - ATA_C_F_SETXFER, ATA_WAIT_READY); + error = ata_controlcmd(atadev, ATA_SETFEATURES, ATA_SF_SETXFER, 0, mode); + if (bootverbose) - ata_prtdev(atadev, "%s setting %s on %s chip\n", - (error) ? "failed" : "success", + ata_prtdev(atadev, "%ssetting %s on %s chip\n", + (error) ? "FAILURE " : "", ata_mode2str(mode), ctlr->chip->text); if (!error) { int treg = 0x54 + (devno < 3) ? (devno << 1) : 7; @@ -1730,35 +1851,35 @@ ata_sis_ident(device_t dev) struct ata_pci_controller *ctlr = device_get_softc(dev); struct ata_chip_id *idx; static struct ata_chip_id ids[] = - {{ ATA_SIS963, 0x00, SIS133NEW, 0, ATA_UDMA6, "SiS 963" }, /* south */ - { ATA_SIS962, 0x00, SIS133NEW, 0, ATA_UDMA6, "SiS 962" }, /* south */ - - { ATA_SIS755, 0x00, SIS_SOUTH, 0, ATA_UDMA6, "SiS 755" }, /* ext south */ - { ATA_SIS752, 0x00, SIS_SOUTH, 0, ATA_UDMA6, "SiS 752" }, /* unknown */ - { ATA_SIS751, 0x00, SIS_SOUTH, 0, ATA_UDMA6, "SiS 751" }, /* unknown */ - { ATA_SIS750, 0x00, SIS_SOUTH, 0, ATA_UDMA6, "SiS 750" }, /* unknown */ - { ATA_SIS748, 0x00, SIS_SOUTH, 0, ATA_UDMA6, "SiS 748" }, /* unknown */ - { ATA_SIS746, 0x00, SIS_SOUTH, 0, ATA_UDMA6, "SiS 746" }, /* ext south */ - { ATA_SIS745, 0x00, SIS100NEW, 0, ATA_UDMA5, "SiS 745" }, /* 1chip */ - { ATA_SIS740, 0x00, SIS_SOUTH, 0, ATA_UDMA5, "SiS 740" }, /* ext south */ - { ATA_SIS735, 0x00, SIS100NEW, 0, ATA_UDMA5, "SiS 735" }, /* 1chip */ - { ATA_SIS733, 0x00, SIS100NEW, 0, ATA_UDMA5, "SiS 733" }, /* 1chip */ - { ATA_SIS730, 0x00, SIS100OLD, 0, ATA_UDMA5, "SiS 730" }, /* 1chip */ - - { ATA_SIS658, 0x00, SIS_SOUTH, 0, ATA_UDMA6, "SiS 658" }, /* ext south */ - { ATA_SIS655, 0x00, SIS_SOUTH, 0, ATA_UDMA6, "SiS 655" }, /* ext south */ - { ATA_SIS652, 0x00, SIS_SOUTH, 0, ATA_UDMA6, "SiS 652" }, /* unknown */ - { ATA_SIS651, 0x00, SIS_SOUTH, 0, ATA_UDMA6, "SiS 651" }, /* ext south */ - { ATA_SIS650, 0x00, SIS_SOUTH, 0, ATA_UDMA6, "SiS 650" }, /* ext south */ - { ATA_SIS648, 0x00, SIS_SOUTH, 0, ATA_UDMA6, "SiS 648" }, /* ext south */ + {{ ATA_SIS963, 0x00, SIS133NEW, 0, ATA_UDMA6, "SiS 963" }, /* south */ + { ATA_SIS962, 0x00, SIS133NEW, 0, ATA_UDMA6, "SiS 962" }, /* south */ + + { ATA_SIS755, 0x00, SIS_SOUTH, 0, ATA_UDMA6, "SiS 755" }, /* ext south */ + { ATA_SIS752, 0x00, SIS_SOUTH, 0, ATA_UDMA6, "SiS 752" }, /* unknown */ + { ATA_SIS751, 0x00, SIS_SOUTH, 0, ATA_UDMA6, "SiS 751" }, /* unknown */ + { ATA_SIS750, 0x00, SIS_SOUTH, 0, ATA_UDMA6, "SiS 750" }, /* unknown */ + { ATA_SIS748, 0x00, SIS_SOUTH, 0, ATA_UDMA6, "SiS 748" }, /* unknown */ + { ATA_SIS746, 0x00, SIS_SOUTH, 0, ATA_UDMA6, "SiS 746" }, /* ext south */ + { ATA_SIS745, 0x00, SIS100NEW, 0, ATA_UDMA5, "SiS 745" }, /* 1chip */ + { ATA_SIS740, 0x00, SIS_SOUTH, 0, ATA_UDMA5, "SiS 740" }, /* ext south */ + { ATA_SIS735, 0x00, SIS100NEW, 0, ATA_UDMA5, "SiS 735" }, /* 1chip */ + { ATA_SIS733, 0x00, SIS100NEW, 0, ATA_UDMA5, "SiS 733" }, /* 1chip */ + { ATA_SIS730, 0x00, SIS100OLD, 0, ATA_UDMA5, "SiS 730" }, /* 1chip */ + + { ATA_SIS658, 0x00, SIS_SOUTH, 0, ATA_UDMA6, "SiS 658" }, /* ext south */ + { ATA_SIS655, 0x00, SIS_SOUTH, 0, ATA_UDMA6, "SiS 655" }, /* ext south */ + { ATA_SIS652, 0x00, SIS_SOUTH, 0, ATA_UDMA6, "SiS 652" }, /* unknown */ + { ATA_SIS651, 0x00, SIS_SOUTH, 0, ATA_UDMA6, "SiS 651" }, /* ext south */ + { ATA_SIS650, 0x00, SIS_SOUTH, 0, ATA_UDMA6, "SiS 650" }, /* ext south */ + { ATA_SIS648, 0x00, SIS_SOUTH, 0, ATA_UDMA6, "SiS 648" }, /* ext south */ { ATA_SIS646, 0x00, SIS_SOUTH, 0, ATA_UDMA6, "SiS 645DX"},/* ext south */ - { ATA_SIS645, 0x00, SIS_SOUTH, 0, ATA_UDMA6, "SiS 645" }, /* ext south */ - { ATA_SIS640, 0x00, SIS_SOUTH, 0, ATA_UDMA4, "SiS 640" }, /* ext south */ - { ATA_SIS635, 0x00, SIS100NEW, 0, ATA_UDMA5, "SiS 635" }, /* 1chip */ - { ATA_SIS633, 0x00, SIS100NEW, 0, ATA_UDMA5, "SiS 633" }, /* unknown */ + { ATA_SIS645, 0x00, SIS_SOUTH, 0, ATA_UDMA6, "SiS 645" }, /* ext south */ + { ATA_SIS640, 0x00, SIS_SOUTH, 0, ATA_UDMA4, "SiS 640" }, /* ext south */ + { ATA_SIS635, 0x00, SIS100NEW, 0, ATA_UDMA5, "SiS 635" }, /* 1chip */ + { ATA_SIS633, 0x00, SIS100NEW, 0, ATA_UDMA5, "SiS 633" }, /* unknown */ { ATA_SIS630, 0x30, SIS100OLD, 0, ATA_UDMA5, "SiS 630S"}, /* 1chip */ - { ATA_SIS630, 0x00, SIS66, 0, ATA_UDMA4, "SiS 630" }, /* 1chip */ - { ATA_SIS620, 0x00, SIS66, 0, ATA_UDMA4, "SiS 620" }, /* 1chip */ + { ATA_SIS630, 0x00, SIS66, 0, ATA_UDMA4, "SiS 630" }, /* 1chip */ + { ATA_SIS620, 0x00, SIS66, 0, ATA_UDMA4, "SiS 620" }, /* 1chip */ { ATA_SIS550, 0x00, SIS66, 0, ATA_UDMA5, "SiS 550" }, { ATA_SIS540, 0x00, SIS66, 0, ATA_UDMA4, "SiS 540" }, @@ -1779,9 +1900,9 @@ ata_sis_ident(device_t dev) sprintf(buffer, "SiS 96X %s controller",ata_mode2str(idx->max_dma)); } else { - struct ata_chip_id id[] = - {{ ATA_SISSOUTH, 0x10, 0, 0, ATA_UDMA6, "SiS 961" }, - { 0, 0, 0, 0, 0, 0 }}; + struct ata_chip_id id[] = + {{ ATA_SISSOUTH, 0x10, 0, 0, ATA_UDMA6, "SiS 961" }, + { 0, 0, 0, 0, 0, 0 }}; if (ata_find_chip(dev, id, pci_get_slot(dev))) idx->cfg1 = SIS133OLD; @@ -1806,7 +1927,7 @@ ata_sis_chipinit(device_t dev) { struct ata_pci_controller *ctlr = device_get_softc(dev); - if (ata_default_interrupt(dev)) + if (ata_setup_interrupt(dev)) return ENXIO; switch (ctlr->chip->cfg1) { @@ -1858,11 +1979,11 @@ ata_sis_setmode(struct ata_device *atadev, int mode) } } - error = ata_command(atadev, ATA_C_SETFEATURES, 0, mode, - ATA_C_F_SETXFER, ATA_WAIT_READY); + error = ata_controlcmd(atadev, ATA_SETFEATURES, ATA_SF_SETXFER, 0, mode); + if (bootverbose) - ata_prtdev(atadev, "%s setting %s on %s chip\n", - (error) ? "failed" : "success", + ata_prtdev(atadev, "%ssetting %s on %s chip\n", + (error) ? "FAILURE " : "", ata_mode2str(mode), ctlr->chip->text); if (!error) { switch (ctlr->chip->cfg1) { @@ -1949,7 +2070,7 @@ ata_via_chipinit(device_t dev) { struct ata_pci_controller *ctlr = device_get_softc(dev); - if (ata_default_interrupt(dev)) + if (ata_setup_interrupt(dev)) return ENXIO; /* prepare for ATA-66 on the 82C686a and 82C596b */ @@ -2045,11 +2166,11 @@ ata_via_family_setmode(struct ata_device *atadev, int mode) pci_write_config(parent, reg - 0x08, timings[ata_mode2idx(mode)], 1); - error = ata_command(atadev, ATA_C_SETFEATURES, 0, mode, - ATA_C_F_SETXFER, ATA_WAIT_READY); + error = ata_controlcmd(atadev, ATA_SETFEATURES, ATA_SF_SETXFER, 0, mode); + if (bootverbose) - ata_prtdev(atadev, "%s setting %s on %s chip\n", - (error) ? "failed" : "success", ata_mode2str(mode), + ata_prtdev(atadev, "%ssetting %s on %s chip\n", + (error) ? "FAILURE " : "", ata_mode2str(mode), ctlr->chip->text); if (!error) { if (mode >= ATA_UDMA0) @@ -2062,26 +2183,6 @@ ata_via_family_setmode(struct ata_device *atadev, int mode) } /* misc functions */ -static int -ata_mode2idx(int mode) -{ - if ((mode & ATA_DMA_MASK) == ATA_UDMA0) - return (mode & ATA_MODE_MASK) + 8; - if ((mode & ATA_DMA_MASK) == ATA_WDMA0) - return (mode & ATA_MODE_MASK) + 5; - return (mode & ATA_MODE_MASK) - ATA_PIO0; -} - -static int -ata_check_80pin(struct ata_device *atadev, int mode) -{ - if (mode > ATA_UDMA2 && !atadev->param->hwres_cblid) { - ata_prtdev(atadev,"DMA limited to UDMA33, non-ATA66 cable or device\n"); - mode = ATA_UDMA2; - } - return mode; -} - static struct ata_chip_id * ata_find_chip(device_t dev, struct ata_chip_id *index, int slot) { @@ -2119,7 +2220,7 @@ ata_match_chip(device_t dev, struct ata_chip_id *index) } static int -ata_default_interrupt(device_t dev) +ata_setup_interrupt(device_t dev) { struct ata_pci_controller *ctlr = device_get_softc(dev); int rid = ATA_IRQ_RID; @@ -2130,7 +2231,7 @@ ata_default_interrupt(device_t dev) device_printf(dev, "unable to map interrupt\n"); return ENXIO; } - if ((bus_setup_intr(dev, ctlr->r_irq, INTR_TYPE_BIO | INTR_ENTROPY, + if ((bus_setup_intr(dev, ctlr->r_irq, ATA_INTR_FLAGS, ata_generic_intr, ctlr, &ctlr->handle))) { device_printf(dev, "unable to setup interrupt\n"); return ENXIO; @@ -2140,7 +2241,7 @@ ata_default_interrupt(device_t dev) } static void -ata_pci_serialize(struct ata_channel *ch, int flags) +ata_serialize(struct ata_channel *ch, int flags) { struct ata_pci_controller *scp = device_get_softc(device_get_parent(ch->dev)); @@ -2162,3 +2263,23 @@ ata_pci_serialize(struct ata_channel *ch, int flags) } return; } + +static int +ata_check_80pin(struct ata_device *atadev, int mode) +{ + if (mode > ATA_UDMA2 && !(atadev->param->hwres & ATA_CABLE_ID)) { + ata_prtdev(atadev,"DMA limited to UDMA33, non-ATA66 cable or device\n"); + mode = ATA_UDMA2; + } + return mode; +} + +static int +ata_mode2idx(int mode) +{ + if ((mode & ATA_DMA_MASK) == ATA_UDMA0) + return (mode & ATA_MODE_MASK) + 8; + if ((mode & ATA_DMA_MASK) == ATA_WDMA0) + return (mode & ATA_MODE_MASK) + 5; + return (mode & ATA_MODE_MASK) - ATA_PIO0; +} diff --git a/sys/dev/ata/ata-commands.h b/sys/dev/ata/ata-commands.h new file mode 100644 index 000000000000..8b81b00bb1aa --- /dev/null +++ b/sys/dev/ata/ata-commands.h @@ -0,0 +1,127 @@ +/*- + * Copyright (c) 1998 - 2003 Søren Schmidt <sos@FreeBSD.org> + * 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 commands */ +#define ATA_NOP 0x00 /* NOP command */ +#define ATA_NF_FLUSHQUEUE 0x00 /* flush queued cmd's */ +#define ATA_NF_AUTOPOLL 0x01 /* start autopoll function */ +#define ATA_ATAPI_RESET 0x08 /* reset ATAPI device */ +#define ATA_READ 0x20 /* read command */ +#define ATA_READ48 0x24 /* read command */ +#define ATA_READ_DMA48 0x25 /* read w/DMA command */ +#define ATA_READ_DMA_QUEUED48 0x26 /* read w/DMA QUEUED command */ +#define ATA_READ_MUL48 0x29 /* read multi command */ +#define ATA_WRITE 0x30 /* write command */ +#define ATA_WRITE48 0x34 /* write command */ +#define ATA_WRITE_DMA48 0x35 /* write w/DMA command */ +#define ATA_WRITE_DMA_QUEUED48 0x36 /* write w/DMA QUEUED command */ +#define ATA_WRITE_MUL48 0x39 /* write multi command */ +#define ATA_PACKET_CMD 0xa0 /* packet command */ +#define ATA_ATAPI_IDENTIFY 0xa1 /* get ATAPI params*/ +#define ATA_SERVICE 0xa2 /* service command */ +#define ATA_READ_MUL 0xc4 /* read multi command */ +#define ATA_WRITE_MUL 0xc5 /* write multi command */ +#define ATA_SET_MULTI 0xc6 /* set multi size command */ +#define ATA_READ_DMA_QUEUED 0xc7 /* read w/DMA QUEUED command */ +#define ATA_READ_DMA 0xc8 /* read w/DMA command */ +#define ATA_WRITE_DMA 0xca /* write w/DMA command */ +#define ATA_WRITE_DMA_QUEUED 0xcc /* write w/DMA QUEUED command */ +#define ATA_SLEEP 0xe6 /* sleep command */ +#define ATA_FLUSHCACHE 0xe7 /* flush cache to disk */ +#define ATA_FLUSHCACHE48 0xea /* flush cache to disk */ +#define ATA_ATA_IDENTIFY 0xec /* get ATA params */ +#define ATA_SETFEATURES 0xef /* features command */ +#define ATA_SF_SETXFER 0x03 /* set transfer mode */ +#define ATA_SF_ENAB_WCACHE 0x02 /* enable write cache */ +#define ATA_SF_DIS_WCACHE 0x82 /* disable write cache */ +#define ATA_SF_ENAB_RCACHE 0xaa /* enable readahead cache */ +#define ATA_SF_DIS_RCACHE 0x55 /* disable readahead cache */ +#define ATA_SF_ENAB_RELIRQ 0x5d /* enable release interrupt */ +#define ATA_SF_DIS_RELIRQ 0xdd /* disable release interrupt */ +#define ATA_SF_ENAB_SRVIRQ 0x5e /* enable service interrupt */ +#define ATA_SF_DIS_SRVIRQ 0xde /* disable service interrupt */ + +/* ATAPI commands */ +#define ATAPI_TEST_UNIT_READY 0x00 /* check if device is ready */ +#define ATAPI_REZERO 0x01 /* rewind */ +#define ATAPI_REQUEST_SENSE 0x03 /* get sense data */ +#define ATAPI_FORMAT 0x04 /* format unit */ +#define ATAPI_READ 0x08 /* read data */ +#define ATAPI_WRITE 0x0a /* write data */ +#define ATAPI_WEOF 0x10 /* write filemark */ +#define ATAPI_WF_WRITE 0x01 +#define ATAPI_SPACE 0x11 /* space command */ +#define ATAPI_SP_FM 0x01 +#define ATAPI_SP_EOD 0x03 +#define ATAPI_MODE_SELECT 0x15 /* mode select */ +#define ATAPI_ERASE 0x19 /* erase */ +#define ATAPI_MODE_SENSE 0x1a /* mode sense */ +#define ATAPI_START_STOP 0x1b /* start/stop unit */ +#define ATAPI_SS_LOAD 0x01 +#define ATAPI_SS_RETENSION 0x02 +#define ATAPI_SS_EJECT 0x04 +#define ATAPI_PREVENT_ALLOW 0x1e /* media removal */ +#define ATAPI_READ_FORMAT_CAPACITIES 0x23 /* get format capacities */ +#define ATAPI_READ_CAPACITY 0x25 /* get volume capacity */ +#define ATAPI_READ_BIG 0x28 /* read data */ +#define ATAPI_WRITE_BIG 0x2a /* write data */ +#define ATAPI_LOCATE 0x2b /* locate to position */ +#define ATAPI_READ_POSITION 0x34 /* read position */ +#define ATAPI_SYNCHRONIZE_CACHE 0x35 /* flush buf, close channel */ +#define ATAPI_WRITE_BUFFER 0x3b /* write device buffer */ +#define ATAPI_READ_BUFFER 0x3c /* read device buffer */ +#define ATAPI_READ_SUBCHANNEL 0x42 /* get subchannel info */ +#define ATAPI_READ_TOC 0x43 /* get table of contents */ +#define ATAPI_PLAY_10 0x45 /* play by lba */ +#define ATAPI_PLAY_MSF 0x47 /* play by MSF address */ +#define ATAPI_PLAY_TRACK 0x48 /* play by track number */ +#define ATAPI_PAUSE 0x4b /* pause audio operation */ +#define ATAPI_READ_DISK_INFO 0x51 /* get disk info structure */ +#define ATAPI_READ_TRACK_INFO 0x52 /* get track info structure */ +#define ATAPI_RESERVE_TRACK 0x53 /* reserve track */ +#define ATAPI_SEND_OPC_INFO 0x54 /* send OPC structurek */ +#define ATAPI_MODE_SELECT_BIG 0x55 /* set device parameters */ +#define ATAPI_REPAIR_TRACK 0x58 /* repair track */ +#define ATAPI_READ_MASTER_CUE 0x59 /* read master CUE info */ +#define ATAPI_MODE_SENSE_BIG 0x5a /* get device parameters */ +#define ATAPI_CLOSE_TRACK 0x5b /* close track/session */ +#define ATAPI_READ_BUFFER_CAPACITY 0x5c /* get buffer capicity */ +#define ATAPI_SEND_CUE_SHEET 0x5d /* send CUE sheet */ +#define ATAPI_BLANK 0xa1 /* blank the media */ +#define ATAPI_SEND_KEY 0xa3 /* send DVD key structure */ +#define ATAPI_REPORT_KEY 0xa4 /* get DVD key structure */ +#define ATAPI_PLAY_12 0xa5 /* play by lba */ +#define ATAPI_LOAD_UNLOAD 0xa6 /* changer control command */ +#define ATAPI_READ_STRUCTURE 0xad /* get DVD structure */ +#define ATAPI_PLAY_CD 0xb4 /* universal play command */ +#define ATAPI_SET_SPEED 0xbb /* set drive speed */ +#define ATAPI_MECH_STATUS 0xbd /* get changer status */ +#define ATAPI_READ_CD 0xbe /* read data */ +#define ATAPI_POLL_DSC 0xff /* poll DSC status bit */ diff --git a/sys/dev/ata/ata-disk.c b/sys/dev/ata/ata-disk.c index b7b274d70e2e..8c2f5821d981 100644 --- a/sys/dev/ata/ata-disk.c +++ b/sys/dev/ata/ata-disk.c @@ -40,6 +40,7 @@ #include <sys/disk.h> #include <sys/cons.h> #include <sys/sysctl.h> +#include <sys/taskqueue.h> #include <vm/vm.h> #include <vm/pmap.h> #include <machine/md_var.h> @@ -52,27 +53,18 @@ #include <dev/ata/ata-raid.h> /* prototypes */ +static void ad_detach(struct ata_device *atadev); +static void ad_start(struct ata_device *atadev); +static void ad_done(struct ata_request *request); static disk_open_t adopen; static disk_strategy_t adstrategy; static dumper_t addump; -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); - -/* misc defines */ -#define AD_MAX_RETRIES 3 +void ad_print(struct ad_softc *adp); +static int ad_version(u_int16_t version); /* internal vars */ -static u_int32_t adp_lun_map = 0; -static int ata_dma = 1; -static int ata_wc = 1; -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); static MALLOC_DEFINE(M_AD, "AD driver", "ATA disk driver"); +static u_int32_t adp_lun_map = 0; /* sysctl vars */ SYSCTL_DECL(_hw_ata); @@ -80,8 +72,6 @@ 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"); void ad_attach(struct ata_device *atadev) @@ -91,7 +81,8 @@ ad_attach(struct ata_device *atadev) u_int64_t lbasize48; if (!(adp = malloc(sizeof(struct ad_softc), M_AD, M_NOWAIT | M_ZERO))) { - ata_prtdev(atadev, "failed to allocate driver storage\n"); + ata_prtdev(atadev, "FAILURE - could not allocate driver storage\n"); + atadev->attach = NULL; return; } adp->device = atadev; @@ -104,12 +95,12 @@ ad_attach(struct ata_device *atadev) adp->heads = atadev->param->heads; adp->sectors = atadev->param->sectors; adp->total_secs = atadev->param->cylinders * adp->heads * adp->sectors; - adp->max_iosize = 256 * DEV_BSIZE; if (adp->device->channel->flags & ATA_USE_PC98GEOM && adp->total_secs < 17 * 8 * 65536) { adp->sectors = 17; adp->heads = 8; } + mtx_init(&adp->queue_mtx, "ATA disk bioqueue lock", MTX_DEF, 0); bioq_init(&adp->queue); lbasize = (u_int32_t)atadev->param->lba_size_1 | @@ -118,7 +109,7 @@ ad_attach(struct ata_device *atadev) /* does this device need oldstyle CHS addressing */ if (!ad_version(atadev->param->version_major) || !(atadev->param->atavalid & ATA_FLAG_54_58) || !lbasize) - adp->flags |= AD_F_CHS_USED; + atadev->flags |= ATA_D_USE_CHS; /* use the 28bit LBA size if valid or bigger than the CHS mapping */ if (atadev->param->cylinders == 16383 || adp->total_secs < lbasize) @@ -130,106 +121,84 @@ ad_attach(struct ata_device *atadev) ((u_int64_t)atadev->param->lba_size48_4 << 48); /* use the 48bit LBA size if valid */ - if (atadev->param->support.address48 && lbasize48 > 268435455) + if ((atadev->param->support.command2 & ATA_SUPPORT_ADDRESS48) && + lbasize48 > 268435455) adp->total_secs = lbasize48; - - ATA_SLEEPLOCK_CH(atadev->channel, ATA_CONTROL); + + /* enable read caching */ + ata_controlcmd(atadev, ATA_SETFEATURES, ATA_SF_ENAB_RCACHE, 0, 0); + + /* enable write caching if enabled */ + if (ata_wc) + ata_controlcmd(atadev, ATA_SETFEATURES, ATA_SF_ENAB_WCACHE, 0, 0); + else + ata_controlcmd(atadev, ATA_SETFEATURES, ATA_SF_DIS_WCACHE, 0, 0); /* use multiple sectors/interrupt if device supports it */ - adp->transfersize = DEV_BSIZE; + adp->max_iosize = DEV_BSIZE; if (ad_version(atadev->param->version_major)) { int secsperint = max(1, min(atadev->param->sectors_intr, 16)); - if (!ata_command(atadev, ATA_C_SET_MULTI, 0, secsperint, - 0, ATA_WAIT_INTR) && !ata_wait(atadev, 0)) - adp->transfersize *= secsperint; - } - - /* enable read caching if not default on device */ - if (ata_command(atadev, ATA_C_SETFEATURES, - 0, 0, ATA_C_F_ENAB_RCACHE, ATA_WAIT_INTR)) - ata_prtdev(atadev, "enabling readahead cache failed\n"); - - /* enable write caching if allowed and not default on device */ - if (ata_wc || (ata_tags && ad_tagsupported(adp))) { - if (ata_command(atadev, ATA_C_SETFEATURES, - 0, 0, ATA_C_F_ENAB_WCACHE, ATA_WAIT_INTR)) - ata_prtdev(atadev, "enabling write cache failed\n"); - } - else { - if (ata_command(atadev, ATA_C_SETFEATURES, - 0, 0, ATA_C_F_DIS_WCACHE, ATA_WAIT_INTR)) - ata_prtdev(atadev, "disabling write cache failed\n"); + if (!ata_controlcmd(atadev, ATA_SET_MULTI, 0, 0, secsperint)) + adp->max_iosize = secsperint * DEV_BSIZE; } /* use DMA if allowed and if drive/controller supports it */ - if (ata_dma && atadev->channel->dma) + if (ata_dma && atadev->channel->dma) atadev->setmode(atadev, ATA_DMA_MAX); - else + else atadev->setmode(atadev, ATA_PIO_MAX); - /* use tagged queueing if allowed and supported */ -#if 0 /* disable tags for now */ - if (ata_tags && ad_tagsupported(adp)) { - adp->num_tags = atadev->param->queuelen; - adp->flags |= AD_F_TAG_ENABLED; - adp->device->channel->flags |= ATA_QUEUED; - if (ata_command(atadev, ATA_C_SETFEATURES, - 0, 0, ATA_C_F_DIS_RELIRQ, ATA_WAIT_INTR)) - ata_prtdev(atadev, "disabling release interrupt failed\n"); - if (ata_command(atadev, ATA_C_SETFEATURES, - 0, 0, ATA_C_F_DIS_SRVIRQ, ATA_WAIT_INTR)) - ata_prtdev(atadev, "disabling service interrupt failed\n"); - } -#endif - ATA_UNLOCK_CH(atadev->channel); + /* setup the function ptrs */ + atadev->detach = ad_detach; + atadev->start = ad_start; + atadev->softc = adp; + /* lets create the disk device */ adp->disk.d_open = adopen; adp->disk.d_strategy = adstrategy; adp->disk.d_dump = addump; adp->disk.d_name = "ad"; adp->disk.d_drv1 = adp; - adp->disk.d_maxsize = adp->max_iosize; + if (atadev->channel->dma) + adp->disk.d_maxsize = atadev->channel->dma->max_iosize; + else + adp->disk.d_maxsize = DFLTPHYS; adp->disk.d_sectorsize = DEV_BSIZE; adp->disk.d_mediasize = DEV_BSIZE * (off_t)adp->total_secs; adp->disk.d_fwsectors = adp->sectors; adp->disk.d_fwheads = adp->heads; - disk_create(adp->lun, &adp->disk, 0, NULL, NULL); + disk_create(adp->lun, &adp->disk, DISKFLAG_NOGIANT, NULL, NULL); - atadev->driver = adp; - atadev->flags = 0; + /* announce we are here */ + ad_print(adp); - ata_enclosure_print(atadev); - if (atadev->driver) - ad_print(adp); +#ifdef DEV_ATARAID ata_raiddisk_attach(adp); +#endif } -void +static void ad_detach(struct ata_device *atadev) { - struct ad_softc *adp = atadev->driver; - struct ad_request *request; + struct ad_softc *adp = atadev->softc; atadev->flags |= ATA_D_DETACHING; - ata_prtdev(atadev, "removed from configuration\n"); - ad_invalidatequeue(adp, NULL); - TAILQ_FOREACH(request, &atadev->channel->ata_queue, chain) { - if (request->softc != adp) - continue; - TAILQ_REMOVE(&atadev->channel->ata_queue, request, chain); - biofinish(request->bp, NULL, ENXIO); - ad_free(request); - } - bioq_flush(&adp->queue, NULL, ENXIO); - disk_destroy(&adp->disk); - +#ifdef DEV_ATARAID if (adp->flags & AD_F_RAID_SUBDISK) ata_raiddisk_detach(adp); - +#endif + mtx_lock(&adp->queue_mtx); + bioq_flush(&adp->queue, NULL, ENXIO); + mtx_unlock(&adp->queue_mtx); + disk_destroy(&adp->disk); + ata_prtdev(atadev, "WARNING - removed from configuration\n"); ata_free_name(atadev); ata_free_lun(&adp_lun_map, adp->lun); - atadev->driver = NULL; + atadev->attach = NULL; + atadev->detach = NULL; + atadev->start = NULL; + atadev->softc = NULL; atadev->flags = 0; free(adp, M_AD); } @@ -239,12 +208,8 @@ adopen(struct disk *dp) { struct ad_softc *adp = dp->d_drv1; - if (adp->flags & AD_F_RAID_SUBDISK) - return EPERM; - - /* hold off access until we are fully attached */ - while (ata_delayed_attach) - tsleep(&ata_delayed_attach, PRIBIO, "adopn", 1); + if (adp->device->flags & ATA_D_DETACHING) + return ENXIO; return 0; } @@ -252,591 +217,145 @@ static void adstrategy(struct bio *bp) { struct ad_softc *adp = bp->bio_disk->d_drv1; - int s; if (adp->device->flags & ATA_D_DETACHING) { biofinish(bp, NULL, ENXIO); return; } - s = splbio(); + mtx_lock(&adp->queue_mtx); bioq_disksort(&adp->queue, bp); - splx(s); + mtx_unlock(&adp->queue_mtx); ata_start(adp->device->channel); } -static int -addump(void *arg, void *virtual, vm_offset_t physical, - off_t offset, size_t length) -{ - struct ad_softc *adp; - struct ad_request request; - static int once; - struct disk *dp; - - dp = arg; - adp = dp->d_drv1; - if (!adp) - return ENXIO; - - if (!once) { - /* force PIO mode for dumps */ - adp->device->mode = ATA_PIO; - adp->device->channel->locking(adp->device->channel, ATA_LF_LOCK); - ata_reinit(adp->device->channel); - adp->device->channel->locking(adp->device->channel, ATA_LF_UNLOCK); - once = 1; - } - - if (length > 0) { - bzero(&request, sizeof(struct ad_request)); - request.softc = adp; - request.blockaddr = offset / DEV_BSIZE; - request.bytecount = length; - request.data = virtual; - - 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); - } - } else { - if (ata_wait(adp->device, ATA_S_READY | ATA_S_DSC) < 0) - ata_prtdev(adp->device, "timeout waiting for final ready\n"); - } - return 0; -} - -void +static void ad_start(struct ata_device *atadev) { - struct ad_softc *adp = atadev->driver; - struct bio *bp = bioq_first(&adp->queue); - struct ad_request *request; - int tag = 0; + struct ad_softc *adp = atadev->softc; + struct bio *bp; + struct ata_request *request; - if (!bp) + /* remove request from drive queue */ + mtx_lock(&adp->queue_mtx); + bp = bioq_first(&adp->queue); + if (!bp) { + mtx_unlock(&adp->queue_mtx); return; - - /* 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; } - - /* remove request from drive queue */ bioq_remove(&adp->queue, bp); + mtx_unlock(&adp->queue_mtx); - if (!(request = malloc(sizeof(struct ad_request), M_AD, M_NOWAIT|M_ZERO))) { - ata_prtdev(atadev, "out of memory in start\n"); + if (!(request = ata_alloc_request())) { + ata_prtdev(atadev, "FAILURE - out of memory in start\n"); biofinish(bp, NULL, ENOMEM); return; } /* setup request */ - request->softc = adp; - request->bp = bp; - request->blockaddr = bp->bio_pblkno; - request->bytecount = bp->bio_bcount; + request->device = atadev; + request->driver = bp; + request->callback = ad_done; + request->timeout = 5; + request->retries = 2; request->data = bp->bio_data; - request->tag = tag; - if (bp->bio_cmd == BIO_READ) - request->flags |= ADR_F_READ; - - if (adp->device->mode >= ATA_DMA && !atadev->channel->dma) - adp->device->mode = ATA_PIO; - - /* insert in tag array */ - adp->tags[tag] = request; - - /* link onto controller queue */ - TAILQ_INSERT_TAIL(&atadev->channel->ata_queue, request, chain); -} - -int -ad_transfer(struct ad_request *request) -{ - struct ad_softc *adp; - u_int64_t lba; - u_int32_t count; - u_int8_t cmd; - int flags = ATA_IMMEDIATE; - - /* get request params */ - adp = request->softc; - - /* calculate transfer details */ - lba = request->blockaddr + (request->donecount / DEV_BSIZE); - - /* start timeout for this transfer */ - if (!request->timeout_handle.callout && !dumping) - request->timeout_handle = - timeout((timeout_t*)ad_timeout, request, 10 * hz); - - if (request->donecount == 0) { - - /* check & setup transfer parameters */ - if (request->bytecount > adp->max_iosize) { - ata_prtdev(adp->device, - "%d byte transfers not supported\n", request->bytecount); - count = howmany(adp->max_iosize, DEV_BSIZE); - } - else - count = howmany(request->bytecount, DEV_BSIZE); - - if (count > (adp->device->param->support.address48 ? 65536 : 256)) { - ata_prtdev(adp->device, - "%d block transfers not supported\n", count); - count = adp->device->param->support.address48 ? 65536 : 256; - } - - 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); - adp->device->flags |= ATA_D_USE_CHS; - } - - /* does this drive & transfer work with DMA ? */ - request->flags &= ~ADR_F_DMA_USED; - if (adp->device->mode >= ATA_DMA && - !adp->device->channel->dma->setup(adp->device, 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->device, cmd, lba, - request->tag << 3, count, flags)) { - ata_prtdev(adp->device, "error executing command"); - goto transfer_failed; - } - if (ata_wait(adp->device, ATA_S_READY)) { - ata_prtdev(adp->device, "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_IDX_INB(adp->device->channel, 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->device, cmd, lba, count, 0, flags)) { - ata_prtdev(adp->device, "error executing command"); - goto transfer_failed; - } -#if 0 - /* - * wait for data transfer phase - * - * well this should be here acording to specs, but older - * promise controllers doesn't like it, they lockup! - */ - if (ata_wait(adp->device, ATA_S_READY | ATA_S_DRQ)) { - ata_prtdev(adp->device, "timeout waiting for data phase\n"); - goto transfer_failed; - } -#endif - } - - /* start transfer, return and wait for interrupt */ - adp->device->channel->dma->start(adp->device->channel, request->data, request->bytecount, - request->flags & ADR_F_READ); - return ATA_OP_CONTINUES; - } - - /* does this drive support multi sector transfers ? */ - if (adp->transfersize > DEV_BSIZE) - cmd = request->flags&ADR_F_READ ? ATA_C_READ_MUL : ATA_C_WRITE_MUL; + request->bytecount = bp->bio_bcount; - /* just plain old single sector transfer */ - else - cmd = request->flags&ADR_F_READ ? ATA_C_READ : ATA_C_WRITE; + /* convert LBA contents if this is an old non-LBA device */ + if (atadev->flags & ATA_D_USE_CHS) { + struct ata_params *param = atadev->param; + int sector = (bp->bio_pblkno % param->sectors) + 1; + int cylinder = bp->bio_pblkno / (param->sectors * param->heads); + int head = (bp->bio_pblkno % + (param->sectors * param->heads)) / param->sectors; - if (ata_command(adp->device, cmd, lba, count, 0, flags)){ - ata_prtdev(adp->device, "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->device, (ATA_S_READY | ATA_S_DSC | ATA_S_DRQ)) < 0) { - ata_prtdev(adp->device, "timeout waiting for DRQ"); - goto transfer_failed; + request->u.ata.lba = + (sector & 0xff) | (cylinder & 0xffff) << 8 | (head & 0xf) << 24; } - - /* output the data */ - if (adp->device->channel->flags & ATA_USE_16BIT) - ATA_IDX_OUTSW_STRM(adp->device->channel, ATA_DATA, - (void *)((uintptr_t)request->data + request->donecount), - request->currentsize / sizeof(int16_t)); else - ATA_IDX_OUTSL_STRM(adp->device->channel, ATA_DATA, - (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); - - /* if retries still permit, reinject this request */ - if (request->retries++ < AD_MAX_RETRIES) - TAILQ_INSERT_HEAD(&adp->device->channel->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; - biodone(request->bp); - ad_free(request); - } - ata_reinit(adp->device->channel); - return ATA_OP_CONTINUES; -} - -int -ad_interrupt(struct ad_request *request) -{ - struct ad_softc *adp = request->softc; - int dma_stat = 0; - - /* finish DMA transfer */ - if (request->flags & ADR_F_DMA_USED) - dma_stat = adp->device->channel->dma->stop(adp->device->channel); - - /* do we have a corrected soft error ? */ - if (adp->device->channel->status & ATA_S_CORR) - disk_err(request->bp, "soft error (ECC corrected)", - request->donecount / DEV_BSIZE, 1); - - /* did any real errors happen ? */ - if ((adp->device->channel->status & ATA_S_ERROR) || - (request->flags & ADR_F_DMA_USED && dma_stat & ATA_BMSTAT_ERROR)) { - adp->device->channel->error = - ATA_IDX_INB(adp->device->channel, ATA_ERROR); - disk_err(request->bp, (adp->device->channel->error & ATA_E_ICRC) ? - "UDMA ICRC error" : "hard error", - request->donecount / DEV_BSIZE, 0); - - /* if this is a UDMA CRC error, reinject request */ - if (request->flags & ADR_F_DMA_USED && - adp->device->channel->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 { - adp->device->setmode(adp->device, ATA_PIO_MAX); - printf(" falling back to PIO mode\n"); - } - TAILQ_INSERT_HEAD(&adp->device->channel->ata_queue, request, chain); - return ATA_OP_FINISHED; - } -#if 0 /* XXX*/ - /* 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); - adp->device->setmode(adp->device, ATA_PIO_MAX); - request->flags |= ADR_F_FORCE_PIO; - printf(" trying PIO mode\n"); - TAILQ_INSERT_HEAD(&adp->device->channel->ata_queue, request, chain); - return ATA_OP_FINISHED; - } -#endif - request->flags |= ADR_F_ERROR; - printf(" status=%02x error=%02x\n", - adp->device->channel->status, adp->device->channel->error); - } - - /* if we arrived here with forced PIO mode, DMA doesn't work right */ - if (request->flags & ADR_F_FORCE_PIO && !(request->flags & ADR_F_ERROR)) - ata_prtdev(adp->device, "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->device->channel->status & (ATA_S_READY|ATA_S_DSC|ATA_S_DRQ)) - != (ATA_S_READY|ATA_S_DSC|ATA_S_DRQ)) - ata_prtdev(adp->device, "read interrupt arrived early"); - - if (ata_wait(adp->device, (ATA_S_READY | ATA_S_DSC | ATA_S_DRQ)) != 0) { - ata_prtdev(adp->device, "read error detected (too) late"); - request->flags |= ADR_F_ERROR; - } - else { - /* data ready, read in */ - if (adp->device->channel->flags & ATA_USE_16BIT) - ATA_IDX_INSW_STRM(adp->device->channel, ATA_DATA, - (void*)((uintptr_t)request->data + - request->donecount), request->currentsize / - sizeof(int16_t)); - else - ATA_IDX_INSL_STRM(adp->device->channel, 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->flags & ADR_F_DMA_USED) && 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; - - biodone(request->bp); - ad_free(request); - adp->outstanding--; - - /* check for SERVICE */ - return ad_service(adp, 1); -} + request->u.ata.lba = bp->bio_pblkno; -int -ad_service(struct ad_softc *adp, int change) -{ - /* do we have to check the other device on this channel ? */ - if (adp->device->channel->flags & ATA_QUEUED && change) { - int device = adp->device->unit; - - if (adp->device->unit == ATA_MASTER) { - if ((adp->device->channel->devices & ATA_ATA_SLAVE) && - (adp->device->channel->device[SLAVE].driver) && - ((struct ad_softc *) (adp->device->channel-> - device[SLAVE].driver))->flags & AD_F_TAG_ENABLED) - device = ATA_SLAVE; - } - else { - if ((adp->device->channel->devices & ATA_ATA_MASTER) && - (adp->device->channel->device[MASTER].driver) && - ((struct ad_softc *) (adp->device->channel-> - device[MASTER].driver))->flags & AD_F_TAG_ENABLED) - device = ATA_MASTER; - } - if (device != adp->device->unit && - ((struct ad_softc *) - (adp->device->channel-> - device[ATA_DEV(device)].driver))->outstanding > 0) { - ATA_IDX_OUTB(adp->device->channel, ATA_DRIVE, ATA_D_IBM | device); - adp = adp->device->channel->device[ATA_DEV(device)].driver; - DELAY(1); - } - } - adp->device->channel->status = - ATA_IDX_INB(adp->device->channel, ATA_ALTSTAT); - - /* do we have a SERVICE request from the drive ? */ - if (adp->flags & AD_F_TAG_ENABLED && - adp->outstanding > 0 && - adp->device->channel->status & ATA_S_SERVICE) { - struct ad_request *request; - int tag; - - /* check for error */ - if (adp->device->channel->status & ATA_S_ERROR) { - ata_prtdev(adp->device, "Oops! controller says s=0x%02x e=0x%02x\n", - adp->device->channel->status, - adp->device->channel->error); - ad_invalidatequeue(adp, NULL); - return ATA_OP_FINISHED; - } - - /* issue SERVICE cmd */ - if (ata_command(adp->device, ATA_C_SERVICE, 0, 0, 0, ATA_IMMEDIATE)) { - ata_prtdev(adp->device, "problem executing SERVICE cmd\n"); - ad_invalidatequeue(adp, NULL); - return ATA_OP_FINISHED; - } + request->u.ata.count = request->bytecount / DEV_BSIZE; + request->transfersize = min(bp->bio_bcount, adp->max_iosize); - /* setup the transfer environment when ready */ - if (ata_wait(adp->device, ATA_S_READY)) { - ata_prtdev(adp->device, "SERVICE timeout tag=%d s=%02x e=%02x\n", - ATA_IDX_INB(adp->device->channel, ATA_COUNT) >> 3, - adp->device->channel->status, - adp->device->channel->error); - ad_invalidatequeue(adp, NULL); - return ATA_OP_FINISHED; + switch (bp->bio_cmd) { + case BIO_READ: + request->flags |= ATA_R_READ; + if (atadev->mode >= ATA_DMA) { + request->u.ata.command = ATA_READ_DMA; + request->flags |= ATA_R_DMA; } - tag = ATA_IDX_INB(adp->device->channel, ATA_COUNT) >> 3; - if (!(request = adp->tags[tag])) { - ata_prtdev(adp->device, "no request for tag=%d\n", tag); - ad_invalidatequeue(adp, NULL); - return ATA_OP_FINISHED; - } - ATA_FORCELOCK_CH(adp->device->channel, ATA_ACTIVE_ATA); - adp->device->channel->running = request; - request->serv++; - - /* start DMA transfer when ready */ - if (ata_wait(adp->device, ATA_S_READY | ATA_S_DRQ)) { - ata_prtdev(adp->device, "timeout starting DMA s=%02x e=%02x\n", - adp->device->channel->status, - adp->device->channel->error); - ad_invalidatequeue(adp, NULL); - return ATA_OP_FINISHED; + else if (adp->max_iosize > DEV_BSIZE) + request->u.ata.command = ATA_READ_MUL; + else + request->u.ata.command = ATA_READ; + + break; + case BIO_WRITE: + request->flags |= ATA_R_WRITE; + if (atadev->mode >= ATA_DMA) { + request->u.ata.command = ATA_WRITE_DMA; + request->flags |= ATA_R_DMA; } - adp->device->channel->dma->start(adp->device->channel, request->data, request->bytecount, - request->flags & ADR_F_READ); - return ATA_OP_CONTINUES; + else if (adp->max_iosize > DEV_BSIZE) + request->u.ata.command = ATA_WRITE_MUL; + else + request->u.ata.command = ATA_WRITE; + break; + default: + ata_prtdev(atadev, "FAILURE - unknown BIO operation\n"); + ata_free_request(request); + biofinish(bp, NULL, EIO); + return; } - return ATA_OP_FINISHED; + request->flags |= ATA_R_SKIPSTART; + ata_queue_request(request); } static void -ad_free(struct ad_request *request) +ad_done(struct ata_request *request) { - request->softc->tags[request->tag] = NULL; - free(request, M_AD); -} + struct bio *bp = request->driver; -static void -ad_invalidatequeue(struct ad_softc *adp, struct ad_request *request) -{ - /* if tags in use invalidate all other outstanding transfers */ - if (adp->flags & AD_F_TAG_ENABLED) { - struct ad_request *tmpreq; - int tag; - - ata_prtdev(adp->device, "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->device->channel->ata_queue, tmpreq, chain); - } - adp->outstanding = 0; - if (ata_command(adp->device, ATA_C_NOP, - 0, 0, ATA_C_F_FLUSHQUEUE, ATA_WAIT_READY)) - ata_prtdev(adp->device, "flush queue failed\n"); - } + /* finish up transfer */ + if ((bp->bio_error = request->result)) + bp->bio_flags |= BIO_ERROR; + bp->bio_resid = bp->bio_bcount - request->donecount; + biodone(bp); + ata_free_request(request); } static int -ad_tagsupported(struct ad_softc *adp) +addump(void *arg, void *virtual, vm_offset_t physical, + off_t offset, size_t length) { - /* check for controllers that we know doesn't support tags */ - switch (adp->device->channel->chiptype) { - case ATA_PDC20265: case ATA_PDC20263: case ATA_PDC20267: - case ATA_PDC20246: case ATA_PDC20262: - return 0; - } - - /* check that drive does DMA, has tags enabled, and is one we know works */ - if (adp->device->mode >= ATA_DMA && adp->device->param->support.queued && - adp->device->param->enabled.queued) { - - /* IBM DTTA series needs transfers <= 64K for tags to work properly */ - if (!strncmp(adp->device->param->model, "IBM-DTTA", 8)) { - adp->max_iosize = 128 * DEV_BSIZE; - return 1; - } + struct ata_request request; + struct disk *dp = arg; + struct ad_softc *adp = dp->d_drv1; - /* IBM DJNA series has broken tags, corrupts data */ - if (!strncmp(adp->device->param->model, "IBM-DJNA", 8)) - return 0; + if (!adp) + return ENXIO; - /* IBM DPTA & IBM DTLA series supports tags */ - if (!strncmp(adp->device->param->model, "IBM-DPTA", 8) || - !strncmp(adp->device->param->model, "IBM-DTLA", 8)) - return 1; + bzero(&request, sizeof(struct ata_request)); + request.data = virtual; + request.bytecount = length; + request.transfersize = min(length, adp->max_iosize); - /* IBM IC series ATA drives supports tags */ - if (!strncmp(adp->device->param->model, "IC", 2) && - (!strncmp(adp->device->param->model + 8, "AT", 2) || - !strncmp(adp->device->param->model + 8, "AV", 2))) - return 1; + request.flags |= ATA_R_WRITE; + if (adp->max_iosize > DEV_BSIZE) + request.u.ata.command = ATA_WRITE_MUL; + else + request.u.ata.command = ATA_WRITE; + request.u.ata.lba = offset / DEV_BSIZE; + request.u.ata.count = request.bytecount / DEV_BSIZE; + + while (request.bytecount > request.donecount) { + if (adp->device->channel->hw.transaction(&request) == ATA_OP_FINISHED) + return EIO; + DELAY(20); } return 0; } -static void -ad_timeout(struct ad_request *request) -{ - struct ad_softc *adp = request->softc; - - adp->device->channel->running = NULL; - request->timeout_handle.callout = NULL; - ata_prtdev(adp->device, "%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) { - adp->device->channel->dma->stop(adp->device->channel); - ad_invalidatequeue(adp, request); - if (request->retries == AD_MAX_RETRIES) { - adp->device->setmode(adp->device, ATA_PIO_MAX); - ata_prtdev(adp->device, "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->device->channel->ata_queue, request, chain); - } - else { - /* retries all used up, return error */ - request->bp->bio_error = EIO; - request->bp->bio_flags |= BIO_ERROR; - biodone(request->bp); - ad_free(request); - } - ata_reinit(adp->device->channel); -} - -void -ad_reinit(struct ata_device *atadev) -{ - struct ad_softc *adp = atadev->driver; - - /* reinit disk parameters */ - ad_invalidatequeue(atadev->driver, NULL); - ata_command(atadev, ATA_C_SET_MULTI, 0, - adp->transfersize / DEV_BSIZE, 0, ATA_WAIT_READY); - atadev->setmode(atadev, adp->device->mode); -} - void ad_print(struct ad_softc *adp) { @@ -857,15 +376,9 @@ ad_print(struct ad_softc *adp) adp->heads, adp->sectors, DEV_BSIZE); ata_prtdev(adp->device, "%d secs/int, %d depth queue, %s%s\n", - adp->transfersize / DEV_BSIZE, adp->num_tags + 1, + adp->max_iosize / DEV_BSIZE, adp->num_tags + 1, (adp->flags & AD_F_TAG_ENABLED) ? "tagged " : "", ata_mode2str(adp->device->mode)); - - ata_prtdev(adp->device, "piomode=%d dmamode=%d udmamode=%d cblid=%d\n", - ata_pmode(adp->device->param), ata_wmode(adp->device->param), - ata_umode(adp->device->param), - adp->device->param->hwres_cblid); - } else ata_prtdev(adp->device,"%lluMB <%.40s> [%lld/%d/%d] at ata%d-%s %s%s\n", diff --git a/sys/dev/ata/ata-disk.h b/sys/dev/ata/ata-disk.h index 11d58c1367b7..1373fd2acc47 100644 --- a/sys/dev/ata/ata-disk.h +++ b/sys/dev/ata/ata-disk.h @@ -28,29 +28,6 @@ * $FreeBSD$ */ -/* structure describing an ATA disk request */ -struct ad_request { - struct ad_softc *softc; /* 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 - - 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 */ - TAILQ_ENTRY(ad_request) chain; /* list management */ -}; - /* structure describing an ATA disk */ struct ad_softc { struct ata_device *device; /* ptr to device softc */ @@ -60,7 +37,7 @@ struct ad_softc { u_int8_t sectors; u_int32_t transfersize; /* size of each transfer */ int num_tags; /* number of tags supported */ - int max_iosize; /* max size of transfer */ + int max_iosize; /* max transfer HW supports */ int flags; /* drive flags */ #define AD_F_LABELLING 0x0001 #define AD_F_CHS_USED 0x0002 @@ -68,17 +45,7 @@ struct ad_softc { #define AD_F_TAG_ENABLED 0x0008 #define AD_F_RAID_SUBDISK 0x0010 - struct ad_request *tags[32]; /* tag array of requests */ - int outstanding; /* tags not serviced yet */ + struct mtx queue_mtx; /* queue lock */ struct bio_queue_head queue; /* head of request queue */ struct disk disk; /* disklabel/slice stuff */ }; - -void ad_attach(struct ata_device *); -void ad_detach(struct ata_device *); -void ad_reinit(struct ata_device *); -void ad_start(struct ata_device *); -int ad_transfer(struct ad_request *); -int ad_interrupt(struct ad_request *); -int ad_service(struct ad_softc *, int); -void ad_print(struct ad_softc *); diff --git a/sys/dev/ata/ata-dma.c b/sys/dev/ata/ata-dma.c index 4dfff5adc695..a94bf186f30d 100644 --- a/sys/dev/ata/ata-dma.c +++ b/sys/dev/ata/ata-dma.c @@ -36,10 +36,11 @@ #include <sys/malloc.h> #include <sys/lock.h> #include <sys/mutex.h> +#include <sys/taskqueue.h> #include <sys/bus.h> -#include <dev/pci/pcivar.h> #include <machine/bus.h> #include <sys/rman.h> +#include <dev/pci/pcivar.h> #include <dev/ata/ata-all.h> #include <dev/ata/ata-pci.h> @@ -67,7 +68,7 @@ int ata_dmainit(struct ata_channel *ch) { if (!(ch->dma = - malloc(sizeof(struct ata_dma_data), M_ATADMA, M_NOWAIT | M_ZERO))) + malloc(sizeof(struct ata_dma), M_ATADMA, M_NOWAIT | M_ZERO))) return ENOMEM; ch->dma->alloc = ata_dmaalloc; ch->dma->free = ata_dmafree; @@ -75,6 +76,7 @@ ata_dmainit(struct ata_channel *ch) ch->dma->start = ata_dmastart; ch->dma->stop = ata_dmastop; ch->dma->alignment = 2; + ch->dma->max_iosize = 64*1024; return 0; } @@ -98,9 +100,10 @@ ata_dmaalloc(struct ata_channel *ch) if (bus_dma_tag_create(NULL, 1, 0, BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL, MAXCTLDMASZ, ATA_DMA_ENTRIES, - BUS_SPACE_MAXSIZE_32BIT, 0, busdma_lock_mutex, - &Giant, &ch->dma->dmatag)) { - printf("DMA tag allocation failed, disabling DMA\n"); + BUS_SPACE_MAXSIZE_32BIT, 0, NULL, NULL, + &ch->dma->dmatag)) { + ata_printf(ch, -1, + "WARNING - DMA tag allocation failed, disabling DMA\n"); } } if (!ch->dma->cdmatag) { @@ -108,8 +111,8 @@ ata_dmaalloc(struct ata_channel *ch) BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL, MAXTABSZ, 1, MAXTABSZ, - BUS_DMA_ALLOCNOW, busdma_lock_mutex, - &Giant, &ch->dma->cdmatag))) + BUS_DMA_ALLOCNOW, NULL, NULL, + &ch->dma->cdmatag))) return error; } if (!ch->dma->ddmatag) { @@ -117,8 +120,8 @@ ata_dmaalloc(struct ata_channel *ch) BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL, MAXPHYS, ATA_DMA_ENTRIES, MAXSEGSZ, - BUS_DMA_ALLOCNOW, busdma_lock_mutex, - &Giant, &ch->dma->ddmatag))) + BUS_DMA_ALLOCNOW, NULL, NULL, + &ch->dma->ddmatag))) return error; } if (!ch->dma->mdmatab) { @@ -211,12 +214,17 @@ ata_dmasetup(struct ata_device *atadev, caddr_t data, int32_t count) if (((uintptr_t)data & (ch->dma->alignment - 1)) || (count & (ch->dma->alignment - 1))) { - ata_prtdev(atadev, "non aligned DMA transfer attempted\n"); + ata_prtdev(atadev, "FAILURE - non aligned DMA transfer attempted\n"); return -1; } - if (!count) { - ata_prtdev(atadev, "zero length DMA transfer attempted\n"); + ata_prtdev(atadev, "FAILURE - zero length DMA transfer attempted\n"); + return -1; + } + if (count > ch->dma->max_iosize) { + ata_prtdev(atadev, + "FAILURE - oversized DMA transfer attempted %d > %d\n", + count, ch->dma->max_iosize); return -1; } return 0; @@ -232,12 +240,10 @@ ata_dmastart(struct ata_channel *ch, caddr_t data, int32_t count, int dir) cba.dmatab = ch->dma->dmatab; bus_dmamap_sync(ch->dma->cdmatag, ch->dma->cdmamap, BUS_DMASYNC_PREWRITE); - if (bus_dmamap_load(ch->dma->ddmatag, ch->dma->ddmamap, data, count, ata_dmasetupd_cb, &cba, 0) || cba.error) return -1; - bus_dmamap_sync(ch->dma->cdmatag, ch->dma->cdmamap, BUS_DMASYNC_POSTWRITE); bus_dmamap_sync(ch->dma->ddmatag, ch->dma->ddmamap, dir ? BUS_DMASYNC_PREREAD : BUS_DMASYNC_PREWRITE); @@ -248,10 +254,13 @@ ata_dmastart(struct ata_channel *ch, caddr_t data, int32_t count, int dir) int ata_dmastop(struct ata_channel *ch) { + bus_dmamap_sync(ch->dma->cdmatag, ch->dma->cdmamap, BUS_DMASYNC_POSTWRITE); + bus_dmamap_sync(ch->dma->ddmatag, ch->dma->ddmamap, (ch->dma->flags & ATA_DMA_READ) != 0 ? BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE); bus_dmamap_unload(ch->dma->ddmatag, ch->dma->ddmamap); + ch->dma->flags = 0; return 0; } diff --git a/sys/dev/ata/ata-isa.c b/sys/dev/ata/ata-isa.c index 0f4688acde8c..719c5e864c02 100644 --- a/sys/dev/ata/ata-isa.c +++ b/sys/dev/ata/ata-isa.c @@ -37,6 +37,7 @@ #include <sys/module.h> #include <sys/bus.h> #include <sys/malloc.h> +#include <sys/taskqueue.h> #include <machine/stdarg.h> #include <machine/resource.h> #include <machine/bus.h> @@ -63,7 +64,7 @@ ata_isa_lock(struct ata_channel *ch, int type) static void ata_isa_setmode(struct ata_device *atadev, int mode) { - atadev->mode = ata_limit_mode(atadev, mode, ATA_PIO_MAX); + atadev->mode = min(mode, ATA_PIO_MAX); } static int @@ -94,10 +95,10 @@ ata_isa_probe(device_t dev) /* allocate the altport range */ rid = ATA_ALTADDR_RID; altio = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid, 0, ~0, - ATA_ALTIOSIZE, RF_ACTIVE); + ATA_ALTIOSIZE, RF_ACTIVE); if (!altio) { - bus_release_resource(dev, SYS_RES_IOPORT, ATA_IOADDR_RID, io); - return ENXIO; + bus_release_resource(dev, SYS_RES_IOPORT, ATA_IOADDR_RID, io); + return ENXIO; } /* setup the resource vectors */ diff --git a/sys/dev/ata/ata-lowlevel.c b/sys/dev/ata/ata-lowlevel.c new file mode 100644 index 000000000000..d38037e2c91f --- /dev/null +++ b/sys/dev/ata/ata-lowlevel.c @@ -0,0 +1,787 @@ +/*- + * Copyright (c) 1998 - 2003 Søren Schmidt <sos@FreeBSD.org> + * 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_ata.h" +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/ata.h> +#include <sys/kernel.h> +#include <sys/conf.h> +#include <sys/bus.h> +#include <sys/mutex.h> +#include <sys/taskqueue.h> +#include <machine/bus.h> +#include <sys/rman.h> +#include <dev/ata/ata-all.h> + +/* prototypes */ +static int ata_transaction(struct ata_request *request); +static void ata_interrupt(void *data); +static void ata_reset(struct ata_channel *ch); +static int ata_wait(struct ata_device *atadev, u_int8_t mask); +static int ata_command(struct ata_device *atadev, u_int8_t command, u_int64_t lba, u_int16_t count, u_int16_t feature); +static void ata_pio_read(struct ata_request *request, int length); +static void ata_pio_write(struct ata_request *request, int length); + +/* local vars */ +static int atadebug = 0; + +/* + * low level ATA functions + */ +void +ata_generic_hw(struct ata_channel *ch) +{ + ch->hw.reset = ata_reset; + ch->hw.transaction = ata_transaction; + ch->hw.interrupt = ata_interrupt; +} + +/* must be called with ATA channel locked */ +static int +ata_transaction(struct ata_request *request) +{ + /* record the request as running */ + request->device->channel->running = request; + + /* disable ATAPI DMA writes if HW doesn't support it */ + if (request->flags & (ATA_R_ATAPI | ATA_R_DMA | ATA_R_WRITE) && + request->device->channel->flags & ATA_ATAPI_DMA_RO) + request->flags &= ~ATA_R_DMA; + + switch (request->flags & (ATA_R_ATAPI | ATA_R_DMA)) { + + /* ATA PIO data transfer and control commands */ + default: + { + /* record command direction here as our request might be done later */ + int write = (request->flags & ATA_R_WRITE); + + /* issue command */ + if (ata_command(request->device, request->u.ata.command, + request->u.ata.lba, request->u.ata.count, + request->u.ata.feature)) { + ata_prtdev(request->device, "error issueing PIO command\n"); + request->result = EIO; + return ATA_OP_FINISHED; + } + + /* if write command output the data */ + if (write) { + if (ata_wait(request->device, + (ATA_S_READY | ATA_S_DSC | ATA_S_DRQ)) < 0) { + ata_prtdev(request->device,"timeout waiting for write DRQ"); + request->result = EIO; + return ATA_OP_FINISHED; + } + ata_pio_write(request, request->transfersize); + } + } + /* return and wait for interrupt */ + return ATA_OP_CONTINUES; + + /* ATA DMA data transfer commands */ + case ATA_R_DMA: + /* check sanity and setup DMA engine */ + if (request->device->channel->dma->setup(request->device, + request->data, + request->bytecount)) { + ata_prtdev(request->device, "setting up DMA failed\n"); + request->result = EIO; + return ATA_OP_FINISHED; + } + + /* issue command */ + if (ata_command(request->device, request->u.ata.command, + request->u.ata.lba, request->u.ata.count, + request->u.ata.feature)) { + ata_prtdev(request->device, "error issuing DMA command\n"); + request->result = EIO; + return ATA_OP_FINISHED; + } + + /* start DMA engine */ + if (request->device->channel->dma->start(request->device->channel, + request->data, + request->bytecount, + request->flags & ATA_R_READ)) { + request->result = EIO; + return ATA_OP_FINISHED; + } + /* return and wait for interrupt */ + return ATA_OP_CONTINUES; + + /* ATAPI PIO commands */ + case ATA_R_ATAPI: + /* is this just a POLL DSC command ? */ + if (request->u.atapi.ccb[0] == ATAPI_POLL_DSC) { + ATA_IDX_OUTB(request->device->channel, ATA_DRIVE, + ATA_D_IBM | request->device->unit); + DELAY(10); + if (!(ATA_IDX_INB(request->device->channel, ATA_ALTSTAT)&ATA_S_DSC)) + request->result = EBUSY; + return ATA_OP_FINISHED; + } + + /* start ATAPI operation */ + if (ata_command(request->device, ATA_PACKET_CMD, + request->transfersize << 8, 0, 0)) { + ata_prtdev(request->device, "error issuing ATA PACKET command\n"); + request->result = EIO; + return ATA_OP_FINISHED; + } + + /* command interrupt device ? just return and wait for interrupt */ + if ((request->device->param->config & ATA_DRQ_MASK) == ATA_DRQ_INTR) + return ATA_OP_CONTINUES; + + /* wait for ready to write ATAPI command block */ + { + int timeout = 5000; /* might be less for fast devices */ + while (timeout--) { + int reason = ATA_IDX_INB(request->device->channel, ATA_IREASON); + int status = ATA_IDX_INB(request->device->channel, ATA_STATUS); + + if (((reason & (ATA_I_CMD | ATA_I_IN)) | + (status & (ATA_S_DRQ | ATA_S_BUSY))) == ATAPI_P_CMDOUT) + break; + DELAY(20); + } + if (timeout <= 0) { + ata_prtdev(request->device, + "timeout waiting for ATAPI ready\n"); + request->result = EIO; + return ATA_OP_FINISHED; + } + } + + /* this seems to be needed for some (slow) devices */ + DELAY(10); + + /* output actual command block */ + ATA_IDX_OUTSW_STRM(request->device->channel, ATA_DATA, + (int16_t *)request->u.atapi.ccb, + (request->device->param->config & ATA_PROTO_MASK) == + ATA_PROTO_ATAPI_12 ? 6 : 8); + + /* return and wait for interrupt */ + return ATA_OP_CONTINUES; + + case ATA_R_ATAPI|ATA_R_DMA: + /* is this just a POLL DSC command ? */ + if (request->u.atapi.ccb[0] == ATAPI_POLL_DSC) { + ATA_IDX_OUTB(request->device->channel, ATA_DRIVE, + ATA_D_IBM | request->device->unit); + DELAY(10); + if (!(ATA_IDX_INB(request->device->channel, ATA_ALTSTAT)&ATA_S_DSC)) + request->result = EBUSY; + return ATA_OP_FINISHED; + } + + /* check sanity and setup DMA engine */ + if (request->device->channel->dma->setup(request->device, + request->data, + request->bytecount)) { + ata_prtdev(request->device, "setting up DMA failed\n"); + request->result = EIO; + return ATA_OP_FINISHED; + } + + /* start ATAPI operation */ + if (ata_command(request->device, ATA_PACKET_CMD, 0, 0, ATA_F_DMA)) { + ata_prtdev(request->device, "error issuing ATAPI packet command\n"); + request->result = EIO; + return ATA_OP_FINISHED; + } + + /* wait for ready to write ATAPI command block */ + { + int timeout = 5000; /* might be less for fast devices */ + while (timeout--) { + int reason = ATA_IDX_INB(request->device->channel, ATA_IREASON); + int status = ATA_IDX_INB(request->device->channel, ATA_STATUS); + + if (((reason & (ATA_I_CMD | ATA_I_IN)) | + (status & (ATA_S_DRQ | ATA_S_BUSY))) == ATAPI_P_CMDOUT) + break; + DELAY(20); + } + if (timeout <= 0) { + ata_prtdev(request->device, + "timeout waiting for ATAPI ready\n"); + request->result = EIO; + return ATA_OP_FINISHED; + } + } + + /* this seems to be needed for some (slow) devices */ + DELAY(10); + + /* output actual command block */ + ATA_IDX_OUTSW_STRM(request->device->channel, ATA_DATA, + (int16_t *)request->u.atapi.ccb, + (request->device->param->config & ATA_PROTO_MASK) == + ATA_PROTO_ATAPI_12 ? 6 : 8); + + /* start DMA engine */ + if (request->device->channel->dma->start(request->device->channel, + request->data, + request->bytecount, + request->flags & ATA_R_READ)) { + request->result = EIO; + return ATA_OP_FINISHED; + } + + /* return and wait for interrupt */ + return ATA_OP_CONTINUES; + } +} + +static void +ata_interrupt(void *data) +{ + struct ata_channel *ch = (struct ata_channel *)data; + struct ata_request *request = ch->running; + int length; + + /* if we dont have a running request shout and ignore this interrupt */ + if (request == NULL) { + if (bootverbose) { + printf("ata%d: spurious interrupt - ", device_get_unit(ch->dev)); + if (request) + printf("request OK - "); + printf("status=0x%02x error=0x%02x reason=0x%02x\n", + ATA_IDX_INB(ch, ATA_ALTSTAT), ATA_IDX_INB(ch, ATA_ERROR), + ATA_IDX_INB(ch, ATA_IREASON)); + } + return; + } + + /* 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; + } + + /* clear interrupt and get status */ + request->status = ATA_IDX_INB(ch, ATA_STATUS); + + switch (request->flags & (ATA_R_ATAPI | ATA_R_DMA)) { + + /* ATA PIO data transfer and control commands */ + default: + + /* if we got an error we are done with the HW */ + if (request->status & ATA_S_ERROR) { + request->error = ATA_IDX_INB(ch, ATA_ERROR); + break; + } + + /* if read data get it */ + if (request->flags & ATA_R_READ) + ata_pio_read(request, request->transfersize); + + /* update how far we've gotten */ + request->donecount += request->transfersize; + + /* do we need a scoop more ? */ + if (request->bytecount > request->donecount) { + + /* set this transfer size according to HW capabilities */ + request->transfersize = + min((request->bytecount-request->donecount), + request->transfersize); + + /* if data write command, output the data */ + if (request->flags & ATA_R_WRITE) { + /* if we get an error here we are done with the HW */ + if (ata_wait(request->device, + (ATA_S_READY | ATA_S_DSC | ATA_S_DRQ)) < 0) { + ata_prtdev(request->device,"timeout waiting for write DRQ"); + request->status = ATA_IDX_INB(ch, ATA_STATUS); + break; + } + else { + /* output data and return waiting for new interrupt */ + ata_pio_write(request, request->transfersize); + return; + } + } + + /* if data read command, return & wait for interrupt */ + else if (request->flags & ATA_R_READ) { + return; + } + else + ata_prtdev(request->device, + "FAILURE - %s shouldn't loop on control cmd\n", + ata_cmd2str(request)); + } + /* done with HW */ + break; + + /* ATA DMA data transfer commands */ + case ATA_R_DMA: + /* stop DMA engine and get status */ + request->dmastat = ch->dma->stop(ch); + + /* did we get error or data */ + if (request->status & ATA_S_ERROR) + request->error = ATA_IDX_INB(ch, ATA_ERROR); + else if (request->dmastat & ATA_BMSTAT_ERROR) + request->status |= ATA_S_ERROR; + else + request->donecount = request->bytecount; + + /* done with HW */ + break; + + /* ATAPI PIO commands */ + case ATA_R_ATAPI: + length = ATA_IDX_INB(ch, ATA_CYL_LSB)|(ATA_IDX_INB(ch, ATA_CYL_MSB)<<8); + + switch ((ATA_IDX_INB(ch, ATA_IREASON) & (ATA_I_CMD | ATA_I_IN)) | + (request->status & ATA_S_DRQ)) { + + case ATAPI_P_CMDOUT: + /* this seems to be needed for some (slow) devices */ + DELAY(10); + + if (!(request->status & ATA_S_DRQ)) { + ata_prtdev(request->device, "command interrupt without DRQ\n"); + request->status = ATA_S_ERROR; + break; + } + ATA_IDX_OUTSW_STRM(ch, ATA_DATA, (int16_t *)request->u.atapi.ccb, + (request->device->param->config & + ATA_PROTO_MASK)== ATA_PROTO_ATAPI_12 ? 6 : 8); + /* return wait for interrupt */ + return; + + case ATAPI_P_WRITE: + if (request->flags & ATA_R_READ) { + request->status = ATA_S_ERROR; + ata_prtdev(request->device, + "%s trying to write on read buffer\n", + ata_cmd2str(request)); + break; + } + ata_pio_write(request, length); + request->donecount += length; + + /* set next transfer size according to HW capabilities */ + request->transfersize = min((request->bytecount-request->donecount), + request->transfersize); + /* return wait for interrupt */ + return; + + case ATAPI_P_READ: + if (request->flags & ATA_R_WRITE) { + request->status = ATA_S_ERROR; + ata_prtdev(request->device, + "%s trying to read on write buffer\n", + ata_cmd2str(request)); + break; + } + ata_pio_read(request, length); + request->donecount += length; + + /* set next transfer size according to HW capabilities */ + request->transfersize = min((request->bytecount-request->donecount), + request->transfersize); + /* return wait for interrupt */ + return; + + case ATAPI_P_DONEDRQ: + ata_prtdev(request->device, + "WARNING - %s DONEDRQ non conformant device\n", + ata_cmd2str(request)); + if (request->flags & ATA_R_READ) { + ata_pio_read(request, length); + request->donecount += length; + } + else if (request->flags & ATA_R_WRITE) { + ata_pio_write(request, length); + request->donecount += length; + } + else + request->status = ATA_S_ERROR; + /* FALLTHROUGH */ + + case ATAPI_P_ABORT: + case ATAPI_P_DONE: + if (request->status & (ATA_S_ERROR | ATA_S_DWF)) + request->error = ATA_IDX_INB(ch, ATA_ERROR); + break; + + default: + ata_prtdev(request->device, "unknown transfer phase\n"); + request->status = ATA_S_ERROR; + } + /* done with HW */ + break; + + /* ATAPI DMA commands */ + case ATA_R_ATAPI|ATA_R_DMA: + + /* stop the engine and get engine status */ + request->dmastat = ch->dma->stop(ch); + + /* did we get error or data */ + if (request->status & (ATA_S_ERROR | ATA_S_DWF)) + request->error = ATA_IDX_INB(ch, ATA_ERROR); + else if (request->dmastat & ATA_BMSTAT_ERROR) + request->status |= ATA_S_ERROR; + else + request->donecount = request->bytecount; + + /* done with HW */ + break; + } + + ata_finish(request); + + /* unlock the ATA HW for new work */ + ch->running = NULL; + ATA_UNLOCK_CH(ch); + ch->locking(ch, ATA_LF_UNLOCK); +} + +/* must be called with ATA channel locked */ +static void +ata_reset(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); + /* in some setups we dont want to test for a slave */ + if (!(ch->flags & ATA_NO_SLAVE)) { + if ((ostat1 & 0xf8) != 0xf8 && ostat1 != 0xa5) { + stat1 = ATA_S_BUSY; + mask |= 0x02; + } + } + + /* if nothing showed up no need to get any further */ + /* SOS is that too strong?, we just might loose devices here XXX */ + ch->devices = 0; + if (!mask) + return; + + 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)) + break; + if (mask == 0x03) /* wait for both master & slave */ + if (!(stat0 & ATA_S_BUSY) && !(stat1 & ATA_S_BUSY)) + 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); +} + +static int +ata_wait(struct ata_device *atadev, u_int8_t mask) +{ + int timeout = 0; + u_int8_t status; + + DELAY(1); + while (timeout < 5000000) { /* timeout 5 secs */ + status = ATA_IDX_INB(atadev->channel, ATA_STATUS); + + /* if drive fails status, reselect the drive just to be sure */ + if (status == 0xff) { + ata_prtdev(atadev, "WARNING no status, reselecting device\n"); + ATA_IDX_OUTB(atadev->channel, ATA_DRIVE, ATA_D_IBM | atadev->unit); + DELAY(10); + status = ATA_IDX_INB(atadev->channel, ATA_STATUS); + if (status == 0xff) + return -1; + } + + /* are we done ? */ + if (!(status & ATA_S_BUSY)) + break; + + if (timeout > 1000) { + timeout += 1000; + DELAY(1000); + } + else { + timeout += 10; + DELAY(10); + } + } + if (timeout >= 5000000) + return -1; + if (!mask) + return (status & ATA_S_ERROR); + + /* wait 50 msec for bits wanted. */ + timeout = 5000; + while (timeout--) { + status = ATA_IDX_INB(atadev->channel, ATA_STATUS); + if ((status & mask) == mask) + return (status & ATA_S_ERROR); + DELAY (10); + } + return -1; +} + +static int +ata_command(struct ata_device *atadev, u_int8_t command, + u_int64_t lba, u_int16_t count, u_int16_t feature) +{ + if (atadebug) + ata_prtdev(atadev, "ata_command: addr=%04lx, command=%02x, " + "lba=%jd, count=%d, feature=%d\n", + rman_get_start(atadev->channel->r_io[ATA_DATA].res), + command, (intmax_t)lba, count, feature); + + /* select device */ + ATA_IDX_OUTB(atadev->channel, ATA_DRIVE, ATA_D_IBM | atadev->unit); + + /* ready to issue command ? */ + if (ata_wait(atadev, 0) < 0) { + ata_prtdev(atadev, "timeout sending command=%02x\n", command); + return -1; + } + + /* only use 48bit addressing if needed (avoid bugs and overhead) */ + if ((lba > 268435455 || count > 256) && atadev->param && + atadev->param->support.command2 & ATA_SUPPORT_ADDRESS48) { + + /* translate command into 48bit version */ + switch (command) { + case ATA_READ: + command = ATA_READ48; break; + case ATA_READ_MUL: + command = ATA_READ_MUL48; break; + case ATA_READ_DMA: + command = ATA_READ_DMA48; break; + case ATA_READ_DMA_QUEUED: + command = ATA_READ_DMA_QUEUED48; break; + case ATA_WRITE: + command = ATA_WRITE48; break; + case ATA_WRITE_MUL: + command = ATA_WRITE_MUL48; break; + case ATA_WRITE_DMA: + command = ATA_WRITE_DMA48; break; + case ATA_WRITE_DMA_QUEUED: + command = ATA_WRITE_DMA_QUEUED48; break; + case ATA_FLUSHCACHE: + command = ATA_FLUSHCACHE48; break; + default: + ata_prtdev(atadev, "can't translate cmd to 48bit version\n"); + return -1; + } + ATA_IDX_OUTB(atadev->channel, ATA_FEATURE, (feature>>8) & 0xff); + ATA_IDX_OUTB(atadev->channel, ATA_FEATURE, feature & 0xff); + 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); + 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; + } + + /* issue command to controller */ + ATA_IDX_OUTB(atadev->channel, ATA_CMD, command); + + return 0; +} + +static void +ata_pio_read(struct ata_request *request, int length) +{ + int size = min(request->transfersize, length); + struct ata_channel *ch = request->device->channel; + int resid; + + if (ch->flags & ATA_USE_16BIT || (size % sizeof(int32_t))) + ATA_IDX_INSW_STRM(ch, ATA_DATA, + (void*)((uintptr_t)request->data+request->donecount), + size / sizeof(int16_t)); + else + ATA_IDX_INSL_STRM(ch, ATA_DATA, + (void*)((uintptr_t)request->data+request->donecount), + size / sizeof(int32_t)); + + if (request->transfersize < length) { + ata_prtdev(request->device, "WARNING - %s read data overrun %d/%d\n", + ata_cmd2str(request), length, request->transfersize); + for (resid = request->transfersize; resid < length; + resid += sizeof(int16_t)) + ATA_IDX_INW(ch, ATA_DATA); + } +} + +static void +ata_pio_write(struct ata_request *request, int length) +{ + int size = min(request->transfersize, length); + struct ata_channel *ch = request->device->channel; + int resid; + + if (ch->flags & ATA_USE_16BIT || (size % sizeof(int32_t))) + ATA_IDX_OUTSW_STRM(ch, ATA_DATA, + (void*)((uintptr_t)request->data+request->donecount), + size / sizeof(int16_t)); + else + ATA_IDX_OUTSL_STRM(ch, ATA_DATA, + (void*)((uintptr_t)request->data+request->donecount), + size / sizeof(int32_t)); + + if (request->transfersize < length) { + ata_prtdev(request->device, "WARNING - %s write data underrun %d/%d\n", + ata_cmd2str(request), length, request->transfersize); + for (resid = request->transfersize; resid < length; + resid += sizeof(int16_t)) + ATA_IDX_OUTW(ch, ATA_DATA, 0); + } +} diff --git a/sys/dev/ata/ata-pci.c b/sys/dev/ata/ata-pci.c index 4a40ae2515a4..efb8e6d23730 100644 --- a/sys/dev/ata/ata-pci.c +++ b/sys/dev/ata/ata-pci.c @@ -35,6 +35,7 @@ #include <sys/module.h> #include <sys/bus.h> #include <sys/malloc.h> +#include <sys/taskqueue.h> #include <machine/stdarg.h> #include <machine/resource.h> #include <machine/bus.h> @@ -79,6 +80,8 @@ ata_pci_probe(device_t dev) return ata_highpoint_ident(dev); case ATA_INTEL_ID: return ata_intel_ident(dev); + case ATA_NATIONAL_ID: + return ata_national_ident(dev); case ATA_NVIDIA_ID: return ata_nvidia_ident(dev); case ATA_PROMISE_ID: @@ -413,13 +416,11 @@ ata_pci_dmastart(struct ata_channel *ch, caddr_t data, int32_t count, int dir) if ((error = ata_dmastart(ch, data, count, dir))) return error; - - ATA_IDX_OUTL(ch, ATA_BMDTP_PORT, ch->dma->mdmatab); - ATA_IDX_OUTB(ch, ATA_BMCMD_PORT, dir ? ATA_BMCMD_WRITE_READ : 0); ATA_IDX_OUTB(ch, ATA_BMSTAT_PORT, (ATA_IDX_INB(ch, ATA_BMSTAT_PORT) | (ATA_BMSTAT_INTERRUPT | ATA_BMSTAT_ERROR))); - ATA_IDX_OUTB(ch, ATA_BMCMD_PORT, - ATA_IDX_INB(ch, ATA_BMCMD_PORT) | ATA_BMCMD_START_STOP); + ATA_IDX_OUTL(ch, ATA_BMDTP_PORT, ch->dma->mdmatab); + ATA_IDX_OUTB(ch, ATA_BMCMD_PORT, + (dir ? ATA_BMCMD_WRITE_READ : 0) | ATA_BMCMD_START_STOP); return 0; } @@ -432,10 +433,8 @@ ata_pci_dmastop(struct ata_channel *ch) ATA_IDX_OUTB(ch, ATA_BMCMD_PORT, ATA_IDX_INB(ch, ATA_BMCMD_PORT) & ~ATA_BMCMD_START_STOP); ATA_IDX_OUTB(ch, ATA_BMSTAT_PORT, ATA_BMSTAT_INTERRUPT | ATA_BMSTAT_ERROR); - ata_dmastop(ch); - - return (error & ATA_BMSTAT_MASK); + return error; } static int @@ -505,8 +504,6 @@ ata_pcisub_probe(device_t dev) if ((error = ctlr->allocate(dev, ch))) return error; - if (ctlr->chip) - ch->chiptype = ctlr->chip->chipid; ch->device[MASTER].setmode = ctlr->setmode; ch->device[SLAVE].setmode = ctlr->setmode; ch->locking = ctlr->locking; diff --git a/sys/dev/ata/ata-pci.h b/sys/dev/ata/ata-pci.h index 9cb19cac4f56..aaab23c419a5 100644 --- a/sys/dev/ata/ata-pci.h +++ b/sys/dev/ata/ata-pci.h @@ -35,7 +35,7 @@ struct ata_chip_id { int cfg1; int cfg2; u_int8_t max_dma; - char *text; + char *text; }; /* structure describing a PCI ATA controller */ @@ -55,7 +55,7 @@ struct ata_pci_controller { struct { void (*function)(void *); void *argument; - } interrupt[4]; /* XXX SOS max ch# for now */ + } interrupt[4]; /* SOS max ch# for now XXX */ }; #define ATA_MASTERDEV(dev) ((pci_get_progif(dev) & 0x80) && \ @@ -115,6 +115,9 @@ struct ata_pci_controller { #define ATA_I82801EB 0x24db8086 #define ATA_I82801EB_1 0x24d18086 +#define ATA_NATIONAL_ID 0x100b +#define ATA_SC1100 0x0502100b + #define ATA_NVIDIA_ID 0x10de #define ATA_NFORCE1 0x01bc10de #define ATA_NFORCE2 0x006510de @@ -147,6 +150,7 @@ struct ata_pci_controller { #define ATA_PDC20621 0x6621105a #define ATA_SERVERWORKS_ID 0x1166 +#define ATA_ROSB4_ISA 0x02001166 #define ATA_ROSB4 0x02111166 #define ATA_CSB5 0x02121166 #define ATA_CSB6 0x02131166 @@ -279,6 +283,7 @@ int ata_cyrix_ident(device_t); int ata_cypress_ident(device_t); int ata_highpoint_ident(device_t); int ata_intel_ident(device_t); +int ata_national_ident(device_t); int ata_nvidia_ident(device_t); int ata_promise_ident(device_t); int ata_serverworks_ident(device_t); diff --git a/sys/dev/ata/ata-queue.c b/sys/dev/ata/ata-queue.c new file mode 100644 index 000000000000..8e0a31f5bf0e --- /dev/null +++ b/sys/dev/ata/ata-queue.c @@ -0,0 +1,471 @@ +/*- + * Copyright (c) 1998 - 2003 Søren Schmidt <sos@FreeBSD.org> + * 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_ata.h" +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/ata.h> +#include <sys/kernel.h> +#include <sys/malloc.h> +#include <sys/bus.h> +#include <sys/conf.h> +#include <sys/lock.h> +#include <sys/mutex.h> +#include <sys/taskqueue.h> +#include <machine/bus.h> +#include <sys/rman.h> +#include <dev/ata/ata-all.h> + +/* prototypes */ +static void ata_completed(void *context, int pending); +static void ata_timeout(struct ata_request *request); +static char *ata_sensekey2str(u_int8_t skey); + +/* local vars */ +static MALLOC_DEFINE(M_ATA_REQ, "ATA request", "ATA request"); +static int atadebug = 0; + +/* + * ATA request related functions + */ +struct ata_request * +ata_alloc_request(void) +{ + struct ata_request *request; + + request = malloc(sizeof(struct ata_request), M_ATA_REQ, M_NOWAIT | M_ZERO); + if (!request) + printf("FAILURE - malloc ATA request failed\n"); + return request; +} + +void +ata_free_request(struct ata_request *request) +{ + free(request, M_ATA_REQ); +} + +void +ata_queue_request(struct ata_request *request) +{ + /* mark request as virgin (it might be a reused one) */ + request->result = request->status = request->error = 0; + request->flags &= ~ATA_R_DONE; + + /* put request on the locked queue at the specified location */ + mtx_lock(&request->device->channel->queue_mtx); + if (request->flags & ATA_R_AT_HEAD) + TAILQ_INSERT_HEAD(&request->device->channel->ata_queue, request, chain); + else + TAILQ_INSERT_TAIL(&request->device->channel->ata_queue, request, chain); + mtx_unlock(&request->device->channel->queue_mtx); + + /* should we skip start ? */ + if (!(request->flags & ATA_R_SKIPSTART)) + ata_start(request->device->channel); + + /* if this was a requeue op callback/sleep already setup */ + if (request->flags & ATA_R_REQUEUE) + return; + + /* if this is not a callback and we havn't seen DONE yet -> sleep */ + if (!request->callback && !(request->flags & ATA_R_DONE)) { + while (tsleep(request, PRIBIO, "atareq", 60*10*hz)) ; + } +} + +int +ata_controlcmd(struct ata_device *atadev, u_int8_t command, u_int16_t feature, + u_int64_t lba, u_int16_t count) +{ + struct ata_request *request = ata_alloc_request(); + int error = ENOMEM; + + if (request) { + request->device = atadev; + request->u.ata.command = command; + request->u.ata.lba = lba; + request->u.ata.count = count; + request->u.ata.feature = feature; + request->flags = ATA_R_CONTROL; + request->timeout = 5; + ata_queue_request(request); + error = request->result; + ata_free_request(request); + } + return error; +} + +int +ata_atapicmd(struct ata_device *atadev, u_int8_t *ccb, caddr_t data, + int count, int flags, int timeout) +{ + struct ata_request *request = ata_alloc_request(); + int packet_size, error = ENOMEM; + + if ((atadev->param->config & ATA_PROTO_MASK) == ATA_PROTO_ATAPI_12) + packet_size = 12; + else + packet_size = 16; + if (request) { + request->device = atadev; + bcopy(ccb, request->u.atapi.ccb, packet_size); + request->data = data; + request->bytecount = count; + request->transfersize = min(request->bytecount, 65534); + request->flags = flags | ATA_R_ATAPI; + request->timeout = timeout; + ata_queue_request(request); + error = request->result; + ata_free_request(request); + } + return error; +} + +void +ata_start(struct ata_channel *ch) +{ + struct ata_request *request; + + /* lock the ATA HW for this request */ + ch->locking(ch, ATA_LF_LOCK); + if (!ATA_LOCK_CH(ch, ATA_ACTIVE)) { + return; + } + +if (atadebug && mtx_owned(&Giant)) printf("ata_start holds GIANT!!!\n"); + + /* if we dont have any work, ask the subdriver(s) */ + mtx_lock(&ch->queue_mtx); + if (TAILQ_EMPTY(&ch->ata_queue)) { + mtx_unlock(&ch->queue_mtx); + if (ch->device[MASTER].start) + ch->device[MASTER].start(&ch->device[MASTER]); + if (ch->device[SLAVE].start) + ch->device[SLAVE].start(&ch->device[SLAVE]); + mtx_lock(&ch->queue_mtx); + } + if ((request = TAILQ_FIRST(&ch->ata_queue))) { + TAILQ_REMOVE(&ch->ata_queue, request, chain); + mtx_unlock(&ch->queue_mtx); + + /* arm timeout */ + if (!request->timeout_handle.callout && !dumping) { + request->timeout_handle = + timeout((timeout_t*)ata_timeout, request, request->timeout*hz); + } + + /* kick HW into action */ + if (ch->hw.transaction(request) == ATA_OP_CONTINUES) + return; + + /* untimeout request */ + untimeout((timeout_t *)ata_timeout, request, request->timeout_handle); + ata_finish(request); + } + else + mtx_unlock(&ch->queue_mtx); + + ATA_UNLOCK_CH(ch); + ch->locking(ch, ATA_LF_UNLOCK); +} + +void +ata_finish(struct ata_request *request) +{ + /* request is done schedule it for completition */ + TASK_INIT(&request->task, 0, ata_completed, request); + taskqueue_enqueue(taskqueue_swi, &request->task); +} + +/* current command finished, clean up and return result */ +static void +ata_completed(void *context, int pending) +{ + struct ata_request *request = (struct ata_request *)context; + struct ata_channel *channel = request->device->channel; + + /* untimeout request now we have control back */ + untimeout((timeout_t *)ata_timeout, request, request->timeout_handle); + + /* do the all the magic for completition evt retry etc etc */ + if (request->status & ATA_S_CORR) + ata_prtdev(request->device, "WARNING - %s soft error (ECC corrected)", + ata_cmd2str(request)); + + /* if this is a UDMA CRC error, retry request */ + if (request->flags & ATA_R_DMA && request->error & ATA_E_ICRC) { + if (request->retries--) { + ata_prtdev(request->device, + "WARNING - %s UDMA ICRC error (retrying request)\n", + ata_cmd2str(request)); + ata_queue_request(request); + return; + } + } + + switch (request->flags & ATA_R_ATAPI) { + /* ATA errors */ + default: + if (request->status & ATA_S_ERROR) { + if (!(request->flags & ATA_R_QUIET)) { + ata_prtdev(request->device, + "FAILURE - %s status=%b error=%b", + ata_cmd2str(request), + request->status, "\20\10BUSY\7READY\6DMA_READY" + "\5DSC\4DRQ\3CORRECTABLE\2INDEX\1ERROR", + request->error, "\20\10ICRC\7UNCORRECTABLE" + "\6MEDIA_CHANGED\5NID_NOT_FOUND\4MEDIA_CHANGE_REQEST" + "\3ABORTED\2NO_MEDIA\1ILLEGAL_LENGTH"); + if (request->flags & ATA_R_DMA && + request->dmastat & ATA_BMSTAT_ERROR) + printf(" dma=0x%02x\n", request->dmastat); + else + printf("\n"); + } + + /* SOS this could be more precise ? XXX*/ + request->result = EIO; + } + break; + + /* ATAPI errors */ + case ATA_R_ATAPI: + /* is result already set return */ + if (request->result) + break; + + if (request->error & ATA_E_MASK) { + switch ((request->result & ATA_SK_MASK)) { + case ATA_SK_RECOVERED_ERROR: + ata_prtdev(request->device, "WARNING - %s recovered error\n", + ata_cmd2str(request)); + /* FALLTHROUGH */ + + case ATA_SK_NO_SENSE: + request->result = 0; + break; + + case ATA_SK_NOT_READY: + request->result = EBUSY; + break; + + case ATA_SK_UNIT_ATTENTION: + request->device->flags |= ATA_D_MEDIA_CHANGED; + request->result = EIO; + break; + + default: + request->result = EIO; + } + if (request->result && !(request->flags & ATA_R_QUIET)) + ata_prtdev(request->device, + "FAILURE - %s status=%b sensekey=%s error=%b\n", + ata_cmd2str(request), + request->status, "\20\10BUSY\7READY\6DMA" + "\5DSC\4DRQ\3CORRECTABLE\2INDEX\1ERROR", + ata_sensekey2str((request->error & ATA_SK_MASK)>>4), + (request->error & ATA_E_MASK), + "\20\4MEDIA_CHANGE_REQUEST\3ABORTED" + "\2NO_MEDIA\1ILLEGAL_LENGTH"); + } + break; + } + + request->flags |= ATA_R_DONE; + if (request->callback) + (request->callback)(request); + else + wakeup(request); + ata_start(channel); +} + +static void +ata_timeout(struct ata_request *request) +{ + /* clear timeout etc */ + request->timeout_handle.callout = NULL; + + /* call interrupt to try finish up the command */ + request->device->channel->hw.interrupt(request->device->channel); + + if (request->device->channel->running == NULL) { + if (!(request->flags & ATA_R_QUIET)) + ata_prtdev(request->device, + "WARNING - %s recovered from missing interrupt\n", + ata_cmd2str(request)); + return; + } + + /* if this was a DMA request stop the engine to be on the safe side */ + if (request->flags & ATA_R_DMA) { + request->dmastat = + request->device->channel->dma->stop(request->device->channel); + } + + /* try to adjust HW's attitude towards work */ + ata_reinit(request->device->channel); + + /* if retries still permit, reinject this request */ + if (request->retries-- > 0) { + if (!(request->flags & ATA_R_QUIET)) + ata_prtdev(request->device, + "TIMEOUT - %s retrying (%d retr%s left)\n", + ata_cmd2str(request), request->retries, + request->retries == 1 ? "y" : "ies"); + request->flags |= (ATA_R_AT_HEAD | ATA_R_REQUEUE); + request->flags &= ~ATA_R_SKIPSTART; + ata_queue_request(request); + } + /* otherwise just schedule finish with error */ + else { + request->status = ATA_S_ERROR; + TASK_INIT(&request->task, 0, ata_completed, request); + taskqueue_enqueue(taskqueue_swi, &request->task); + } +} + +char * +ata_cmd2str(struct ata_request *request) +{ + static char buffer[20]; + + if (request->flags & ATA_R_ATAPI) { + switch (request->u.atapi.ccb[0]) { + case 0x00: return ("TEST_UNIT_READY"); + case 0x01: return ("REZERO"); + case 0x03: return ("REQUEST_SENSE"); + case 0x04: return ("FORMAT"); + 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 0x23: return ("ATAPI_READ_FORMAT_CAPACITIES"); + 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"); + } + } + else { + switch (request->u.ata.command) { + case 0x00: return ("NOP"); + case 0x08: return ("ATAPI_RESET"); + case 0x20: return ("READ"); + case 0x24: return ("READ48"); + case 0x25: return ("READ_DMA48"); + case 0x26: return ("READ_DMA_QUEUED48"); + case 0x29: return ("READ_MUL48"); + case 0x30: return ("WRITE"); + case 0x34: return ("WRITE48"); + case 0x35: return ("WRITE_DMA48"); + case 0x36: return ("WRITE_DMA_QUEUED48"); + case 0x39: return ("WRITE_MUL48"); + case 0xa0: return ("PACKET_CMD"); + case 0xa1: return ("ATAPI_IDENTIFY"); + case 0xa2: return ("SERVICE"); + case 0xc4: return ("READ_MUL"); + case 0xc5: return ("WRITE_MUL"); + case 0xc6: return ("SET_MULTI"); + case 0xc7: return ("READ_DMA_QUEUED"); + case 0xc8: return ("READ_DMA"); + case 0xca: return ("WRITE_DMA"); + case 0xcc: return ("WRITE_DMA_QUEUED"); + case 0xe6: return ("SLEEP"); + case 0xe7: return ("FLUSHCACHE"); + case 0xea: return ("FLUSHCACHE48"); + case 0xec: return ("ATA_IDENTIFY"); + case 0xef: return ("SETFEATURES"); + } + } + sprintf(buffer, "unknown CMD (0x%02x)", request->u.ata.command); + return buffer; +} + +static char * +ata_sensekey2str(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"); + } +} diff --git a/sys/dev/ata/ata-raid.c b/sys/dev/ata/ata-raid.c index 8e13c630b0ab..26f234610417 100644 --- a/sys/dev/ata/ata-raid.c +++ b/sys/dev/ata/ata-raid.c @@ -42,9 +42,12 @@ #include <sys/cons.h> #include <sys/unistd.h> #include <sys/kthread.h> +#include <sys/taskqueue.h> #include <machine/bus.h> #include <sys/rman.h> #include <geom/geom_disk.h> +#include <dev/pci/pcivar.h> +#include <dev/pci/pcireg.h> #include <dev/ata/ata-all.h> #include <dev/ata/ata-pci.h> #include <dev/ata/ata-disk.h> @@ -105,7 +108,7 @@ ata_raiddisk_attach(struct ad_softc *adp) return 0; } - switch(adp->device->channel->chiptype & 0xffff) { + switch(pci_get_vendor(device_get_parent(adp->device->channel->dev))) { case ATA_PROMISE_ID: /* test RAID bit in PCI reg XXX */ return (ar_promise_read_conf(adp, ar_table, 0)); @@ -219,7 +222,7 @@ ar_attach_raid(struct ar_softc *rdp, int update) printf(" disk%d SPARE ", disk); else printf(" disk%d FREE ", disk); - printf("on %s at ata%d-%s\n", rdp->disks[disk].device->name, + printf("on %s at ata%d-%s\n", rdp->disks[disk].device->name, device_get_unit(rdp->disks[disk].device->channel->dev), (rdp->disks[disk].device->unit == ATA_MASTER) ? "master" : "slave"); @@ -255,7 +258,7 @@ ata_raid_addspare(int array, int disk) (AR_DF_PRESENT | AR_DF_ONLINE)) && rdp->disks[i].device) continue; if ((atadev = ar_locate_disk(disk))) { - if (((struct ad_softc*)(atadev->driver))->flags & AD_F_RAID_SUBDISK) + if (((struct ad_softc*)(atadev->softc))->flags & AD_F_RAID_SUBDISK) return EBUSY; rdp->disks[i].device = atadev; rdp->disks[i].flags |= (AR_DF_PRESENT|AR_DF_ASSIGNED|AR_DF_SPARE); @@ -306,7 +309,8 @@ ata_raid_create(struct raid_setup *setup) return EBUSY; } - switch (rdp->disks[disk].device->channel->chiptype & 0xffff) { + switch(pci_get_vendor(device_get_parent( + rdp->disks[disk].device->channel->dev))) { case ATA_HIGHPOINT_ID: ctlr |= AR_F_HIGHPOINT_RAID; rdp->disks[disk].disk_sectors = @@ -323,6 +327,7 @@ ata_raid_create(struct raid_setup *setup) PR_LBA(AD_SOFTC(rdp->disks[disk])); break; } + if (rdp->flags & (AR_F_PROMISE_RAID|AR_F_HIGHPOINT_RAID) && (rdp->flags & (AR_F_PROMISE_RAID|AR_F_HIGHPOINT_RAID)) != (ctlr & (AR_F_PROMISE_RAID|AR_F_HIGHPOINT_RAID))) { @@ -437,7 +442,9 @@ ata_raid_delete(int array) for (disk = 0; disk < rdp->total_disks; disk++) { if ((rdp->disks[disk].flags&AR_DF_PRESENT) && rdp->disks[disk].device) { AD_SOFTC(rdp->disks[disk])->flags &= ~AD_F_RAID_SUBDISK; +/* SOS ata_enclosure_leds(rdp->disks[disk].device, ATA_LED_GREEN); + XXX */ rdp->disks[disk].flags = 0; } } @@ -556,15 +563,15 @@ ardump(void *arg, void *virtual, vm_offset_t physical, chunk = blkno % rdp->interleave; if (blkno >= (rdp->total_sectors / (rdp->interleave * rdp->width)) * (rdp->interleave * rdp->width) ) { - lbs = (rdp->total_sectors - + lbs = (rdp->total_sectors - ((rdp->total_sectors / (rdp->interleave * rdp->width)) * (rdp->interleave * rdp->width))) / rdp->width; - drv = (blkno - + drv = (blkno - ((rdp->total_sectors / (rdp->interleave * rdp->width)) * (rdp->interleave * rdp->width))) / lbs; - lba = ((tmplba / rdp->width) * rdp->interleave) + - (blkno - ((tmplba / rdp->width) * rdp->interleave)) % lbs; - chunk = min(count, lbs); + lba = ((tmplba / rdp->width) * rdp->interleave) + + (blkno - ((tmplba / rdp->width) * rdp->interleave)) % lbs; + chunk = min(count, lbs); } else { drv = tmplba % rdp->width; @@ -670,15 +677,15 @@ arstrategy(struct bio *bp) chunk = blkno % rdp->interleave; if (blkno >= (rdp->total_sectors / (rdp->interleave * rdp->width)) * (rdp->interleave * rdp->width) ) { - lbs = (rdp->total_sectors - + lbs = (rdp->total_sectors - ((rdp->total_sectors / (rdp->interleave * rdp->width)) * (rdp->interleave * rdp->width))) / rdp->width; - drv = (blkno - + drv = (blkno - ((rdp->total_sectors / (rdp->interleave * rdp->width)) * (rdp->interleave * rdp->width))) / lbs; - lba = ((tmplba / rdp->width) * rdp->interleave) + - (blkno - ((tmplba / rdp->width) * rdp->interleave)) % lbs; - chunk = min(count, lbs); + lba = ((tmplba / rdp->width) * rdp->interleave) + + (blkno - ((tmplba / rdp->width) * rdp->interleave)) % lbs; + chunk = min(count, lbs); } else { drv = tmplba % rdp->width; @@ -718,7 +725,7 @@ arstrategy(struct bio *bp) case AR_F_RAID0: if ((rdp->disks[buf1->drive].flags & (AR_DF_PRESENT|AR_DF_ONLINE))==(AR_DF_PRESENT|AR_DF_ONLINE) && - !rdp->disks[buf1->drive].device->driver) { + !rdp->disks[buf1->drive].device->softc) { rdp->disks[buf1->drive].flags &= ~AR_DF_ONLINE; ar_config_changed(rdp, 1); free(buf1, M_AR); @@ -743,13 +750,13 @@ arstrategy(struct bio *bp) } if ((rdp->disks[buf1->drive].flags & (AR_DF_PRESENT|AR_DF_ONLINE))==(AR_DF_PRESENT|AR_DF_ONLINE) && - !rdp->disks[buf1->drive].device->driver) { + !rdp->disks[buf1->drive].device->softc) { rdp->disks[buf1->drive].flags &= ~AR_DF_ONLINE; change = 1; } if ((rdp->disks[buf1->drive + rdp->width].flags & (AR_DF_PRESENT|AR_DF_ONLINE))==(AR_DF_PRESENT|AR_DF_ONLINE) && - !rdp->disks[buf1->drive + rdp->width].device->driver) { + !rdp->disks[buf1->drive + rdp->width].device->softc) { rdp->disks[buf1->drive + rdp->width].flags &= ~AR_DF_ONLINE; change = 1; } @@ -948,10 +955,12 @@ ar_config_changed(struct ar_softc *rdp, int writeback) break; } if ((rdp->disks[disk].flags&AR_DF_PRESENT) && rdp->disks[disk].device) { +/* SOS if (rdp->disks[disk].flags & AR_DF_ONLINE) ata_enclosure_leds(rdp->disks[disk].device, ATA_LED_GREEN); else ata_enclosure_leds(rdp->disks[disk].device, ATA_LED_RED); + XXX */ } } if (writeback) { @@ -986,7 +995,9 @@ ar_rebuild(void *arg) #endif continue; } +/* SOS ata_enclosure_leds(rdp->disks[disk].device, ATA_LED_ORANGE); + XXX */ count++; } } @@ -1278,7 +1289,7 @@ ar_highpoint_write_conf(struct ar_softc *rdp) config->total_sectors = rdp->total_sectors; config->rebuild_lba = rdp->lock_start; - if (rdp->disks[disk].device && rdp->disks[disk].device->driver && + if (rdp->disks[disk].device && rdp->disks[disk].device->softc && !(rdp->disks[disk].device->flags & ATA_D_DETACHING)) { if (ar_rw(AD_SOFTC(rdp->disks[disk]), HPT_LBA, sizeof(struct highpoint_raid_conf), @@ -1356,7 +1367,8 @@ ar_promise_read_conf(struct ad_softc *adp, struct ar_softc **raidp, int local) if (raid->flags & AR_F_HIGHPOINT_RAID) continue; - magic = (adp->device->channel->chiptype >> 16) | + magic = (pci_get_device(device_get_parent( + adp->device->channel->dev)) >> 16) | (info->raid.array_number << 16); if (raid->flags & AR_F_PROMISE_RAID && magic != raid->magic_0) @@ -1486,7 +1498,7 @@ ar_promise_write_conf(struct ar_softc *rdp) if (rdp->disks[disk].flags & AR_DF_PRESENT && rdp->disks[disk].device) { config->raid.channel = rdp->disks[disk].device->channel->unit; config->raid.device = (rdp->disks[disk].device->unit != 0); - if (rdp->disks[disk].device->driver) + if (rdp->disks[disk].device->softc) config->raid.disk_sectors = PR_LBA(AD_SOFTC(rdp->disks[disk])); /*config->raid.disk_offset*/ } @@ -1558,10 +1570,10 @@ ar_promise_write_conf(struct ar_softc *rdp) PR_MAGIC0(rdp->disks[drive]) | timestamp.tv_sec; } - if (rdp->disks[disk].device && rdp->disks[disk].device->driver && + if (rdp->disks[disk].device && rdp->disks[disk].device->softc && !(rdp->disks[disk].device->flags & ATA_D_DETACHING)) { if ((rdp->disks[disk].flags & (AR_DF_PRESENT | AR_DF_ONLINE)) == - (AR_DF_PRESENT | AR_DF_ONLINE)) { + (AR_DF_PRESENT | AR_DF_ONLINE)) { if (local) bcopy(ATA_MAGIC, config->promise_id, sizeof(ATA_MAGIC)); else @@ -1635,12 +1647,12 @@ ar_locate_disk(int diskno) if (!(ch = devclass_get_softc(ata_devclass, ctlr))) continue; if (ch->devices & ATA_ATA_MASTER) - if (ch->device[MASTER].driver && - ((struct ad_softc *)(ch->device[MASTER].driver))->lun == diskno) + if (ch->device[MASTER].softc && + ((struct ad_softc *)(ch->device[MASTER].softc))->lun == diskno) return &ch->device[MASTER]; if (ch->devices & ATA_ATA_SLAVE) - if (ch->device[SLAVE].driver && - ((struct ad_softc *)(ch->device[SLAVE].driver))->lun == diskno) + if (ch->device[SLAVE].softc && + ((struct ad_softc *)(ch->device[SLAVE].softc))->lun == diskno) return &ch->device[SLAVE]; } return NULL; @@ -1656,7 +1668,7 @@ ar_print_conf(struct ar_softc *config) printf("magic_1 0x%08x\n", config->magic_1); printf("flags 0x%02x %b\n", config->flags, config->flags, "\20\16HIGHPOINT\15PROMISE\13REBUILDING\12DEGRADED\11READY\3SPAN\2RAID1\1RAID0\n"); - printf("total_disks %d\n", config->total_disks); + printf("total_disks %d\n", config->total_disks); printf("generation %d\n", config->generation); printf("width %d\n", config->width); printf("heads %d\n", config->heads); @@ -1670,6 +1682,6 @@ ar_print_conf(struct ar_softc *config) printf("disk %d: flags = 0x%02x %b\n", i, config->disks[i].flags, config->disks[i].flags, "\20\4ONLINE\3SPARE\2ASSIGNED\1PRESENT\n"); if (config->disks[i].device) printf(" %s\n", config->disks[i].device->name); - printf(" sectors %lld\n", (long long)config->disks[i].disk_sectors); + printf(" sectors %lld\n", (long long)config->disks[i].disk_sectors); } } diff --git a/sys/dev/ata/ata-raid.h b/sys/dev/ata/ata-raid.h index 2b6ba54f1dbd..9af598eacf15 100644 --- a/sys/dev/ata/ata-raid.h +++ b/sys/dev/ata/ata-raid.h @@ -36,7 +36,7 @@ #define AR_WRITE 0x02 #define AR_WAIT 0x04 #define AR_STRATEGY(x) (x)->bio_disk->d_strategy((x)) -#define AD_SOFTC(x) ((struct ad_softc *)(x.device->driver)) +#define AD_SOFTC(x) ((struct ad_softc *)(x.device->softc)) #define ATA_MAGIC "FreeBSD ATA driver RAID " struct ar_disk { diff --git a/sys/dev/ata/atapi-all.c b/sys/dev/ata/atapi-all.c deleted file mode 100644 index 1b27ca4038f7..000000000000 --- a/sys/dev/ata/atapi-all.c +++ /dev/null @@ -1,699 +0,0 @@ -/*- - * Copyright (c) 1998 - 2003 Søren Schmidt <sos@FreeBSD.org> - * 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_ata.h" -#include <sys/param.h> -#include <sys/systm.h> -#include <sys/ata.h> -#include <sys/kernel.h> -#include <sys/bus.h> -#include <sys/malloc.h> -#include <sys/bio.h> -#include <sys/sysctl.h> -#include <machine/bus.h> -#include <sys/rman.h> -#include <dev/ata/ata-all.h> -#include <dev/ata/atapi-all.h> - -/* 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_cmd2str(u_int8_t); -static char *atapi_skey2str(u_int8_t); - -/* misc defines */ -#define ATAPI_MAX_RETRIES 3 - -/* internal vars */ -static int atapi_dma = 0; -TUNABLE_INT("hw.ata.atapi_dma", &atapi_dma); -static MALLOC_DEFINE(M_ATAPI, "ATAPI generic", "ATAPI driver generic layer"); - -/* systcl vars */ -SYSCTL_DECL(_hw_ata); -SYSCTL_INT(_hw_ata, OID_AUTO, atapi_dma, CTLFLAG_RD, &atapi_dma, 0, - "ATAPI device DMA mode control"); - -void -atapi_attach(struct ata_device *atadev) -{ - if (bootverbose) - ata_prtdev(atadev, "piomode=%d dmamode=%d udmamode=%d dmaflag=%d\n", - ata_pmode(atadev->param), ata_wmode(atadev->param), - ata_umode(atadev->param), atadev->param->support_dma); - - /* use DMA if allowed and if drive/controller supports it */ - ATA_SLEEPLOCK_CH(atadev->channel, ATA_CONTROL); - if (atapi_dma && atadev->channel->dma && - !(atadev->param->drq_type == ATAPI_DRQT_INTR)) - atadev->setmode(atadev, ATA_DMA_MAX); - else - atadev->setmode(atadev, ATA_PIO_MAX); - ATA_UNLOCK_CH(atadev->channel); - - if (!(atadev->result = malloc(sizeof(struct atapi_reqsense), M_ATAPI, - M_NOWAIT | M_ZERO))) - ata_prtdev(atadev, "no memory for sense data\n"); - - switch (atadev->param->type) { -#ifdef DEV_ATAPICD - case ATAPI_TYPE_CDROM: - if (acdattach(atadev)) - return; - break; -#endif -#ifdef DEV_ATAPIFD - case ATAPI_TYPE_DIRECT: - if (afdattach(atadev)) - return; - break; -#endif -#ifdef DEV_ATAPIST - case ATAPI_TYPE_TAPE: - if (astattach(atadev)) - return; - break; -#endif - } -#ifndef DEV_ATAPICAM - ata_prtdev(atadev, "<%.40s/%.8s> - NO DRIVER!\n", - atadev->param->model, atadev->param->revision); - free(atadev->result, M_ATAPI); - atadev->driver = NULL; -#endif -} - -void -atapi_detach(struct ata_device *atadev) -{ - struct atapi_request *request; - - atadev->flags |= ATA_D_DETACHING; - ata_prtdev(atadev, "removed from configuration\n"); - switch (atadev->param->type) { -#ifdef DEV_ATAPICD - case ATAPI_TYPE_CDROM: - acddetach(atadev); - break; -#endif -#ifdef DEV_ATAPIFD - case ATAPI_TYPE_DIRECT: - afddetach(atadev); - break; -#endif -#ifdef DEV_ATAPIST - case ATAPI_TYPE_TAPE: - astdetach(atadev); - break; -#endif - default: - return; - } - TAILQ_FOREACH(request, &atadev->channel->atapi_queue, chain) { - if (request->device != atadev) - continue; - TAILQ_REMOVE(&atadev->channel->atapi_queue, request, chain); - if (request->driver) { - struct bio *bp = (struct bio *) request->driver; - biofinish(bp, NULL, ENXIO); - } - free(request, M_ATAPI); - } - free(atadev->result, M_ATAPI); - atadev->driver = NULL; - atadev->flags = 0; - -} - -int -atapi_queue_cmd(struct ata_device *atadev, 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 = atadev; - request->data = data; - request->bytecount = count; - request->flags = flags; - request->error = EINPROGRESS; - request->timeout = timeout * hz; - request->ccbsize = atadev->param->packet_size ? 16 : 12; - bcopy(ccb, request->ccb, request->ccbsize); - if (callback) { - request->callback = callback; - request->driver = driver; - } - if (atadev->mode >= ATA_DMA && !atadev->channel->dma) - atadev->mode = ATA_PIO; - -#ifdef ATAPI_DEBUG - ata_prtdev(atadev, "queueing %s ", atapi_cmd2str(request->ccb[0])); - atapi_dump("ccb = ", &request->ccb[0], sizeof(request->ccb)); -#endif - /* append onto controller queue and try to start controller */ - s = splbio(); - if (flags & ATPR_F_AT_HEAD) - TAILQ_INSERT_HEAD(&atadev->channel->atapi_queue, request, chain); - else - TAILQ_INSERT_TAIL(&atadev->channel->atapi_queue, request, chain); - ata_start(atadev->channel); - - /* if callback used, then just return, gets called from interrupt context */ - if (callback) { - splx(s); - return 0; - } - - /* only sleep when command is in progress */ - if (request->error == EINPROGRESS) - tsleep(request, PRIBIO, "atprq", 0); - splx(s); - error = request->error; - if (error) - bcopy(&request->sense, atadev->result, sizeof(struct atapi_reqsense)); - free(request, M_ATAPI); - return error; -} - -void -atapi_start(struct ata_device *atadev) -{ - switch (atadev->param->type) { -#ifdef DEV_ATAPICD - case ATAPI_TYPE_CDROM: - acd_start(atadev); - break; -#endif -#ifdef DEV_ATAPIFD - case ATAPI_TYPE_DIRECT: - afd_start(atadev); - break; -#endif -#ifdef DEV_ATAPIST - case ATAPI_TYPE_TAPE: - ast_start(atadev); - break; -#endif - default: - return; - } -} - -int -atapi_transfer(struct atapi_request *request) -{ - struct ata_device *atadev = request->device; - int timout; - u_int8_t reason; - -#ifdef ATAPI_DEBUG - ata_prtdev(atadev, "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_IDX_OUTB(atadev->channel, ATA_DRIVE, ATA_D_IBM | atadev->unit); - DELAY(10); - if (ATA_IDX_INB(atadev->channel, 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)) - atadev->cmd = request->ccb[0]; - - /* if DMA enabled setup DMA hardware */ - request->flags &= ~ATPR_F_DMA_USED; - if ((atadev->mode >= ATA_DMA) && - (request->ccb[0] == ATAPI_READ || - request->ccb[0] == ATAPI_READ_BIG || - request->ccb[0] == ATAPI_READ_CD || - ((request->ccb[0] == ATAPI_WRITE || - request->ccb[0] == ATAPI_WRITE_BIG) && - !(atadev->channel->flags & ATA_ATAPI_DMA_RO))) && - !atadev->channel->dma->setup(atadev, (void *)request->data, request->bytecount)) { - request->flags |= ATPR_F_DMA_USED; - } - - /* start ATAPI operation */ - if (ata_command(atadev, ATA_C_PACKET_CMD, - min(request->bytecount, 65534) << 8, 0, - (request->flags & ATPR_F_DMA_USED) ? ATA_F_DMA : 0, - ATA_IMMEDIATE)) - ata_prtdev(atadev, "failure to send ATAPI packet command\n"); - - if (request->flags & ATPR_F_DMA_USED) - atadev->channel->dma->start(atadev->channel, request->data, request->bytecount, - request->flags & ATPR_F_READ); - - /* command interrupt device ? just return */ - if (atadev->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_IDX_INB(atadev->channel, ATA_IREASON); - atadev->channel->status = ATA_IDX_INB(atadev->channel, ATA_STATUS); - if (((reason & (ATA_I_CMD | ATA_I_IN)) | - (atadev->channel->status&(ATA_S_DRQ|ATA_S_BUSY)))==ATAPI_P_CMDOUT) - break; - DELAY(20); - } - if (timout <= 0) { - ata_prtdev(atadev, "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_IDX_OUTSW_STRM(atadev->channel, ATA_DATA, (int16_t *)request->ccb, - request->ccbsize / sizeof(int16_t)); - return ATA_OP_CONTINUES; -} - -int -atapi_interrupt(struct atapi_request *request) -{ - struct ata_device *atadev = request->device; - int reason, dma_stat = 0; - - reason = (ATA_IDX_INB(atadev->channel, ATA_IREASON) & (ATA_I_CMD | ATA_I_IN)) | - (atadev->channel->status & ATA_S_DRQ); - - if (reason == ATAPI_P_CMDOUT) { - if (!(atadev->channel->status & ATA_S_DRQ)) { - ata_prtdev(atadev, "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_IDX_OUTSW_STRM(atadev->channel, ATA_DATA, (int16_t *)request->ccb, - request->ccbsize / sizeof(int16_t)); - return ATA_OP_CONTINUES; - } - - if (request->flags & ATPR_F_DMA_USED) { - dma_stat = atadev->channel->dma->stop(atadev->channel); - if ((atadev->channel->status & (ATA_S_ERROR | ATA_S_DWF)) || - dma_stat & ATA_BMSTAT_ERROR) { - request->result = ATA_IDX_INB(atadev->channel, ATA_ERROR); - } - else { - request->result = 0; - request->donecount = request->bytecount; - request->bytecount = 0; - } - } - else { - int length = ATA_IDX_INB(atadev->channel, ATA_CYL_LSB) | - ATA_IDX_INB(atadev->channel, ATA_CYL_MSB) << 8; - - switch (reason) { - case ATAPI_P_WRITE: - if (request->flags & ATPR_F_READ) { - request->result = ATA_IDX_INB(atadev->channel, ATA_ERROR); - ata_prtdev(atadev, "%s trying to write on read buffer\n", - atapi_cmd2str(atadev->cmd)); - break; - } - atapi_write(request, length); - return ATA_OP_CONTINUES; - - case ATAPI_P_READ: - if (!(request->flags & ATPR_F_READ)) { - request->result = ATA_IDX_INB(atadev->channel, ATA_ERROR); - ata_prtdev(atadev, "%s trying to read on write buffer\n", - atapi_cmd2str(atadev->cmd)); - break; - } - atapi_read(request, length); - return ATA_OP_CONTINUES; - - case ATAPI_P_DONEDRQ: - ata_prtdev(atadev, "%s DONEDRQ\n", atapi_cmd2str(atadev->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 (atadev->channel->status & (ATA_S_ERROR | ATA_S_DWF)) - request->result = ATA_IDX_INB(atadev->channel, ATA_ERROR); - else - if (!(request->flags & ATPR_F_INTERNAL)) - request->result = 0; - break; - - default: - ata_prtdev(atadev, "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(&atadev->channel->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_prtdev(atadev, "%s - recovered error\n", - atapi_cmd2str(atadev->cmd)); - request->error = 0; - break; - - case ATAPI_SK_NOT_READY: - request->error = EBUSY; - break; - - case ATAPI_SK_UNIT_ATTENTION: - atadev->flags |= ATA_D_MEDIA_CHANGED; - request->error = EIO; - break; - - default: - request->error = EIO; - - if (request->flags & ATPR_F_QUIET) - break; - - ata_prtdev(atadev, "%s - %s asc=0x%02x ascq=0x%02x ", - atapi_cmd2str(atadev->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 ata_device *atadev) -{ - /* reinit device parameters */ - atadev->setmode(atadev, atadev->mode); -} - -int -atapi_test_ready(struct ata_device *atadev) -{ - 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(atadev, ccb, NULL, 0, 0, 30, NULL, NULL); -} - -int -atapi_wait_dsc(struct ata_device *atadev, 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(atadev, ccb, NULL, 0, 0, 0, NULL, NULL); - if (error != EBUSY) - break; - tsleep(&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_channel *ch = request->device->channel; - int resid; - - if (request->flags & ATPR_F_INTERNAL) - *buffer = (int8_t *)&request->sense; - - if (ch->flags & ATA_USE_16BIT || (size % sizeof(int32_t))) - ATA_IDX_INSW_STRM(ch, ATA_DATA, (void *)((uintptr_t)*buffer), - size / sizeof(int16_t)); - else - ATA_IDX_INSL_STRM(ch, ATA_DATA, (void *)((uintptr_t)*buffer), - size / sizeof(int32_t)); - - if (request->bytecount < length) { - ata_prtdev(request->device, "read data overrun %d/%d\n", - length, request->bytecount); - for (resid=request->bytecount; resid<length; resid+=sizeof(int16_t)) - ATA_IDX_INW(ch, 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_channel *ch = request->device->channel; - int resid; - - if (request->flags & ATPR_F_INTERNAL) - *buffer = (int8_t *)&request->sense; - - if (ch->flags & ATA_USE_16BIT || (size % sizeof(int32_t))) - ATA_IDX_OUTSW_STRM(ch, ATA_DATA, (void *)((uintptr_t)*buffer), - size / sizeof(int16_t)); - else - ATA_IDX_OUTSL_STRM(ch, ATA_DATA, (void *)((uintptr_t)*buffer), - size / sizeof(int32_t)); - - if (request->bytecount < length) { - ata_prtdev(request->device, "write data underrun %d/%d\n", - length, request->bytecount); - for (resid=request->bytecount; resid<length; resid+=sizeof(int16_t)) - ATA_IDX_OUTW(ch, ATA_DATA, 0); - } - *buffer += size; - request->bytecount -= size; - request->donecount += size; -} - -static void -atapi_finish(struct atapi_request *request) -{ -#ifdef ATAPI_DEBUG - ata_prtdev(request->device, "finished %s%s\n", - request->callback ? "callback " : "", - atapi_cmd2str(request->ccb[0])); -#endif - if (request->callback) { - if (!((request->callback)(request))) - free(request, M_ATAPI); - } - else - wakeup(request); -} - -static void -atapi_timeout(struct atapi_request *request) -{ - struct ata_device *atadev = request->device; - - atadev->channel->running = NULL; - ata_prtdev(atadev, "%s command timeout - resetting\n", - atapi_cmd2str(request->ccb[0])); - - if (request->flags & ATPR_F_DMA_USED) { - atadev->channel->dma->stop(atadev->channel); - if (request->retries == ATAPI_MAX_RETRIES) { - atadev->setmode(atadev, ATA_PIO_MAX); - ata_prtdev(atadev, "trying fallback to PIO mode\n"); - request->retries = 0; - } - } - - /* if retries still permit, reinject this request */ - if (request->retries++ < ATAPI_MAX_RETRIES) { - int s = splbio(); - - TAILQ_INSERT_HEAD(&atadev->channel->atapi_queue, request, chain); - splx(s); - } - else { - /* retries all used up, return error */ - request->error = EIO; - wakeup(request); - } - ata_reinit(atadev->channel); -} - -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 0x23: return ("ATAPI_READ_FORMAT_CAPACITIES"); - 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[20]; - 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"); - } -} diff --git a/sys/dev/ata/atapi-all.h b/sys/dev/ata/atapi-all.h deleted file mode 100644 index d41b696f5d71..000000000000 --- a/sys/dev/ata/atapi-all.h +++ /dev/null @@ -1,196 +0,0 @@ -/*- - * Copyright (c) 1998 - 2003 Søren Schmidt <sos@FreeBSD.org> - * 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$ - */ - -/* ATAPI misc defines */ -#define ATAPI_MAGIC_LSB 0x14 -#define ATAPI_MAGIC_MSB 0xeb -#define ATAPI_P_READ (ATA_S_DRQ | ATA_I_IN) -#define ATAPI_P_WRITE (ATA_S_DRQ) -#define ATAPI_P_CMDOUT (ATA_S_DRQ | ATA_I_CMD) -#define ATAPI_P_DONEDRQ (ATA_S_DRQ | ATA_I_CMD | ATA_I_IN) -#define ATAPI_P_DONE (ATA_I_CMD | ATA_I_IN) -#define ATAPI_P_ABORT 0 - -/* error register bits */ -#define ATAPI_E_MASK 0x0f /* error mask */ -#define ATAPI_E_ILI 0x01 /* illegal length indication */ -#define ATAPI_E_EOM 0x02 /* end of media detected */ -#define ATAPI_E_ABRT 0x04 /* command aborted */ -#define ATAPI_E_MCR 0x08 /* media change requested */ -#define ATAPI_SK_MASK 0xf0 /* sense key mask */ -#define ATAPI_SK_NO_SENSE 0x00 /* no specific sense key info */ -#define ATAPI_SK_RECOVERED_ERROR 0x10 /* command OK, data recovered */ -#define ATAPI_SK_NOT_READY 0x20 /* no access to drive */ -#define ATAPI_SK_MEDIUM_ERROR 0x30 /* non-recovered data error */ -#define ATAPI_SK_HARDWARE_ERROR 0x40 /* non-recoverable HW failure */ -#define ATAPI_SK_ILLEGAL_REQUEST 0x50 /* invalid command param(s) */ -#define ATAPI_SK_UNIT_ATTENTION 0x60 /* media changed */ -#define ATAPI_SK_DATA_PROTECT 0x70 /* write protect */ -#define ATAPI_SK_BLANK_CHECK 0x80 /* blank check */ -#define ATAPI_SK_VENDOR_SPECIFIC 0x90 /* vendor specific skey */ -#define ATAPI_SK_COPY_ABORTED 0xa0 /* copy aborted */ -#define ATAPI_SK_ABORTED_COMMAND 0xb0 /* command aborted, try again */ -#define ATAPI_SK_EQUAL 0xc0 /* equal */ -#define ATAPI_SK_VOLUME_OVERFLOW 0xd0 /* volume overflow */ -#define ATAPI_SK_MISCOMPARE 0xe0 /* data dont match the medium */ -#define ATAPI_SK_RESERVED 0xf0 - -/* ATAPI commands */ -#define ATAPI_TEST_UNIT_READY 0x00 /* check if device is ready */ -#define ATAPI_REZERO 0x01 /* rewind */ -#define ATAPI_REQUEST_SENSE 0x03 /* get sense data */ -#define ATAPI_FORMAT 0x04 /* format unit */ -#define ATAPI_READ 0x08 /* read data */ -#define ATAPI_WRITE 0x0a /* write data */ -#define ATAPI_WEOF 0x10 /* write filemark */ -#define WF_WRITE 0x01 -#define ATAPI_SPACE 0x11 /* space command */ -#define SP_FM 0x01 -#define SP_EOD 0x03 -#define ATAPI_MODE_SELECT 0x15 /* mode select */ -#define ATAPI_ERASE 0x19 /* erase */ -#define ATAPI_MODE_SENSE 0x1a /* mode sense */ -#define ATAPI_START_STOP 0x1b /* start/stop unit */ -#define SS_LOAD 0x01 -#define SS_RETENSION 0x02 -#define SS_EJECT 0x04 -#define ATAPI_PREVENT_ALLOW 0x1e /* media removal */ -#define ATAPI_READ_FORMAT_CAPACITIES 0x23 /* get format capacities */ -#define ATAPI_READ_CAPACITY 0x25 /* get volume capacity */ -#define ATAPI_READ_BIG 0x28 /* read data */ -#define ATAPI_WRITE_BIG 0x2a /* write data */ -#define ATAPI_LOCATE 0x2b /* locate to position */ -#define ATAPI_READ_POSITION 0x34 /* read position */ -#define ATAPI_SYNCHRONIZE_CACHE 0x35 /* flush buf, close channel */ -#define ATAPI_WRITE_BUFFER 0x3b /* write device buffer */ -#define ATAPI_READ_BUFFER 0x3c /* read device buffer */ -#define ATAPI_READ_SUBCHANNEL 0x42 /* get subchannel info */ -#define ATAPI_READ_TOC 0x43 /* get table of contents */ -#define ATAPI_PLAY_10 0x45 /* play by lba */ -#define ATAPI_PLAY_MSF 0x47 /* play by MSF address */ -#define ATAPI_PLAY_TRACK 0x48 /* play by track number */ -#define ATAPI_PAUSE 0x4b /* pause audio operation */ -#define ATAPI_READ_DISK_INFO 0x51 /* get disk info structure */ -#define ATAPI_READ_TRACK_INFO 0x52 /* get track info structure */ -#define ATAPI_RESERVE_TRACK 0x53 /* reserve track */ -#define ATAPI_SEND_OPC_INFO 0x54 /* send OPC structurek */ -#define ATAPI_MODE_SELECT_BIG 0x55 /* set device parameters */ -#define ATAPI_REPAIR_TRACK 0x58 /* repair track */ -#define ATAPI_READ_MASTER_CUE 0x59 /* read master CUE info */ -#define ATAPI_MODE_SENSE_BIG 0x5a /* get device parameters */ -#define ATAPI_CLOSE_TRACK 0x5b /* close track/session */ -#define ATAPI_READ_BUFFER_CAPACITY 0x5c /* get buffer capicity */ -#define ATAPI_SEND_CUE_SHEET 0x5d /* send CUE sheet */ -#define ATAPI_BLANK 0xa1 /* blank the media */ -#define ATAPI_SEND_KEY 0xa3 /* send DVD key structure */ -#define ATAPI_REPORT_KEY 0xa4 /* get DVD key structure */ -#define ATAPI_PLAY_12 0xa5 /* play by lba */ -#define ATAPI_LOAD_UNLOAD 0xa6 /* changer control command */ -#define ATAPI_READ_STRUCTURE 0xad /* get DVD structure */ -#define ATAPI_PLAY_CD 0xb4 /* universal play command */ -#define ATAPI_SET_SPEED 0xbb /* set drive speed */ -#define ATAPI_MECH_STATUS 0xbd /* get changer status */ -#define ATAPI_READ_CD 0xbe /* read data */ -#define ATAPI_POLL_DSC 0xff /* poll DSC status bit */ - -/* ATAPI request sense structure */ -struct atapi_reqsense { - u_int8_t error_code :7; /* current or deferred errors */ - u_int8_t valid :1; /* follows ATAPI spec */ - u_int8_t segment; /* Segment number */ - u_int8_t sense_key :4; /* sense key */ - u_int8_t reserved2_4 :1; /* reserved */ - u_int8_t ili :1; /* incorrect length indicator */ - u_int8_t eom :1; /* end of medium */ - u_int8_t filemark :1; /* filemark */ - /* cmd information */ - u_int32_t cmd_info __packed; - u_int8_t sense_length; /* additional sense len (n-7) */ - /* additional cmd spec info */ - u_int32_t cmd_specific_info __packed; - u_int8_t asc; /* additional sense code */ - u_int8_t ascq; /* additional sense code qual */ - u_int8_t replaceable_unit_code; /* replaceable unit code */ - u_int8_t sk_specific :7; /* sense key specific */ - u_int8_t sksv :1; /* sense key specific info OK */ - u_int8_t sk_specific1; /* sense key specific */ - u_int8_t sk_specific2; /* sense key specific */ -}; - -typedef int atapi_callback_t(struct atapi_request *); - -struct atapi_request { - struct ata_device *device; /* ptr to parent softc */ - u_int8_t ccb[16]; /* command control block */ - int ccbsize; /* size of ccb (12 | 16) */ - u_int32_t bytecount; /* bytes to transfer */ - u_int32_t donecount; /* bytes transferred */ - int timeout; /* timeout for this cmd */ - struct callout_handle timeout_handle; /* handle for untimeout */ - int retries; /* retry count */ - int result; /* result of this cmd */ - int error; /* result translated to errno */ - struct atapi_reqsense sense; /* sense data if error */ - int flags; -#define ATPR_F_READ 0x0001 -#define ATPR_F_DMA_USED 0x0002 -#define ATPR_F_AT_HEAD 0x0004 -#define ATPR_F_INTERNAL 0x0008 -#define ATPR_F_QUIET 0x0010 - - caddr_t data; /* pointer to data buf */ - atapi_callback_t *callback; /* ptr to callback func */ - void *driver; /* driver specific */ - TAILQ_ENTRY(atapi_request) chain; /* list management */ -}; - -void atapi_attach(struct ata_device *); -void atapi_cam_attach_bus(struct ata_channel *); -void atapi_detach(struct ata_device *); -void atapi_cam_detach_bus(struct ata_channel *); -void atapi_cam_reinit_bus(struct ata_channel *); -void atapi_reinit(struct ata_device *); -void atapi_start(struct ata_device *); -int atapi_transfer(struct atapi_request *); -int atapi_interrupt(struct atapi_request *); -int atapi_queue_cmd(struct ata_device *, int8_t [], caddr_t, int, int, int, atapi_callback_t, void *); -int atapi_test_ready(struct ata_device *); -int atapi_wait_dsc(struct ata_device *, int); -void atapi_request_sense(struct ata_device *, struct atapi_reqsense *); -void atapi_dump(char *, void *, int); -int acdattach(struct ata_device *); -void acddetach(struct ata_device *); -void acd_start(struct ata_device *); -int afdattach(struct ata_device *); -void afddetach(struct ata_device *); -void afd_start(struct ata_device *); -int astattach(struct ata_device *); -void astdetach(struct ata_device *); -void ast_start(struct ata_device *); diff --git a/sys/dev/ata/atapi-cam.c b/sys/dev/ata/atapi-cam.c index b694ac62a2c5..0aea83f1c0af 100644 --- a/sys/dev/ata/atapi-cam.c +++ b/sys/dev/ata/atapi-cam.c @@ -1,5 +1,5 @@ /*- - * Copyright (c) 2001,2002 Thomas Quinot <thomas@cuivre.fr.eu.org> + * Copyright (c) 2001-2003 Thomas Quinot <thomas@cuivre.fr.eu.org> * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -34,6 +34,9 @@ #include <sys/kernel.h> #include <sys/malloc.h> #include <sys/ata.h> +#include <sys/taskqueue.h> +#include <sys/lock.h> +#include <sys/mutex.h> #include <machine/bus.h> #include <cam/cam.h> @@ -45,7 +48,6 @@ #include <cam/scsi/scsi_all.h> #include <dev/ata/ata-all.h> -#include <dev/ata/atapi-all.h> /* hardware command descriptor block */ struct atapi_hcb { @@ -55,7 +57,6 @@ struct atapi_hcb { int target; int lun; union ccb *ccb; - u_int8_t cmd[CAM_MAX_CDBLEN]; int flags; #define DOING_AUTOSENSE 1 @@ -78,6 +79,7 @@ struct atapi_xpt_softc { enum reinit_reason { BOOT_ATTACH, ATTACH, RESET }; +static struct mtx atapicam_softc_mtx; static LIST_HEAD(,atapi_xpt_softc) all_buses = LIST_HEAD_INITIALIZER(all_buses); /* CAM XPT methods */ @@ -85,7 +87,7 @@ static void atapi_action(struct cam_sim *, union ccb *); static void atapi_poll(struct cam_sim *); static void atapi_async(void *, u_int32_t, struct cam_path *, void *); static void atapi_async1(void *, u_int32_t, struct cam_path *, void *); -static int atapi_cb(struct atapi_request *); +static void atapi_cb(struct ata_request *); /* internal functions */ static void reinit_bus(struct atapi_xpt_softc *scp, enum reinit_reason reason); @@ -102,7 +104,7 @@ static struct ata_device *get_ata_device(struct atapi_xpt_softc *scp, int id); static MALLOC_DEFINE(M_ATACAM, "ATA CAM transport", "ATA driver CAM-XPT layer"); -void +void atapi_cam_attach_bus(struct ata_channel *ata_ch) { struct atapi_xpt_softc *scp = NULL; @@ -111,10 +113,21 @@ atapi_cam_attach_bus(struct ata_channel *ata_ch) struct cam_path *path = NULL; int unit; + GIANT_REQUIRED; + + if (mtx_initialized(&atapicam_softc_mtx) == 0) + mtx_init(&atapicam_softc_mtx, "ATAPI/CAM softc mutex", NULL, MTX_DEF); + + mtx_lock(&atapicam_softc_mtx); + LIST_FOREACH(scp, &all_buses, chain) { if (scp->ata_ch == ata_ch) - return; + break; } + mtx_unlock(&atapicam_softc_mtx); + + if (scp != NULL) + return; if ((scp = malloc(sizeof(struct atapi_xpt_softc), M_ATACAM, M_NOWAIT | M_ZERO)) == NULL) @@ -157,11 +170,14 @@ error: free_softc(scp); } -void +void atapi_cam_detach_bus(struct ata_channel *ata_ch) { struct atapi_xpt_softc *scp = get_softc(ata_ch); + + mtx_lock(&Giant); free_softc(scp); + mtx_unlock(&Giant); } void @@ -173,12 +189,18 @@ atapi_cam_reinit_bus(struct ata_channel *ata_ch) { * the boot-up sequence, before the ATAPI bus is registered. */ - if (scp != NULL) + if (scp != NULL) { + mtx_lock(&Giant); reinit_bus(scp, RESET); + mtx_unlock(&Giant); + } } static void reinit_bus(struct atapi_xpt_softc *scp, enum reinit_reason reason) { + + GIANT_REQUIRED; + if (scp->ata_ch->devices & ATA_ATAPI_MASTER) setup_dev(scp, &scp->ata_ch->device[MASTER]); if (scp->ata_ch->devices & ATA_ATAPI_SLAVE) @@ -199,11 +221,11 @@ reinit_bus(struct atapi_xpt_softc *scp, enum reinit_reason reason) { static void setup_dev(struct atapi_xpt_softc *scp, struct ata_device *atp) { - if (atp->driver == NULL) { + if (atp->softc == NULL) { ata_set_name(atp, "atapicam", 2 * device_get_unit(atp->channel->dev) + (atp->unit == ATA_MASTER) ? 0 : 1); - atp->driver = (void *)scp; + atp->softc = (void *)scp; } } @@ -212,6 +234,8 @@ setup_async_cb(struct atapi_xpt_softc *scp, uint32_t events) { struct ccb_setasync csa; + GIANT_REQUIRED; + xpt_setup_ccb(&csa.ccb_h, scp->path, /*priority*/ 5); csa.ccb_h.func_code = XPT_SASYNC_CB; csa.event_enable = events; @@ -220,15 +244,16 @@ setup_async_cb(struct atapi_xpt_softc *scp, uint32_t events) xpt_action((union ccb *) &csa); } -static void +static void atapi_action(struct cam_sim *sim, union ccb *ccb) { struct atapi_xpt_softc *softc = (struct atapi_xpt_softc*)cam_sim_softc(sim); struct ccb_hdr *ccb_h = &ccb->ccb_h; struct atapi_hcb *hcb = NULL; + struct ata_request *request = NULL; int unit = cam_sim_unit(sim); int bus = cam_sim_bus(sim); - int len, s; + int len; char *buf; switch (ccb_h->func_code) { @@ -292,7 +317,7 @@ atapi_action(struct cam_sim *sim, union ccb *ccb) struct ata_device *dev = get_ata_device(softc, tid); CAM_DEBUG(ccb->ccb_h.path, CAM_DEBUG_SUBTRACE, ("dev reset\n")); - atapi_reinit(dev); + ata_controlcmd(dev, ATA_ATAPI_RESET, 0, 0, 0); ccb->ccb_h.status = CAM_REQ_CMP; xpt_done(ccb); return; @@ -352,37 +377,45 @@ atapi_action(struct cam_sim *sim, union ccb *ccb) if (dev == NULL) { CAM_DEBUG(ccb_h->path, CAM_DEBUG_SUBTRACE, ("SCSI IO received for invalid device\n")); - ccb_h->status = CAM_TID_INVALID; - xpt_done(ccb); - return; + goto action_invalid; } if (lid > 0) { CAM_DEBUG(ccb_h->path, CAM_DEBUG_SUBTRACE, ("SCSI IO received for invalid lun %d\n", lid)); - ccb_h->status = CAM_LUN_INVALID; - xpt_done(ccb); - return; + goto action_invalid; + } + if (csio->cdb_len > sizeof request->u.atapi.ccb) { + CAM_DEBUG(ccb_h->path, CAM_DEBUG_SUBTRACE, + ("CAM CCB too long for ATAPI")); + goto action_invalid; } if ((ccb_h->flags & CAM_SCATTER_VALID)) { /* scatter-gather not supported */ xpt_print_path(ccb_h->path); - printf("ATAPI-CAM does not support scatter-gather yet!\n"); + printf("ATAPI/CAM does not support scatter-gather yet!\n"); break; } - if ((hcb = allocate_hcb(softc, unit, bus, ccb)) == NULL) + + if ((hcb = allocate_hcb(softc, unit, bus, ccb)) == NULL) { + printf("cannot allocate ATAPI/CAM hcb\n"); goto action_oom; + } + if ((request = ata_alloc_request()) == NULL) { + printf("cannot allocate ATAPI/CAM request\n"); + goto action_oom; + } ccb_h->status |= CAM_SIM_QUEUED; bcopy((ccb_h->flags & CAM_CDB_POINTER) ? csio->cdb_io.cdb_ptr : csio->cdb_io.cdb_bytes, - hcb->cmd, csio->cdb_len); + request->u.atapi.ccb, csio->cdb_len); #ifdef CAMDEBUG if (CAM_DEBUGGED(ccb_h->path, CAM_DEBUG_CDB)) { char cdb_str[(SCSI_MAX_CDBLEN * 3) + 1]; printf("atapi_action: hcb@%p: %s\n", hcb, - scsi_cdb_string(hcb->cmd, cdb_str, sizeof(cdb_str))); + scsi_cdb_string(request->u.atapi.ccb, cdb_str, sizeof(cdb_str))); } #endif @@ -390,7 +423,7 @@ atapi_action(struct cam_sim *sim, union ccb *ccb) buf = csio->data_ptr; /* some SCSI commands require special processing */ - switch (hcb->cmd[0]) { + switch (request->u.atapi.ccb[0]) { case INQUIRY: { /* * many ATAPI devices seem to report more than @@ -399,7 +432,7 @@ atapi_action(struct cam_sim *sim, union ccb *ccb) * when actually asked for it, so we are going to pretend * that only SHORT_INQUIRY_LENGTH are expected, anyway. */ - struct scsi_inquiry *inq = (struct scsi_inquiry *) &hcb->cmd[0]; + struct scsi_inquiry *inq = (struct scsi_inquiry *) &request->u.atapi.ccb[0]; if (inq->byte2 == 0 && inq->page_code == 0 && inq->length > SHORT_INQUIRY_LENGTH) { @@ -412,19 +445,19 @@ atapi_action(struct cam_sim *sim, union ccb *ccb) /* FALLTHROUGH */ case WRITE_6: - CAM_DEBUG(ccb_h->path, CAM_DEBUG_SUBTRACE, + CAM_DEBUG(ccb_h->path, CAM_DEBUG_SUBTRACE, ("Translating %s into _10 equivalent\n", - (hcb->cmd[0] == READ_6) ? "READ_6" : "WRITE_6")); - hcb->cmd[0] |= 0x20; - hcb->cmd[9] = hcb->cmd[5]; - hcb->cmd[8] = hcb->cmd[4]; - hcb->cmd[7] = 0; - hcb->cmd[6] = 0; - hcb->cmd[5] = hcb->cmd[3]; - hcb->cmd[4] = hcb->cmd[2]; - hcb->cmd[3] = hcb->cmd[1] & 0x1f; - hcb->cmd[2] = 0; - hcb->cmd[1] = 0; + (request->u.atapi.ccb[0] == READ_6) ? "READ_6" : "WRITE_6")); + request->u.atapi.ccb[0] |= 0x20; + request->u.atapi.ccb[9] = request->u.atapi.ccb[5]; + request->u.atapi.ccb[8] = request->u.atapi.ccb[4]; + request->u.atapi.ccb[7] = 0; + request->u.atapi.ccb[6] = 0; + request->u.atapi.ccb[5] = request->u.atapi.ccb[3]; + request->u.atapi.ccb[4] = request->u.atapi.ccb[2]; + request->u.atapi.ccb[3] = request->u.atapi.ccb[1] & 0x1f; + request->u.atapi.ccb[2] = 0; + request->u.atapi.ccb[1] = 0; break; } @@ -432,28 +465,48 @@ atapi_action(struct cam_sim *sim, union ccb *ccb) /* ATA always transfers an even number of bytes */ if (!(buf = hcb->dxfer_alloc = malloc(++len, M_ATACAM, M_NOWAIT | M_ZERO))) + printf("cannot allocate ATAPI/CAM buffer\n"); goto action_oom; } - s = splbio(); + request->device = dev; + request->driver = hcb; + request->data = buf; + request->bytecount = len; + request->transfersize = min(request->bytecount, 65534); + request->timeout = ccb_h->timeout; + request->retries = 2; + request->callback = &atapi_cb; + request->flags = (ATA_R_QUIET | ATA_R_ATAPI); + switch (ccb_h->flags & CAM_DIR_MASK) { + case CAM_DIR_IN: + request->flags |= ATA_R_READ; + break; + case CAM_DIR_OUT: + request->flags |= ATA_R_WRITE; + break; + case CAM_DIR_NONE: + request->flags |= ATA_R_CONTROL; + break; + default: + ata_prtdev(dev, "unknown IO operation\n"); + goto action_invalid; + } + TAILQ_INSERT_TAIL(&softc->pending_hcbs, hcb, chain); - splx(s); - if (atapi_queue_cmd(dev, hcb->cmd, buf, len, - (((ccb_h->flags & CAM_DIR_MASK) == CAM_DIR_IN) ? - ATPR_F_READ : 0) | ATPR_F_QUIET, - ccb_h->timeout, atapi_cb, (void *)hcb) == 0) - return; - break; + + ata_queue_request(request); + return; } default: CAM_DEBUG(ccb_h->path, CAM_DEBUG_SUBTRACE, ("unsupported function code 0x%02x\n", ccb_h->func_code)); - ccb_h->status = CAM_REQ_INVALID; - xpt_done(ccb); - return; + goto action_invalid; } action_oom: + if (request != NULL) + ata_free_request(request); if (hcb != NULL) free_hcb(hcb); xpt_print_path(ccb_h->path); @@ -462,22 +515,29 @@ action_oom: xpt_freeze_simq(sim, /*count*/ 1); ccb_h->status = CAM_REQUEUE_REQ; xpt_done(ccb); + return; + +action_invalid: + ccb_h->status = CAM_REQ_INVALID; + xpt_done(ccb); + return; } -static void +static void atapi_poll(struct cam_sim *sim) { /* do nothing - we do not actually service any interrupts */ printf("atapi_poll called!\n"); } -static int -atapi_cb(struct atapi_request *req) +static void +atapi_cb(struct ata_request *request) { - struct atapi_hcb *hcb = (struct atapi_hcb *) req->driver; + struct atapi_hcb *hcb = (struct atapi_hcb *) request->driver; struct ccb_scsiio *csio = &hcb->ccb->csio; - int hcb_status = req->result; - int s = splbio(); + int hcb_status = request->result; + + mtx_lock(&Giant); #ifdef CAMDEBUG if (CAM_DEBUGGED(csio->ccb_h.path, CAM_DEBUG_CDB)) { @@ -486,29 +546,35 @@ atapi_cb(struct atapi_request *req) (hcb_status & 4) ? " ABRT" : "", (hcb_status & 2) ? " EOM" : "", (hcb_status & 1) ? " ILI" : ""); - printf(" %s: cmd %02x - sk=%02x asc=%02x ascq=%02x\n", - req->device->name, req->ccb[0], req->sense.sense_key, - req->sense.asc, req->sense.ascq); + printf(" %s: cmd %02x\n", + request->device->name, request->u.atapi.ccb[0]); } #endif if (hcb_status != 0) { csio->scsi_status = SCSI_STATUS_CHECK_COND; if ((csio->ccb_h.flags & CAM_DIS_AUTOSENSE) == 0) { - csio->ccb_h.status |= CAM_AUTOSNS_VALID; - bcopy((void *)&req->sense, (void *)&csio->sense_data, - sizeof(struct atapi_reqsense)); + int8_t ccb[16] = { ATAPI_REQUEST_SENSE, 0, 0, 0, + sizeof(struct atapi_sense), 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0 }; + + if (ata_atapicmd(request->device, ccb, (caddr_t)&csio->sense_data, + sizeof(struct atapi_sense), ATA_R_READ, 30) == 0) + { + csio->ccb_h.status |= CAM_AUTOSNS_VALID; + } } free_hcb_and_ccb_done(hcb, CAM_SCSI_STATUS_ERROR); - } + } else { if (((csio->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) && hcb->dxfer_alloc != NULL) + { bcopy(hcb->dxfer_alloc, csio->data_ptr, csio->dxfer_len); + } csio->scsi_status = SCSI_STATUS_OK; free_hcb_and_ccb_done(hcb, CAM_REQ_CMP); } - splx(s); - return 0; + mtx_unlock(&Giant); } static void @@ -517,6 +583,8 @@ free_hcb_and_ccb_done(struct atapi_hcb *hcb, u_int32_t status) struct atapi_xpt_softc *softc = hcb->softc; union ccb *ccb = hcb->ccb; + GIANT_REQUIRED; + if (hcb != NULL) { /* we're about to free a hcb, so the shortage has ended */ if (softc->flags & RESOURCE_SHORTAGE) { @@ -525,22 +593,21 @@ free_hcb_and_ccb_done(struct atapi_hcb *hcb, u_int32_t status) } free_hcb(hcb); } - ccb->ccb_h.status = + ccb->ccb_h.status = status | (ccb->ccb_h.status & ~(CAM_STATUS_MASK | CAM_SIM_QUEUED)); xpt_done(ccb); } -static void +static void atapi_async(void *callback_arg, u_int32_t code, struct cam_path *path, void *arg) { - int s = splbio(); - + mtx_lock(&Giant); atapi_async1(callback_arg, code, path, arg); - splx(s); + mtx_unlock(&Giant); } -static void +static void atapi_async1(void *callback_arg, u_int32_t code, struct cam_path* path, void *arg) { @@ -548,6 +615,8 @@ atapi_async1(void *callback_arg, u_int32_t code, struct cam_sim *sim; int targ; + GIANT_REQUIRED; + sim = (struct cam_sim *) callback_arg; softc = (struct atapi_xpt_softc *) cam_sim_softc(sim); switch (code) { @@ -570,10 +639,10 @@ cam_rescan_callback(struct cam_periph *periph, union ccb *ccb) { if (ccb->ccb_h.status != CAM_REQ_CMP) { CAM_DEBUG(ccb->ccb_h.path, CAM_DEBUG_TRACE, - ("Rescan failed, 0x%04x\n", ccb->ccb_h.status)); + ("Rescan failed, 0x%04x\n", ccb->ccb_h.status)); } else { CAM_DEBUG(ccb->ccb_h.path, CAM_DEBUG_TRACE, - ("Rescan succeeded\n")); + ("Rescan succeeded\n")); } xpt_free_path(ccb->ccb_h.path); free(ccb, M_ATACAM); @@ -584,7 +653,7 @@ cam_rescan(struct cam_sim *sim) { struct cam_path *path; union ccb *ccb = malloc(sizeof(union ccb), M_ATACAM, M_WAITOK | M_ZERO); - + if (xpt_create_path(&path, xpt_periph, cam_sim_path(sim), CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD) != CAM_REQ_CMP) return; @@ -613,7 +682,7 @@ allocate_hcb(struct atapi_xpt_softc *softc, int unit, int bus, union ccb *ccb) return hcb; } -static void +static void free_hcb(struct atapi_hcb *hcb) { TAILQ_REMOVE(&hcb->softc->pending_hcbs, hcb, chain); @@ -627,6 +696,8 @@ free_softc(struct atapi_xpt_softc *scp) { struct atapi_hcb *hcb; + GIANT_REQUIRED; + if (scp != NULL) { TAILQ_FOREACH(hcb, &scp->pending_hcbs, chain) { free_hcb_and_ccb_done(hcb, CAM_UNREC_HBA_ERROR); @@ -653,12 +724,15 @@ free_softc(struct atapi_xpt_softc *scp) static struct atapi_xpt_softc * get_softc(struct ata_channel *ata_ch) { - struct atapi_xpt_softc *scp; + struct atapi_xpt_softc *scp = NULL; + + mtx_lock(&atapicam_softc_mtx); LIST_FOREACH(scp, &all_buses, chain) { - if (scp->ata_ch == ata_ch) - return scp; + if (scp->ata_ch == ata_ch) + break; } - return NULL; + mtx_unlock(&atapicam_softc_mtx); + return scp; } static struct ata_device * diff --git a/sys/dev/ata/atapi-cd.c b/sys/dev/ata/atapi-cd.c index 751a2c4c1956..9b7e865fc6ac 100644 --- a/sys/dev/ata/atapi-cd.c +++ b/sys/dev/ata/atapi-cd.c @@ -44,36 +44,40 @@ #include <sys/fcntl.h> #include <sys/conf.h> #include <sys/ctype.h> +#include <sys/taskqueue.h> +#include <sys/mutex.h> #include <machine/bus.h> #include <dev/ata/ata-all.h> -#include <dev/ata/atapi-all.h> #include <dev/ata/atapi-cd.h> /* device structures */ -static d_open_t acdopen; -static d_close_t acdclose; -static d_ioctl_t acdioctl; -static d_strategy_t acdstrategy; +static d_open_t acd_open; +static d_close_t acd_close; +static d_ioctl_t acd_ioctl; +static d_strategy_t acd_strategy; static struct cdevsw acd_cdevsw = { - .d_open = acdopen, - .d_close = acdclose, + .d_open = acd_open, + .d_close = acd_close, .d_read = physread, .d_write = physwrite, - .d_ioctl = acdioctl, - .d_strategy = acdstrategy, + .d_ioctl = acd_ioctl, + .d_strategy = acd_strategy, .d_name = "acd", .d_maj = 117, - .d_flags = D_DISK | D_TRACKCLOSE, + .d_flags = D_DISK | D_TRACKCLOSE | D_NOGIANT, }; /* prototypes */ +static void acd_detach(struct ata_device *atadev); +static void acd_start(struct ata_device *atadev); + static struct acd_softc *acd_init_lun(struct ata_device *); static void acd_make_dev(struct acd_softc *); static void acd_set_ioparm(struct acd_softc *); static void acd_describe(struct acd_softc *); static void lba2msf(u_int32_t, u_int8_t *, u_int8_t *, u_int8_t *); static u_int32_t msf2lba(u_int8_t, u_int8_t, u_int8_t); -static int acd_done(struct atapi_request *); +static void acd_done(struct ata_request *); static void acd_read_toc(struct acd_softc *); static int acd_play(struct acd_softc *, int, int); static int acd_setchan(struct acd_softc *, u_int8_t, u_int8_t, u_int8_t, u_int8_t); @@ -99,27 +103,29 @@ static int acd_set_speed(struct acd_softc *, int, int); static void acd_get_cap(struct acd_softc *); static int acd_read_format_caps(struct acd_softc *, struct cdr_format_capacities *); static int acd_format(struct acd_softc *, struct cdr_format_params *); +static int acd_test_ready(struct ata_device *atadev); +static int acd_request_sense(struct ata_device *atadev, struct atapi_sense *sense); /* internal vars */ static u_int32_t acd_lun_map = 0; static MALLOC_DEFINE(M_ACD, "ACD driver", "ATAPI CD driver buffers"); -int -acdattach(struct ata_device *atadev) +void +acd_attach(struct ata_device *atadev) { struct acd_softc *cdp; struct changer *chp; if ((cdp = acd_init_lun(atadev)) == NULL) { - ata_prtdev(atadev, "acd: out of memory\n"); - return 0; + ata_prtdev(atadev, "out of memory\n"); + return; } ata_set_name(atadev, "acd", cdp->lun); acd_get_cap(cdp); /* if this is a changer device, allocate the neeeded lun's */ - if (cdp->cap.mech == MST_MECH_CHANGER) { + if ((cdp->cap.mechanism & MST_MECH_MASK) == MST_MECH_CHANGER) { int8_t ccb[16] = { ATAPI_MECH_STATUS, 0, 0, 0, 0, 0, 0, 0, sizeof(struct changer)>>8, sizeof(struct changer), 0, 0, 0, 0, 0, 0 }; @@ -128,11 +134,10 @@ acdattach(struct ata_device *atadev) if (chp == NULL) { ata_prtdev(atadev, "out of memory\n"); free(cdp, M_ACD); - return 0; + return; } - if (!atapi_queue_cmd(cdp->device, ccb, (caddr_t)chp, - sizeof(struct changer), - ATPR_F_READ, 60, NULL, NULL)) { + if (!ata_atapicmd(cdp->device, ccb, (caddr_t)chp, + sizeof(struct changer), ATA_R_READ, 60)) { struct acd_softc *tmpcdp = cdp; struct acd_softc **cdparr; char *name; @@ -144,7 +149,7 @@ acdattach(struct ata_device *atadev) ata_prtdev(atadev, "out of memory\n"); free(chp, M_ACD); free(cdp, M_ACD); - return 0; + return; } for (count = 0; count < chp->slots; count++) { if (count > 0) { @@ -167,7 +172,7 @@ acdattach(struct ata_device *atadev) if (!(name = malloc(strlen(atadev->name) + 2, M_ACD, M_NOWAIT))) { ata_prtdev(atadev, "out of memory\n"); free(cdp, M_ACD); - return 0; + return; } strcpy(name, atadev->name); strcat(name, "-"); @@ -183,15 +188,27 @@ acdattach(struct ata_device *atadev) DEVSTAT_TYPE_CDROM | DEVSTAT_TYPE_IF_IDE, DEVSTAT_PRIORITY_CD); } + + /* use DMA if allowed and if drive/controller supports it */ + if (atapi_dma && atadev->channel->dma && + (atadev->param->config & ATA_DRQ_MASK) != ATA_DRQ_INTR) + atadev->setmode(atadev, ATA_DMA_MAX); + else + atadev->setmode(atadev, ATA_PIO_MAX); + + /* setup the function ptrs */ + atadev->detach = acd_detach; + atadev->start = acd_start; + atadev->softc = cdp; + + /* announce we are here */ acd_describe(cdp); - atadev->driver = cdp; - return 1; } -void -acddetach(struct ata_device *atadev) +static void +acd_detach(struct ata_device *atadev) { - struct acd_softc *cdp = atadev->driver; + struct acd_softc *cdp = atadev->softc; struct acd_devlist *entry; int subdev; @@ -199,7 +216,9 @@ acddetach(struct ata_device *atadev) for (subdev = 0; subdev < cdp->changer_info->slots; subdev++) { if (cdp->driver[subdev] == cdp) continue; + mtx_lock(&cdp->driver[subdev]->queue_mtx); bioq_flush(&cdp->driver[subdev]->queue, NULL, ENXIO); + mtx_unlock(&cdp->driver[subdev]->queue_mtx); destroy_dev(cdp->driver[subdev]->dev); while ((entry = TAILQ_FIRST(&cdp->driver[subdev]->dev_list))) { destroy_dev(entry->dev); @@ -213,7 +232,9 @@ acddetach(struct ata_device *atadev) free(cdp->driver, M_ACD); free(cdp->changer_info, M_ACD); } + mtx_lock(&cdp->queue_mtx); bioq_flush(&cdp->queue, NULL, ENXIO); + mtx_unlock(&cdp->queue_mtx); while ((entry = TAILQ_FIRST(&cdp->dev_list))) { destroy_dev(entry->dev); TAILQ_REMOVE(&cdp->dev_list, entry, chain); @@ -222,10 +243,15 @@ acddetach(struct ata_device *atadev) destroy_dev(cdp->dev); EVENTHANDLER_DEREGISTER(dev_clone, cdp->clone_evh); devstat_remove_entry(cdp->stats); + ata_prtdev(atadev, "WARNING - removed from configuration\n"); ata_free_name(atadev); ata_free_lun(&acd_lun_map, cdp->lun); + atadev->attach = NULL; + atadev->detach = NULL; + atadev->start = NULL; + atadev->softc = NULL; + atadev->flags = 0; free(cdp, M_ACD); - atadev->driver = NULL; } static struct acd_softc * @@ -237,6 +263,7 @@ acd_init_lun(struct ata_device *atadev) return NULL; TAILQ_INIT(&cdp->dev_list); bioq_init(&cdp->queue); + mtx_init(&cdp->queue_mtx, "ATAPI CD bioqueue lock", MTX_DEF, 0); cdp->device = atadev; cdp->lun = ata_get_lun(&acd_lun_map); cdp->block_size = 2048; @@ -279,7 +306,12 @@ acd_make_dev(struct acd_softc *cdp) static void acd_set_ioparm(struct acd_softc *cdp) { - cdp->dev->si_iosize_max = ((256*DEV_BSIZE)/cdp->block_size)*cdp->block_size; + if (cdp->device->channel->dma) + cdp->dev->si_iosize_max = (min(cdp->device->channel->dma->max_iosize, + 65534)/cdp->block_size)*cdp->block_size; + else + cdp->dev->si_iosize_max = (min(DFLTPHYS, + 65534)/cdp->block_size)*cdp->block_size; cdp->dev->si_bsize_phys = cdp->block_size; } @@ -292,11 +324,11 @@ acd_describe(struct acd_softc *cdp) if (bootverbose) { ata_prtdev(cdp->device, "<%.40s/%.8s> %s drive at ata%d as %s\n", cdp->device->param->model, cdp->device->param->revision, - (cdp->cap.write_dvdr) ? "DVD-R" : - (cdp->cap.write_dvdram) ? "DVD-RAM" : - (cdp->cap.write_cdrw) ? "CD-RW" : - (cdp->cap.write_cdr) ? "CD-R" : - (cdp->cap.read_dvdrom) ? "DVD-ROM" : "CDROM", + (cdp->cap.media & MST_WRITE_DVDR) ? "DVDR" : + (cdp->cap.media & MST_WRITE_DVDRAM) ? "DVDRAM" : + (cdp->cap.media & MST_WRITE_CDRW) ? "CDRW" : + (cdp->cap.media & MST_WRITE_CDR) ? "CDR" : + (cdp->cap.media & MST_READ_DVDROM) ? "DVDROM" : "CDROM", device_get_unit(cdp->device->channel->dev), (cdp->device->unit == ATA_MASTER) ? "master" : "slave"); @@ -306,8 +338,8 @@ acd_describe(struct acd_softc *cdp) if (cdp->cap.max_read_speed) printf(" (%dKB/s)", cdp->cap.max_read_speed * 1000 / 1024); if ((cdp->cap.cur_write_speed) && - (cdp->cap.write_cdr || cdp->cap.write_cdrw || - cdp->cap.write_dvdr || cdp->cap.write_dvdram)) { + (cdp->cap.media & (MST_WRITE_CDR | MST_WRITE_CDRW | + MST_WRITE_DVDR | MST_WRITE_DVDRAM))) { printf(" write %dKB/s", cdp->cap.cur_write_speed * 1000 / 1024); if (cdp->cap.max_write_speed) printf(" (%dKB/s)", cdp->cap.max_write_speed * 1000 / 1024); @@ -322,65 +354,65 @@ acd_describe(struct acd_softc *cdp) ata_prtdev(cdp->device, "Reads:"); comma = 0; - if (cdp->cap.read_cdr) { - printf(" CD-R"); comma = 1; + if (cdp->cap.media & MST_READ_CDR) { + printf(" CDR"); comma = 1; } - if (cdp->cap.read_cdrw) { - printf("%s CD-RW", comma ? "," : ""); comma = 1; + if (cdp->cap.media & MST_READ_CDRW) { + printf("%s CDRW", comma ? "," : ""); comma = 1; } - if (cdp->cap.cd_da) { - if (cdp->cap.cd_da_stream) - printf("%s CD-DA stream", comma ? "," : ""); + if (cdp->cap.capabilities & MST_READ_CDDA) { + if (cdp->cap.capabilities & MST_CDDA_STREAM) + printf("%s CDDA stream", comma ? "," : ""); else - printf("%s CD-DA", comma ? "," : ""); + printf("%s CDDA", comma ? "," : ""); comma = 1; } - if (cdp->cap.read_dvdrom) { - printf("%s DVD-ROM", comma ? "," : ""); comma = 1; + if (cdp->cap.media & MST_READ_DVDROM) { + printf("%s DVDROM", comma ? "," : ""); comma = 1; } - if (cdp->cap.read_dvdr) { - printf("%s DVD-R", comma ? "," : ""); comma = 1; + if (cdp->cap.media & MST_READ_DVDR) { + printf("%s DVDR", comma ? "," : ""); comma = 1; } - if (cdp->cap.read_dvdram) { - printf("%s DVD-RAM", comma ? "," : ""); comma = 1; + if (cdp->cap.media & MST_READ_DVDRAM) { + printf("%s DVDRAM", comma ? "," : ""); comma = 1; } - if (cdp->cap.read_packet) + if (cdp->cap.media & MST_READ_PACKET) printf("%s packet", comma ? "," : ""); printf("\n"); ata_prtdev(cdp->device, "Writes:"); - if (cdp->cap.write_cdr || cdp->cap.write_cdrw || - cdp->cap.write_dvdr || cdp->cap.write_dvdram) { + if (cdp->cap.media & (MST_WRITE_CDR | MST_WRITE_CDRW | + MST_WRITE_DVDR | MST_WRITE_DVDRAM)) { comma = 0; - if (cdp->cap.write_cdr) { - printf(" CD-R" ); comma = 1; + if (cdp->cap.media & MST_WRITE_CDR) { + printf(" CDR" ); comma = 1; } - if (cdp->cap.write_cdrw) { - printf("%s CD-RW", comma ? "," : ""); comma = 1; + if (cdp->cap.media & MST_WRITE_CDRW) { + printf("%s CDRW", comma ? "," : ""); comma = 1; } - if (cdp->cap.write_dvdr) { - printf("%s DVD-R", comma ? "," : ""); comma = 1; + if (cdp->cap.media & MST_WRITE_DVDR) { + printf("%s DVDR", comma ? "," : ""); comma = 1; } - if (cdp->cap.write_dvdram) { - printf("%s DVD-RAM", comma ? "," : ""); comma = 1; + if (cdp->cap.media & MST_WRITE_DVDRAM) { + printf("%s DVDRAM", comma ? "," : ""); comma = 1; } - if (cdp->cap.test_write) { + if (cdp->cap.media & MST_WRITE_TEST) { printf("%s test write", comma ? "," : ""); comma = 1; } - if (cdp->cap.burnproof) + if (cdp->cap.capabilities & MST_BURNPROOF) printf("%s burnproof", comma ? "," : ""); } printf("\n"); - if (cdp->cap.audio_play) { + if (cdp->cap.capabilities & MST_AUDIO_PLAY) { ata_prtdev(cdp->device, "Audio: "); - if (cdp->cap.audio_play) + if (cdp->cap.capabilities & MST_AUDIO_PLAY) printf("play"); if (cdp->cap.max_vol_levels) printf(", %d volume levels", cdp->cap.max_vol_levels); printf("\n"); } ata_prtdev(cdp->device, "Mechanism: "); - switch (cdp->cap.mech) { + switch (cdp->cap.mechanism & MST_MECH_MASK) { case MST_MECH_CADDY: mechanism = "caddy"; break; case MST_MECH_TRAY: @@ -395,17 +427,18 @@ acd_describe(struct acd_softc *cdp) mechanism = 0; break; } if (mechanism) - printf("%s%s", cdp->cap.eject ? "ejectable " : "", mechanism); - else if (cdp->cap.eject) + printf("%s%s", (cdp->cap.mechanism & MST_EJECT) ? + "ejectable " : "", mechanism); + else if (cdp->cap.mechanism & MST_EJECT) printf("ejectable"); - if (cdp->cap.lock) - printf(cdp->cap.locked ? ", locked" : ", unlocked"); - if (cdp->cap.prevent) + if (cdp->cap.mechanism & MST_LOCKABLE) + printf((cdp->cap.mechanism & MST_LOCKED) ? ", locked":", unlocked"); + if (cdp->cap.mechanism & MST_PREVENT) printf(", lock protected"); printf("\n"); - if (cdp->cap.mech != MST_MECH_CHANGER) { + if ((cdp->cap.mechanism & MST_MECH_MASK) != MST_MECH_CHANGER) { ata_prtdev(cdp->device, "Medium: "); switch (cdp->cap.medium_type & MST_TYPE_MASK_HIGH) { case MST_CDROM: @@ -457,15 +490,13 @@ acd_describe(struct acd_softc *cdp) } else { ata_prtdev(cdp->device, "%s ", - (cdp->cap.write_dvdr) ? "DVD-R" : - (cdp->cap.write_dvdram) ? "DVD-RAM" : - (cdp->cap.write_cdrw) ? "CD-RW" : - (cdp->cap.write_cdr) ? "CD-R" : - (cdp->cap.read_dvdrom) ? "DVD-ROM" : "CDROM"); - + (cdp->cap.media & MST_WRITE_DVDR) ? "DVDR" : + (cdp->cap.media & MST_WRITE_DVDRAM) ? "DVDRAM" : + (cdp->cap.media & MST_WRITE_CDRW) ? "CDRW" : + (cdp->cap.media & MST_WRITE_CDR) ? "CDR" : + (cdp->cap.media & MST_READ_DVDROM) ? "DVDROM" : "CDROM"); if (cdp->changer_info) printf("with %d CD changer ", cdp->changer_info->slots); - printf("<%.40s> at ata%d-%s %s\n", cdp->device->param->model, device_get_unit(cdp->device->channel->dev), (cdp->device->unit == ATA_MASTER) ? "master" : "slave", @@ -491,26 +522,26 @@ msf2lba(u_int8_t m, u_int8_t s, u_int8_t f) } static int -acdopen(dev_t dev, int flags, int fmt, struct thread *td) +acd_open(dev_t dev, int flags, int fmt, struct thread *td) { struct acd_softc *cdp = dev->si_drv1; int timeout = 60; - if (!cdp) + if (!cdp || cdp->device->flags & ATA_D_DETACHING) return ENXIO; /* wait if drive is not finished loading the medium */ while (timeout--) { - struct atapi_reqsense *sense = cdp->device->result; + struct atapi_sense sense; - if (!atapi_test_ready(cdp->device)) + if (!acd_test_ready(cdp->device)) break; - if (sense->sense_key == 2 && sense->asc == 4 && sense->ascq == 1) + acd_request_sense(cdp->device, &sense); + if (sense.sense_key == 2 && sense.asc == 4 && sense.ascq == 1) tsleep(&timeout, PRIBIO, "acdld", hz / 2); else break; } - if (count_dev(dev) == 1) { if (cdp->changer_info && cdp->slot != cdp->changer_info->current_slot) { acd_select_slot(cdp); @@ -524,7 +555,7 @@ acdopen(dev_t dev, int flags, int fmt, struct thread *td) } static int -acdclose(dev_t dev, int flags, int fmt, struct thread *td) +acd_close(dev_t dev, int flags, int fmt, struct thread *td) { struct acd_softc *cdp = dev->si_drv1; @@ -543,7 +574,7 @@ acdclose(dev_t dev, int flags, int fmt, struct thread *td) } static int -acdioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct thread *td) +acd_ioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct thread *td) { struct acd_softc *cdp = dev->si_drv1; int error = 0; @@ -558,7 +589,7 @@ acdioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct thread *td) if (cdp->device->flags & ATA_D_MEDIA_CHANGED) switch (cmd) { case CDIOCRESET: - atapi_test_ready(cdp->device); + acd_test_ready(cdp->device); break; default: @@ -599,7 +630,7 @@ acdioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct thread *td) error = suser(td); if (error) break; - error = atapi_test_ready(cdp->device); + error = acd_test_ready(cdp->device); break; case CDIOCEJECT: @@ -749,9 +780,8 @@ acdioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct thread *td) ccb[1] = args->address_format & CD_MSF_FORMAT; - if ((error = atapi_queue_cmd(cdp->device,ccb,(caddr_t)&cdp->subchan, - sizeof(cdp->subchan), ATPR_F_READ, 10, - NULL, NULL))) + if ((error = ata_atapicmd(cdp->device,ccb,(caddr_t)&cdp->subchan, + sizeof(cdp->subchan), ATA_R_READ, 10))) break; if ((format == CD_MEDIA_CATALOG) || (format == CD_TRACK_INFO)) { @@ -764,10 +794,9 @@ acdioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct thread *td) if (format == CD_TRACK_INFO) ccb[6] = args->track; - if ((error = atapi_queue_cmd(cdp->device, ccb, - (caddr_t)&cdp->subchan, - sizeof(cdp->subchan), ATPR_F_READ, - 10, NULL, NULL))) { + if ((error = ata_atapicmd(cdp->device, ccb, + (caddr_t)&cdp->subchan, + sizeof(cdp->subchan),ATA_R_READ,10))){ break; } } @@ -819,79 +848,6 @@ acdioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct thread *td) break; } - case CDIOCREADAUDIO: - { - struct ioc_read_audio *args = (struct ioc_read_audio *)addr; - int32_t lba; - caddr_t buffer, ubuf = args->buffer; - int8_t ccb[16]; - int frames; - - if (!cdp->toc.hdr.ending_track) { - error = EIO; - break; - } - - if ((frames = args->nframes) < 0) { - error = EINVAL; - break; - } - - if (args->address_format == CD_LBA_FORMAT) - lba = args->address.lba; - else if (args->address_format == CD_MSF_FORMAT) - lba = msf2lba(args->address.msf.minute, - args->address.msf.second, - args->address.msf.frame); - else { - error = EINVAL; - break; - } - -#ifndef CD_BUFFER_BLOCKS -#define CD_BUFFER_BLOCKS 13 -#endif - if (!(buffer = malloc(CD_BUFFER_BLOCKS * 2352, M_ACD, M_NOWAIT))){ - error = ENOMEM; - break; - } - bzero(ccb, sizeof(ccb)); - while (frames > 0) { - int8_t blocks; - int size; - - blocks = (frames>CD_BUFFER_BLOCKS) ? CD_BUFFER_BLOCKS : frames; - size = blocks * 2352; - - ccb[0] = ATAPI_READ_CD; - ccb[1] = 4; - ccb[2] = lba>>24; - ccb[3] = lba>>16; - ccb[4] = lba>>8; - ccb[5] = lba; - ccb[8] = blocks; - ccb[9] = 0xf0; - if ((error = atapi_queue_cmd(cdp->device, ccb, buffer, size, - ATPR_F_READ, 30, NULL,NULL))) - break; - - if ((error = copyout(buffer, ubuf, size))) - break; - - ubuf += size; - frames -= blocks; - lba += blocks; - } - free(buffer, M_ACD); - if (args->address_format == CD_LBA_FORMAT) - args->address.lba = lba; - else if (args->address_format == CD_MSF_FORMAT) - lba2msf(lba, &args->address.msf.minute, - &args->address.msf.second, - &args->address.msf.frame); - break; - } - case CDIOCGETVOL: { struct ioc_vol *arg = (struct ioc_vol *)addr; @@ -1047,24 +1003,24 @@ acdioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct thread *td) break; case DVDIOCREPORTKEY: - if (!cdp->cap.read_dvdrom) - error = EINVAL; - else + if (cdp->cap.media & MST_READ_DVDROM) error = acd_report_key(cdp, (struct dvd_authinfo *)addr); + else + error = EINVAL; break; case DVDIOCSENDKEY: - if (!cdp->cap.read_dvdrom) - error = EINVAL; - else + if (cdp->cap.media & MST_READ_DVDROM) error = acd_send_key(cdp, (struct dvd_authinfo *)addr); + else + error = EINVAL; break; case DVDIOCREADSTRUCTURE: - if (!cdp->cap.read_dvdrom) - error = EINVAL; - else + if (cdp->cap.media & MST_READ_DVDROM) error = acd_read_structure(cdp, (struct dvd_struct *)addr); + else + error = EINVAL; break; default: @@ -1074,10 +1030,9 @@ acdioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct thread *td) } static void -acdstrategy(struct bio *bp) +acd_strategy(struct bio *bp) { struct acd_softc *cdp = bp->bio_dev->si_drv1; - int s; if (cdp->device->flags & ATA_D_DETACHING) { biofinish(bp, NULL, ENXIO); @@ -1094,17 +1049,18 @@ acdstrategy(struct bio *bp) bp->bio_pblkno = bp->bio_blkno; bp->bio_resid = bp->bio_bcount; - s = splbio(); + mtx_lock(&cdp->queue_mtx); bioq_disksort(&cdp->queue, bp); - splx(s); + mtx_unlock(&cdp->queue_mtx); ata_start(cdp->device->channel); } -void +static void acd_start(struct ata_device *atadev) { - struct acd_softc *cdp = atadev->driver; - struct bio *bp = bioq_first(&cdp->queue); + struct acd_softc *cdp = atadev->softc; + struct bio *bp; + struct ata_request *request; u_int32_t lba, lastlba, count; int8_t ccb[16]; int track, blocksize; @@ -1113,23 +1069,34 @@ acd_start(struct ata_device *atadev) int i; cdp = cdp->driver[cdp->changer_info->current_slot]; + mtx_lock(&cdp->queue_mtx); bp = bioq_first(&cdp->queue); + mtx_unlock(&cdp->queue_mtx); /* check for work pending on any other slot */ for (i = 0; i < cdp->changer_info->slots; i++) { if (i == cdp->changer_info->current_slot) continue; + mtx_lock(&cdp->queue_mtx); if (bioq_first(&(cdp->driver[i]->queue))) { if (!bp || time_second > (cdp->timestamp + 10)) { + mtx_unlock(&cdp->queue_mtx); acd_select_slot(cdp->driver[i]); return; } } + mtx_unlock(&cdp->queue_mtx); + } } - if (!bp) + mtx_lock(&cdp->queue_mtx); + bp = bioq_first(&cdp->queue); + if (!bp) { + mtx_unlock(&cdp->queue_mtx); return; + } bioq_remove(&cdp->queue, bp); + mtx_unlock(&cdp->queue_mtx); /* reject all queued entries if media changed */ if (cdp->device->flags & ATA_D_MEDIA_CHANGED) { @@ -1197,27 +1164,54 @@ acd_start(struct ata_device *atadev) ccb[7] = count>>8; ccb[8] = count; - devstat_start_transaction_bio(cdp->stats, bp); bp->bio_caller1 = cdp; - atapi_queue_cmd(cdp->device, ccb, bp->bio_data, count * blocksize, - bp->bio_cmd == BIO_READ ? ATPR_F_READ : 0, - (ccb[0] == ATAPI_WRITE_BIG) ? 60 : 30, acd_done, bp); + if (!(request = ata_alloc_request())) { + biofinish(bp, NULL, EIO); + return; + } + request->device = atadev; + request->driver = bp; + bcopy(ccb, request->u.atapi.ccb, + (request->device->param->config & ATA_PROTO_MASK) == + ATA_PROTO_ATAPI_12 ? 16 : 12); + request->data = bp->bio_data; + request->bytecount = count * blocksize; + request->transfersize = min(request->bytecount, 65534); + request->timeout = (ccb[0] == ATAPI_WRITE_BIG) ? 60 : 30; + request->retries = 2; + request->callback = acd_done; + request->flags = ATA_R_SKIPSTART | ATA_R_ATAPI; + if (request->device->mode >= ATA_DMA) + request->flags |= ATA_R_DMA; + switch (bp->bio_cmd) { + case BIO_READ: + request->flags |= ATA_R_READ; + break; + case BIO_WRITE: + request->flags |= ATA_R_WRITE; + break; + default: + ata_prtdev(atadev, "unknown BIO operation\n"); + ata_free_request(request); + biofinish(bp, NULL, EIO); + return; + } + devstat_start_transaction_bio(cdp->stats, bp); + ata_queue_request(request); } -static int -acd_done(struct atapi_request *request) +static void +acd_done(struct ata_request *request) { struct bio *bp = request->driver; struct acd_softc *cdp = bp->bio_caller1; - if (request->error) { - bp->bio_error = request->error; + /* finish up transfer */ + if ((bp->bio_error = request->result)) bp->bio_flags |= BIO_ERROR; - } - else - bp->bio_resid = bp->bio_bcount - request->donecount; + bp->bio_resid = bp->bio_bcount - request->donecount; biofinish(bp, cdp->stats, 0); - return 0; + ata_free_request(request); } static void @@ -1231,7 +1225,7 @@ acd_read_toc(struct acd_softc *cdp) bzero(&cdp->toc, sizeof(cdp->toc)); bzero(ccb, sizeof(ccb)); - if (atapi_test_ready(cdp->device) != 0) + if (acd_test_ready(cdp->device) != 0) return; cdp->device->flags &= ~ATA_D_MEDIA_CHANGED; @@ -1240,8 +1234,8 @@ acd_read_toc(struct acd_softc *cdp) ccb[0] = ATAPI_READ_TOC; ccb[7] = len>>8; ccb[8] = len; - if (atapi_queue_cmd(cdp->device, ccb, (caddr_t)&cdp->toc, len, - ATPR_F_READ | ATPR_F_QUIET, 30, NULL, NULL)) { + if (ata_atapicmd(cdp->device, ccb, (caddr_t)&cdp->toc, len, + ATA_R_READ | ATA_R_QUIET, 30)) { bzero(&cdp->toc, sizeof(cdp->toc)); return; } @@ -1256,8 +1250,8 @@ acd_read_toc(struct acd_softc *cdp) ccb[0] = ATAPI_READ_TOC; ccb[7] = len>>8; ccb[8] = len; - if (atapi_queue_cmd(cdp->device, ccb, (caddr_t)&cdp->toc, len, - ATPR_F_READ | ATPR_F_QUIET, 30, NULL, NULL)) { + if (ata_atapicmd(cdp->device, ccb, (caddr_t)&cdp->toc, len, + ATA_R_READ | ATA_R_QUIET, 30)) { bzero(&cdp->toc, sizeof(cdp->toc)); return; } @@ -1267,8 +1261,8 @@ acd_read_toc(struct acd_softc *cdp) acd_set_ioparm(cdp); bzero(ccb, sizeof(ccb)); ccb[0] = ATAPI_READ_CAPACITY; - if (atapi_queue_cmd(cdp->device, ccb, (caddr_t)sizes, sizeof(sizes), - ATPR_F_READ | ATPR_F_QUIET, 30, NULL, NULL)) { + if (ata_atapicmd(cdp->device, ccb, (caddr_t)sizes, sizeof(sizes), + ATA_R_READ | ATA_R_QUIET, 30)) { bzero(&cdp->toc, sizeof(cdp->toc)); return; } @@ -1313,7 +1307,7 @@ acd_play(struct acd_softc *cdp, int start, int end) ccb[0] = ATAPI_PLAY_MSF; lba2msf(start, &ccb[3], &ccb[4], &ccb[5]); lba2msf(end, &ccb[6], &ccb[7], &ccb[8]); - return atapi_queue_cmd(cdp->device, ccb, NULL, 0, 0, 10, NULL, NULL); + return ata_atapicmd(cdp->device, ccb, NULL, 0, 0, 10); } static int @@ -1335,39 +1329,52 @@ acd_setchan(struct acd_softc *cdp, return acd_mode_select(cdp, (caddr_t)&cdp->au, sizeof(cdp->au)); } -static int -acd_select_done1(struct atapi_request *request) +static void +acd_load_done(struct ata_request *request) { struct acd_softc *cdp = request->driver; + /* finish the slot select and wakeup caller */ cdp->changer_info->current_slot = cdp->slot; cdp->driver[cdp->changer_info->current_slot]->timestamp = time_second; wakeup(&cdp->changer_info); - return 0; } -static int -acd_select_done(struct atapi_request *request) +static void +acd_unload_done(struct ata_request *request) { struct acd_softc *cdp = request->driver; int8_t ccb[16] = { ATAPI_LOAD_UNLOAD, 0, 0, 0, 3, 0, 0, 0, cdp->slot, 0, 0, 0, 0, 0, 0, 0 }; /* load the wanted slot */ - atapi_queue_cmd(cdp->device, ccb, NULL, 0, ATPR_F_AT_HEAD, 30, - acd_select_done1, cdp); - return 0; + bcopy(ccb, request->u.atapi.ccb, + (request->device->param->config & ATA_PROTO_MASK) == + ATA_PROTO_ATAPI_12 ? 16 : 12); + request->callback = acd_load_done; + ata_queue_request(request); } static void acd_select_slot(struct acd_softc *cdp) { + struct ata_request *request; int8_t ccb[16] = { ATAPI_LOAD_UNLOAD, 0, 0, 0, 2, 0, 0, 0, cdp->changer_info->current_slot, 0, 0, 0, 0, 0, 0, 0 }; /* unload the current media from player */ - atapi_queue_cmd(cdp->device, ccb, NULL, 0, ATPR_F_AT_HEAD, 30, - acd_select_done, cdp); + if (!(request = ata_alloc_request())) { + return; + } + request->device = cdp->device; + request->driver = cdp; + bcopy(ccb, request->u.atapi.ccb, + (request->device->param->config & ATA_PROTO_MASK) == + ATA_PROTO_ATAPI_12 ? 16 : 12); + request->timeout = 30; + request->callback = acd_unload_done; + request->flags |= (ATA_R_ATAPI | ATA_R_AT_HEAD); + ata_queue_request(request); } static int @@ -1377,10 +1384,10 @@ acd_init_writer(struct acd_softc *cdp, int test_write) bzero(ccb, sizeof(ccb)); ccb[0] = ATAPI_REZERO; - atapi_queue_cmd(cdp->device, ccb, NULL, 0, ATPR_F_QUIET, 60, NULL, NULL); + ata_atapicmd(cdp->device, ccb, NULL, 0, ATA_R_QUIET, 60); ccb[0] = ATAPI_SEND_OPC_INFO; ccb[1] = 0x01; - atapi_queue_cmd(cdp->device, ccb, NULL, 0, ATPR_F_QUIET, 30, NULL, NULL); + ata_atapicmd(cdp->device, ccb, NULL, 0, ATA_R_QUIET, 30); return 0; } @@ -1406,19 +1413,19 @@ acd_fixate(struct acd_softc *cdp, int multisession) if ((error = acd_mode_select(cdp, (caddr_t)¶m, param.page_length + 10))) return error; - error = atapi_queue_cmd(cdp->device, ccb, NULL, 0, 0, 30, NULL, NULL); + error = ata_atapicmd(cdp->device, ccb, NULL, 0, 0, 30); if (error) return error; /* some drives just return ready, wait for the expected fixate time */ - if ((error = atapi_test_ready(cdp->device)) != EBUSY) { + if ((error = acd_test_ready(cdp->device)) != EBUSY) { timeout = timeout / (cdp->cap.cur_write_speed / 177); tsleep(&error, PRIBIO, "acdfix", timeout * hz / 2); - return atapi_test_ready(cdp->device); + return acd_test_ready(cdp->device); } while (timeout-- > 0) { - if ((error = atapi_test_ready(cdp->device)) != EBUSY) + if ((error = acd_test_ready(cdp->device)) != EBUSY) return error; tsleep(&error, PRIBIO, "acdcld", hz/2); } @@ -1444,7 +1451,7 @@ acd_init_track(struct acd_softc *cdp, struct cdr_track *track) param.fp = 0; param.packet_size = 0; - if (cdp->cap.burnproof) + if (cdp->cap.capabilities & MST_BURNPROOF) param.burnproof = 1; switch (track->datablock_type) { @@ -1511,8 +1518,7 @@ acd_flush(struct acd_softc *cdp) int8_t ccb[16] = { ATAPI_SYNCHRONIZE_CACHE, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; - return atapi_queue_cmd(cdp->device, ccb, NULL, 0, ATPR_F_QUIET, 60, - NULL, NULL); + return ata_atapicmd(cdp->device, ccb, NULL, 0, ATA_R_QUIET, 60); } static int @@ -1526,8 +1532,8 @@ acd_read_track_info(struct acd_softc *cdp, 0, 0, 0, 0, 0, 0, 0 }; int error; - if ((error = atapi_queue_cmd(cdp->device, ccb, (caddr_t)info, sizeof(*info), - ATPR_F_READ, 30, NULL, NULL))) + if ((error = ata_atapicmd(cdp->device, ccb, (caddr_t)info, sizeof(*info), + ATA_R_READ, 30))) return error; info->track_start_addr = ntohl(info->track_start_addr); info->next_writeable_addr = ntohl(info->next_writeable_addr); @@ -1542,16 +1548,14 @@ acd_get_progress(struct acd_softc *cdp, int *finished) { int8_t ccb[16] = { ATAPI_READ_CAPACITY, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; - struct atapi_reqsense *sense = cdp->device->result; + struct atapi_sense sense; int8_t dummy[8]; - if (atapi_queue_cmd(cdp->device, ccb, dummy, sizeof(dummy), - ATPR_F_READ, 30, NULL, NULL) != EBUSY) { - *finished = 100; - return 0; - } - if (sense->sksv) - *finished = ((sense->sk_specific2|(sense->sk_specific1<<8))*100)/65535; + ata_atapicmd(cdp->device, ccb, dummy, sizeof(dummy), ATA_R_READ, 30); + acd_request_sense(cdp->device, &sense); + + if (sense.sksv) + *finished = ((sense.sk_specific2|(sense.sk_specific1<<8))*100)/65535; else *finished = 0; return 0; @@ -1585,7 +1589,7 @@ acd_send_cue(struct acd_softc *cdp, struct cdr_cuesheet *cuesheet) param.track_mode = CDR_TMODE_AUDIO; param.datablock_type = CDR_DB_RAW; param.session_format = cuesheet->session_format; - if (cdp->cap.burnproof) + if (cdp->cap.capabilities & MST_BURNPROOF) param.burnproof = 1; if ((error = acd_mode_select(cdp, (caddr_t)¶m, param.page_length + 10))) @@ -1604,8 +1608,7 @@ acd_send_cue(struct acd_softc *cdp, struct cdr_cuesheet *cuesheet) printf("\n%02x", buffer[i]); printf("\n"); #endif - error = atapi_queue_cmd(cdp->device, ccb, buffer, cuesheet->len, 0, - 30, NULL, NULL); + error = ata_atapicmd(cdp->device, ccb, buffer, cuesheet->len, 0, 30); } free(buffer, M_ACD); return error; @@ -1656,9 +1659,8 @@ acd_report_key(struct acd_softc *cdp, struct dvd_authinfo *ai) d = malloc(length, M_ACD, M_NOWAIT | M_ZERO); d->length = htons(length - 2); - error = atapi_queue_cmd(cdp->device, ccb, (caddr_t)d, length, - ai->format == DVD_INVALIDATE_AGID ? 0 : ATPR_F_READ, - 10, NULL, NULL); + error = ata_atapicmd(cdp->device, ccb, (caddr_t)d, length, + ai->format == DVD_INVALIDATE_AGID ? 0 : ATA_R_READ,10); if (error) { free(d, M_ACD); return error; @@ -1743,8 +1745,7 @@ acd_send_key(struct acd_softc *cdp, struct dvd_authinfo *ai) ccb[9] = length & 0xff; ccb[10] = (ai->agid << 6) | ai->format; d->length = htons(length - 2); - error = atapi_queue_cmd(cdp->device, ccb, (caddr_t)d, length, 0, - 10, NULL, NULL); + error = ata_atapicmd(cdp->device, ccb, (caddr_t)d, length, 0, 10); free(d, M_ACD); return error; } @@ -1802,8 +1803,7 @@ acd_read_structure(struct acd_softc *cdp, struct dvd_struct *s) ccb[8] = (length >> 8) & 0xff; ccb[9] = length & 0xff; ccb[10] = s->agid << 6; - error = atapi_queue_cmd(cdp->device, ccb, (caddr_t)d, length, ATPR_F_READ, - 30, NULL, NULL); + error = ata_atapicmd(cdp->device, ccb, (caddr_t)d, length, ATA_R_READ, 30); if (error) { free(d, M_ACD); return error; @@ -1887,7 +1887,7 @@ acd_blank(struct acd_softc *cdp, int blanktype) 0, 0, 0, 0, 0, 0, 0, 0 }; cdp->device->flags |= ATA_D_MEDIA_CHANGED; - return atapi_queue_cmd(cdp->device, ccb, NULL, 0, 0, 30, NULL, NULL); + return ata_atapicmd(cdp->device, ccb, NULL, 0, 0, 30); } static int @@ -1896,7 +1896,7 @@ acd_prevent_allow(struct acd_softc *cdp, int lock) int8_t ccb[16] = { ATAPI_PREVENT_ALLOW, 0, 0, 0, lock, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; - return atapi_queue_cmd(cdp->device, ccb, NULL, 0, 0, 30, NULL, NULL); + return ata_atapicmd(cdp->device, ccb, NULL, 0, 0, 30); } static int @@ -1905,7 +1905,7 @@ acd_start_stop(struct acd_softc *cdp, int start) int8_t ccb[16] = { ATAPI_START_STOP, 0, 0, 0, start, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; - return atapi_queue_cmd(cdp->device, ccb, NULL, 0, 0, 30, NULL, NULL); + return ata_atapicmd(cdp->device, ccb, NULL, 0, 0, 30); } static int @@ -1914,7 +1914,7 @@ acd_pause_resume(struct acd_softc *cdp, int pause) int8_t ccb[16] = { ATAPI_PAUSE, 0, 0, 0, 0, 0, 0, 0, pause, 0, 0, 0, 0, 0, 0, 0 }; - return atapi_queue_cmd(cdp->device, ccb, NULL, 0, 0, 30, NULL, NULL); + return ata_atapicmd(cdp->device, ccb, NULL, 0, 0, 30); } static int @@ -1924,8 +1924,7 @@ acd_mode_sense(struct acd_softc *cdp, int page, caddr_t pagebuf, int pagesize) pagesize>>8, pagesize, 0, 0, 0, 0, 0, 0, 0 }; int error; - error = atapi_queue_cmd(cdp->device, ccb, pagebuf, pagesize, ATPR_F_READ, - 10, NULL, NULL); + error = ata_atapicmd(cdp->device, ccb, pagebuf, pagesize, ATA_R_READ, 10); #ifdef ACD_DEBUG atapi_dump("acd: mode sense ", pagebuf, pagesize); #endif @@ -1943,8 +1942,7 @@ acd_mode_select(struct acd_softc *cdp, caddr_t pagebuf, int pagesize) "modeselect pagesize=%d\n", pagesize); atapi_dump("mode select ", pagebuf, pagesize); #endif - return atapi_queue_cmd(cdp->device, ccb, pagebuf, pagesize, 0, - 30, NULL, NULL); + return ata_atapicmd(cdp->device, ccb, pagebuf, pagesize, 0, 30); } static int @@ -1954,7 +1952,7 @@ acd_set_speed(struct acd_softc *cdp, int rdspeed, int wrspeed) wrspeed >> 8, wrspeed, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; int error; - error = atapi_queue_cmd(cdp->device, ccb, NULL, 0, 0, 30, NULL, NULL); + error = ata_atapicmd(cdp->device, ccb, NULL, 0, 0, 30); if (!error) acd_get_cap(cdp); return error; @@ -1963,18 +1961,21 @@ acd_set_speed(struct acd_softc *cdp, int rdspeed, int wrspeed) static void acd_get_cap(struct acd_softc *cdp) { - int retry = 5; - - /* get drive capabilities, some drives needs this repeated */ - while (retry-- && acd_mode_sense(cdp, ATAPI_CDROM_CAP_PAGE, - (caddr_t)&cdp->cap, sizeof(cdp->cap))) - - cdp->cap.max_read_speed = ntohs(cdp->cap.max_read_speed); - cdp->cap.cur_read_speed = ntohs(cdp->cap.cur_read_speed); - cdp->cap.max_write_speed = ntohs(cdp->cap.max_write_speed); - cdp->cap.cur_write_speed = max(ntohs(cdp->cap.cur_write_speed), 177); - cdp->cap.max_vol_levels = ntohs(cdp->cap.max_vol_levels); - cdp->cap.buf_size = ntohs(cdp->cap.buf_size); + int count; + + /* get drive capabilities, some bugridden drives needs this repeated */ + for (count = 0 ; count < 5 ; count++) { + if (!acd_mode_sense(cdp, ATAPI_CDROM_CAP_PAGE, + (caddr_t)&cdp->cap, sizeof(cdp->cap)) && + cdp->cap.page_code == ATAPI_CDROM_CAP_PAGE) { + cdp->cap.max_read_speed = ntohs(cdp->cap.max_read_speed); + cdp->cap.cur_read_speed = ntohs(cdp->cap.cur_read_speed); + cdp->cap.max_write_speed = ntohs(cdp->cap.max_write_speed); + cdp->cap.cur_write_speed = max(ntohs(cdp->cap.cur_write_speed),177); + cdp->cap.max_vol_levels = ntohs(cdp->cap.max_vol_levels); + cdp->cap.buf_size = ntohs(cdp->cap.buf_size); + } + } } static int @@ -1985,9 +1986,8 @@ acd_read_format_caps(struct acd_softc *cdp, struct cdr_format_capacities *caps) sizeof(struct cdr_format_capacities) & 0xff, 0, 0, 0, 0, 0, 0, 0 }; - return atapi_queue_cmd(cdp->device, ccb, (caddr_t)caps, - sizeof(struct cdr_format_capacities), - ATPR_F_READ, 30, NULL, NULL); + return ata_atapicmd(cdp->device, ccb, (caddr_t)caps, + sizeof(struct cdr_format_capacities), ATA_R_READ, 30); } static int @@ -1997,8 +1997,26 @@ acd_format(struct acd_softc *cdp, struct cdr_format_params* params) int8_t ccb[16] = { ATAPI_FORMAT, 0x11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; - error = atapi_queue_cmd(cdp->device, ccb, (u_int8_t *)params, - sizeof(struct cdr_format_params), 0, 30, NULL,NULL); - + error = ata_atapicmd(cdp->device, ccb, (u_int8_t *)params, + sizeof(struct cdr_format_params), 0, 30); return error; } + +static int +acd_test_ready(struct ata_device *atadev) +{ + int8_t ccb[16] = { ATAPI_TEST_UNIT_READY, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + + return ata_atapicmd(atadev, ccb, NULL, 0, 0, 30); +} + +static int +acd_request_sense(struct ata_device *atadev, struct atapi_sense *sense) +{ + int8_t ccb[16] = { ATAPI_REQUEST_SENSE, 0, 0, 0, sizeof(struct atapi_sense), + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + + return ata_atapicmd(atadev, ccb, (caddr_t)sense, + sizeof(struct atapi_sense), ATA_R_READ, 30); +} diff --git a/sys/dev/ata/atapi-cd.h b/sys/dev/ata/atapi-cd.h index 19d742cc18a5..71d1c0359af4 100644 --- a/sys/dev/ata/atapi-cd.h +++ b/sys/dev/ata/atapi-cd.h @@ -76,6 +76,12 @@ struct audiopage { } port[4]; }; + +/* CDROM Capabilities and Mechanical Status Page */ +struct cappage { + /* mode page data header */ + u_int16_t data_length; + u_int8_t medium_type; #define MST_TYPE_MASK_LOW 0x0f #define MST_FMT_NONE 0x00 #define MST_DATA_120 0x01 @@ -96,126 +102,61 @@ struct audiopage { #define MST_DOOR_OPEN 0x71 #define MST_FMT_ERROR 0x72 -#define MST_MECH_CADDY 0 -#define MST_MECH_TRAY 1 -#define MST_MECH_POPUP 2 -#define MST_MECH_CHANGER 4 -#define MST_MECH_CARTRIDGE 5 - -#define MST_DLEN_32 0 -#define MST_DLEN_16 1 -#define MST_DLEN_24 2 -#define MST_DLEN_24_I2S 3 - -#define ATAPI_CDROM_CAP_PAGE 0x2a - -/* CDROM Capabilities and Mechanical Status Page */ -struct cappage { - /* mode page data header */ - u_int16_t data_length; - u_int8_t medium_type; - u_int8_t dev_spec; - u_int8_t unused[2]; + u_int16_t unused; u_int16_t blk_desc_len; /* capabilities page */ u_int8_t page_code; +#define ATAPI_CDROM_CAP_PAGE 0x2a u_int8_t param_len; -#if BYTE_ORDER == LITTLE_ENDIAN - u_int8_t read_cdr :1; /* supports CD-R read */ - u_int8_t read_cdrw :1; /* supports CD-RW read */ - u_int8_t read_packet :1; /* supports reading packet tracks */ - u_int8_t read_dvdrom :1; /* supports DVD-ROM read */ - u_int8_t read_dvdr :1; /* supports DVD-R read */ - u_int8_t read_dvdram :1; /* supports DVD-RAM read */ - u_int8_t reserved2_67 :2; - - u_int8_t write_cdr :1; /* supports CD-R write */ - u_int8_t write_cdrw :1; /* supports CD-RW write */ - u_int8_t test_write :1; /* supports test writing */ - u_int8_t reserved3_3 :1; - u_int8_t write_dvdr :1; /* supports DVD-R write */ - u_int8_t write_dvdram :1; /* supports DVD-RAM write */ - u_int8_t reserved3_67 :2; - - u_int8_t audio_play :1; /* audio play supported */ - u_int8_t composite :1; /* composite audio/video supported */ - u_int8_t dport1 :1; /* digital audio on port 1 */ - u_int8_t dport2 :1; /* digital audio on port 2 */ - u_int8_t mode2_form1 :1; /* mode 2 form 1 (XA) read */ - u_int8_t mode2_form2 :1; /* mode 2 form 2 format */ - u_int8_t multisession :1; /* multi-session photo-CD */ - u_int8_t burnproof :1; /* supports burnproof */ - - u_int8_t cd_da :1; /* audio-CD read supported */ - u_int8_t cd_da_stream :1; /* CD-DA streaming */ - u_int8_t rw :1; /* combined R-W subchannels */ - u_int8_t rw_corr :1; /* R-W subchannel data corrected */ - u_int8_t c2 :1; /* C2 error pointers supported */ - u_int8_t isrc :1; /* can return the ISRC info */ - u_int8_t upc :1; /* can return the catalog number UPC */ - u_int8_t :1; - - u_int8_t lock :1; /* can be locked */ - u_int8_t locked :1; /* current lock state */ - u_int8_t prevent :1; /* prevent jumper installed */ - u_int8_t eject :1; /* can eject */ - u_int8_t :1; - u_int8_t mech :3; /* loading mechanism type */ - - u_int8_t sep_vol :1; /* independent volume of channels */ - u_int8_t sep_mute :1; /* independent mute of channels */ - u_int8_t:6; -#else - /* This is read using 16-bit stream transfers */ - u_int8_t reserved2_67 :2; - u_int8_t read_dvdram :1; /* supports DVD-RAM read */ - u_int8_t read_dvdr :1; /* supports DVD-R read */ - u_int8_t read_dvdrom :1; /* supports DVD-ROM read */ - u_int8_t read_packet :1; /* supports reading packet tracks */ - u_int8_t read_cdrw :1; /* supports CD-RW read */ - u_int8_t read_cdr :1; /* supports CD-R read */ - - u_int8_t reserved3_67 :2; - u_int8_t write_dvdram :1; /* supports DVD-RAM write */ - u_int8_t write_dvdr :1; /* supports DVD-R write */ - u_int8_t reserved3_3 :1; - u_int8_t test_write :1; /* supports test writing */ - u_int8_t write_cdrw :1; /* supports CD-RW write */ - u_int8_t write_cdr :1; /* supports CD-R write */ - - u_int8_t burnproof :1; /* supports burnproof */ - u_int8_t multisession :1; /* multi-session photo-CD */ - u_int8_t mode2_form2 :1; /* mode 2 form 2 format */ - u_int8_t mode2_form1 :1; /* mode 2 form 1 (XA) read */ - u_int8_t dport2 :1; /* digital audio on port 2 */ - u_int8_t dport1 :1; /* digital audio on port 1 */ - u_int8_t composite :1; /* composite audio/video supported */ - u_int8_t audio_play :1; /* audio play supported */ - - u_int8_t :1; - u_int8_t upc :1; /* can return the catalog number UPC */ - u_int8_t isrc :1; /* can return the ISRC info */ - u_int8_t c2 :1; /* C2 error pointers supported */ - u_int8_t rw_corr :1; /* R-W subchannel data corrected */ - u_int8_t rw :1; /* combined R-W subchannels */ - u_int8_t cd_da_stream :1; /* CD-DA streaming */ - u_int8_t cd_da :1; /* audio-CD read supported */ - - u_int8_t mech :3; /* loading mechanism type */ - u_int8_t :1; - u_int8_t eject :1; /* can eject */ - u_int8_t prevent :1; /* prevent jumper installed */ - u_int8_t locked :1; /* current lock state */ - u_int8_t lock :1; /* can be locked */ - - u_int8_t:6; - u_int8_t sep_mute :1; /* independent mute of channels */ - u_int8_t sep_vol :1; /* independent volume of channels */ -#endif + u_int16_t media; +#define MST_READ_CDR 0x0001 +#define MST_READ_CDRW 0x0002 +#define MST_READ_PACKET 0x0004 +#define MST_READ_DVDROM 0x0008 +#define MST_READ_DVDR 0x0010 +#define MST_READ_DVDRAM 0x0020 +#define MST_WRITE_CDR 0x0100 +#define MST_WRITE_CDRW 0x0200 +#define MST_WRITE_TEST 0x0400 +#define MST_WRITE_DVDR 0x1000 +#define MST_WRITE_DVDRAM 0x2000 + + u_int16_t capabilities; +#define MST_AUDIO_PLAY 0x0001 +#define MST_COMPOSITE 0x0002 +#define MST_AUDIO_P1 0x0004 +#define MST_AUDIO_P2 0x0008 +#define MST_MODE2_f1 0x0010 +#define MST_MODE2_f2 0x0020 +#define MST_MULTISESSION 0x0040 +#define MST_BURNPROOF 0x0080 +#define MST_READ_CDDA 0x0100 +#define MST_CDDA_STREAM 0x0200 +#define MST_COMBINED_RW 0x0400 +#define MST_CORRECTED_RW 0x0800 +#define MST_SUPPORT_C2 0x1000 +#define MST_ISRC 0x2000 +#define MST_UPC 0x4000 + + u_int8_t mechanism; +#define MST_LOCKABLE 0x01 +#define MST_LOCKED 0x02 +#define MST_PREVENT 0x04 +#define MST_EJECT 0x08 +#define MST_MECH_MASK 0xe0 +#define MST_MECH_CADDY 0x00 +#define MST_MECH_TRAY 0x20 +#define MST_MECH_POPUP 0x40 +#define MST_MECH_CHANGER 0x80 +#define MST_MECH_CARTRIDGE 0xa0 + + uint8_t audio; +#define MST_SEP_VOL 0x01 +#define MST_SEP_MUTE 0x02 u_int16_t max_read_speed; /* max raw data rate in bytes/1000 */ u_int16_t max_vol_levels; /* number of discrete volume levels */ @@ -223,21 +164,7 @@ struct cappage { u_int16_t cur_read_speed; /* current data rate in bytes/1000 */ u_int8_t reserved3; -#if BYTE_ORDER == LITTLE_ENDIAN - u_int8_t bckf :1; /* data valid on failing edge of BCK */ - u_int8_t rch :1; /* high LRCK indicates left channel */ - u_int8_t lsbf :1; /* set if LSB first */ - u_int8_t dlen :2; - - u_int8_t :3; -#else - u_int8_t :3; - - u_int8_t dlen :2; - u_int8_t lsbf :1; /* set if LSB first */ - u_int8_t rch :1; /* high LRCK indicates left channel */ - u_int8_t bckf :1; /* data valid on failing edge of BCK */ -#endif + u_int8_t misc; u_int16_t max_write_speed; /* max raw data rate in bytes/1000 */ u_int16_t cur_write_speed; /* current data rate in bytes/1000 */ @@ -379,6 +306,7 @@ struct acd_softc { int flags; /* device state flags */ #define F_LOCKED 0x0001 /* this unit is locked */ + struct mtx queue_mtx; /* queue lock */ struct bio_queue_head queue; /* queue of i/o requests */ TAILQ_HEAD(, acd_devlist) dev_list; /* list of "track" devices */ struct toc toc; /* table of disc contents */ diff --git a/sys/dev/ata/atapi-fd.c b/sys/dev/ata/atapi-fd.c index 5772242b330f..91c211117bc2 100644 --- a/sys/dev/ata/atapi-fd.c +++ b/sys/dev/ata/atapi-fd.c @@ -37,79 +37,105 @@ #include <sys/bus.h> #include <sys/conf.h> #include <sys/cdio.h> +#include <sys/taskqueue.h> #include <machine/bus.h> #include <geom/geom_disk.h> #include <dev/ata/ata-all.h> -#include <dev/ata/atapi-all.h> #include <dev/ata/atapi-fd.h> /* prototypes */ -static disk_open_t afdopen; -static disk_close_t afdclose; +static disk_open_t afd_open; +static disk_close_t afd_close; #ifdef notyet -static disk_ioctl_t afdioctl; +static disk_ioctl_t afd_ioctl; #endif -static disk_strategy_t afdstrategy; +static disk_strategy_t afdstrategy; +static void afd_detach(struct ata_device *atadev); +static void afd_start(struct ata_device *atadev); static int afd_sense(struct afd_softc *); static void afd_describe(struct afd_softc *); -static int afd_done(struct atapi_request *); +static void afd_done(struct ata_request *); static int afd_eject(struct afd_softc *, int); static int afd_start_stop(struct afd_softc *, int); static int afd_prevent_allow(struct afd_softc *, int); +static int afd_test_ready(struct ata_device *atadev); /* internal vars */ static u_int32_t afd_lun_map = 0; static MALLOC_DEFINE(M_AFD, "AFD driver", "ATAPI floppy driver buffers"); -int -afdattach(struct ata_device *atadev) +void +afd_attach(struct ata_device *atadev) { struct afd_softc *fdp; fdp = malloc(sizeof(struct afd_softc), M_AFD, M_NOWAIT | M_ZERO); if (!fdp) { ata_prtdev(atadev, "out of memory\n"); - return 0; + return; } fdp->device = atadev; fdp->lun = ata_get_lun(&afd_lun_map); ata_set_name(atadev, "afd", fdp->lun); bioq_init(&fdp->queue); + mtx_init(&fdp->queue_mtx, "ATAPI FD bioqueue lock", MTX_DEF, 0); if (afd_sense(fdp)) { free(fdp, M_AFD); - return 0; + return; } - fdp->disk.d_open = afdopen; - fdp->disk.d_close = afdclose; + /* use DMA if allowed and if drive/controller supports it */ + if (atapi_dma && atadev->channel->dma && + (atadev->param->config & ATA_DRQ_MASK) != ATA_DRQ_INTR) + atadev->setmode(atadev, ATA_DMA_MAX); + else + atadev->setmode(atadev, ATA_PIO_MAX); + + /* setup the function ptrs */ + atadev->detach = afd_detach; + atadev->start = afd_start; + atadev->softc = fdp; + atadev->flags |= ATA_D_MEDIA_CHANGED; + + /* lets create the disk device */ + fdp->disk.d_open = afd_open; + fdp->disk.d_close = afd_close; #ifdef notyet - fdp->disk.d_ioctl = afdioctl; + fdp->disk.d_ioctl = afd_ioctl; #endif fdp->disk.d_strategy = afdstrategy; fdp->disk.d_name = "afd"; fdp->disk.d_drv1 = fdp; - fdp->disk.d_maxsize = 256 * DEV_BSIZE; - disk_create(fdp->lun, &fdp->disk, 0, NULL, NULL); + if (atadev->channel->dma) + fdp->disk.d_maxsize = atadev->channel->dma->max_iosize; + else + fdp->disk.d_maxsize = DFLTPHYS; + disk_create(fdp->lun, &fdp->disk, DISKFLAG_NOGIANT, NULL, NULL); + /* announce we are here */ afd_describe(fdp); - atadev->flags |= ATA_D_MEDIA_CHANGED; - atadev->driver = fdp; - return 1; } -void -afddetach(struct ata_device *atadev) +static void +afd_detach(struct ata_device *atadev) { - struct afd_softc *fdp = atadev->driver; + struct afd_softc *fdp = atadev->softc; + mtx_lock(&fdp->queue_mtx); bioq_flush(&fdp->queue, NULL, ENXIO); + mtx_unlock(&fdp->queue_mtx); disk_destroy(&fdp->disk); + ata_prtdev(atadev, "WARNING - removed from configuration\n"); ata_free_name(atadev); ata_free_lun(&afd_lun_map, fdp->lun); + atadev->attach = NULL; + atadev->detach = NULL; + atadev->start = NULL; + atadev->softc = NULL; + atadev->flags = 0; free(fdp, M_AFD); - atadev->driver = NULL; } static int @@ -118,7 +144,7 @@ afd_sense(struct afd_softc *fdp) int8_t ccb[16] = { ATAPI_MODE_SENSE_BIG, 0, ATAPI_REWRITEABLE_CAP_PAGE, 0, 0, 0, 0, sizeof(struct afd_cappage) >> 8, sizeof(struct afd_cappage) & 0xff, 0, 0, 0, 0, 0, 0, 0 }; - int count, error = 0; + int count; /* The IOMEGA Clik! doesn't support reading the cap page, fake it */ if (!strncmp(fdp->device->param->model, "IOMEGA Clik!", 12)) { @@ -127,23 +153,22 @@ afd_sense(struct afd_softc *fdp) fdp->cap.sectors = 2; fdp->cap.cylinders = 39441; fdp->cap.sector_size = 512; - atapi_test_ready(fdp->device); + afd_test_ready(fdp->device); return 0; } - /* get drive capabilities, some drives needs this repeated */ + /* get drive capabilities, some bugridden drives needs this repeated */ for (count = 0 ; count < 5 ; count++) { - if (!(error = atapi_queue_cmd(fdp->device, ccb, (caddr_t)&fdp->cap, - sizeof(struct afd_cappage), - ATPR_F_READ, 30, NULL, NULL))) - break; + if (!ata_atapicmd(fdp->device, ccb, (caddr_t)&fdp->cap, + sizeof(struct afd_cappage), ATA_R_READ, 30) && + fdp->cap.page_code == ATAPI_REWRITEABLE_CAP_PAGE) { + fdp->cap.cylinders = ntohs(fdp->cap.cylinders); + fdp->cap.sector_size = ntohs(fdp->cap.sector_size); + fdp->cap.transfer_rate = ntohs(fdp->cap.transfer_rate); + return 0; + } } - if (error || fdp->cap.page_code != ATAPI_REWRITEABLE_CAP_PAGE) - return 1; - fdp->cap.cylinders = ntohs(fdp->cap.cylinders); - fdp->cap.sector_size = ntohs(fdp->cap.sector_size); - fdp->cap.transfer_rate = ntohs(fdp->cap.transfer_rate); - return 0; + return 1; } static void @@ -151,7 +176,7 @@ afd_describe(struct afd_softc *fdp) { if (bootverbose) { ata_prtdev(fdp->device, - "<%.40s/%.8s> rewriteable drive at ata%d as %s\n", + "<%.40s/%.8s> removable drive at ata%d as %s\n", fdp->device->param->model, fdp->device->param->revision, device_get_unit(fdp->device->channel->dev), (fdp->device->unit == ATA_MASTER) ? "master" : "slave"); @@ -187,11 +212,8 @@ afd_describe(struct afd_softc *fdp) } } else { - ata_prtdev(fdp->device, "%luMB <%.40s> [%d/%d/%d] at ata%d-%s %s\n", - (fdp->cap.cylinders * fdp->cap.heads * fdp->cap.sectors) / - ((1024L * 1024L) / fdp->cap.sector_size), + ata_prtdev(fdp->device, "REMOVABLE <%.40s> at ata%d-%s %s\n", fdp->device->param->model, - fdp->cap.cylinders, fdp->cap.heads, fdp->cap.sectors, device_get_unit(fdp->device->channel->dev), (fdp->device->unit == ATA_MASTER) ? "master" : "slave", ata_mode2str(fdp->device->mode)); @@ -199,15 +221,14 @@ afd_describe(struct afd_softc *fdp) } static int -afdopen(struct disk *dp) +afd_open(struct disk *dp) { struct afd_softc *fdp = dp->d_drv1; - /* hold off access to we are fully attached */ - while (ata_delayed_attach) - tsleep(&ata_delayed_attach, PRIBIO, "afdopn", 1); + if (fdp->device->flags & ATA_D_DETACHING) + return ENXIO; - atapi_test_ready(fdp->device); + afd_test_ready(fdp->device); afd_prevent_allow(fdp, 1); @@ -226,7 +247,7 @@ afdopen(struct disk *dp) } static int -afdclose(struct disk *dp) +afd_close(struct disk *dp) { struct afd_softc *fdp = dp->d_drv1; @@ -239,7 +260,7 @@ afdclose(struct disk *dp) #ifdef notyet static int -afdioctl(struct disk *dp, u_long cmd, void *addr, int flag, struct thread *td) +afd_ioctl(struct disk *dp, u_long cmd, void *addr, int flag, struct thread *td) { struct afd_softc *fdp = dp->d_drv1; @@ -264,7 +285,6 @@ static void afdstrategy(struct bio *bp) { struct afd_softc *fdp = bp->bio_disk->d_drv1; - int s; if (fdp->device->flags & ATA_D_DETACHING) { biofinish(bp, NULL, ENXIO); @@ -278,26 +298,31 @@ afdstrategy(struct bio *bp) return; } - s = splbio(); + mtx_lock(&fdp->queue_mtx); bioq_disksort(&fdp->queue, bp); - splx(s); + mtx_unlock(&fdp->queue_mtx); ata_start(fdp->device->channel); } -void +static void afd_start(struct ata_device *atadev) { - struct afd_softc *fdp = atadev->driver; - struct bio *bp = bioq_first(&fdp->queue); + struct afd_softc *fdp = atadev->softc; + struct bio *bp; + struct ata_request *request; u_int32_t lba; u_int16_t count; int8_t ccb[16]; - caddr_t data_ptr; - if (!bp) - return; + mtx_lock(&fdp->queue_mtx); + bp = bioq_first(&fdp->queue); + if (!bp) { + mtx_unlock(&fdp->queue_mtx); + return; + } bioq_remove(&fdp->queue, bp); + mtx_unlock(&fdp->queue_mtx); /* should reject all queued entries if media have changed. */ if (fdp->device->flags & ATA_D_MEDIA_CHANGED) { @@ -307,7 +332,6 @@ afd_start(struct ata_device *atadev) lba = bp->bio_pblkno; count = bp->bio_bcount / fdp->cap.sector_size; - data_ptr = bp->bio_data; bp->bio_resid = bp->bio_bcount; bzero(ccb, sizeof(ccb)); @@ -324,24 +348,49 @@ afd_start(struct ata_device *atadev) ccb[7] = count>>8; ccb[8] = count; - atapi_queue_cmd(fdp->device, ccb, data_ptr, count * fdp->cap.sector_size, - (bp->bio_cmd == BIO_READ) ? ATPR_F_READ : 0, 30, - afd_done, bp); + if (!(request = ata_alloc_request())) { + biofinish(bp, NULL, EIO); + return; + } + request->device = atadev; + request->driver = bp; + bcopy(ccb, request->u.atapi.ccb, + (request->device->param->config & ATA_PROTO_MASK) == + ATA_PROTO_ATAPI_12 ? 16 : 12); + request->data = bp->bio_data; + request->bytecount = count * fdp->cap.sector_size; + request->transfersize = min(request->bytecount, 65534); + request->timeout = (ccb[0] == ATAPI_WRITE_BIG) ? 60 : 30; + request->retries = 2; + request->callback = afd_done; + switch (bp->bio_cmd) { + case BIO_READ: + request->flags |= (ATA_R_SKIPSTART | ATA_R_ATAPI | ATA_R_READ); + break; + case BIO_WRITE: + request->flags |= (ATA_R_SKIPSTART | ATA_R_ATAPI | ATA_R_WRITE); + break; + default: + ata_prtdev(atadev, "unknown BIO operation\n"); + ata_free_request(request); + biofinish(bp, NULL, EIO); + return; + } + ata_queue_request(request); + } -static int -afd_done(struct atapi_request *request) +static void +afd_done(struct ata_request *request) { struct bio *bp = request->driver; - if (request->error || (bp->bio_flags & BIO_ERROR)) { - bp->bio_error = request->error; + /* finish up transfer */ + if ((bp->bio_error = request->result)) bp->bio_flags |= BIO_ERROR; - } - else - bp->bio_resid = bp->bio_bcount - request->donecount; + bp->bio_resid = bp->bio_bcount - request->donecount; biodone(bp); - return 0; + ata_free_request(request); } static int @@ -372,7 +421,7 @@ afd_start_stop(struct afd_softc *fdp, int start) int8_t ccb[16] = { ATAPI_START_STOP, 0, 0, 0, start, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; - return atapi_queue_cmd(fdp->device, ccb, NULL, 0, 0, 30, NULL, NULL); + return ata_atapicmd(fdp->device, ccb, NULL, 0, 0, 30); } static int @@ -383,5 +432,14 @@ afd_prevent_allow(struct afd_softc *fdp, int lock) if (!strncmp(fdp->device->param->model, "IOMEGA Clik!", 12)) return 0; - return atapi_queue_cmd(fdp->device, ccb, NULL, 0, 0, 30, NULL, NULL); + return ata_atapicmd(fdp->device, ccb, NULL, 0, 0, 30); +} + +static int +afd_test_ready(struct ata_device *atadev) +{ + int8_t ccb[16] = { ATAPI_TEST_UNIT_READY, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + + return ata_atapicmd(atadev, ccb, NULL, 0, 0, 30); } diff --git a/sys/dev/ata/atapi-fd.h b/sys/dev/ata/atapi-fd.h index 89794093d549..90223f495c9b 100644 --- a/sys/dev/ata/atapi-fd.h +++ b/sys/dev/ata/atapi-fd.h @@ -71,6 +71,7 @@ struct afd_cappage { struct afd_softc { struct ata_device *device; /* device softc */ int lun; /* logical device unit */ + struct mtx queue_mtx; /* queue lock */ struct bio_queue_head queue; /* queue of i/o requests */ struct afd_cappage cap; /* capabilities page info */ struct disk disk; /* virtual drives */ diff --git a/sys/dev/ata/atapi-tape.c b/sys/dev/ata/atapi-tape.c index cfd0b28178b4..f9f7e82b47ad 100644 --- a/sys/dev/ata/atapi-tape.c +++ b/sys/dev/ata/atapi-tape.c @@ -39,32 +39,34 @@ #include <sys/bus.h> #include <sys/mtio.h> #include <sys/devicestat.h> +#include <sys/taskqueue.h> #include <machine/bus.h> #include <dev/ata/ata-all.h> -#include <dev/ata/atapi-all.h> #include <dev/ata/atapi-tape.h> /* device structures */ -static d_open_t astopen; -static d_close_t astclose; -static d_ioctl_t astioctl; -static d_strategy_t aststrategy; +static d_open_t ast_open; +static d_close_t ast_close; +static d_ioctl_t ast_ioctl; +static d_strategy_t ast_strategy; static struct cdevsw ast_cdevsw = { - .d_open = astopen, - .d_close = astclose, + .d_open = ast_open, + .d_close = ast_close, .d_read = physread, .d_write = physwrite, - .d_ioctl = astioctl, - .d_strategy = aststrategy, + .d_ioctl = ast_ioctl, + .d_strategy = ast_strategy, .d_name = "ast", .d_maj = 119, - .d_flags = D_TAPE | D_TRACKCLOSE, + .d_flags = D_TAPE | D_TRACKCLOSE | D_NOGIANT, }; /* prototypes */ +static void ast_detach(struct ata_device *atadev); +static void ast_start(struct ata_device *atadev); static int ast_sense(struct ast_softc *); static void ast_describe(struct ast_softc *); -static int ast_done(struct atapi_request *); +static void ast_done(struct ata_request *); static int ast_mode_sense(struct ast_softc *, int, void *, int); static int ast_mode_select(struct ast_softc *, void *, int); static int ast_write_filemark(struct ast_softc *, u_int8_t); @@ -75,14 +77,16 @@ static int ast_prevent_allow(struct ast_softc *stp, int); static int ast_load_unload(struct ast_softc *, u_int8_t); static int ast_rewind(struct ast_softc *); static int ast_erase(struct ast_softc *); +static int ast_test_ready(struct ata_device *atadev); +static int ast_wait_dsc(struct ata_device *atadev, int timeout); /* internal vars */ static u_int32_t ast_lun_map = 0; static u_int64_t ast_total = 0; static MALLOC_DEFINE(M_AST, "AST driver", "ATAPI tape driver buffers"); -int -astattach(struct ata_device *atadev) +void +ast_attach(struct ata_device *atadev) { struct ast_softc *stp; struct ast_readposition position; @@ -91,17 +95,18 @@ astattach(struct ata_device *atadev) stp = malloc(sizeof(struct ast_softc), M_AST, M_NOWAIT | M_ZERO); if (!stp) { ata_prtdev(atadev, "out of memory\n"); - return 0; + return; } stp->device = atadev; stp->lun = ata_get_lun(&ast_lun_map); ata_set_name(atadev, "ast", stp->lun); bioq_init(&stp->queue); + mtx_init(&stp->queue_mtx, "ATAPI TAPE bioqueue lock", MTX_DEF, 0); if (ast_sense(stp)) { free(stp, M_AST); - return 0; + return; } if (!strcmp(atadev->param->model, "OnStream DI-30")) { @@ -127,43 +132,70 @@ astattach(struct ata_device *atadev) dev = make_dev(&ast_cdevsw, 2 * stp->lun, UID_ROOT, GID_OPERATOR, 0640, "ast%d", stp->lun); dev->si_drv1 = stp; - dev->si_iosize_max = 256 * DEV_BSIZE; + if (atadev->channel->dma) + dev->si_iosize_max = atadev->channel->dma->max_iosize; + else + dev->si_iosize_max = DFLTPHYS; stp->dev1 = dev; dev = make_dev(&ast_cdevsw, 2 * stp->lun + 1, UID_ROOT, GID_OPERATOR, 0640, "nast%d", stp->lun); + dev->si_drv1 = stp; - dev->si_iosize_max = 256 * DEV_BSIZE; + if (atadev->channel->dma) + dev->si_iosize_max = atadev->channel->dma->max_iosize; + else + dev->si_iosize_max = DFLTPHYS; stp->dev2 = dev; - stp->device->flags |= ATA_D_MEDIA_CHANGED; + + /* use DMA if allowed and if drive/controller supports it */ + if (atapi_dma && atadev->channel->dma && + (atadev->param->config & ATA_DRQ_MASK) != ATA_DRQ_INTR) + atadev->setmode(atadev, ATA_DMA_MAX); + else + atadev->setmode(atadev, ATA_PIO_MAX); + + /* setup the function ptrs */ + atadev->detach = ast_detach; + atadev->start = ast_start; + atadev->softc = stp; + atadev->flags |= ATA_D_MEDIA_CHANGED; + + /* announce we are here */ ast_describe(stp); - atadev->driver = stp; - return 1; } -void -astdetach(struct ata_device *atadev) +static void +ast_detach(struct ata_device *atadev) { - struct ast_softc *stp = atadev->driver; + struct ast_softc *stp = atadev->softc; + mtx_lock(&stp->queue_mtx); bioq_flush(&stp->queue, NULL, ENXIO); + mtx_unlock(&stp->queue_mtx); destroy_dev(stp->dev1); destroy_dev(stp->dev2); devstat_remove_entry(stp->stats); + ata_prtdev(atadev, "WARNING - removed from configuration\n"); ata_free_name(atadev); ata_free_lun(&ast_lun_map, stp->lun); + atadev->attach = NULL; + atadev->detach = NULL; + atadev->start = NULL; + atadev->softc = NULL; + atadev->flags = 0; free(stp, M_AST); - atadev->driver = NULL; } static int ast_sense(struct ast_softc *stp) { - int count, error = 0; + int count; - /* get drive capabilities, some drives needs this repeated */ + /* get drive capabilities, some bugridden drives needs this repeated */ for (count = 0 ; count < 5 ; count++) { - if (!(error = ast_mode_sense(stp, ATAPI_TAPE_CAP_PAGE, - &stp->cap, sizeof(stp->cap)))) { + if (!ast_mode_sense(stp, ATAPI_TAPE_CAP_PAGE, + &stp->cap, sizeof(stp->cap)) && + stp->cap.page_code == ATAPI_TAPE_CAP_PAGE) { if (stp->cap.blk32k) stp->blksize = 32768; if (stp->cap.blk1024) @@ -235,17 +267,17 @@ ast_describe(struct ast_softc *stp) } static int -astopen(dev_t dev, int flags, int fmt, struct thread *td) +ast_open(dev_t dev, int flags, int fmt, struct thread *td) { struct ast_softc *stp = dev->si_drv1; - if (!stp) + if (!stp || stp->device->flags & ATA_D_DETACHING) return ENXIO; if (count_dev(dev) > 1) return EBUSY; - atapi_test_ready(stp->device); + ast_test_ready(stp->device); if (stp->cap.lock) ast_prevent_allow(stp, 1); @@ -260,7 +292,7 @@ astopen(dev_t dev, int flags, int fmt, struct thread *td) } static int -astclose(dev_t dev, int flags, int fmt, struct thread *td) +ast_close(dev_t dev, int flags, int fmt, struct thread *td) { struct ast_softc *stp = dev->si_drv1; @@ -271,7 +303,7 @@ astclose(dev_t dev, int flags, int fmt, struct thread *td) /* write filemark if data written to tape */ if (!(stp->flags & F_ONSTREAM) && (stp->flags & (F_DATA_WRITTEN | F_FM_WRITTEN)) == F_DATA_WRITTEN) - ast_write_filemark(stp, WF_WRITE); + ast_write_filemark(stp, ATAPI_WF_WRITE); /* if minor is even rewind on close */ if (!(minor(dev) & 0x01)) @@ -283,13 +315,13 @@ astclose(dev_t dev, int flags, int fmt, struct thread *td) stp->flags &= ~F_CTL_WARN; #ifdef AST_DEBUG ata_prtdev(stp->device, "%ju total bytes transferred\n", - (uintmax_t)ast_total); + (uintmax_t)ast_total); #endif return 0; } static int -astioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct thread *td) +ast_ioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct thread *td) { struct ast_softc *stp = dev->si_drv1; int error = 0; @@ -321,17 +353,17 @@ astioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct thread *td) case MTWEOF: for (i=0; i < mt->mt_count && !error; i++) - error = ast_write_filemark(stp, WF_WRITE); + error = ast_write_filemark(stp, ATAPI_WF_WRITE); break; case MTFSF: if (mt->mt_count) - error = ast_space(stp, SP_FM, mt->mt_count); + error = ast_space(stp, ATAPI_SP_FM, mt->mt_count); break; case MTBSF: if (mt->mt_count) - error = ast_space(stp, SP_FM, -(mt->mt_count)); + error = ast_space(stp, ATAPI_SP_FM, -(mt->mt_count)); break; case MTREW: @@ -339,7 +371,7 @@ astioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct thread *td) break; case MTOFFL: - error = ast_load_unload(stp, SS_EJECT); + error = ast_load_unload(stp, ATAPI_SS_EJECT); break; case MTNOP: @@ -351,11 +383,11 @@ astioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct thread *td) break; case MTEOD: - error = ast_space(stp, SP_EOD, 0); + error = ast_space(stp, ATAPI_SP_EOD, 0); break; case MTRETENS: - error = ast_load_unload(stp, SS_RETENSION | SS_LOAD); + error = ast_load_unload(stp, ATAPI_SS_RETENSION|ATAPI_SS_LOAD); break; case MTFSR: @@ -401,10 +433,9 @@ astioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct thread *td) } static void -aststrategy(struct bio *bp) +ast_strategy(struct bio *bp) { struct ast_softc *stp = bp->bio_dev->si_drv1; - int s; if (stp->device->flags & ATA_D_DETACHING) { biofinish(bp, NULL, ENXIO); @@ -439,22 +470,29 @@ aststrategy(struct bio *bp) } } - s = splbio(); + mtx_lock(&stp->queue_mtx); bioq_insert_tail(&stp->queue, bp); - splx(s); + mtx_unlock(&stp->queue_mtx); ata_start(stp->device->channel); } -void +static void ast_start(struct ata_device *atadev) { - struct ast_softc *stp = atadev->driver; - struct bio *bp = bioq_first(&stp->queue); + struct ast_softc *stp = atadev->softc; + struct bio *bp; + struct ata_request *request; u_int32_t blkcount; int8_t ccb[16]; - if (!bp) + mtx_lock(&stp->queue_mtx); + bp = bioq_first(&stp->queue); + if (!bp) { + mtx_unlock(&stp->queue_mtx); return; + } + bioq_remove(&stp->queue, bp); + mtx_unlock(&stp->queue_mtx); bzero(ccb, sizeof(ccb)); @@ -463,7 +501,6 @@ ast_start(struct ata_device *atadev) else ccb[0] = ATAPI_WRITE; - bioq_remove(&stp->queue, bp); blkcount = bp->bio_bcount / stp->blksize; ccb[1] = 1; @@ -471,31 +508,53 @@ ast_start(struct ata_device *atadev) ccb[3] = blkcount>>8; ccb[4] = blkcount; + if (!(request = ata_alloc_request())) { + biofinish(bp, NULL, EIO); + return; + } + request->device = atadev; + request->driver = bp; + bcopy(ccb, request->u.atapi.ccb, + (request->device->param->config & ATA_PROTO_MASK) == + ATA_PROTO_ATAPI_12 ? 16 : 12); + request->data = bp->bio_data; + request->bytecount = blkcount * stp->blksize; + request->transfersize = min(request->bytecount, 65534); + request->timeout = (ccb[0] == ATAPI_WRITE_BIG) ? 180 : 120; + request->retries = 2; + request->callback = ast_done; + switch (bp->bio_cmd) { + case BIO_READ: + request->flags |= (ATA_R_SKIPSTART | ATA_R_ATAPI | ATA_R_READ); + break; + case BIO_WRITE: + request->flags |= (ATA_R_SKIPSTART | ATA_R_ATAPI | ATA_R_WRITE); + break; + default: + ata_prtdev(atadev, "unknown BIO operation\n"); + ata_free_request(request); + biofinish(bp, NULL, EIO); + return; + } devstat_start_transaction_bio(stp->stats, bp); - - atapi_queue_cmd(stp->device, ccb, bp->bio_data, blkcount * stp->blksize, - (bp->bio_cmd == BIO_READ) ? ATPR_F_READ : 0, - 120, ast_done, bp); + ata_queue_request(request); } -static int -ast_done(struct atapi_request *request) +static void +ast_done(struct ata_request *request) { struct bio *bp = request->driver; - struct ast_softc *stp = request->device->driver; + struct ast_softc *stp = request->device->softc; - if (request->error) { - bp->bio_error = request->error; + /* finish up transfer */ + if ((bp->bio_error = request->result)) bp->bio_flags |= BIO_ERROR; - } - else { - if (!(bp->bio_cmd == BIO_READ)) - stp->flags |= F_DATA_WRITTEN; - bp->bio_resid = bp->bio_bcount - request->donecount; - ast_total += (bp->bio_bcount - bp->bio_resid); - } + if (bp->bio_cmd == BIO_WRITE) + stp->flags |= F_DATA_WRITTEN; + bp->bio_resid = bp->bio_bcount - request->donecount; + ast_total += (bp->bio_bcount - bp->bio_resid); biofinish(bp, stp->stats, 0); - return 0; + ata_free_request(request); } static int @@ -505,8 +564,7 @@ ast_mode_sense(struct ast_softc *stp, int page, void *pagebuf, int pagesize) 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; int error; - error = atapi_queue_cmd(stp->device, ccb, pagebuf, pagesize, ATPR_F_READ, - 10, NULL, NULL); + error = ata_atapicmd(stp->device, ccb, pagebuf, pagesize, ATA_R_READ, 10); #ifdef AST_DEBUG atapi_dump("ast: mode sense ", pagebuf, pagesize); #endif @@ -523,8 +581,7 @@ ast_mode_select(struct ast_softc *stp, void *pagebuf, int pagesize) ata_prtdev(stp->device, "modeselect pagesize=%d\n", pagesize); atapi_dump("mode select ", pagebuf, pagesize); #endif - return atapi_queue_cmd(stp->device, ccb, pagebuf, pagesize, 0, - 10, NULL, NULL); + return ata_atapicmd(stp->device, ccb, pagebuf, pagesize, 0, 10); } static int @@ -544,10 +601,10 @@ ast_write_filemark(struct ast_softc *stp, u_int8_t function) stp->flags |= F_FM_WRITTEN; } } - error = atapi_queue_cmd(stp->device, ccb, NULL, 0, 0, 10, NULL, NULL); + error = ata_atapicmd(stp->device, ccb, NULL, 0, 0, 10); if (error) return error; - return atapi_wait_dsc(stp->device, 10*60); + return ast_wait_dsc(stp->device, 10*60); } static int @@ -558,9 +615,8 @@ ast_read_position(struct ast_softc *stp, int hard, 0, 0, 0, 0, 0, 0, 0, 0 }; int error; - error = atapi_queue_cmd(stp->device, ccb, (caddr_t)position, - sizeof(struct ast_readposition), ATPR_F_READ, 10, - NULL, NULL); + error = ata_atapicmd(stp->device, ccb, (caddr_t)position, + sizeof(struct ast_readposition), ATA_R_READ, 10); position->tape = ntohl(position->tape); position->host = ntohl(position->host); return error; @@ -572,7 +628,7 @@ ast_space(struct ast_softc *stp, u_int8_t function, int32_t count) int8_t ccb[16] = { ATAPI_SPACE, function, count>>16, count>>8, count, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; - return atapi_queue_cmd(stp->device, ccb, NULL, 0, 0, 60*60, NULL, NULL); + return ata_atapicmd(stp->device, ccb, NULL, 0, 0, 60*60); } static int @@ -583,10 +639,10 @@ ast_locate(struct ast_softc *stp, int hard, u_int32_t pos) 0, 0, 0, 0, 0, 0, 0, 0, 0 }; int error; - error = atapi_queue_cmd(stp->device, ccb, NULL, 0, 0, 10, NULL, NULL); + error = ata_atapicmd(stp->device, ccb, NULL, 0, 0, 10); if (error) return error; - return atapi_wait_dsc(stp->device, 60*60); + return ast_wait_dsc(stp->device, 60*60); } static int @@ -595,7 +651,7 @@ ast_prevent_allow(struct ast_softc *stp, int lock) int8_t ccb[16] = { ATAPI_PREVENT_ALLOW, 0, 0, 0, lock, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; - return atapi_queue_cmd(stp->device, ccb, NULL, 0, 0,30, NULL, NULL); + return ata_atapicmd(stp->device, ccb, NULL, 0, 0, 30); } static int @@ -605,15 +661,15 @@ ast_load_unload(struct ast_softc *stp, u_int8_t function) 0, 0, 0, 0, 0, 0, 0, 0 }; int error; - if ((function & SS_EJECT) && !stp->cap.eject) + if ((function & ATAPI_SS_EJECT) && !stp->cap.eject) return 0; - error = atapi_queue_cmd(stp->device, ccb, NULL, 0, 0, 10, NULL, NULL); + error = ata_atapicmd(stp->device, ccb, NULL, 0, 0, 10); if (error) return error; tsleep((caddr_t)&error, PRIBIO, "astlu", 1 * hz); - if (function == SS_EJECT) + if (function == ATAPI_SS_EJECT) return 0; - return atapi_wait_dsc(stp->device, 60*60); + return ast_wait_dsc(stp->device, 60*60); } static int @@ -623,10 +679,10 @@ ast_rewind(struct ast_softc *stp) 0, 0, 0, 0, 0, 0, 0, 0 }; int error; - error = atapi_queue_cmd(stp->device, ccb, NULL, 0, 0, 10, NULL, NULL); + error = ata_atapicmd(stp->device, ccb, NULL, 0, 0, 10); if (error) return error; - return atapi_wait_dsc(stp->device, 60*60); + return ast_wait_dsc(stp->device, 60*60); } static int @@ -639,5 +695,32 @@ ast_erase(struct ast_softc *stp) if ((error = ast_rewind(stp))) return error; - return atapi_queue_cmd(stp->device, ccb, NULL, 0, 0, 60*60, NULL, NULL); + return ata_atapicmd(stp->device, ccb, NULL, 0, 0, 60*60); +} + +static int +ast_test_ready(struct ata_device *atadev) +{ + int8_t ccb[16] = { ATAPI_TEST_UNIT_READY, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + + return ata_atapicmd(atadev, ccb, NULL, 0, 0, 30); +} + +static int +ast_wait_dsc(struct ata_device *atadev, 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 = ata_atapicmd(atadev, ccb, NULL, 0, 0, 0); + if (error != EBUSY) + break; + tsleep(&error, PRIBIO, "atpwt", hz / 2); + timeout -= (hz / 2); + } + return error; } diff --git a/sys/dev/ata/atapi-tape.h b/sys/dev/ata/atapi-tape.h index 18b44495f939..77c907697c47 100644 --- a/sys/dev/ata/atapi-tape.h +++ b/sys/dev/ata/atapi-tape.h @@ -154,6 +154,7 @@ struct ast_softc { #define F_ONSTREAM 0x0100 /* OnStream ADR device */ int blksize; /* block size (512 | 1024) */ + struct mtx queue_mtx; /* queue lock */ struct bio_queue_head queue; /* queue of i/o requests */ struct atapi_params *param; /* drive parameters table */ struct ast_cappage cap; /* capabilities page info */ diff --git a/sys/sys/ata.h b/sys/sys/ata.h index f40d8bed7807..e10b8b43ed03 100644 --- a/sys/sys/ata.h +++ b/sys/sys/ata.h @@ -33,57 +33,22 @@ #include <sys/ioccom.h> -#define ATAPI_PSIZE_12 0 /* 12 bytes */ -#define ATAPI_PSIZE_16 1 /* 16 bytes */ - -#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 */ - -#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 */ - -#define ATA_PROTO_ATA 0 -#define ATA_PROTO_ATAPI 1 - -#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 */ - -#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 */ - -/* ATA/ATAPI device parameter information */ +/* ATA/ATAPI device parameters */ struct ata_params { - -#if BYTE_ORDER == LITTLE_ENDIAN -/*000*/ u_int16_t packet_size :2; /* packet command size */ - - u_int16_t incomplete :1; - u_int16_t :2; - u_int16_t drq_type :2; /* DRQ type */ - - u_int16_t removable :1; /* device is removable */ - u_int16_t type :5; /* device type */ - - u_int16_t :2; - u_int16_t cmd_protocol :1; /* command protocol */ -#else - u_int16_t cmd_protocol :1; /* command protocol */ - u_int16_t :2; - - u_int16_t type :5; /* device type */ - u_int16_t removable :1; /* device is removable */ - - u_int16_t drq_type :2; /* DRQ type */ - u_int16_t :2; - u_int16_t incomplete :1; - - u_int16_t packet_size :2; /* packet command size */ -#endif +/*000*/ u_int16_t config; /* configuration info */ +#define ATA_PROTO_MASK 0x8003 +#define ATA_PROTO_ATA 0x0002 +#define ATA_PROTO_ATAPI_12 0x8000 +#define ATA_PROTO_ATAPI_16 0x8001 +#define ATA_ATAPI_TYPE_MASK 0x1f00 +#define ATA_ATAPI_TYPE_DIRECT 0x0000 /* disk/floppy */ +#define ATA_ATAPI_TYPE_TAPE 0x0100 /* streaming tape */ +#define ATA_ATAPI_TYPE_CDROM 0x0500 /* CD-ROM device */ +#define ATA_ATAPI_TYPE_OPTICAL 0x0700 /* optical disk */ +#define ATA_DRQ_MASK 0x0060 +#define ATA_DRQ_SLOW 0x0000 /* cpu 3 ms delay */ +#define ATA_DRQ_INTR 0x0020 /* interrupt 10 ms delay */ +#define ATA_DRQ_FAST 0x0040 /* accel 50 us delay */ /*001*/ u_int16_t cylinders; /* # of cylinders */ u_int16_t reserved2; @@ -93,77 +58,33 @@ struct ata_params { /*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; +/*020*/ 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 */ - -#if BYTE_ORDER == LITTLE_ENDIAN -/*047*/ u_int16_t sectors_intr:8; /* sectors per interrupt */ - u_int16_t :8; -#else - u_int16_t :8; - u_int16_t sectors_intr:8; /* sectors per interrupt */ -#endif - +/*047*/ u_int16_t sectors_intr; /* sectors per interrupt */ /*048*/ u_int16_t usedmovsd; /* double word read/write? */ +/*049*/ u_int16_t capabilities1; +#define ATA_SUPPORT_DMA 0x0100 +#define ATA_SUPPORT_LBA 0x0200 +#define ATA_SUPPORT_OVERLAP 0x4000 -#if BYTE_ORDER == LITTLE_ENDIAN -/*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 */ - -/*050*/ u_int16_t device_stdby_min:1; - u_int16_t :13; - u_int16_t capability_one:1; - u_int16_t capability_zero:1; - -/*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 */ -#else - u_int16_t support_idma :1; /* interleaved DMA supported */ - u_int16_t support_queueing:1; /* supports queuing overlap */ - u_int16_t stdby_ovlap :1; /* standby/overlap supported */ - u_int16_t softreset :1; /* needs softreset when busy */ - u_int16_t support_iordy :1; /* IORDY supported */ - u_int16_t disable_iordy :1; /* IORDY may be disabled */ - u_int16_t support_lba :1; /* LBA supported */ - u_int16_t support_dma :1; /* DMA supported */ - u_int16_t retired49:8; - - u_int16_t capability_zero:1; - u_int16_t capability_one:1; - u_int16_t :13; - u_int16_t device_stdby_min:1; - - u_int16_t retired_piomode:8; /* PIO modes 0-2 */ - u_int16_t vendor51:8; - u_int16_t retired_dmamode:8; /* DMA modes, not ATA-3 */ - u_int16_t vendor52:8; -#endif +/*050*/ u_int16_t capabilities2; +/*051*/ u_int16_t retired_piomode; /* PIO modes 0-2 */ +#define ATA_RETIRED_PIO_MASK 0x0003 -/*053*/ u_int16_t atavalid; /* fields valid */ +/*052*/ u_int16_t retired_dmamode; /* DMA modes */ +#define ATA_RETIRED_DMA_MASK 0x0003 - u_int16_t obsolete54[5]; +/*053*/ u_int16_t atavalid; /* fields valid */ +#define ATA_FLAG_54_58 0x0001 /* words 54-58 valid */ +#define ATA_FLAG_64_70 0x0002 /* words 64-70 valid */ +#define ATA_FLAG_88 0x0004 /* word 88 valid */ -#if BYTE_ORDER == LITTLE_ENDIAN -/*059*/ u_int16_t multi_count:8; - u_int16_t multi_valid:1; - u_int16_t :7; -#else - u_int16_t :7; - u_int16_t multi_valid:1; - u_int16_t multi_count:8; -#endif +/*054*/ u_int16_t obsolete54[5]; +/*059*/ u_int16_t multi; +#define ATA_MULTI_VALID 0x0100 /*060*/ u_int16_t lba_size_1; u_int16_t lba_size_2; @@ -181,14 +102,8 @@ struct ata_params { /*072*/ u_int16_t rlsservice; /* rel time (us) for service */ u_int16_t reserved73; u_int16_t reserved74; - -#if BYTE_ORDER == LITTLE_ENDIAN -/*075*/ u_int16_t queuelen:5; - u_int16_t :11; -#else - u_int16_t :11; - u_int16_t queuelen:5; -#endif +/*075*/ u_int16_t queue; +#define ATA_QUEUE_LEN(x) ((x) & 0x001f) u_int16_t reserved76; u_int16_t reserved77; @@ -196,96 +111,40 @@ struct ata_params { u_int16_t reserved79; /*080*/ u_int16_t version_major; /*081*/ u_int16_t version_minor; + struct { -#if BYTE_ORDER == LITTLE_ENDIAN -/*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; -#else - u_int16_t :1; - u_int16_t nop:1; - u_int16_t read_buffer:1; - u_int16_t write_buffer:1; - u_int16_t :1; - u_int16_t protected:1; - u_int16_t reset:1; - u_int16_t service_irq:1; - u_int16_t release_irq:1; - u_int16_t look_ahead:1; - u_int16_t write_cache:1; - u_int16_t packet:1; - u_int16_t power_mngt:1; - u_int16_t removable:1; - u_int16_t security:1; - u_int16_t smart:1; - - u_int16_t support_zero:1; - u_int16_t support_one:1; - u_int16_t flush_cache48:1; - u_int16_t flush_cache:1; - u_int16_t config_overlay:1; - u_int16_t address48:1; - u_int16_t auto_acoustic:1; - u_int16_t max_security:1; - u_int16_t :1; - u_int16_t spinup:1; - u_int16_t standby:1; - u_int16_t notify:1; - u_int16_t apm:1; - u_int16_t cfa:1; - u_int16_t queued:1; - u_int16_t microcode:1; - - u_int16_t extended_zero:1; - u_int16_t extended_one:1; - u_int16_t :8; - u_int16_t logging:1; - u_int16_t streaming:1; - u_int16_t media_card_pass:1; - u_int16_t media_serial_no:1; - u_int16_t smart_self_test:1; - u_int16_t smart_error_log:1; -#endif +/*082/085*/ u_int16_t command1; +#define ATA_SUPPORT_SMART 0x0001 +#define ATA_SUPPORT_SECURITY 0x0002 +#define ATA_SUPPORT_REMOVABLE 0x0004 +#define ATA_SUPPORT_POWERMGT 0x0008 +#define ATA_SUPPORT_PACKET 0x0010 +#define ATA_SUPPORT_WRITECACHE 0x0020 +#define ATA_SUPPORT_LOOKAHEAD 0x0040 +#define ATA_SUPPORT_RELEASEIRQ 0x0080 +#define ATA_SUPPORT_SERVICEIRQ 0x0100 +#define ATA_SUPPORT_RESET 0x0200 +#define ATA_SUPPORT_PROTECTED 0x0400 +#define ATA_SUPPORT_WRITEBUFFER 0x1000 +#define ATA_SUPPORT_READBUFFER 0x2000 +#define ATA_SUPPORT_NOP 0x4000 + +/*083/086*/ u_int16_t command2; +#define ATA_SUPPORT_MICROCODE 0x0001 +#define ATA_SUPPORT_QUEUED 0x0002 +#define ATA_SUPPORT_CFA 0x0004 +#define ATA_SUPPORT_APM 0x0008 +#define ATA_SUPPORT_NOTIFY 0x0010 +#define ATA_SUPPORT_STANDBY 0x0020 +#define ATA_SUPPORT_SPINUP 0x0040 +#define ATA_SUPPORT_MAXSECURITY 0x0100 +#define ATA_SUPPORT_AUTOACOUSTIC 0x0200 +#define ATA_SUPPORT_ADDRESS48 0x0400 +#define ATA_SUPPORT_OVERLAY 0x0800 +#define ATA_SUPPORT_FLUSHCACHE 0x1000 +#define ATA_SUPPORT_FLUSHCACHE48 0x2000 + +/*084/087*/ u_int16_t extension; } support, enabled; /*088*/ u_int16_t udmamodes; /* UltraDMA modes */ @@ -293,24 +152,12 @@ struct ata_params { /*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; +#define ATA_CABLE_ID 0x2000 -#if BYTE_ORDER == LITTLE_ENDIAN -/*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; -#else - u_int16_t hwres_valid:2; - u_int16_t hwres_cblid :1; - u_int16_t hwres_slave :5; - u_int16_t hwres_master :8; - - u_int16_t vendor_acoustic:8; - u_int16_t current_acoustic:8; -#endif +/*094*/ u_int16_t acoustic; +#define ATA_ACOUSTIC_CURRENT(x) ((x) & 0x00ff) +#define ATA_ACOUSTIC_VENDOR(x) (((x) & 0xff00) >> 8) /*095*/ u_int16_t stream_min_req_size; /*096*/ u_int16_t stream_transfer_time; @@ -331,6 +178,7 @@ struct ata_params { /*255*/ u_int16_t integrity; }; +/* ATA transfer modes */ #define ATA_MODE_MASK 0x0f #define ATA_DMA_MASK 0xf0 #define ATA_PIO 0x00 @@ -354,34 +202,160 @@ struct ata_params { #define ATA_SA150 0x47 #define ATA_DMA_MAX 0x4f +/* ATA commands */ +#define ATA_NOP 0x00 /* NOP command */ +#define ATA_NF_FLUSHQUEUE 0x00 /* flush queued cmd's */ +#define ATA_NF_AUTOPOLL 0x01 /* start autopoll function */ +#define ATA_ATAPI_RESET 0x08 /* reset ATAPI device */ +#define ATA_READ 0x20 /* read command */ +#define ATA_READ48 0x24 /* read command */ +#define ATA_READ_DMA48 0x25 /* read w/DMA command */ +#define ATA_READ_DMA_QUEUED48 0x26 /* read w/DMA QUEUED command */ +#define ATA_READ_MUL48 0x29 /* read multi command */ +#define ATA_WRITE 0x30 /* write command */ +#define ATA_WRITE48 0x34 /* write command */ +#define ATA_WRITE_DMA48 0x35 /* write w/DMA command */ +#define ATA_WRITE_DMA_QUEUED48 0x36 /* write w/DMA QUEUED command */ +#define ATA_WRITE_MUL48 0x39 /* write multi command */ +#define ATA_PACKET_CMD 0xa0 /* packet command */ +#define ATA_ATAPI_IDENTIFY 0xa1 /* get ATAPI params*/ +#define ATA_SERVICE 0xa2 /* service command */ +#define ATA_READ_MUL 0xc4 /* read multi command */ +#define ATA_WRITE_MUL 0xc5 /* write multi command */ +#define ATA_SET_MULTI 0xc6 /* set multi size command */ +#define ATA_READ_DMA_QUEUED 0xc7 /* read w/DMA QUEUED command */ +#define ATA_READ_DMA 0xc8 /* read w/DMA command */ +#define ATA_WRITE_DMA 0xca /* write w/DMA command */ +#define ATA_WRITE_DMA_QUEUED 0xcc /* write w/DMA QUEUED command */ +#define ATA_SLEEP 0xe6 /* sleep command */ +#define ATA_FLUSHCACHE 0xe7 /* flush cache to disk */ +#define ATA_FLUSHCACHE48 0xea /* flush cache to disk */ +#define ATA_ATA_IDENTIFY 0xec /* get ATA params */ +#define ATA_SETFEATURES 0xef /* features command */ +#define ATA_SF_SETXFER 0x03 /* set transfer mode */ +#define ATA_SF_ENAB_WCACHE 0x02 /* enable write cache */ +#define ATA_SF_DIS_WCACHE 0x82 /* disable write cache */ +#define ATA_SF_ENAB_RCACHE 0xaa /* enable readahead cache */ +#define ATA_SF_DIS_RCACHE 0x55 /* disable readahead cache */ +#define ATA_SF_ENAB_RELIRQ 0x5d /* enable release interrupt */ +#define ATA_SF_DIS_RELIRQ 0xdd /* disable release interrupt */ +#define ATA_SF_ENAB_SRVIRQ 0x5e /* enable service interrupt */ +#define ATA_SF_DIS_SRVIRQ 0xde /* disable service interrupt */ + +/* ATAPI commands */ +#define ATAPI_TEST_UNIT_READY 0x00 /* check if device is ready */ +#define ATAPI_REZERO 0x01 /* rewind */ +#define ATAPI_REQUEST_SENSE 0x03 /* get sense data */ +#define ATAPI_FORMAT 0x04 /* format unit */ +#define ATAPI_READ 0x08 /* read data */ +#define ATAPI_WRITE 0x0a /* write data */ +#define ATAPI_WEOF 0x10 /* write filemark */ +#define ATAPI_WF_WRITE 0x01 +#define ATAPI_SPACE 0x11 /* space command */ +#define ATAPI_SP_FM 0x01 +#define ATAPI_SP_EOD 0x03 +#define ATAPI_MODE_SELECT 0x15 /* mode select */ +#define ATAPI_ERASE 0x19 /* erase */ +#define ATAPI_MODE_SENSE 0x1a /* mode sense */ +#define ATAPI_START_STOP 0x1b /* start/stop unit */ +#define ATAPI_SS_LOAD 0x01 +#define ATAPI_SS_RETENSION 0x02 +#define ATAPI_SS_EJECT 0x04 +#define ATAPI_PREVENT_ALLOW 0x1e /* media removal */ +#define ATAPI_READ_FORMAT_CAPACITIES 0x23 /* get format capacities */ +#define ATAPI_READ_CAPACITY 0x25 /* get volume capacity */ +#define ATAPI_READ_BIG 0x28 /* read data */ +#define ATAPI_WRITE_BIG 0x2a /* write data */ +#define ATAPI_LOCATE 0x2b /* locate to position */ +#define ATAPI_READ_POSITION 0x34 /* read position */ +#define ATAPI_SYNCHRONIZE_CACHE 0x35 /* flush buf, close channel */ +#define ATAPI_WRITE_BUFFER 0x3b /* write device buffer */ +#define ATAPI_READ_BUFFER 0x3c /* read device buffer */ +#define ATAPI_READ_SUBCHANNEL 0x42 /* get subchannel info */ +#define ATAPI_READ_TOC 0x43 /* get table of contents */ +#define ATAPI_PLAY_10 0x45 /* play by lba */ +#define ATAPI_PLAY_MSF 0x47 /* play by MSF address */ +#define ATAPI_PLAY_TRACK 0x48 /* play by track number */ +#define ATAPI_PAUSE 0x4b /* pause audio operation */ +#define ATAPI_READ_DISK_INFO 0x51 /* get disk info structure */ +#define ATAPI_READ_TRACK_INFO 0x52 /* get track info structure */ +#define ATAPI_RESERVE_TRACK 0x53 /* reserve track */ +#define ATAPI_SEND_OPC_INFO 0x54 /* send OPC structurek */ +#define ATAPI_MODE_SELECT_BIG 0x55 /* set device parameters */ +#define ATAPI_REPAIR_TRACK 0x58 /* repair track */ +#define ATAPI_READ_MASTER_CUE 0x59 /* read master CUE info */ +#define ATAPI_MODE_SENSE_BIG 0x5a /* get device parameters */ +#define ATAPI_CLOSE_TRACK 0x5b /* close track/session */ +#define ATAPI_READ_BUFFER_CAPACITY 0x5c /* get buffer capicity */ +#define ATAPI_SEND_CUE_SHEET 0x5d /* send CUE sheet */ +#define ATAPI_BLANK 0xa1 /* blank the media */ +#define ATAPI_SEND_KEY 0xa3 /* send DVD key structure */ +#define ATAPI_REPORT_KEY 0xa4 /* get DVD key structure */ +#define ATAPI_PLAY_12 0xa5 /* play by lba */ +#define ATAPI_LOAD_UNLOAD 0xa6 /* changer control command */ +#define ATAPI_READ_STRUCTURE 0xad /* get DVD structure */ +#define ATAPI_PLAY_CD 0xb4 /* universal play command */ +#define ATAPI_SET_SPEED 0xbb /* set drive speed */ +#define ATAPI_MECH_STATUS 0xbd /* get changer status */ +#define ATAPI_READ_CD 0xbe /* read data */ +#define ATAPI_POLL_DSC 0xff /* poll DSC status bit */ + 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 -#define ATARAIDREBUILD 8 -#define ATARAIDCREATE 9 -#define ATARAIDDELETE 10 -#define ATARAIDSTATUS 11 -#define ATAENCSTAT 12 -#define ATAGMAXCHANNEL 13 -#define ATARAIDADDSPARE 14 +#define ATAGMAXCHANNEL 0x0101 +#define ATAGPARM 0x0102 +#define ATAGMODE 0x0103 +#define ATASMODE 0x0104 +#define ATAREQUEST 0x0108 +#define ATAREINIT 0x0110 +#define ATAATTACH 0x0111 +#define ATADETACH 0x0112 +#define ATARAIDCREATE 0x0120 +#define ATARAIDDELETE 0x0121 +#define ATARAIDSTATUS 0x0122 +#define ATARAIDADDSPARE 0x0123 +#define ATARAIDREBUILD 0x0124 +#define ATAENCSTAT 0x0130 union { - struct { - int mode[2]; - } mode; + int maxchan; + struct { int type[2]; char name[2][32]; struct ata_params params[2]; } param; + + struct { + int mode[2]; + } mode; + + struct { + union { + struct { + u_int8_t command; + u_int8_t feature; + u_int64_t lba; + u_int16_t count; + } ata; + struct { + char ccb[16]; + } atapi; + } u; + caddr_t data; + int count; + int flags; +#define ATA_CMD_CONTROL 0x01 +#define ATA_CMD_READ 0x02 +#define ATA_CMD_WRITE 0x04 +#define ATA_CMD_ATAPI 0x08 + + int timeout; + int error; + } request; + struct raid_setup { int type; #define AR_RAID0 1 @@ -393,9 +367,7 @@ struct ata_cmd { int interleave; int unit; } raid_setup; - struct { - int disk; - } raid_spare; + struct raid_status { int type; int total_disks; @@ -408,26 +380,17 @@ struct ata_cmd { int progress; } raid_status; + + struct { + int disk; + } raid_spare; + struct { int fan; int temp; int v05; int v12; } enclosure; - 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; - int maxchan; } u; }; |