diff --git a/sys/arm/mv/mv_sata.c b/sys/arm/mv/mv_sata.c index 13372526ccef..35939563c50c 100644 --- a/sys/arm/mv/mv_sata.c +++ b/sys/arm/mv/mv_sata.c @@ -1,862 +1,861 @@ /*- * Copyright (C) 2008-2009 Semihalf * All rights reserved. * * Initial version developed by Ilya Bakulin. Full functionality and bringup * by Piotr Ziecik. * * 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. * 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. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 AUTHOR OR CONTRIBUTORS 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. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "ata_if.h" #include "mvreg.h" #include "mvvar.h" /* Useful macros */ #define EDMA_TIMEOUT 100000 /* 100 ms */ #define SATA_INL(sc, reg) ATA_INL((sc)->sc_mem_res, reg) #define SATA_OUTL(sc, reg, val) ATA_OUTL((sc)->sc_mem_res, reg, val) /* HW-related data structures */ struct sata_prdentry { uint32_t prd_addrlo; uint32_t prd_count; uint32_t prd_addrhi; uint32_t prd_reserved; }; struct sata_crqb { uint32_t crqb_prdlo; uint32_t crqb_prdhi; uint32_t crqb_flags; uint16_t crqb_count; uint16_t crqb_reserved1[2]; uint8_t crqb_ata_command; uint8_t crqb_ata_feature; uint8_t crqb_ata_lba_low; uint8_t crqb_ata_lba_mid; uint8_t crqb_ata_lba_high; uint8_t crqb_ata_device; uint8_t crqb_ata_lba_low_p; uint8_t crqb_ata_lba_mid_p; uint8_t crqb_ata_lba_high_p; uint8_t crqb_ata_feature_p; uint8_t crqb_ata_count; uint8_t crqb_ata_count_p; uint16_t crqb_reserved2; }; struct sata_crpb { uint8_t crpb_tag; uint8_t crpb_reserved; uint8_t crpb_edma_status; uint8_t crpb_dev_status; uint32_t crpb_timestamp; }; /* Identification section. */ struct sata_softc { device_t sc_dev; unsigned int sc_version; unsigned int sc_edma_qlen; uint32_t sc_edma_reqis_mask; uint32_t sc_edma_resos_mask; struct resource *sc_mem_res; bus_space_tag_t sc_mem_res_bustag; bus_space_handle_t sc_mem_res_bushdl; struct resource *sc_irq_res; void *sc_irq_cookiep; struct { void (*function)(void *); void *argument; } sc_interrupt[SATA_CHAN_NUM]; }; /* Controller functions */ static int sata_probe(device_t dev); static int sata_attach(device_t dev); static int sata_detach(device_t dev); static void sata_intr(void*); static struct resource * sata_alloc_resource(device_t dev, device_t child, int type, int *rid, u_long start, u_long end, u_long count, u_int flags); static int sata_release_resource(device_t dev, device_t child, int type, int rid, struct resource *r); static int sata_setup_intr(device_t dev, device_t child, struct resource *irq, int flags, driver_filter_t *filt, driver_intr_t *function, void *argument, void **cookiep); static int sata_teardown_intr(device_t dev, device_t child, struct resource *irq, void *cookie); /* Channel functions */ static int sata_channel_probe(device_t dev); static int sata_channel_attach(device_t dev); static int sata_channel_detach(device_t dev); static int sata_channel_begin_transaction(struct ata_request *request); static int sata_channel_end_transaction(struct ata_request *request); static int sata_channel_status(device_t dev); static void sata_channel_setmode(device_t parent, device_t dev); static void sata_channel_reset(device_t dev); static void sata_channel_dmasetprd(void *xsc, bus_dma_segment_t *segs, int nsegs, int error); /* EDMA functions */ static int sata_edma_ctrl(device_t dev, int on); static int sata_edma_is_running(device_t); static device_method_t sata_methods[] = { /* Device method */ DEVMETHOD(device_probe, sata_probe), DEVMETHOD(device_attach, sata_attach), DEVMETHOD(device_detach, sata_detach), DEVMETHOD(device_shutdown, bus_generic_shutdown), DEVMETHOD(device_suspend, bus_generic_suspend), DEVMETHOD(device_resume, bus_generic_resume), /* ATA bus methods. */ DEVMETHOD(bus_alloc_resource, sata_alloc_resource), DEVMETHOD(bus_release_resource, sata_release_resource), DEVMETHOD(bus_activate_resource, bus_generic_activate_resource), DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), DEVMETHOD(bus_setup_intr, sata_setup_intr), DEVMETHOD(bus_teardown_intr, sata_teardown_intr), { 0, 0 }, }; static driver_t sata_driver = { "sata", sata_methods, sizeof(struct sata_softc), }; devclass_t sata_devclass; DRIVER_MODULE(sata, mbus, sata_driver, sata_devclass, 0, 0); MODULE_VERSION(sata, 1); MODULE_DEPEND(sata, ata, 1, 1, 1); static int sata_probe(device_t dev) { struct sata_softc *sc; uint32_t d, r; soc_id(&d, &r); sc = device_get_softc(dev); /* No SATA controller on the 88F5281 SoC */ if (d == MV_DEV_88F5281) return (ENXIO); switch(d) { case MV_DEV_88F5182: sc->sc_version = 1; sc->sc_edma_qlen = 128; break; case MV_DEV_88F6281: case MV_DEV_MV78100: case MV_DEV_MV78100_Z0: sc->sc_version = 2; sc->sc_edma_qlen = 32; break; default: device_printf(dev, "unsupported SoC (ID: 0x%08X)!\n", d); return (ENXIO); } sc->sc_edma_reqis_mask = (sc->sc_edma_qlen - 1) << SATA_EDMA_REQIS_OFS; sc->sc_edma_resos_mask = (sc->sc_edma_qlen - 1) << SATA_EDMA_RESOS_OFS; device_set_desc(dev, "Marvell Integrated SATA Controller"); return (0); } static int sata_attach(device_t dev) { struct sata_softc *sc; int mem_id, irq_id, error, i; device_t ata_chan; uint32_t reg; sc = device_get_softc(dev); sc->sc_dev = dev; mem_id = 0; irq_id = 0; /* Allocate resources */ sc->sc_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &mem_id, RF_ACTIVE); if (sc->sc_mem_res == NULL) { device_printf(dev, "could not allocate memory.\n"); return (ENOMEM); } sc->sc_mem_res_bustag = rman_get_bustag(sc->sc_mem_res); sc->sc_mem_res_bushdl = rman_get_bushandle(sc->sc_mem_res); KASSERT(sc->sc_mem_res_bustag && sc->sc_mem_res_bushdl, ("cannot get bus handle or tag.")); sc->sc_irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &irq_id, RF_ACTIVE); if (sc->sc_irq_res == NULL) { device_printf(dev, "could not allocate IRQ.\n"); error = ENOMEM; goto err; } error = bus_setup_intr(dev, sc->sc_irq_res, INTR_TYPE_BIO | INTR_MPSAFE | INTR_ENTROPY, NULL, sata_intr, sc, &sc->sc_irq_cookiep); if (error != 0) { device_printf(dev, "could not setup interrupt.\n"); goto err; } /* Attach channels */ for (i = 0; i < SATA_CHAN_NUM; i++) { ata_chan = device_add_child(dev, "ata", devclass_find_free_unit(ata_devclass, 0)); if (!ata_chan) { device_printf(dev, "cannot add channel %d.\n", i); error = ENOMEM; goto err; } } /* Disable interrupt coalescing */ reg = SATA_INL(sc, SATA_CR); for (i = 0; i < SATA_CHAN_NUM; i++) reg |= SATA_CR_COALDIS(i); /* Disable DMA byte swapping */ if (sc->sc_version == 2) reg |= SATA_CR_NODMABS | SATA_CR_NOEDMABS | SATA_CR_NOPRDPBS; SATA_OUTL(sc, SATA_CR, reg); /* Clear and mask all interrupts */ SATA_OUTL(sc, SATA_ICR, 0); SATA_OUTL(sc, SATA_MIMR, 0); return(bus_generic_attach(dev)); err: sata_detach(dev); return (error); } static int sata_detach(device_t dev) { struct sata_softc *sc; sc = device_get_softc(dev); if (device_is_attached(dev)) bus_generic_detach(dev); if (sc->sc_mem_res != NULL) { bus_release_resource(dev, SYS_RES_MEMORY, rman_get_rid(sc->sc_mem_res), sc->sc_mem_res); sc->sc_mem_res = NULL; } if (sc->sc_irq_res != NULL) { bus_teardown_intr(dev, sc->sc_irq_res, sc->sc_irq_cookiep); bus_release_resource(dev, SYS_RES_IRQ, rman_get_rid(sc->sc_irq_res), sc->sc_irq_res); sc->sc_irq_res = NULL; } return (0); } static struct resource * sata_alloc_resource(device_t dev, device_t child, int type, int *rid, u_long start, u_long end, u_long count, u_int flags) { struct sata_softc *sc; sc = device_get_softc(dev); KASSERT(type == SYS_RES_IRQ && *rid == ATA_IRQ_RID, ("illegal resource request (type %u, rid %u).", type, *rid)); return (sc->sc_irq_res); } static int sata_release_resource(device_t dev, device_t child, int type, int rid, struct resource *r) { KASSERT(type == SYS_RES_IRQ && rid == ATA_IRQ_RID, ("strange type %u and/or rid %u while releasing resource.", type, rid)); return (0); } static int sata_setup_intr(device_t dev, device_t child, struct resource *irq, int flags, driver_filter_t *filt, driver_intr_t *function, void *argument, void **cookiep) { struct sata_softc *sc; struct ata_channel *ch; sc = device_get_softc(dev); ch = device_get_softc(child); if (filt != NULL) { device_printf(dev, "filter interrupts are not supported.\n"); return (EINVAL); } sc->sc_interrupt[ch->unit].function = function; sc->sc_interrupt[ch->unit].argument = argument; *cookiep = sc; return (0); } static int sata_teardown_intr(device_t dev, device_t child, struct resource *irq, void *cookie) { struct sata_softc *sc; struct ata_channel *ch; sc = device_get_softc(dev); ch = device_get_softc(child); sc->sc_interrupt[ch->unit].function = NULL; sc->sc_interrupt[ch->unit].argument = NULL; return (0); } static void sata_intr(void *xsc) { struct sata_softc *sc; int unit; sc = xsc; /* * Behave like ata_generic_intr() for PCI controllers. * Simply invoke ISRs on all channels. */ for (unit = 0; unit < SATA_CHAN_NUM; unit++) if (sc->sc_interrupt[unit].function != NULL) sc->sc_interrupt[unit].function( sc->sc_interrupt[unit].argument); } static int sata_channel_probe(device_t dev) { device_set_desc(dev, "Marvell Integrated SATA Channel"); return (ata_probe(dev)); } static int sata_channel_attach(device_t dev) { struct sata_softc *sc; struct ata_channel *ch; uint64_t work; int error, i; sc = device_get_softc(device_get_parent(dev)); ch = device_get_softc(dev); if (ch->attached) return (0); ch->dev = dev; ch->unit = device_get_unit(dev); ch->flags |= ATA_USE_16BIT | ATA_NO_SLAVE; /* Set legacy ATA resources. */ for (i = ATA_DATA; i <= ATA_COMMAND; i++) { ch->r_io[i].res = sc->sc_mem_res; ch->r_io[i].offset = SATA_SHADOWR_BASE(ch->unit) + (i << 2); } ch->r_io[ATA_CONTROL].res = sc->sc_mem_res; ch->r_io[ATA_CONTROL].offset = SATA_SHADOWR_CONTROL(ch->unit); ch->r_io[ATA_IDX_ADDR].res = sc->sc_mem_res; ata_default_registers(dev); /* Set SATA resources. */ ch->r_io[ATA_SSTATUS].res = sc->sc_mem_res; ch->r_io[ATA_SSTATUS].offset = SATA_SATA_SSTATUS(ch->unit); ch->r_io[ATA_SERROR].res = sc->sc_mem_res; ch->r_io[ATA_SERROR].offset = SATA_SATA_SERROR(ch->unit); ch->r_io[ATA_SCONTROL].res = sc->sc_mem_res; ch->r_io[ATA_SCONTROL].offset = SATA_SATA_SCONTROL(ch->unit); ata_generic_hw(dev); ch->hw.begin_transaction = sata_channel_begin_transaction; ch->hw.end_transaction = sata_channel_end_transaction; ch->hw.status = sata_channel_status; /* Set DMA resources */ ata_dmainit(dev); ch->dma.setprd = sata_channel_dmasetprd; /* Clear work area */ KASSERT(sc->sc_edma_qlen * (sizeof(struct sata_crqb) + sizeof(struct sata_crpb)) <= ch->dma.max_iosize, ("insufficient DMA memory for request/response queues.\n")); bzero(ch->dma.work, sc->sc_edma_qlen * (sizeof(struct sata_crqb) + sizeof(struct sata_crpb))); bus_dmamap_sync(ch->dma.work_tag, ch->dma.work_map, BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); /* Turn off EDMA engine */ error = sata_edma_ctrl(dev, 0); if (error) { ata_dmafini(dev); return (error); } /* * Initialize EDMA engine: * - Native Command Queuing off, * - Non-Queued operation, * - Host Queue Cache enabled. */ SATA_OUTL(sc, SATA_EDMA_CFG(ch->unit), SATA_EDMA_CFG_HQCACHE | (sc->sc_version == 1) ? SATA_EDMA_CFG_QL128 : 0); /* Set request queue pointers */ work = ch->dma.work_bus; SATA_OUTL(sc, SATA_EDMA_REQBAHR(ch->unit), work >> 32); SATA_OUTL(sc, SATA_EDMA_REQIPR(ch->unit), work & 0xFFFFFFFF); SATA_OUTL(sc, SATA_EDMA_REQOPR(ch->unit), work & 0xFFFFFFFF); /* Set response queue pointers */ work += sc->sc_edma_qlen * sizeof(struct sata_crqb); SATA_OUTL(sc, SATA_EDMA_RESBAHR(ch->unit), work >> 32); SATA_OUTL(sc, SATA_EDMA_RESIPR(ch->unit), work & 0xFFFFFFFF); SATA_OUTL(sc, SATA_EDMA_RESOPR(ch->unit), work & 0xFFFFFFFF); /* Clear any outstanding interrupts */ ATA_IDX_OUTL(ch, ATA_SERROR, ATA_IDX_INL(ch, ATA_SERROR)); SATA_OUTL(sc, SATA_SATA_FISICR(ch->unit), 0); SATA_OUTL(sc, SATA_EDMA_IECR(ch->unit), 0); SATA_OUTL(sc, SATA_ICR, ~(SATA_ICR_DEV(ch->unit) | SATA_ICR_DMADONE(ch->unit))); /* Umask channel interrupts */ SATA_OUTL(sc, SATA_EDMA_IEMR(ch->unit), 0xFFFFFFFF); SATA_OUTL(sc, SATA_MIMR, SATA_INL(sc, SATA_MIMR) | SATA_MICR_DONE(ch->unit) | SATA_MICR_DMADONE(ch->unit) | SATA_MICR_ERR(ch->unit)); ch->attached = 1; return (ata_attach(dev)); } static int sata_channel_detach(device_t dev) { struct sata_softc *sc; struct ata_channel *ch; int error; sc = device_get_softc(device_get_parent(dev)); ch = device_get_softc(dev); if (!ch->attached) return (0); /* Turn off EDMA engine */ sata_edma_ctrl(dev, 0); /* Mask chanel interrupts */ SATA_OUTL(sc, SATA_EDMA_IEMR(ch->unit), 0); SATA_OUTL(sc, SATA_MIMR, SATA_INL(sc, SATA_MIMR) & ~( SATA_MICR_DONE(ch->unit) | SATA_MICR_DMADONE(ch->unit) | SATA_MICR_ERR(ch->unit))); error = ata_detach(dev); ata_dmafini(dev); ch->attached = 0; return (error); } static int sata_channel_begin_transaction(struct ata_request *request) { struct sata_softc *sc; struct ata_channel *ch; struct sata_crqb *crqb; uint32_t req_in; int error, slot; - sc = device_get_softc(GRANDPARENT(request->dev)); + sc = device_get_softc(device_get_parent(request->parent)); ch = device_get_softc(request->parent); mtx_assert(&ch->state_mtx, MA_OWNED); /* Only DMA R/W goes through the EDMA machine. */ if (request->u.ata.command != ATA_READ_DMA && - request->u.ata.command != ATA_WRITE_DMA) { + request->u.ata.command != ATA_WRITE_DMA && + request->u.ata.command != ATA_READ_DMA48 && + request->u.ata.command != ATA_WRITE_DMA48) { /* Disable EDMA before accessing legacy registers */ if (sata_edma_is_running(request->parent)) { error = sata_edma_ctrl(request->parent, 0); if (error) { request->result = error; return (ATA_OP_FINISHED); } } return (ata_begin_transaction(request)); } - /* Check for 48 bit access and convert if needed */ - ata_modify_if_48bit(request); - /* Prepare data for DMA */ if ((error = ch->dma.load(request, NULL, NULL))) { - device_printf(request->dev, "setting up DMA failed!\n"); + device_printf(request->parent, "setting up DMA failed!\n"); request->result = error; return ATA_OP_FINISHED; } /* Get next free queue slot */ req_in = SATA_INL(sc, SATA_EDMA_REQIPR(ch->unit)); slot = (req_in & sc->sc_edma_reqis_mask) >> SATA_EDMA_REQIS_OFS; crqb = (struct sata_crqb *)(ch->dma.work + (slot << SATA_EDMA_REQIS_OFS)); /* Fill in request */ bus_dmamap_sync(ch->dma.work_tag, ch->dma.work_map, BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); crqb->crqb_prdlo = htole32((uint64_t)request->dma->sg_bus & 0xFFFFFFFF); crqb->crqb_prdhi = htole32((uint64_t)request->dma->sg_bus >> 32); crqb->crqb_flags = htole32((request->flags & ATA_R_READ ? 0x01 : 0x00) | (request->tag << 1)); crqb->crqb_ata_command = request->u.ata.command; crqb->crqb_ata_feature = request->u.ata.feature; crqb->crqb_ata_lba_low = request->u.ata.lba; crqb->crqb_ata_lba_mid = request->u.ata.lba >> 8; crqb->crqb_ata_lba_high = request->u.ata.lba >> 16; crqb->crqb_ata_device = ((request->u.ata.lba >> 24) & 0x0F) | (1 << 6); crqb->crqb_ata_count = request->u.ata.count; bus_dmamap_sync(ch->dma.work_tag, ch->dma.work_map, BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); /* Enable EDMA if disabled */ if (!sata_edma_is_running(request->parent)) { error = sata_edma_ctrl(request->parent, 1); if (error) { ch->dma.unload(request); request->result = error; return (ATA_OP_FINISHED); } } /* Tell EDMA about new request */ req_in = (req_in & ~sc->sc_edma_reqis_mask) | (((slot + 1) << SATA_EDMA_REQIS_OFS) & sc->sc_edma_reqis_mask); SATA_OUTL(sc, SATA_EDMA_REQIPR(ch->unit), req_in); return (ATA_OP_CONTINUES); } static int sata_channel_end_transaction(struct ata_request *request) { struct sata_softc *sc; struct ata_channel *ch; struct sata_crpb *crpb; uint32_t res_in, res_out, icr; int slot; - sc = device_get_softc(GRANDPARENT(request->dev)); + sc = device_get_softc(device_get_parent(request->parent)); ch = device_get_softc(request->parent); mtx_assert(&ch->state_mtx, MA_OWNED); icr = SATA_INL(sc, SATA_ICR); if (icr & SATA_ICR_DMADONE(ch->unit)) { /* Get current response slot */ res_out = SATA_INL(sc, SATA_EDMA_RESOPR(ch->unit)); slot = (res_out & sc->sc_edma_resos_mask) >> SATA_EDMA_RESOS_OFS; crpb = (struct sata_crpb *)(ch->dma.work + (sc->sc_edma_qlen * sizeof(struct sata_crqb)) + (slot << SATA_EDMA_RESOS_OFS)); /* Record this request status */ bus_dmamap_sync(ch->dma.work_tag, ch->dma.work_map, BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); request->status = crpb->crpb_dev_status; request->error = 0; bus_dmamap_sync(ch->dma.work_tag, ch->dma.work_map, BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); /* Update response queue pointer */ res_out = (res_out & ~sc->sc_edma_resos_mask) | (((slot + 1) << SATA_EDMA_RESOS_OFS) & sc->sc_edma_resos_mask); SATA_OUTL(sc, SATA_EDMA_RESOPR(ch->unit), res_out); /* Ack DMA interrupt if there is nothing more to do */ res_in = SATA_INL(sc, SATA_EDMA_RESIPR(ch->unit)); res_in &= sc->sc_edma_resos_mask; res_out &= sc->sc_edma_resos_mask; if (res_in == res_out) SATA_OUTL(sc, SATA_ICR, ~SATA_ICR_DMADONE(ch->unit)); /* Update progress */ if (!(request->status & ATA_S_ERROR) && !(request->flags & ATA_R_TIMEOUT)) request->donecount = request->bytecount; /* Unload DMA data */ ch->dma.unload(request); return(ATA_OP_FINISHED); } /* Legacy ATA interrupt */ return (ata_end_transaction(request)); } static int sata_channel_status(device_t dev) { struct sata_softc *sc; struct ata_channel *ch; uint32_t icr, iecr; sc = device_get_softc(device_get_parent(dev)); ch = device_get_softc(dev); icr = SATA_INL(sc, SATA_ICR); iecr = SATA_INL(sc, SATA_EDMA_IECR(ch->unit)); if ((icr & SATA_ICR_DEV(ch->unit)) || iecr) { /* Disable EDMA before accessing SATA registers */ sata_edma_ctrl(dev, 0); ata_sata_phy_check_events(dev); /* Ack device and error interrupt */ SATA_OUTL(sc, SATA_ICR, ~SATA_ICR_DEV(ch->unit)); SATA_OUTL(sc, SATA_EDMA_IECR(ch->unit), 0); } icr &= SATA_ICR_DEV(ch->unit) | SATA_ICR_DMADONE(ch->unit); return (icr); } static void sata_channel_reset(device_t dev) { struct sata_softc *sc; struct ata_channel *ch; sc = device_get_softc(device_get_parent(dev)); ch = device_get_softc(dev); /* Disable EDMA before using legacy registers */ sata_edma_ctrl(dev, 0); /* Mask all EDMA interrups */ SATA_OUTL(sc, SATA_EDMA_IEMR(ch->unit), 0); /* Reset EDMA */ SATA_OUTL(sc, SATA_EDMA_CMD(ch->unit), SATA_EDMA_CMD_RESET); DELAY(25); SATA_OUTL(sc, SATA_EDMA_CMD(ch->unit), 0); /* Reset PHY and device */ if (ata_sata_phy_reset(dev, -1, 1)) ata_generic_reset(dev); else ch->devices = 0; /* Clear EDMA errors */ SATA_OUTL(sc, SATA_SATA_FISICR(ch->unit), 0); SATA_OUTL(sc, SATA_EDMA_IECR(ch->unit), 0); /* Unmask all EDMA interrups */ SATA_OUTL(sc, SATA_EDMA_IEMR(ch->unit), 0xFFFFFFFF); } static void sata_channel_setmode(device_t parent, device_t dev) { struct ata_device *atadev; atadev = device_get_softc(dev); /* Disable EDMA before using legacy registers */ sata_edma_ctrl(parent, 0); ata_sata_setmode(dev, ATA_PIO_MAX); if (atadev->mode >= ATA_DMA) ata_sata_setmode(dev, atadev->mode); } static void sata_channel_dmasetprd(void *xsc, bus_dma_segment_t *segs, int nsegs, int error) { struct ata_dmasetprd_args *args; struct sata_prdentry *prd; int i; args = xsc; prd = args->dmatab; if ((args->error = error)) return; for (i = 0; i < nsegs; i++) { prd[i].prd_addrlo = htole32(segs[i].ds_addr); prd[i].prd_addrhi = htole32((uint64_t)segs[i].ds_addr >> 32); prd[i].prd_count = htole32(segs[i].ds_len); } prd[i - 1].prd_count |= htole32(ATA_DMA_EOT); KASSERT(nsegs <= ATA_DMA_ENTRIES, ("too many DMA segment entries.\n")); args->nsegs = nsegs; } static int sata_edma_ctrl(device_t dev, int on) { struct sata_softc *sc; struct ata_channel *ch; int bit, timeout; uint32_t reg; sc = device_get_softc(device_get_parent(dev)); ch = device_get_softc(dev); bit = on ? SATA_EDMA_CMD_ENABLE : SATA_EDMA_CMD_DISABLE; timeout = EDMA_TIMEOUT; SATA_OUTL(sc, SATA_EDMA_CMD(ch->unit), bit); while (1) { DELAY(1); reg = SATA_INL(sc, SATA_EDMA_CMD(ch->unit)); /* Enable bit will be 1 after disable command completion */ if (on && (reg & SATA_EDMA_CMD_ENABLE)) break; /* Disable bit will be 0 after disable command completion */ if (!on && !(reg & SATA_EDMA_CMD_DISABLE)) break; if (timeout-- <= 0) { device_printf(dev, "EDMA command timeout!\n"); return (ETIMEDOUT); } } return (0); } static int sata_edma_is_running(device_t dev) { struct sata_softc *sc; struct ata_channel *ch; sc = device_get_softc(device_get_parent(dev)); ch = device_get_softc(dev); return (SATA_INL(sc, SATA_EDMA_CMD(ch->unit)) & SATA_EDMA_CMD_ENABLE); } static device_method_t sata_channel_methods[] = { /* Device interface. */ DEVMETHOD(device_probe, sata_channel_probe), DEVMETHOD(device_attach, sata_channel_attach), DEVMETHOD(device_detach, sata_channel_detach), DEVMETHOD(device_shutdown, bus_generic_shutdown), DEVMETHOD(device_suspend, ata_suspend), DEVMETHOD(device_resume, ata_resume), /* ATA channel interface */ DEVMETHOD(ata_reset, sata_channel_reset), DEVMETHOD(ata_setmode, sata_channel_setmode), { 0, 0 } }; driver_t sata_channel_driver = { "ata", sata_channel_methods, sizeof(struct ata_channel), }; DRIVER_MODULE(ata, sata, sata_channel_driver, ata_devclass, 0, 0); diff --git a/sys/dev/ata/ata-all.c b/sys/dev/ata/ata-all.c index 1460a2117d4f..d0a07c362896 100644 --- a/sys/dev/ata/ata-all.c +++ b/sys/dev/ata/ata-all.c @@ -1,1148 +1,1148 @@ /*- * Copyright (c) 1998 - 2008 Søren Schmidt * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer, * without modification, immediately at the beginning of the file. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * 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. */ #include __FBSDID("$FreeBSD$"); #include "opt_ata.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* device structure */ static d_ioctl_t ata_ioctl; static struct cdevsw ata_cdevsw = { .d_version = D_VERSION, .d_flags = D_NEEDGIANT, /* we need this as newbus isn't mpsafe */ .d_ioctl = ata_ioctl, .d_name = "ata", }; /* prototypes */ static void ata_boot_attach(void); static device_t ata_add_child(device_t, struct ata_device *, int); static void ata_conn_event(void *, int); static void bswap(int8_t *, int); static void btrim(int8_t *, int); static void bpack(int8_t *, int8_t *, int); /* global vars */ MALLOC_DEFINE(M_ATA, "ata_generic", "ATA driver generic layer"); int (*ata_raid_ioctl_func)(u_long cmd, caddr_t data) = NULL; struct intr_config_hook *ata_delayed_attach = NULL; devclass_t ata_devclass; uma_zone_t ata_request_zone; uma_zone_t ata_composite_zone; int ata_wc = 1; int ata_setmax = 0; int ata_dma_check_80pin = 1; /* local vars */ static int ata_dma = 1; static int atapi_dma = 1; /* sysctl vars */ SYSCTL_NODE(_hw, OID_AUTO, ata, CTLFLAG_RD, 0, "ATA driver parameters"); TUNABLE_INT("hw.ata.ata_dma", &ata_dma); SYSCTL_INT(_hw_ata, OID_AUTO, ata_dma, CTLFLAG_RDTUN, &ata_dma, 0, "ATA disk DMA mode control"); TUNABLE_INT("hw.ata.ata_dma_check_80pin", &ata_dma_check_80pin); SYSCTL_INT(_hw_ata, OID_AUTO, ata_dma_check_80pin, CTLFLAG_RDTUN, &ata_dma_check_80pin, 1, "Check for 80pin cable before setting ATA DMA mode"); TUNABLE_INT("hw.ata.atapi_dma", &atapi_dma); SYSCTL_INT(_hw_ata, OID_AUTO, atapi_dma, CTLFLAG_RDTUN, &atapi_dma, 0, "ATAPI device DMA mode control"); TUNABLE_INT("hw.ata.wc", &ata_wc); SYSCTL_INT(_hw_ata, OID_AUTO, wc, CTLFLAG_RDTUN, &ata_wc, 0, "ATA disk write caching"); TUNABLE_INT("hw.ata.setmax", &ata_setmax); SYSCTL_INT(_hw_ata, OID_AUTO, setmax, CTLFLAG_RDTUN, &ata_setmax, 0, "ATA disk set max native address"); /* * newbus device interface related functions */ int ata_probe(device_t dev) { return 0; } int ata_attach(device_t dev) { struct ata_channel *ch = device_get_softc(dev); int error, rid; /* check that we have a virgin channel to attach */ if (ch->r_irq) return EEXIST; /* initialize the softc basics */ ch->dev = dev; ch->state = ATA_IDLE; bzero(&ch->state_mtx, sizeof(struct mtx)); mtx_init(&ch->state_mtx, "ATA state lock", NULL, MTX_DEF); bzero(&ch->queue_mtx, sizeof(struct mtx)); mtx_init(&ch->queue_mtx, "ATA queue lock", NULL, MTX_DEF); TAILQ_INIT(&ch->ata_queue); TASK_INIT(&ch->conntask, 0, ata_conn_event, dev); /* reset the controller HW, the channel and device(s) */ while (ATA_LOCKING(dev, ATA_LF_LOCK) != ch->unit) pause("ataatch", 1); ATA_RESET(dev); ATA_LOCKING(dev, ATA_LF_UNLOCK); /* allocate DMA resources if DMA HW present*/ if (ch->dma.alloc) ch->dma.alloc(dev); /* setup interrupt delivery */ rid = ATA_IRQ_RID; ch->r_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, RF_SHAREABLE | RF_ACTIVE); if (!ch->r_irq) { device_printf(dev, "unable to allocate interrupt\n"); return ENXIO; } if ((error = bus_setup_intr(dev, ch->r_irq, ATA_INTR_FLAGS, NULL, ata_interrupt, ch, &ch->ih))) { device_printf(dev, "unable to setup interrupt\n"); return error; } /* probe and attach devices on this channel unless we are in early boot */ if (!ata_delayed_attach) ata_identify(dev); return 0; } int ata_detach(device_t dev) { struct ata_channel *ch = device_get_softc(dev); device_t *children; int nchildren, i; /* check that we have a valid channel to detach */ if (!ch->r_irq) return ENXIO; /* grap the channel lock so no new requests gets launched */ mtx_lock(&ch->state_mtx); ch->state |= ATA_STALL_QUEUE; mtx_unlock(&ch->state_mtx); /* detach & delete all children */ if (!device_get_children(dev, &children, &nchildren)) { for (i = 0; i < nchildren; i++) if (children[i]) device_delete_child(dev, children[i]); free(children, M_TEMP); } taskqueue_drain(taskqueue_thread, &ch->conntask); /* release resources */ 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; /* free DMA resources if DMA HW present*/ if (ch->dma.free) ch->dma.free(dev); mtx_destroy(&ch->state_mtx); mtx_destroy(&ch->queue_mtx); return 0; } static void ata_conn_event(void *context, int dummy) { device_t dev = (device_t)context; ata_reinit(dev); } int ata_reinit(device_t dev) { struct ata_channel *ch = device_get_softc(dev); struct ata_request *request; device_t *children; int nchildren, i; /* check that we have a valid channel to reinit */ if (!ch || !ch->r_irq) return ENXIO; if (bootverbose) device_printf(dev, "reiniting channel ..\n"); /* poll for locking the channel */ while (ATA_LOCKING(dev, ATA_LF_LOCK) != ch->unit) pause("atarini", 1); /* catch eventual request in ch->running */ mtx_lock(&ch->state_mtx); if (ch->state & ATA_STALL_QUEUE) { /* Recursive reinits and reinits during detach prohobited. */ mtx_unlock(&ch->state_mtx); return (ENXIO); } if ((request = ch->running)) callout_stop(&request->callout); ch->running = NULL; /* unconditionally grap the channel lock */ ch->state |= ATA_STALL_QUEUE; mtx_unlock(&ch->state_mtx); /* reset the controller HW, the channel and device(s) */ ATA_RESET(dev); /* reinit the children and delete any that fails */ if (!device_get_children(dev, &children, &nchildren)) { mtx_lock(&Giant); /* newbus suckage it needs Giant */ for (i = 0; i < nchildren; i++) { /* did any children go missing ? */ if (children[i] && device_is_attached(children[i]) && ATA_REINIT(children[i])) { /* * if we had a running request and its device matches * this child we need to inform the request that the * device is gone. */ if (request && request->dev == children[i]) { request->result = ENXIO; device_printf(request->dev, "FAILURE - device detached\n"); /* if not timeout finish request here */ if (!(request->flags & ATA_R_TIMEOUT)) ata_finish(request); request = NULL; } device_delete_child(dev, children[i]); } } free(children, M_TEMP); mtx_unlock(&Giant); /* newbus suckage dealt with, release Giant */ } /* if we still have a good request put it on the queue again */ if (request && !(request->flags & ATA_R_TIMEOUT)) { device_printf(request->dev, "WARNING - %s requeued due to channel reset", ata_cmd2str(request)); if (!(request->flags & (ATA_R_ATAPI | ATA_R_CONTROL))) printf(" LBA=%ju", request->u.ata.lba); printf("\n"); request->flags |= ATA_R_REQUEUE; ata_queue_request(request); } /* we're done release the channel for new work */ mtx_lock(&ch->state_mtx); ch->state = ATA_IDLE; mtx_unlock(&ch->state_mtx); ATA_LOCKING(dev, ATA_LF_UNLOCK); /* Add new children. */ /* ata_identify(dev); */ if (bootverbose) device_printf(dev, "reinit done ..\n"); /* kick off requests on the queue */ ata_start(dev); return 0; } int ata_suspend(device_t dev) { struct ata_channel *ch; /* check for valid device */ if (!dev || !(ch = device_get_softc(dev))) return ENXIO; /* wait for the channel to be IDLE or detached before suspending */ while (ch->r_irq) { mtx_lock(&ch->state_mtx); if (ch->state == ATA_IDLE) { ch->state = ATA_ACTIVE; mtx_unlock(&ch->state_mtx); break; } mtx_unlock(&ch->state_mtx); tsleep(ch, PRIBIO, "atasusp", hz/10); } ATA_LOCKING(dev, ATA_LF_UNLOCK); return 0; } int ata_resume(device_t dev) { int error; /* check for valid device */ if (!dev || !device_get_softc(dev)) return ENXIO; /* reinit the devices, we dont know what mode/state they are in */ error = ata_reinit(dev); /* kick off requests on the queue */ ata_start(dev); return error; } void ata_interrupt(void *data) { struct ata_channel *ch = (struct ata_channel *)data; struct ata_request *request; mtx_lock(&ch->state_mtx); do { /* ignore interrupt if its not for us */ if (ch->hw.status && !ch->hw.status(ch->dev)) break; /* do we have a running request */ if (!(request = ch->running)) break; ATA_DEBUG_RQ(request, "interrupt"); /* safetycheck for the right state */ if (ch->state == ATA_IDLE) { device_printf(request->dev, "interrupt on idle channel ignored\n"); break; } /* * we have the HW locks, so end the transaction for this request * if it finishes immediately otherwise wait for next interrupt */ if (ch->hw.end_transaction(request) == ATA_OP_FINISHED) { ch->running = NULL; if (ch->state == ATA_ACTIVE) ch->state = ATA_IDLE; mtx_unlock(&ch->state_mtx); ATA_LOCKING(ch->dev, ATA_LF_UNLOCK); ata_finish(request); return; } } while (0); mtx_unlock(&ch->state_mtx); } /* * device related interfaces */ static int ata_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int32_t flag, struct thread *td) { device_t device, *children; struct ata_ioc_devices *devices = (struct ata_ioc_devices *)data; int *value = (int *)data; int i, nchildren, error = ENOTTY; switch (cmd) { case IOCATAGMAXCHANNEL: /* In case we have channel 0..n this will return n+1. */ *value = devclass_get_maxunit(ata_devclass); error = 0; break; case IOCATAREINIT: if (*value >= devclass_get_maxunit(ata_devclass) || !(device = devclass_get_device(ata_devclass, *value)) || !device_is_attached(device)) return ENXIO; error = ata_reinit(device); break; case IOCATAATTACH: if (*value >= devclass_get_maxunit(ata_devclass) || !(device = devclass_get_device(ata_devclass, *value)) || !device_is_attached(device)) return ENXIO; error = DEVICE_ATTACH(device); break; case IOCATADETACH: if (*value >= devclass_get_maxunit(ata_devclass) || !(device = devclass_get_device(ata_devclass, *value)) || !device_is_attached(device)) return ENXIO; error = DEVICE_DETACH(device); break; case IOCATADEVICES: if (devices->channel >= devclass_get_maxunit(ata_devclass) || !(device = devclass_get_device(ata_devclass, devices->channel)) || !device_is_attached(device)) return ENXIO; bzero(devices->name[0], 32); bzero(&devices->params[0], sizeof(struct ata_params)); bzero(devices->name[1], 32); bzero(&devices->params[1], sizeof(struct ata_params)); if (!device_get_children(device, &children, &nchildren)) { for (i = 0; i < nchildren; i++) { if (children[i] && device_is_attached(children[i])) { struct ata_device *atadev = device_get_softc(children[i]); if (atadev->unit == ATA_MASTER) { /* XXX SOS PM */ strncpy(devices->name[0], device_get_nameunit(children[i]), 32); bcopy(&atadev->param, &devices->params[0], sizeof(struct ata_params)); } if (atadev->unit == ATA_SLAVE) { /* XXX SOS PM */ strncpy(devices->name[1], device_get_nameunit(children[i]), 32); bcopy(&atadev->param, &devices->params[1], sizeof(struct ata_params)); } } } free(children, M_TEMP); error = 0; } else error = ENODEV; break; default: if (ata_raid_ioctl_func) error = ata_raid_ioctl_func(cmd, data); } return error; } int ata_device_ioctl(device_t dev, u_long cmd, caddr_t data) { struct ata_device *atadev = device_get_softc(dev); struct ata_channel *ch = device_get_softc(device_get_parent(dev)); struct ata_ioc_request *ioc_request = (struct ata_ioc_request *)data; struct ata_params *params = (struct ata_params *)data; int *mode = (int *)data; struct ata_request *request; caddr_t buf; int error; switch (cmd) { case IOCATAREQUEST: if (ioc_request->count > (ch->dma.max_iosize ? ch->dma.max_iosize : DFLTPHYS)) { return (EFBIG); } if (!(buf = malloc(ioc_request->count, M_ATA, M_NOWAIT))) { return ENOMEM; } if (!(request = ata_alloc_request())) { free(buf, M_ATA); return ENOMEM; } request->dev = atadev->dev; if (ioc_request->flags & ATA_CMD_WRITE) { error = copyin(ioc_request->data, buf, ioc_request->count); if (error) { free(buf, M_ATA); ata_free_request(request); return error; } } if (ioc_request->flags & ATA_CMD_ATAPI) { request->flags = ATA_R_ATAPI; bcopy(ioc_request->u.atapi.ccb, request->u.atapi.ccb, 16); } else { request->u.ata.command = ioc_request->u.ata.command; request->u.ata.feature = ioc_request->u.ata.feature; request->u.ata.lba = ioc_request->u.ata.lba; request->u.ata.count = ioc_request->u.ata.count; } request->timeout = ioc_request->timeout; request->data = buf; request->bytecount = ioc_request->count; request->transfersize = request->bytecount; if (ioc_request->flags & ATA_CMD_CONTROL) request->flags |= ATA_R_CONTROL; if (ioc_request->flags & ATA_CMD_READ) request->flags |= ATA_R_READ; if (ioc_request->flags & ATA_CMD_WRITE) request->flags |= ATA_R_WRITE; ata_queue_request(request); if (request->flags & ATA_R_ATAPI) { bcopy(&request->u.atapi.sense, &ioc_request->u.atapi.sense, sizeof(struct atapi_sense)); } else { ioc_request->u.ata.command = request->u.ata.command; ioc_request->u.ata.feature = request->u.ata.feature; ioc_request->u.ata.lba = request->u.ata.lba; ioc_request->u.ata.count = request->u.ata.count; } ioc_request->error = request->result; if (ioc_request->flags & ATA_CMD_READ) error = copyout(buf, ioc_request->data, ioc_request->count); else error = 0; free(buf, M_ATA); ata_free_request(request); return error; case IOCATAGPARM: ata_getparam(atadev, 0); bcopy(&atadev->param, params, sizeof(struct ata_params)); return 0; case IOCATASMODE: atadev->mode = *mode; ATA_SETMODE(device_get_parent(dev), dev); return 0; case IOCATAGMODE: *mode = atadev->mode; return 0; case IOCATASSPINDOWN: atadev->spindown = *mode; return 0; case IOCATAGSPINDOWN: *mode = atadev->spindown; return 0; default: return ENOTTY; } } static void ata_boot_attach(void) { struct ata_channel *ch; int ctlr; mtx_lock(&Giant); /* newbus suckage it needs Giant */ /* kick of probe and attach on all channels */ for (ctlr = 0; ctlr < devclass_get_maxunit(ata_devclass); ctlr++) { if ((ch = devclass_get_softc(ata_devclass, ctlr))) { ata_identify(ch->dev); } } /* release the hook that got us here, we are only needed once during boot */ if (ata_delayed_attach) { config_intrhook_disestablish(ata_delayed_attach); free(ata_delayed_attach, M_TEMP); ata_delayed_attach = NULL; } mtx_unlock(&Giant); /* newbus suckage dealt with, release Giant */ } /* * misc support functions */ static device_t ata_add_child(device_t parent, struct ata_device *atadev, int unit) { device_t child; if ((child = device_add_child(parent, NULL, unit))) { device_set_softc(child, atadev); device_quiet(child); atadev->dev = child; atadev->max_iosize = DEV_BSIZE; atadev->mode = ATA_PIO_MAX; } return child; } int ata_getparam(struct ata_device *atadev, int init) { struct ata_channel *ch = device_get_softc(device_get_parent(atadev->dev)); struct ata_request *request; u_int8_t command = 0; int error = ENOMEM, retries = 2; if (ch->devices & (ATA_ATA_MASTER << atadev->unit)) command = ATA_ATA_IDENTIFY; if (ch->devices & (ATA_ATAPI_MASTER << atadev->unit)) command = ATA_ATAPI_IDENTIFY; if (!command) return ENXIO; while (retries-- > 0 && error) { if (!(request = ata_alloc_request())) break; request->dev = atadev->dev; request->timeout = 1; request->retries = 0; request->u.ata.command = command; request->flags = (ATA_R_READ|ATA_R_AT_HEAD|ATA_R_DIRECT); if (!bootverbose) request->flags |= ATA_R_QUIET; request->data = (void *)&atadev->param; request->bytecount = sizeof(struct ata_params); request->donecount = 0; request->transfersize = DEV_BSIZE; ata_queue_request(request); error = request->result; ata_free_request(request); } if (!error && (isprint(atadev->param.model[0]) || isprint(atadev->param.model[1]))) { struct ata_params *atacap = &atadev->param; int16_t *ptr; for (ptr = (int16_t *)atacap; ptr < (int16_t *)atacap + sizeof(struct ata_params)/2; ptr++) { *ptr = le16toh(*ptr); } if (!(!strncmp(atacap->model, "FX", 2) || !strncmp(atacap->model, "NEC", 3) || !strncmp(atacap->model, "Pioneer", 7) || !strncmp(atacap->model, "SHARP", 5))) { bswap(atacap->model, sizeof(atacap->model)); bswap(atacap->revision, sizeof(atacap->revision)); bswap(atacap->serial, sizeof(atacap->serial)); } btrim(atacap->model, sizeof(atacap->model)); bpack(atacap->model, atacap->model, sizeof(atacap->model)); btrim(atacap->revision, sizeof(atacap->revision)); bpack(atacap->revision, atacap->revision, sizeof(atacap->revision)); btrim(atacap->serial, sizeof(atacap->serial)); bpack(atacap->serial, atacap->serial, sizeof(atacap->serial)); if (bootverbose) printf("ata%d-%s: pio=%s wdma=%s udma=%s cable=%s wire\n", device_get_unit(ch->dev), ata_unit2str(atadev), ata_mode2str(ata_pmode(atacap)), ata_mode2str(ata_wmode(atacap)), ata_mode2str(ata_umode(atacap)), (atacap->hwres & ATA_CABLE_ID) ? "80":"40"); if (init) { char buffer[64]; sprintf(buffer, "%.40s/%.8s", atacap->model, atacap->revision); device_set_desc_copy(atadev->dev, buffer); if ((atadev->param.config & ATA_PROTO_ATAPI) && (atadev->param.config != ATA_CFA_MAGIC1) && (atadev->param.config != ATA_CFA_MAGIC2)) { if (atapi_dma && (atadev->param.config & ATA_DRQ_MASK) != ATA_DRQ_INTR && ata_umode(&atadev->param) >= ATA_UDMA2) atadev->mode = ATA_DMA_MAX; } else { if (ata_dma && (ata_umode(&atadev->param) > 0 || ata_wmode(&atadev->param) > 0)) atadev->mode = ATA_DMA_MAX; } } } else { if (!error) error = ENXIO; } return error; } int ata_identify(device_t dev) { struct ata_channel *ch = device_get_softc(dev); struct ata_device *atadev; device_t *children; device_t child, master = NULL; int nchildren, i, n = ch->devices; if (bootverbose) device_printf(dev, "Identifying devices: %08x\n", ch->devices); mtx_lock(&Giant); /* Skip existing devices. */ if (!device_get_children(dev, &children, &nchildren)) { for (i = 0; i < nchildren; i++) { if (children[i] && (atadev = device_get_softc(children[i]))) n &= ~((ATA_ATA_MASTER | ATA_ATAPI_MASTER) << atadev->unit); } free(children, M_TEMP); } /* Create new devices. */ if (bootverbose) device_printf(dev, "New devices: %08x\n", n); if (n == 0) { mtx_unlock(&Giant); return (0); } for (i = 0; i < ATA_PM; ++i) { if (n & (((ATA_ATA_MASTER | ATA_ATAPI_MASTER) << i))) { int unit = -1; if (!(atadev = malloc(sizeof(struct ata_device), M_ATA, M_NOWAIT | M_ZERO))) { device_printf(dev, "out of memory\n"); return ENOMEM; } atadev->unit = i; #ifdef ATA_STATIC_ID if (n & (ATA_ATA_MASTER << i)) unit = (device_get_unit(dev) << 1) + i; #endif if ((child = ata_add_child(dev, atadev, unit))) { /* * PATA slave should be identified first, to allow * device cable detection on master to work properly. */ if (i == 0 && (n & ATA_PORTMULTIPLIER) == 0 && (n & ((ATA_ATA_MASTER | ATA_ATAPI_MASTER) << 1)) != 0) { master = child; continue; } if (ata_getparam(atadev, 1)) { device_delete_child(dev, child); free(atadev, M_ATA); } } else free(atadev, M_ATA); } } if (master) { atadev = device_get_softc(master); if (ata_getparam(atadev, 1)) { device_delete_child(dev, master); free(atadev, M_ATA); } } bus_generic_probe(dev); bus_generic_attach(dev); mtx_unlock(&Giant); return 0; } void ata_default_registers(device_t dev) { struct ata_channel *ch = device_get_softc(dev); /* fill in the defaults from whats setup already */ ch->r_io[ATA_ERROR].res = ch->r_io[ATA_FEATURE].res; ch->r_io[ATA_ERROR].offset = ch->r_io[ATA_FEATURE].offset; ch->r_io[ATA_IREASON].res = ch->r_io[ATA_COUNT].res; ch->r_io[ATA_IREASON].offset = ch->r_io[ATA_COUNT].offset; ch->r_io[ATA_STATUS].res = ch->r_io[ATA_COMMAND].res; ch->r_io[ATA_STATUS].offset = ch->r_io[ATA_COMMAND].offset; ch->r_io[ATA_ALTSTAT].res = ch->r_io[ATA_CONTROL].res; ch->r_io[ATA_ALTSTAT].offset = ch->r_io[ATA_CONTROL].offset; } void ata_modify_if_48bit(struct ata_request *request) { - struct ata_channel *ch = device_get_softc(device_get_parent(request->dev)); + struct ata_channel *ch = device_get_softc(request->parent); struct ata_device *atadev = device_get_softc(request->dev); - atadev->flags &= ~ATA_D_48BIT_ACTIVE; + request->flags &= ~ATA_R_48BIT; if (((request->u.ata.lba + request->u.ata.count) >= ATA_MAX_28BIT_LBA || request->u.ata.count > 256) && atadev->param.support.command2 & ATA_SUPPORT_ADDRESS48) { /* translate command into 48bit version */ switch (request->u.ata.command) { case ATA_READ: request->u.ata.command = ATA_READ48; break; case ATA_READ_MUL: request->u.ata.command = ATA_READ_MUL48; break; case ATA_READ_DMA: if (ch->flags & ATA_NO_48BIT_DMA) { if (request->transfersize > DEV_BSIZE) request->u.ata.command = ATA_READ_MUL48; else request->u.ata.command = ATA_READ48; request->flags &= ~ATA_R_DMA; } else request->u.ata.command = ATA_READ_DMA48; break; case ATA_READ_DMA_QUEUED: if (ch->flags & ATA_NO_48BIT_DMA) { if (request->transfersize > DEV_BSIZE) request->u.ata.command = ATA_READ_MUL48; else request->u.ata.command = ATA_READ48; request->flags &= ~ATA_R_DMA; } else request->u.ata.command = ATA_READ_DMA_QUEUED48; break; case ATA_WRITE: request->u.ata.command = ATA_WRITE48; break; case ATA_WRITE_MUL: request->u.ata.command = ATA_WRITE_MUL48; break; case ATA_WRITE_DMA: if (ch->flags & ATA_NO_48BIT_DMA) { if (request->transfersize > DEV_BSIZE) request->u.ata.command = ATA_WRITE_MUL48; else request->u.ata.command = ATA_WRITE48; request->flags &= ~ATA_R_DMA; } else request->u.ata.command = ATA_WRITE_DMA48; break; case ATA_WRITE_DMA_QUEUED: if (ch->flags & ATA_NO_48BIT_DMA) { if (request->transfersize > DEV_BSIZE) request->u.ata.command = ATA_WRITE_MUL48; else request->u.ata.command = ATA_WRITE48; request->u.ata.command = ATA_WRITE48; request->flags &= ~ATA_R_DMA; } else request->u.ata.command = ATA_WRITE_DMA_QUEUED48; break; case ATA_FLUSHCACHE: request->u.ata.command = ATA_FLUSHCACHE48; break; case ATA_SET_MAX_ADDRESS: request->u.ata.command = ATA_SET_MAX_ADDRESS48; break; default: return; } - atadev->flags |= ATA_D_48BIT_ACTIVE; + request->flags |= ATA_R_48BIT; } else if (atadev->param.support.command2 & ATA_SUPPORT_ADDRESS48) { /* translate command into 48bit version */ switch (request->u.ata.command) { case ATA_FLUSHCACHE: request->u.ata.command = ATA_FLUSHCACHE48; break; case ATA_READ_NATIVE_MAX_ADDRESS: request->u.ata.command = ATA_READ_NATIVE_MAX_ADDRESS48; break; case ATA_SET_MAX_ADDRESS: request->u.ata.command = ATA_SET_MAX_ADDRESS48; break; default: return; } - atadev->flags |= ATA_D_48BIT_ACTIVE; + request->flags |= ATA_R_48BIT; } } void ata_udelay(int interval) { /* for now just use DELAY, the timer/sleep subsytems are not there yet */ if (1 || interval < (1000000/hz) || ata_delayed_attach) DELAY(interval); else pause("ataslp", interval/(1000000/hz)); } char * ata_unit2str(struct ata_device *atadev) { struct ata_channel *ch = device_get_softc(device_get_parent(atadev->dev)); static char str[8]; if (ch->devices & ATA_PORTMULTIPLIER) sprintf(str, "port%d", atadev->unit); else sprintf(str, "%s", atadev->unit == ATA_MASTER ? "master" : "slave"); return str; } char * ata_mode2str(int mode) { switch (mode) { case -1: return "UNSUPPORTED"; case ATA_PIO0: return "PIO0"; case ATA_PIO1: return "PIO1"; case ATA_PIO2: return "PIO2"; case ATA_PIO3: return "PIO3"; case ATA_PIO4: return "PIO4"; case ATA_WDMA0: return "WDMA0"; case ATA_WDMA1: return "WDMA1"; case ATA_WDMA2: return "WDMA2"; case ATA_UDMA0: return "UDMA16"; case ATA_UDMA1: return "UDMA25"; case ATA_UDMA2: return "UDMA33"; case ATA_UDMA3: return "UDMA40"; case ATA_UDMA4: return "UDMA66"; case ATA_UDMA5: return "UDMA100"; case ATA_UDMA6: return "UDMA133"; case ATA_SA150: return "SATA150"; case ATA_SA300: return "SATA300"; case ATA_USB: return "USB"; case ATA_USB1: return "USB1"; case ATA_USB2: return "USB2"; default: if (mode & ATA_DMA_MASK) return "BIOSDMA"; else return "BIOSPIO"; } } int ata_atapi(device_t dev) { struct ata_channel *ch = device_get_softc(device_get_parent(dev)); struct ata_device *atadev = device_get_softc(dev); return (ch->devices & (ATA_ATAPI_MASTER << atadev->unit)); } int ata_pmode(struct ata_params *ap) { if (ap->atavalid & ATA_FLAG_64_70) { if (ap->apiomodes & 0x02) return ATA_PIO4; if (ap->apiomodes & 0x01) return ATA_PIO3; } if (ap->mwdmamodes & 0x04) return ATA_PIO4; if (ap->mwdmamodes & 0x02) return ATA_PIO3; if (ap->mwdmamodes & 0x01) return ATA_PIO2; if ((ap->retired_piomode & ATA_RETIRED_PIO_MASK) == 0x200) return ATA_PIO2; if ((ap->retired_piomode & ATA_RETIRED_PIO_MASK) == 0x100) return ATA_PIO1; if ((ap->retired_piomode & ATA_RETIRED_PIO_MASK) == 0x000) return ATA_PIO0; return ATA_PIO0; } int ata_wmode(struct ata_params *ap) { if (ap->mwdmamodes & 0x04) return ATA_WDMA2; if (ap->mwdmamodes & 0x02) return ATA_WDMA1; if (ap->mwdmamodes & 0x01) return ATA_WDMA0; return -1; } int ata_umode(struct ata_params *ap) { if (ap->atavalid & ATA_FLAG_88) { if (ap->udmamodes & 0x40) return ATA_UDMA6; if (ap->udmamodes & 0x20) return ATA_UDMA5; if (ap->udmamodes & 0x10) return ATA_UDMA4; if (ap->udmamodes & 0x08) return ATA_UDMA3; if (ap->udmamodes & 0x04) return ATA_UDMA2; if (ap->udmamodes & 0x02) return ATA_UDMA1; if (ap->udmamodes & 0x01) return ATA_UDMA0; } return -1; } int ata_limit_mode(device_t dev, int mode, int maxmode) { struct ata_device *atadev = device_get_softc(dev); if (maxmode && mode > maxmode) mode = maxmode; if (mode >= ATA_UDMA0 && ata_umode(&atadev->param) > 0) return min(mode, ata_umode(&atadev->param)); if (mode >= ATA_WDMA0 && ata_wmode(&atadev->param) > 0) return min(mode, ata_wmode(&atadev->param)); if (mode > ata_pmode(&atadev->param)) return min(mode, ata_pmode(&atadev->param)); return mode; } 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 == '_') *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; } /* * module handeling */ static int ata_module_event_handler(module_t mod, int what, void *arg) { static struct cdev *atacdev; switch (what) { case MOD_LOAD: /* register controlling device */ atacdev = make_dev(&ata_cdevsw, 0, UID_ROOT, GID_OPERATOR, 0600, "ata"); if (cold) { /* register boot attach to be run when interrupts are enabled */ if (!(ata_delayed_attach = (struct intr_config_hook *) malloc(sizeof(struct intr_config_hook), M_TEMP, M_NOWAIT | M_ZERO))) { printf("ata: malloc of delayed attach hook failed\n"); return EIO; } ata_delayed_attach->ich_func = (void*)ata_boot_attach; if (config_intrhook_establish(ata_delayed_attach) != 0) { printf("ata: config_intrhook_establish failed\n"); free(ata_delayed_attach, M_TEMP); } } return 0; case MOD_UNLOAD: /* deregister controlling device */ destroy_dev(atacdev); return 0; default: return EOPNOTSUPP; } } static moduledata_t ata_moduledata = { "ata", ata_module_event_handler, NULL }; DECLARE_MODULE(ata, ata_moduledata, SI_SUB_CONFIGURE, SI_ORDER_SECOND); MODULE_VERSION(ata, 1); static void ata_init(void) { ata_request_zone = uma_zcreate("ata_request", sizeof(struct ata_request), NULL, NULL, NULL, NULL, 0, 0); ata_composite_zone = uma_zcreate("ata_composite", sizeof(struct ata_composite), NULL, NULL, NULL, NULL, 0, 0); } SYSINIT(ata_register, SI_SUB_DRIVERS, SI_ORDER_SECOND, ata_init, NULL); static void ata_uninit(void) { uma_zdestroy(ata_composite_zone); uma_zdestroy(ata_request_zone); } SYSUNINIT(ata_unregister, SI_SUB_DRIVERS, SI_ORDER_SECOND, ata_uninit, NULL); diff --git a/sys/dev/ata/ata-all.h b/sys/dev/ata/ata-all.h index adee8f58127d..2bc893691599 100644 --- a/sys/dev/ata/ata-all.h +++ b/sys/dev/ata/ata-all.h @@ -1,723 +1,727 @@ /*- * Copyright (c) 1998 - 2008 Søren Schmidt * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer, * without modification, immediately at the beginning of the file. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * 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$ */ #if 0 #define ATA_LEGACY_SUPPORT /* Enable obsolete features that break * some modern devices */ #endif /* ATA register defines */ #define ATA_DATA 0 /* (RW) data */ #define ATA_FEATURE 1 /* (W) feature */ #define ATA_F_DMA 0x01 /* enable DMA */ #define ATA_F_OVL 0x02 /* enable overlap */ #define ATA_COUNT 2 /* (W) sector count */ #define ATA_SECTOR 3 /* (RW) sector # */ #define ATA_CYL_LSB 4 /* (RW) cylinder# LSB */ #define ATA_CYL_MSB 5 /* (RW) cylinder# MSB */ #define ATA_DRIVE 6 /* (W) Sector/Drive/Head */ #define ATA_D_LBA 0x40 /* use LBA addressing */ #define ATA_D_IBM 0xa0 /* 512 byte sectors, ECC */ #define ATA_COMMAND 7 /* (W) command */ #define ATA_ERROR 8 /* (R) error */ #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 */ #define ATA_E_IDNF 0x10 /* ID not found */ #define ATA_E_MC 0x20 /* media changed */ #define ATA_E_UNC 0x40 /* uncorrectable data */ #define ATA_E_ICRC 0x80 /* UDMA crc error */ #define ATA_E_ATAPI_SENSE_MASK 0xf0 /* ATAPI sense key mask */ #define ATA_IREASON 9 /* (R) interrupt reason */ #define ATA_I_CMD 0x01 /* cmd (1) | data (0) */ #define ATA_I_IN 0x02 /* read (1) | write (0) */ #define ATA_I_RELEASE 0x04 /* released bus (1) */ #define ATA_I_TAGMASK 0xf8 /* tag mask */ #define ATA_STATUS 10 /* (R) status */ #define ATA_ALTSTAT 11 /* (R) alternate status */ #define ATA_S_ERROR 0x01 /* error */ #define ATA_S_INDEX 0x02 /* index */ #define ATA_S_CORR 0x04 /* data corrected */ #define ATA_S_DRQ 0x08 /* data request */ #define ATA_S_DSC 0x10 /* drive seek completed */ #define ATA_S_SERVICE 0x10 /* drive needs service */ #define ATA_S_DWF 0x20 /* drive write fault */ #define ATA_S_DMA 0x20 /* DMA ready */ #define ATA_S_READY 0x40 /* drive ready */ #define ATA_S_BUSY 0x80 /* busy */ #define ATA_CONTROL 12 /* (W) control */ #define ATA_CTLOFFSET 0x206 /* control register offset */ #define ATA_PCCARD_CTLOFFSET 0x0e /* do for PCCARD devices */ #define ATA_PC98_CTLOFFSET 0x10c /* do for PC98 devices */ #define ATA_A_IDS 0x02 /* disable interrupts */ #define ATA_A_RESET 0x04 /* RESET controller */ #ifdef ATA_LEGACY_SUPPORT #define ATA_A_4BIT 0x08 /* 4 head bits: obsolete 1996 */ #else #define ATA_A_4BIT 0x00 #endif #define ATA_A_HOB 0x80 /* High Order Byte enable */ /* SATA register defines */ #define ATA_SSTATUS 13 #define ATA_SS_DET_MASK 0x0000000f #define ATA_SS_DET_NO_DEVICE 0x00000000 #define ATA_SS_DET_DEV_PRESENT 0x00000001 #define ATA_SS_DET_PHY_ONLINE 0x00000003 #define ATA_SS_DET_PHY_OFFLINE 0x00000004 #define ATA_SS_SPD_MASK 0x000000f0 #define ATA_SS_SPD_NO_SPEED 0x00000000 #define ATA_SS_SPD_GEN1 0x00000010 #define ATA_SS_SPD_GEN2 0x00000020 #define ATA_SS_IPM_MASK 0x00000f00 #define ATA_SS_IPM_NO_DEVICE 0x00000000 #define ATA_SS_IPM_ACTIVE 0x00000100 #define ATA_SS_IPM_PARTIAL 0x00000200 #define ATA_SS_IPM_SLUMBER 0x00000600 #define ATA_SS_CONWELL_MASK \ (ATA_SS_DET_MASK|ATA_SS_SPD_MASK|ATA_SS_IPM_MASK) #define ATA_SS_CONWELL_GEN1 \ (ATA_SS_DET_PHY_ONLINE|ATA_SS_SPD_GEN1|ATA_SS_IPM_ACTIVE) #define ATA_SS_CONWELL_GEN2 \ (ATA_SS_DET_PHY_ONLINE|ATA_SS_SPD_GEN2|ATA_SS_IPM_ACTIVE) #define ATA_SERROR 14 #define ATA_SE_DATA_CORRECTED 0x00000001 #define ATA_SE_COMM_CORRECTED 0x00000002 #define ATA_SE_DATA_ERR 0x00000100 #define ATA_SE_COMM_ERR 0x00000200 #define ATA_SE_PROT_ERR 0x00000400 #define ATA_SE_HOST_ERR 0x00000800 #define ATA_SE_PHY_CHANGED 0x00010000 #define ATA_SE_PHY_IERROR 0x00020000 #define ATA_SE_COMM_WAKE 0x00040000 #define ATA_SE_DECODE_ERR 0x00080000 #define ATA_SE_PARITY_ERR 0x00100000 #define ATA_SE_CRC_ERR 0x00200000 #define ATA_SE_HANDSHAKE_ERR 0x00400000 #define ATA_SE_LINKSEQ_ERR 0x00800000 #define ATA_SE_TRANSPORT_ERR 0x01000000 #define ATA_SE_UNKNOWN_FIS 0x02000000 #define ATA_SCONTROL 15 #define ATA_SC_DET_MASK 0x0000000f #define ATA_SC_DET_IDLE 0x00000000 #define ATA_SC_DET_RESET 0x00000001 #define ATA_SC_DET_DISABLE 0x00000004 #define ATA_SC_SPD_MASK 0x000000f0 #define ATA_SC_SPD_NO_SPEED 0x00000000 #define ATA_SC_SPD_SPEED_GEN1 0x00000010 #define ATA_SC_SPD_SPEED_GEN2 0x00000020 #define ATA_SC_IPM_MASK 0x00000f00 #define ATA_SC_IPM_NONE 0x00000000 #define ATA_SC_IPM_DIS_PARTIAL 0x00000100 #define ATA_SC_IPM_DIS_SLUMBER 0x00000200 #define ATA_SACTIVE 16 /* SATA AHCI v1.0 register defines */ #define ATA_AHCI_CAP 0x00 #define ATA_AHCI_CAP_NPMASK 0x0000001f #define ATA_AHCI_CAP_SXS 0x00000020 #define ATA_AHCI_CAP_EMS 0x00000040 #define ATA_AHCI_CAP_CCCS 0x00000080 #define ATA_AHCI_CAP_NCS 0x00001F00 #define ATA_AHCI_CAP_NCS_SHIFT 8 #define ATA_AHCI_CAP_PSC 0x00002000 #define ATA_AHCI_CAP_SSC 0x00004000 #define ATA_AHCI_CAP_PMD 0x00008000 #define ATA_AHCI_CAP_FBSS 0x00010000 #define ATA_AHCI_CAP_SPM 0x00020000 #define ATA_AHCI_CAP_SAM 0x00080000 #define ATA_AHCI_CAP_ISS 0x00F00000 #define ATA_AHCI_CAP_ISS_SHIFT 20 #define ATA_AHCI_CAP_SCLO 0x01000000 #define ATA_AHCI_CAP_SAL 0x02000000 #define ATA_AHCI_CAP_SALP 0x04000000 #define ATA_AHCI_CAP_SSS 0x08000000 #define ATA_AHCI_CAP_SMPS 0x10000000 #define ATA_AHCI_CAP_SSNTF 0x20000000 #define ATA_AHCI_CAP_SNCQ 0x40000000 #define ATA_AHCI_CAP_64BIT 0x80000000 #define ATA_AHCI_GHC 0x04 #define ATA_AHCI_GHC_AE 0x80000000 #define ATA_AHCI_GHC_IE 0x00000002 #define ATA_AHCI_GHC_HR 0x00000001 #define ATA_AHCI_IS 0x08 #define ATA_AHCI_PI 0x0c #define ATA_AHCI_VS 0x10 #define ATA_AHCI_OFFSET 0x80 #define ATA_AHCI_P_CLB 0x100 #define ATA_AHCI_P_CLBU 0x104 #define ATA_AHCI_P_FB 0x108 #define ATA_AHCI_P_FBU 0x10c #define ATA_AHCI_P_IS 0x110 #define ATA_AHCI_P_IE 0x114 #define ATA_AHCI_P_IX_DHR 0x00000001 #define ATA_AHCI_P_IX_PS 0x00000002 #define ATA_AHCI_P_IX_DS 0x00000004 #define ATA_AHCI_P_IX_SDB 0x00000008 #define ATA_AHCI_P_IX_UF 0x00000010 #define ATA_AHCI_P_IX_DP 0x00000020 #define ATA_AHCI_P_IX_PC 0x00000040 #define ATA_AHCI_P_IX_DI 0x00000080 #define ATA_AHCI_P_IX_PRC 0x00400000 #define ATA_AHCI_P_IX_IPM 0x00800000 #define ATA_AHCI_P_IX_OF 0x01000000 #define ATA_AHCI_P_IX_INF 0x04000000 #define ATA_AHCI_P_IX_IF 0x08000000 #define ATA_AHCI_P_IX_HBD 0x10000000 #define ATA_AHCI_P_IX_HBF 0x20000000 #define ATA_AHCI_P_IX_TFE 0x40000000 #define ATA_AHCI_P_IX_CPD 0x80000000 #define ATA_AHCI_P_CMD 0x118 #define ATA_AHCI_P_CMD_ST 0x00000001 #define ATA_AHCI_P_CMD_SUD 0x00000002 #define ATA_AHCI_P_CMD_POD 0x00000004 #define ATA_AHCI_P_CMD_CLO 0x00000008 #define ATA_AHCI_P_CMD_FRE 0x00000010 #define ATA_AHCI_P_CMD_CCS_MASK 0x00001f00 #define ATA_AHCI_P_CMD_ISS 0x00002000 #define ATA_AHCI_P_CMD_FR 0x00004000 #define ATA_AHCI_P_CMD_CR 0x00008000 #define ATA_AHCI_P_CMD_CPS 0x00010000 #define ATA_AHCI_P_CMD_PMA 0x00020000 #define ATA_AHCI_P_CMD_HPCP 0x00040000 #define ATA_AHCI_P_CMD_ISP 0x00080000 #define ATA_AHCI_P_CMD_CPD 0x00100000 #define ATA_AHCI_P_CMD_ATAPI 0x01000000 #define ATA_AHCI_P_CMD_DLAE 0x02000000 #define ATA_AHCI_P_CMD_ALPE 0x04000000 #define ATA_AHCI_P_CMD_ASP 0x08000000 #define ATA_AHCI_P_CMD_ICC_MASK 0xf0000000 #define ATA_AHCI_P_CMD_NOOP 0x00000000 #define ATA_AHCI_P_CMD_ACTIVE 0x10000000 #define ATA_AHCI_P_CMD_PARTIAL 0x20000000 #define ATA_AHCI_P_CMD_SLUMBER 0x60000000 #define ATA_AHCI_P_TFD 0x120 #define ATA_AHCI_P_SIG 0x124 #define ATA_AHCI_P_SSTS 0x128 #define ATA_AHCI_P_SCTL 0x12c #define ATA_AHCI_P_SERR 0x130 #define ATA_AHCI_P_SACT 0x134 #define ATA_AHCI_P_CI 0x138 #define ATA_AHCI_P_SNTF 0x13C #define ATA_AHCI_P_FBS 0x140 #define ATA_AHCI_CL_SIZE 32 #define ATA_AHCI_CL_OFFSET 0 #define ATA_AHCI_FB_OFFSET (ATA_AHCI_CL_SIZE * 32) #define ATA_AHCI_CT_OFFSET (ATA_AHCI_FB_OFFSET + 4096) -#define ATA_AHCI_CT_SIZE (1024 + 128) +#define ATA_AHCI_CT_SIZE (2176 + 128) struct ata_ahci_dma_prd { u_int64_t dba; u_int32_t reserved; u_int32_t dbc; /* 0 based */ #define ATA_AHCI_PRD_MASK 0x003fffff /* max 4MB */ #define ATA_AHCI_PRD_IPC (1<<31) } __packed; struct ata_ahci_cmd_tab { u_int8_t cfis[64]; u_int8_t acmd[32]; u_int8_t reserved[32]; -#define ATA_AHCI_DMA_ENTRIES 64 +#define ATA_AHCI_DMA_ENTRIES 129 struct ata_ahci_dma_prd prd_tab[ATA_AHCI_DMA_ENTRIES]; } __packed; struct ata_ahci_cmd_list { u_int16_t cmd_flags; #define ATA_AHCI_CMD_ATAPI 0x0020 #define ATA_AHCI_CMD_WRITE 0x0040 #define ATA_AHCI_CMD_PREFETCH 0x0080 #define ATA_AHCI_CMD_RESET 0x0100 #define ATA_AHCI_CMD_BIST 0x0200 #define ATA_AHCI_CMD_CLR_BUSY 0x0400 u_int16_t prd_length; /* PRD entries */ u_int32_t bytecount; u_int64_t cmd_table_phys; /* 128byte aligned */ } __packed; /* DMA register defines */ #define ATA_DMA_ENTRIES 256 #define ATA_DMA_EOT 0x80000000 #define ATA_BMCMD_PORT 17 #define ATA_BMCMD_START_STOP 0x01 #define ATA_BMCMD_WRITE_READ 0x08 #define ATA_BMDEVSPEC_0 18 #define ATA_BMSTAT_PORT 19 #define ATA_BMSTAT_ACTIVE 0x01 #define ATA_BMSTAT_ERROR 0x02 #define ATA_BMSTAT_INTERRUPT 0x04 #define ATA_BMSTAT_MASK 0x07 #define ATA_BMSTAT_DMA_MASTER 0x20 #define ATA_BMSTAT_DMA_SLAVE 0x40 #define ATA_BMSTAT_DMA_SIMPLEX 0x80 #define ATA_BMDEVSPEC_1 20 #define ATA_BMDTP_PORT 21 #define ATA_IDX_ADDR 22 #define ATA_IDX_DATA 23 #define ATA_MAX_RES 24 /* misc defines */ #define ATA_PRIMARY 0x1f0 #define ATA_SECONDARY 0x170 #define ATA_PC98_BANK 0x432 #define ATA_IOSIZE 0x08 #define ATA_PC98_IOSIZE 0x10 #define ATA_CTLIOSIZE 0x01 #define ATA_BMIOSIZE 0x08 #define ATA_PC98_BANKIOSIZE 0x01 #define ATA_IOADDR_RID 0 #define ATA_CTLADDR_RID 1 #define ATA_BMADDR_RID 0x20 #define ATA_PC98_CTLADDR_RID 8 #define ATA_PC98_BANKADDR_RID 9 #define ATA_IRQ_RID 0 #define ATA_DEV(unit) ((unit > 0) ? 0x10 : 0) #define ATA_CFA_MAGIC1 0x844A #define ATA_CFA_MAGIC2 0x848A #define ATA_CFA_MAGIC3 0x8400 #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 #define ATA_INTR_FLAGS (INTR_MPSAFE|INTR_TYPE_BIO|INTR_ENTROPY) #define ATA_OP_CONTINUES 0 #define ATA_OP_FINISHED 1 #define ATA_MAX_28BIT_LBA 268435455UL /* structure used for composite atomic operations */ #define MAX_COMPOSITES 32 /* u_int32_t bits */ struct ata_composite { struct mtx lock; /* control lock */ u_int32_t rd_needed; /* needed read subdisks */ u_int32_t rd_done; /* done read subdisks */ u_int32_t wr_needed; /* needed write subdisks */ u_int32_t wr_depend; /* write depends on subdisks */ u_int32_t wr_done; /* done write subdisks */ struct ata_request *request[MAX_COMPOSITES]; u_int32_t residual; /* bytes still to transfer */ caddr_t data_1; caddr_t data_2; }; /* structure used to queue an ATA/ATAPI request */ struct ata_request { device_t dev; /* device handle */ device_t parent; /* channel handle */ + int unit; /* physical unit */ union { struct { u_int8_t command; /* command reg */ u_int16_t feature; /* feature reg */ u_int16_t count; /* count reg */ u_int64_t lba; /* lba reg */ } ata; struct { u_int8_t ccb[16]; /* ATAPI command block */ struct atapi_sense sense; /* ATAPI request sense data */ u_int8_t saved_cmd; /* ATAPI saved command */ } atapi; } u; u_int32_t bytecount; /* bytes to transfer */ u_int32_t transfersize; /* bytes pr transfer */ caddr_t data; /* pointer to data buf */ u_int32_t tag; /* HW tag of this request */ int flags; #define ATA_R_CONTROL 0x00000001 #define ATA_R_READ 0x00000002 #define ATA_R_WRITE 0x00000004 #define ATA_R_ATAPI 0x00000008 #define ATA_R_DMA 0x00000010 #define ATA_R_QUIET 0x00000020 #define ATA_R_TIMEOUT 0x00000040 +#define ATA_R_48BIT 0x00000080 #define ATA_R_ORDERED 0x00000100 #define ATA_R_AT_HEAD 0x00000200 #define ATA_R_REQUEUE 0x00000400 #define ATA_R_THREAD 0x00000800 #define ATA_R_DIRECT 0x00001000 +#define ATA_R_ATAPI16 0x00010000 +#define ATA_R_ATAPI_INTR 0x00020000 + #define ATA_R_DEBUG 0x10000000 #define ATA_R_DANGER1 0x20000000 #define ATA_R_DANGER2 0x40000000 struct ata_dmaslot *dma; /* DMA slot of this request */ u_int8_t status; /* ATA status */ u_int8_t error; /* ATA error */ u_int32_t donecount; /* bytes transferred */ int result; /* result error code */ void (*callback)(struct ata_request *request); struct sema done; /* request done sema */ int retries; /* retry count */ int timeout; /* timeout for this cmd */ struct callout callout; /* callout management */ struct task task; /* task management */ struct bio *bio; /* bio for this request */ int this; /* this request ID */ struct ata_composite *composite; /* for composite atomic ops */ void *driver; /* driver specific */ TAILQ_ENTRY(ata_request) chain; /* list management */ }; /* define this for debugging request processing */ #if 0 #define ATA_DEBUG_RQ(request, string) \ { \ if (request->flags & ATA_R_DEBUG) \ - device_printf(request->dev, "req=%p %s " string "\n", \ + device_printf(request->parent, "req=%p %s " string "\n", \ request, ata_cmd2str(request)); \ } #else #define ATA_DEBUG_RQ(request, string) #endif /* structure describing an ATA/ATAPI device */ struct ata_device { device_t dev; /* device handle */ int unit; /* physical unit */ #define ATA_MASTER 0x00 #define ATA_SLAVE 0x01 #define ATA_PM 0x0f struct ata_params param; /* ata param structure */ int mode; /* current transfermode */ u_int32_t max_iosize; /* max IO size */ int spindown; /* idle spindown timeout */ struct callout spindown_timer; int spindown_state; int flags; #define ATA_D_USE_CHS 0x0001 #define ATA_D_MEDIA_CHANGED 0x0002 #define ATA_D_ENC_PRESENT 0x0004 -#define ATA_D_48BIT_ACTIVE 0x0008 }; /* structure for holding DMA Physical Region Descriptors (PRD) entries */ struct ata_dma_prdentry { u_int32_t addr; u_int32_t count; }; /* structure used by the setprd function */ struct ata_dmasetprd_args { void *dmatab; int nsegs; int error; }; struct ata_dmaslot { u_int8_t status; /* DMA status */ bus_dma_tag_t sg_tag; /* SG list DMA tag */ bus_dmamap_t sg_map; /* SG list DMA map */ void *sg; /* DMA transfer table */ bus_addr_t sg_bus; /* bus address of dmatab */ bus_dma_tag_t data_tag; /* data DMA tag */ bus_dmamap_t data_map; /* data DMA map */ }; /* structure holding DMA related information */ struct ata_dma { bus_dma_tag_t dmatag; /* parent DMA tag */ bus_dma_tag_t work_tag; /* workspace DMA tag */ bus_dmamap_t work_map; /* workspace DMA map */ u_int8_t *work; /* workspace */ bus_addr_t work_bus; /* bus address of dmatab */ -#define ATA_DMA_SLOTS 32 +#define ATA_DMA_SLOTS 1 int dma_slots; /* DMA slots allocated */ struct ata_dmaslot slot[ATA_DMA_SLOTS]; u_int32_t alignment; /* DMA SG list alignment */ u_int32_t boundary; /* DMA SG list boundary */ u_int32_t segsize; /* DMA SG list segment size */ u_int32_t max_iosize; /* DMA data max IO size */ u_int64_t max_address; /* highest DMA'able address */ int flags; #define ATA_DMA_ACTIVE 0x01 /* DMA transfer in progress */ void (*alloc)(device_t dev); void (*free)(device_t dev); void (*setprd)(void *xsc, bus_dma_segment_t *segs, int nsegs, int error); int (*load)(struct ata_request *request, void *addr, int *nsegs); int (*unload)(struct ata_request *request); int (*start)(struct ata_request *request); int (*stop)(struct ata_request *request); void (*reset)(device_t dev); }; /* structure holding lowlevel functions */ struct ata_lowlevel { u_int32_t (*softreset)(device_t dev, int pmport); int (*pm_read)(device_t dev, int port, int reg, u_int32_t *result); int (*pm_write)(device_t dev, int port, int reg, u_int32_t value); int (*status)(device_t dev); int (*begin_transaction)(struct ata_request *request); int (*end_transaction)(struct ata_request *request); int (*command)(struct ata_request *request); void (*tf_read)(struct ata_request *request); void (*tf_write)(struct ata_request *request); }; /* structure holding resources for an ATA channel */ struct ata_resource { struct resource *res; int offset; }; /* structure describing an ATA channel */ struct ata_channel { device_t dev; /* device handle */ int unit; /* physical channel */ int attached; /* channel is attached */ 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_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_ATAPI_DMA_RO 0x04 #define ATA_NO_48BIT_DMA 0x08 #define ATA_ALWAYS_DMASTAT 0x10 int pm_level; /* power management level */ int devices; /* what is present */ #define ATA_ATA_MASTER 0x00000001 #define ATA_ATA_SLAVE 0x00000002 #define ATA_PORTMULTIPLIER 0x00008000 #define ATA_ATAPI_MASTER 0x00010000 #define ATA_ATAPI_SLAVE 0x00020000 struct mtx state_mtx; /* state lock */ int state; /* ATA channel state */ #define ATA_IDLE 0x0000 #define ATA_ACTIVE 0x0001 #define ATA_STALL_QUEUE 0x0002 struct mtx queue_mtx; /* queue lock */ TAILQ_HEAD(, ata_request) ata_queue; /* head of ATA queue */ struct ata_request *freezepoint; /* composite freezepoint */ struct ata_request *running; /* currently running request */ struct task conntask; /* PHY events handling task */ }; /* disk bay/enclosure related */ #define ATA_LED_OFF 0x00 #define ATA_LED_RED 0x01 #define ATA_LED_GREEN 0x02 #define ATA_LED_ORANGE 0x03 #define ATA_LED_MASK 0x03 /* externs */ extern int (*ata_raid_ioctl_func)(u_long cmd, caddr_t data); extern struct intr_config_hook *ata_delayed_attach; extern devclass_t ata_devclass; extern int ata_wc; extern int ata_setmax; extern int ata_dma_check_80pin; /* public prototypes */ /* ata-all.c: */ int ata_probe(device_t dev); int ata_attach(device_t dev); int ata_detach(device_t dev); int ata_reinit(device_t dev); int ata_suspend(device_t dev); int ata_resume(device_t dev); void ata_interrupt(void *data); int ata_device_ioctl(device_t dev, u_long cmd, caddr_t data); int ata_getparam(struct ata_device *atadev, int init); int ata_identify(device_t dev); void ata_default_registers(device_t dev); void ata_modify_if_48bit(struct ata_request *request); void ata_udelay(int interval); char *ata_unit2str(struct ata_device *atadev); char *ata_mode2str(int mode); int ata_atapi(device_t dev); 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(device_t dev, int mode, int maxmode); /* ata-queue.c: */ int ata_controlcmd(device_t dev, u_int8_t command, u_int16_t feature, u_int64_t lba, u_int16_t count); int ata_atapicmd(device_t dev, u_int8_t *ccb, caddr_t data, int count, int flags, int timeout); void ata_queue_request(struct ata_request *request); void ata_start(device_t dev); void ata_finish(struct ata_request *request); void ata_timeout(struct ata_request *); void ata_catch_inflight(device_t dev); void ata_fail_requests(device_t dev); void ata_drop_requests(device_t dev); char *ata_cmd2str(struct ata_request *request); /* ata-lowlevel.c: */ void ata_generic_hw(device_t dev); int ata_begin_transaction(struct ata_request *); int ata_end_transaction(struct ata_request *); void ata_generic_reset(device_t dev); int ata_generic_command(struct ata_request *request); /* ata-dma.c: */ void ata_dmainit(device_t); void ata_dmafini(device_t dev); /* ata-sata.c: */ void ata_sata_phy_check_events(device_t dev); int ata_sata_scr_read(struct ata_channel *ch, int port, int reg, uint32_t *val); int ata_sata_scr_write(struct ata_channel *ch, int port, int reg, uint32_t val); int ata_sata_phy_reset(device_t dev, int port, int quick); void ata_sata_setmode(device_t dev, int mode); int ata_request2fis_h2d(struct ata_request *request, u_int8_t *fis); void ata_pm_identify(device_t dev); /* macros for alloc/free of struct ata_request */ extern uma_zone_t ata_request_zone; #define ata_alloc_request() uma_zalloc(ata_request_zone, M_NOWAIT | M_ZERO) #define ata_free_request(request) { \ if (!(request->flags & ATA_R_DANGER2)) \ uma_zfree(ata_request_zone, request); \ } /* macros for alloc/free of struct ata_composite */ extern uma_zone_t ata_composite_zone; #define ata_alloc_composite() uma_zalloc(ata_composite_zone, M_NOWAIT | M_ZERO) #define ata_free_composite(composite) uma_zfree(ata_composite_zone, composite) MALLOC_DECLARE(M_ATA); /* misc newbus defines */ #define GRANDPARENT(dev) device_get_parent(device_get_parent(dev)) /* macros to hide busspace uglyness */ #define ATA_INB(res, offset) \ bus_read_1((res), (offset)) #define ATA_INW(res, offset) \ bus_read_2((res), (offset)) #define ATA_INL(res, offset) \ bus_read_4((res), (offset)) #define ATA_INSW(res, offset, addr, count) \ bus_read_multi_2((res), (offset), (addr), (count)) #define ATA_INSW_STRM(res, offset, addr, count) \ bus_read_multi_stream_2((res), (offset), (addr), (count)) #define ATA_INSL(res, offset, addr, count) \ bus_read_multi_4((res), (offset), (addr), (count)) #define ATA_INSL_STRM(res, offset, addr, count) \ bus_read_multi_stream_4((res), (offset), (addr), (count)) #define ATA_OUTB(res, offset, value) \ bus_write_1((res), (offset), (value)) #define ATA_OUTW(res, offset, value) \ bus_write_2((res), (offset), (value)) #define ATA_OUTL(res, offset, value) \ bus_write_4((res), (offset), (value)) #define ATA_OUTSW(res, offset, addr, count) \ bus_write_multi_2((res), (offset), (addr), (count)) #define ATA_OUTSW_STRM(res, offset, addr, count) \ bus_write_multi_stream_2((res), (offset), (addr), (count)) #define ATA_OUTSL(res, offset, addr, count) \ bus_write_multi_4((res), (offset), (addr), (count)) #define ATA_OUTSL_STRM(res, offset, addr, count) \ bus_write_multi_stream_4((res), (offset), (addr), (count)) #define ATA_IDX_INB(ch, idx) \ ATA_INB(ch->r_io[idx].res, ch->r_io[idx].offset) #define ATA_IDX_INW(ch, idx) \ ATA_INW(ch->r_io[idx].res, ch->r_io[idx].offset) #define ATA_IDX_INL(ch, idx) \ ATA_INL(ch->r_io[idx].res, ch->r_io[idx].offset) #define ATA_IDX_INSW(ch, idx, addr, count) \ ATA_INSW(ch->r_io[idx].res, ch->r_io[idx].offset, addr, count) #define ATA_IDX_INSW_STRM(ch, idx, addr, count) \ ATA_INSW_STRM(ch->r_io[idx].res, ch->r_io[idx].offset, addr, count) #define ATA_IDX_INSL(ch, idx, addr, count) \ ATA_INSL(ch->r_io[idx].res, ch->r_io[idx].offset, addr, count) #define ATA_IDX_INSL_STRM(ch, idx, addr, count) \ ATA_INSL_STRM(ch->r_io[idx].res, ch->r_io[idx].offset, addr, count) #define ATA_IDX_OUTB(ch, idx, value) \ ATA_OUTB(ch->r_io[idx].res, ch->r_io[idx].offset, value) #define ATA_IDX_OUTW(ch, idx, value) \ ATA_OUTW(ch->r_io[idx].res, ch->r_io[idx].offset, value) #define ATA_IDX_OUTL(ch, idx, value) \ ATA_OUTL(ch->r_io[idx].res, ch->r_io[idx].offset, value) #define ATA_IDX_OUTSW(ch, idx, addr, count) \ ATA_OUTSW(ch->r_io[idx].res, ch->r_io[idx].offset, addr, count) #define ATA_IDX_OUTSW_STRM(ch, idx, addr, count) \ ATA_OUTSW_STRM(ch->r_io[idx].res, ch->r_io[idx].offset, addr, count) #define ATA_IDX_OUTSL(ch, idx, addr, count) \ ATA_OUTSL(ch->r_io[idx].res, ch->r_io[idx].offset, addr, count) #define ATA_IDX_OUTSL_STRM(ch, idx, addr, count) \ ATA_OUTSL_STRM(ch->r_io[idx].res, ch->r_io[idx].offset, addr, count) diff --git a/sys/dev/ata/ata-dma.c b/sys/dev/ata/ata-dma.c index 770b13f0e3c9..eae434833462 100644 --- a/sys/dev/ata/ata-dma.c +++ b/sys/dev/ata/ata-dma.c @@ -1,335 +1,334 @@ /*- * Copyright (c) 1998 - 2008 Søren Schmidt * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer, * without modification, immediately at the beginning of the file. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * 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. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* prototypes */ static void ata_dmasetupc_cb(void *xsc, bus_dma_segment_t *segs, int nsegs, int error); static void ata_dmaalloc(device_t dev); static void ata_dmafree(device_t dev); static void ata_dmasetprd(void *xsc, bus_dma_segment_t *segs, int nsegs, int error); static int ata_dmaload(struct ata_request *request, void *addr, int *nsegs); static int ata_dmaunload(struct ata_request *request); /* local vars */ static MALLOC_DEFINE(M_ATADMA, "ata_dma", "ATA driver DMA"); /* misc defines */ #define MAXTABSZ PAGE_SIZE #define MAXWSPCSZ PAGE_SIZE*2 struct ata_dc_cb_args { bus_addr_t maddr; int error; }; void ata_dmainit(device_t dev) { struct ata_channel *ch = device_get_softc(dev); struct ata_dc_cb_args dcba; ch->dma.alloc = ata_dmaalloc; ch->dma.free = ata_dmafree; ch->dma.setprd = ata_dmasetprd; ch->dma.load = ata_dmaload; ch->dma.unload = ata_dmaunload; ch->dma.alignment = 2; ch->dma.boundary = 65536; ch->dma.segsize = 65536; ch->dma.max_iosize = 128 * DEV_BSIZE; ch->dma.max_address = BUS_SPACE_MAXADDR_32BIT; - ch->dma.dma_slots = 6; + ch->dma.dma_slots = 1; if (bus_dma_tag_create(bus_get_dma_tag(dev), ch->dma.alignment, 0, ch->dma.max_address, BUS_SPACE_MAXADDR, NULL, NULL, ch->dma.max_iosize, ATA_DMA_ENTRIES, ch->dma.segsize, 0, NULL, NULL, &ch->dma.dmatag)) goto error; if (bus_dma_tag_create(ch->dma.dmatag, PAGE_SIZE, 64 * 1024, ch->dma.max_address, BUS_SPACE_MAXADDR, NULL, NULL, MAXWSPCSZ, 1, MAXWSPCSZ, 0, NULL, NULL, &ch->dma.work_tag)) goto error; if (bus_dmamem_alloc(ch->dma.work_tag, (void **)&ch->dma.work, 0, &ch->dma.work_map)) goto error; if (bus_dmamap_load(ch->dma.work_tag, ch->dma.work_map, ch->dma.work, MAXWSPCSZ, ata_dmasetupc_cb, &dcba, 0) || dcba.error) { bus_dmamem_free(ch->dma.work_tag, ch->dma.work, ch->dma.work_map); goto error; } ch->dma.work_bus = dcba.maddr; return; error: device_printf(dev, "WARNING - DMA initialization failed, disabling DMA\n"); ata_dmafini(dev); } void ata_dmafini(device_t dev) { struct ata_channel *ch = device_get_softc(dev); if (ch->dma.work_bus) { bus_dmamap_unload(ch->dma.work_tag, ch->dma.work_map); bus_dmamem_free(ch->dma.work_tag, ch->dma.work, ch->dma.work_map); ch->dma.work_bus = 0; ch->dma.work_map = NULL; ch->dma.work = NULL; } if (ch->dma.work_tag) { bus_dma_tag_destroy(ch->dma.work_tag); ch->dma.work_tag = NULL; } if (ch->dma.dmatag) { bus_dma_tag_destroy(ch->dma.dmatag); ch->dma.dmatag = NULL; } } static void ata_dmasetupc_cb(void *xsc, bus_dma_segment_t *segs, int nsegs, int error) { struct ata_dc_cb_args *dcba = (struct ata_dc_cb_args *)xsc; if (!(dcba->error = error)) dcba->maddr = segs[0].ds_addr; } static void ata_dmaalloc(device_t dev) { struct ata_channel *ch = device_get_softc(dev); struct ata_dc_cb_args dcba; int i; /* alloc and setup needed dma slots */ bzero(ch->dma.slot, sizeof(struct ata_dmaslot) * ATA_DMA_SLOTS); for (i = 0; i < ch->dma.dma_slots; i++) { struct ata_dmaslot *slot = &ch->dma.slot[i]; if (bus_dma_tag_create(ch->dma.dmatag, PAGE_SIZE, PAGE_SIZE, ch->dma.max_address, BUS_SPACE_MAXADDR, NULL, NULL, PAGE_SIZE, 1, PAGE_SIZE, 0, NULL, NULL, &slot->sg_tag)) { device_printf(ch->dev, "FAILURE - create sg_tag\n"); goto error; } if (bus_dmamem_alloc(slot->sg_tag, (void **)&slot->sg, 0, &slot->sg_map)) { device_printf(ch->dev, "FAILURE - alloc sg_map\n"); goto error; } if (bus_dmamap_load(slot->sg_tag, slot->sg_map, slot->sg, MAXTABSZ, ata_dmasetupc_cb, &dcba, 0) || dcba.error) { device_printf(ch->dev, "FAILURE - load sg\n"); goto error; } slot->sg_bus = dcba.maddr; if (bus_dma_tag_create(ch->dma.dmatag, ch->dma.alignment, ch->dma.boundary, ch->dma.max_address, BUS_SPACE_MAXADDR, NULL, NULL, ch->dma.max_iosize, ATA_DMA_ENTRIES, ch->dma.segsize, BUS_DMA_ALLOCNOW, NULL, NULL, &slot->data_tag)) { device_printf(ch->dev, "FAILURE - create data_tag\n"); goto error; } if (bus_dmamap_create(slot->data_tag, 0, &slot->data_map)) { device_printf(ch->dev, "FAILURE - create data_map\n"); goto error; } } return; error: device_printf(dev, "WARNING - DMA allocation failed, disabling DMA\n"); ata_dmafree(dev); } static void ata_dmafree(device_t dev) { struct ata_channel *ch = device_get_softc(dev); int i; /* free all dma slots */ for (i = 0; i < ATA_DMA_SLOTS; i++) { struct ata_dmaslot *slot = &ch->dma.slot[i]; if (slot->sg_bus) { bus_dmamap_unload(slot->sg_tag, slot->sg_map); slot->sg_bus = 0; } if (slot->sg_map) { bus_dmamem_free(slot->sg_tag, slot->sg, slot->sg_map); bus_dmamap_destroy(slot->sg_tag, slot->sg_map); slot->sg = NULL; slot->sg_map = NULL; } if (slot->data_map) { bus_dmamap_destroy(slot->data_tag, slot->data_map); slot->data_map = NULL; } if (slot->sg_tag) { bus_dma_tag_destroy(slot->sg_tag); slot->sg_tag = NULL; } if (slot->data_tag) { bus_dma_tag_destroy(slot->data_tag); slot->data_tag = NULL; } } } static void ata_dmasetprd(void *xsc, bus_dma_segment_t *segs, int nsegs, int error) { struct ata_dmasetprd_args *args = xsc; struct ata_dma_prdentry *prd = args->dmatab; int i; if ((args->error = error)) return; for (i = 0; i < nsegs; i++) { prd[i].addr = htole32(segs[i].ds_addr); prd[i].count = htole32(segs[i].ds_len); } prd[i - 1].count |= htole32(ATA_DMA_EOT); KASSERT(nsegs <= ATA_DMA_ENTRIES, ("too many DMA segment entries\n")); args->nsegs = nsegs; } static int ata_dmaload(struct ata_request *request, void *addr, int *entries) { struct ata_channel *ch = device_get_softc(request->parent); - struct ata_device *atadev = device_get_softc(request->dev); struct ata_dmasetprd_args dspa; int error; ATA_DEBUG_RQ(request, "dmaload"); if (request->dma) { - device_printf(request->dev, + device_printf(request->parent, "FAILURE - already active DMA on this device\n"); return EIO; } if (!request->bytecount) { - device_printf(request->dev, + device_printf(request->parent, "FAILURE - zero length DMA transfer attempted\n"); return EIO; } if (request->bytecount & (ch->dma.alignment - 1)) { - device_printf(request->dev, + device_printf(request->parent, "FAILURE - odd-sized DMA transfer attempt %d %% %d\n", request->bytecount, ch->dma.alignment); return EIO; } if (request->bytecount > ch->dma.max_iosize) { - device_printf(request->dev, + device_printf(request->parent, "FAILURE - oversized DMA transfer attempt %d > %d\n", request->bytecount, ch->dma.max_iosize); return EIO; } - /* set our slot, unit for simplicity XXX SOS NCQ will change that */ - request->dma = &ch->dma.slot[atadev->unit]; + /* set our slot. XXX SOS NCQ will change that */ + request->dma = &ch->dma.slot[0]; if (addr) dspa.dmatab = addr; else dspa.dmatab = request->dma->sg; if ((error = bus_dmamap_load(request->dma->data_tag, request->dma->data_map, request->data, request->bytecount, ch->dma.setprd, &dspa, BUS_DMA_NOWAIT)) || (error = dspa.error)) { - device_printf(request->dev, "FAILURE - load data\n"); + device_printf(request->parent, "FAILURE - load data\n"); goto error; } if (entries) *entries = dspa.nsegs; bus_dmamap_sync(request->dma->sg_tag, request->dma->sg_map, BUS_DMASYNC_PREWRITE); bus_dmamap_sync(request->dma->data_tag, request->dma->data_map, (request->flags & ATA_R_READ) ? BUS_DMASYNC_PREREAD : BUS_DMASYNC_PREWRITE); return 0; error: ata_dmaunload(request); return EIO; } int ata_dmaunload(struct ata_request *request) { ATA_DEBUG_RQ(request, "dmaunload"); if (request->dma) { bus_dmamap_sync(request->dma->sg_tag, request->dma->sg_map, BUS_DMASYNC_POSTWRITE); bus_dmamap_sync(request->dma->data_tag, request->dma->data_map, (request->flags & ATA_R_READ) ? BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE); bus_dmamap_unload(request->dma->data_tag, request->dma->data_map); request->dma = NULL; } return 0; } diff --git a/sys/dev/ata/ata-lowlevel.c b/sys/dev/ata/ata-lowlevel.c index c46caa680135..2dbb9862d0e1 100644 --- a/sys/dev/ata/ata-lowlevel.c +++ b/sys/dev/ata/ata-lowlevel.c @@ -1,859 +1,858 @@ /*- * Copyright (c) 1998 - 2008 Søren Schmidt * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer, * without modification, immediately at the beginning of the file. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * 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. */ #include __FBSDID("$FreeBSD$"); #include "opt_ata.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* prototypes */ static int ata_generic_status(device_t dev); -static int ata_wait(struct ata_channel *ch, struct ata_device *, u_int8_t); +static int ata_wait(struct ata_channel *ch, int unit, u_int8_t); static void ata_pio_read(struct ata_request *, int); static void ata_pio_write(struct ata_request *, int); static void ata_tf_read(struct ata_request *); static void ata_tf_write(struct ata_request *); /* * low level ATA functions */ void ata_generic_hw(device_t dev) { struct ata_channel *ch = device_get_softc(dev); ch->hw.begin_transaction = ata_begin_transaction; ch->hw.end_transaction = ata_end_transaction; ch->hw.status = ata_generic_status; ch->hw.softreset = NULL; ch->hw.command = ata_generic_command; ch->hw.tf_read = ata_tf_read; ch->hw.tf_write = ata_tf_write; ch->hw.pm_read = NULL; ch->hw.pm_write = NULL; } /* must be called with ATA channel locked and state_mtx held */ int ata_begin_transaction(struct ata_request *request) { struct ata_channel *ch = device_get_softc(request->parent); - struct ata_device *atadev = device_get_softc(request->dev); int dummy, error; ATA_DEBUG_RQ(request, "begin transaction"); /* disable ATAPI DMA writes if HW doesn't support it */ if ((ch->flags & ATA_ATAPI_DMA_RO) && ((request->flags & (ATA_R_ATAPI | ATA_R_DMA | ATA_R_WRITE)) == (ATA_R_ATAPI | ATA_R_DMA | ATA_R_WRITE))) request->flags &= ~ATA_R_DMA; - /* check for 48 bit access and convert if needed */ - ata_modify_if_48bit(request); - 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 gone later */ int write = (request->flags & ATA_R_WRITE); /* issue command */ if (ch->hw.command(request)) { - device_printf(request->dev, "error issuing %s command\n", + device_printf(request->parent, "error issuing %s command\n", ata_cmd2str(request)); request->result = EIO; goto begin_finished; } /* device reset doesn't interrupt */ if (request->u.ata.command == ATA_DEVICE_RESET) { int timeout = 1000000; do { DELAY(10); request->status = ATA_IDX_INB(ch, ATA_STATUS); } while (request->status & ATA_S_BUSY && timeout--); if (request->status & ATA_S_ERROR) request->error = ATA_IDX_INB(ch, ATA_ERROR); goto begin_finished; } /* if write command output the data */ if (write) { - if (ata_wait(ch, atadev, (ATA_S_READY | ATA_S_DRQ)) < 0) { - device_printf(request->dev, + if (ata_wait(ch, request->unit, (ATA_S_READY | ATA_S_DRQ)) < 0) { + device_printf(request->parent, "timeout waiting for write DRQ\n"); request->result = EIO; goto begin_finished; } ata_pio_write(request, request->transfersize); } } goto begin_continue; /* ATA DMA data transfer commands */ case ATA_R_DMA: /* check sanity, setup SG list and DMA engine */ if ((error = ch->dma.load(request, NULL, &dummy))) { - device_printf(request->dev, "setting up DMA failed\n"); + device_printf(request->parent, "setting up DMA failed\n"); request->result = error; goto begin_finished; } /* issue command */ if (ch->hw.command(request)) { - device_printf(request->dev, "error issuing %s command\n", + device_printf(request->parent, "error issuing %s command\n", ata_cmd2str(request)); request->result = EIO; goto begin_finished; } /* start DMA engine */ if (ch->dma.start && ch->dma.start(request)) { - device_printf(request->dev, "error starting DMA\n"); + device_printf(request->parent, "error starting DMA\n"); request->result = EIO; goto begin_finished; } goto begin_continue; /* 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(ch, ATA_DRIVE, ATA_D_IBM | ATA_DEV(atadev->unit)); + ATA_IDX_OUTB(ch, ATA_DRIVE, ATA_D_IBM | ATA_DEV(request->unit)); DELAY(10); if (!(ATA_IDX_INB(ch, ATA_ALTSTAT) & ATA_S_DSC)) request->result = EBUSY; goto begin_finished; } /* start ATAPI operation */ if (ch->hw.command(request)) { - device_printf(request->dev, "error issuing ATA PACKET command\n"); + device_printf(request->parent, "error issuing ATA PACKET command\n"); request->result = EIO; goto begin_finished; } goto begin_continue; /* ATAPI DMA commands */ 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(ch, ATA_DRIVE, ATA_D_IBM | ATA_DEV(atadev->unit)); + ATA_IDX_OUTB(ch, ATA_DRIVE, ATA_D_IBM | ATA_DEV(request->unit)); DELAY(10); if (!(ATA_IDX_INB(ch, ATA_ALTSTAT) & ATA_S_DSC)) request->result = EBUSY; goto begin_finished; } /* check sanity, setup SG list and DMA engine */ if ((error = ch->dma.load(request, NULL, &dummy))) { - device_printf(request->dev, "setting up DMA failed\n"); + device_printf(request->parent, "setting up DMA failed\n"); request->result = error; goto begin_finished; } /* start ATAPI operation */ if (ch->hw.command(request)) { - device_printf(request->dev, "error issuing ATA PACKET command\n"); + device_printf(request->parent, "error issuing ATA PACKET command\n"); request->result = EIO; goto begin_finished; } /* start DMA engine */ if (ch->dma.start && ch->dma.start(request)) { request->result = EIO; goto begin_finished; } goto begin_continue; } /* NOT REACHED */ printf("ata_begin_transaction OOPS!!!\n"); begin_finished: if (ch->dma.unload) { ch->dma.unload(request); } return ATA_OP_FINISHED; begin_continue: callout_reset(&request->callout, request->timeout * hz, (timeout_t*)ata_timeout, request); return ATA_OP_CONTINUES; } /* must be called with ATA channel locked and state_mtx held */ int ata_end_transaction(struct ata_request *request) { struct ata_channel *ch = device_get_softc(request->parent); - struct ata_device *atadev = device_get_softc(request->dev); int length; ATA_DEBUG_RQ(request, "end transaction"); /* clear interrupt and get status */ request->status = ATA_IDX_INB(ch, ATA_STATUS); switch (request->flags & (ATA_R_ATAPI | ATA_R_DMA | ATA_R_CONTROL)) { /* ATA PIO data transfer and control commands */ default: /* on timeouts we have no data or anything so just return */ if (request->flags & ATA_R_TIMEOUT) goto end_finished; /* on control commands read back registers to the request struct */ if (request->flags & ATA_R_CONTROL) { ch->hw.tf_read(request); } /* 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); goto end_finished; } /* are we moving data ? */ if (request->flags & (ATA_R_READ | ATA_R_WRITE)) { /* if read data get it */ if (request->flags & ATA_R_READ) { int flags = ATA_S_DRQ; if (request->u.ata.command != ATA_ATAPI_IDENTIFY) flags |= ATA_S_READY; - if (ata_wait(ch, atadev, flags) < 0) { - device_printf(request->dev, + if (ata_wait(ch, request->unit, flags) < 0) { + device_printf(request->parent, "timeout waiting for read DRQ\n"); request->result = EIO; goto end_finished; } 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(ch, atadev, (ATA_S_READY | ATA_S_DRQ)) < 0) { - device_printf(request->dev, + if (ata_wait(ch, request->unit, (ATA_S_READY | ATA_S_DRQ)) < 0) { + device_printf(request->parent, "timeout waiting for write DRQ\n"); request->status = ATA_IDX_INB(ch, ATA_STATUS); goto end_finished; } /* output data and return waiting for new interrupt */ ata_pio_write(request, request->transfersize); goto end_continue; } /* if data read command, return & wait for interrupt */ if (request->flags & ATA_R_READ) goto end_continue; } } /* done with HW */ goto end_finished; /* ATA DMA data transfer commands */ case ATA_R_DMA: /* stop DMA engine and get status */ if (ch->dma.stop) request->dma->status = ch->dma.stop(request); /* did we get error or data */ if (request->status & ATA_S_ERROR) request->error = ATA_IDX_INB(ch, ATA_ERROR); else if (request->dma->status & ATA_BMSTAT_ERROR) request->status |= ATA_S_ERROR; else if (!(request->flags & ATA_R_TIMEOUT)) request->donecount = request->bytecount; /* release SG list etc */ ch->dma.unload(request); /* done with HW */ goto end_finished; /* ATAPI PIO commands */ case ATA_R_ATAPI: length = ATA_IDX_INB(ch, ATA_CYL_LSB)|(ATA_IDX_INB(ch, ATA_CYL_MSB)<<8); /* on timeouts we have no data or anything so just return */ if (request->flags & ATA_R_TIMEOUT) goto end_finished; 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)) { - device_printf(request->dev, "command interrupt without DRQ\n"); + device_printf(request->parent, "command interrupt without DRQ\n"); request->status = ATA_S_ERROR; goto end_finished; } ATA_IDX_OUTSW_STRM(ch, ATA_DATA, (int16_t *)request->u.atapi.ccb, - (atadev->param.config & - ATA_PROTO_MASK)== ATA_PROTO_ATAPI_12 ? 6 : 8); + (request->flags & ATA_R_ATAPI16) ? 8 : 6); /* return wait for interrupt */ goto end_continue; case ATAPI_P_WRITE: if (request->flags & ATA_R_READ) { request->status = ATA_S_ERROR; - device_printf(request->dev, + device_printf(request->parent, "%s trying to write on read buffer\n", ata_cmd2str(request)); goto end_finished; 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 */ goto end_continue; case ATAPI_P_READ: if (request->flags & ATA_R_WRITE) { request->status = ATA_S_ERROR; - device_printf(request->dev, + device_printf(request->parent, "%s trying to read on write buffer\n", ata_cmd2str(request)); goto end_finished; } 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 */ goto end_continue; case ATAPI_P_DONEDRQ: - device_printf(request->dev, + device_printf(request->parent, "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); goto end_finished; default: - device_printf(request->dev, "unknown transfer phase\n"); + device_printf(request->parent, "unknown transfer phase\n"); request->status = ATA_S_ERROR; } /* done with HW */ goto end_finished; /* ATAPI DMA commands */ case ATA_R_ATAPI|ATA_R_DMA: /* stop DMA engine and get status */ if (ch->dma.stop) request->dma->status = ch->dma.stop(request); /* 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->dma->status & ATA_BMSTAT_ERROR) request->status |= ATA_S_ERROR; else if (!(request->flags & ATA_R_TIMEOUT)) request->donecount = request->bytecount; /* release SG list etc */ ch->dma.unload(request); /* done with HW */ goto end_finished; } /* NOT REACHED */ printf("ata_end_transaction OOPS!!\n"); end_finished: callout_stop(&request->callout); return ATA_OP_FINISHED; end_continue: return ATA_OP_CONTINUES; } /* must be called with ATA channel locked and state_mtx held */ void ata_generic_reset(device_t dev) { struct ata_channel *ch = device_get_softc(dev); u_int8_t ostat0 = 0, stat0 = 0, ostat1 = 0, stat1 = 0; u_int8_t err = 0, lsb = 0, msb = 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_D_LBA | ATA_DEV(ATA_MASTER)); DELAY(10); ostat0 = ATA_IDX_INB(ch, ATA_STATUS); if ((ostat0 & 0xf8) != 0xf8 && ostat0 != 0xa5) { stat0 = ATA_S_BUSY; mask |= 0x01; } /* in some setups we dont want to test for a slave */ if (!(ch->flags & ATA_NO_SLAVE)) { ATA_IDX_OUTB(ch, ATA_DRIVE, ATA_D_IBM | ATA_D_LBA | ATA_DEV(ATA_SLAVE)); DELAY(10); ostat1 = ATA_IDX_INB(ch, ATA_STATUS); if ((ostat1 & 0xf8) != 0xf8 && ostat1 != 0xa5) { stat1 = ATA_S_BUSY; mask |= 0x02; } } if (bootverbose) device_printf(dev, "reset tp1 mask=%02x ostat0=%02x ostat1=%02x\n", mask, ostat0, ostat1); /* if nothing showed up there is no need to get any further */ /* XXX SOS is that too strong?, we just might loose devices here */ ch->devices = 0; if (!mask) return; /* reset (both) devices on this channel */ ATA_IDX_OUTB(ch, ATA_DRIVE, ATA_D_IBM | ATA_D_LBA | ATA_DEV(ATA_MASTER)); DELAY(10); ATA_IDX_OUTB(ch, ATA_CONTROL, ATA_A_IDS | ATA_A_RESET); ata_udelay(10000); ATA_IDX_OUTB(ch, ATA_CONTROL, ATA_A_IDS); ata_udelay(100000); ATA_IDX_INB(ch, ATA_ERROR); /* wait for BUSY to go inactive */ for (timeout = 0; timeout < 310; timeout++) { if ((mask & 0x01) && (stat0 & ATA_S_BUSY)) { ATA_IDX_OUTB(ch, ATA_DRIVE, ATA_D_IBM | ATA_DEV(ATA_MASTER)); DELAY(10); err = ATA_IDX_INB(ch, ATA_ERROR); lsb = ATA_IDX_INB(ch, ATA_CYL_LSB); msb = ATA_IDX_INB(ch, ATA_CYL_MSB); stat0 = ATA_IDX_INB(ch, ATA_STATUS); if (bootverbose) device_printf(dev, "stat0=0x%02x err=0x%02x lsb=0x%02x msb=0x%02x\n", stat0, err, lsb, msb); if (stat0 == err && lsb == err && msb == err && timeout > (stat0 & ATA_S_BUSY ? 100 : 10)) mask &= ~0x01; if (!(stat0 & ATA_S_BUSY)) { if ((err & 0x7f) == ATA_E_ILI) { if (lsb == ATAPI_MAGIC_LSB && msb == ATAPI_MAGIC_MSB) { ch->devices |= ATA_ATAPI_MASTER; } else if (stat0 & ATA_S_READY) { ch->devices |= ATA_ATA_MASTER; } } else if ((stat0 & 0x0f) && err == lsb && err == msb) { stat0 |= ATA_S_BUSY; } } } if ((mask & 0x02) && (stat1 & ATA_S_BUSY) && !((mask & 0x01) && (stat0 & ATA_S_BUSY))) { ATA_IDX_OUTB(ch, ATA_DRIVE, ATA_D_IBM | ATA_DEV(ATA_SLAVE)); DELAY(10); err = ATA_IDX_INB(ch, ATA_ERROR); lsb = ATA_IDX_INB(ch, ATA_CYL_LSB); msb = ATA_IDX_INB(ch, ATA_CYL_MSB); stat1 = ATA_IDX_INB(ch, ATA_STATUS); if (bootverbose) device_printf(dev, "stat1=0x%02x err=0x%02x lsb=0x%02x msb=0x%02x\n", stat1, err, lsb, msb); if (stat1 == err && lsb == err && msb == err && timeout > (stat1 & ATA_S_BUSY ? 100 : 10)) mask &= ~0x02; if (!(stat1 & ATA_S_BUSY)) { if ((err & 0x7f) == ATA_E_ILI) { if (lsb == ATAPI_MAGIC_LSB && msb == ATAPI_MAGIC_MSB) { ch->devices |= ATA_ATAPI_SLAVE; } else if (stat1 & ATA_S_READY) { ch->devices |= ATA_ATA_SLAVE; } } else if ((stat1 & 0x0f) && err == lsb && err == msb) { stat1 |= ATA_S_BUSY; } } } if (mask == 0x00) /* nothing to wait for */ break; if (mask == 0x01) /* wait for master only */ if (!(stat0 & ATA_S_BUSY) || (stat0 == 0xff && timeout > 10)) break; if (mask == 0x02) /* wait for slave only */ if (!(stat1 & ATA_S_BUSY) || (stat1 == 0xff && timeout > 10)) break; if (mask == 0x03) { /* wait for both master & slave */ if (!(stat0 & ATA_S_BUSY) && !(stat1 & ATA_S_BUSY)) break; if ((stat0 == 0xff) && (timeout > 20)) mask &= ~0x01; if ((stat1 == 0xff) && (timeout > 20)) mask &= ~0x02; } ata_udelay(100000); } if (bootverbose) device_printf(dev, "reset tp2 stat0=%02x stat1=%02x devices=0x%x\n", stat0, stat1, ch->devices); } /* must be called with ATA channel locked and state_mtx held */ int ata_generic_status(device_t dev) { struct ata_channel *ch = device_get_softc(dev); if (ATA_IDX_INB(ch, ATA_ALTSTAT) & ATA_S_BUSY) { DELAY(100); if (ATA_IDX_INB(ch, ATA_ALTSTAT) & ATA_S_BUSY) return 0; } return 1; } static int -ata_wait(struct ata_channel *ch, struct ata_device *atadev, u_int8_t mask) +ata_wait(struct ata_channel *ch, int unit, u_int8_t mask) { u_int8_t status; int timeout = 0; DELAY(1); /* wait at max 1 second for device to get !BUSY */ while (timeout < 1000000) { status = ATA_IDX_INB(ch, ATA_ALTSTAT); /* if drive fails status, reselect the drive and try again */ if (status == 0xff) { - ATA_IDX_OUTB(ch, ATA_DRIVE, ATA_D_IBM | ATA_DEV(atadev->unit)); + ATA_IDX_OUTB(ch, ATA_DRIVE, ATA_D_IBM | ATA_DEV(unit)); timeout += 1000; DELAY(1000); continue; } /* are we done ? */ if (!(status & ATA_S_BUSY)) break; if (timeout > 1000) { timeout += 1000; DELAY(1000); } else { timeout += 10; DELAY(10); } } if (timeout >= 1000000) return -2; if (!mask) return (status & ATA_S_ERROR); DELAY(1); /* wait 50 msec for bits wanted */ timeout = 5000; while (timeout--) { status = ATA_IDX_INB(ch, ATA_ALTSTAT); if ((status & mask) == mask) return (status & ATA_S_ERROR); DELAY(10); } return -3; } int ata_generic_command(struct ata_request *request) { struct ata_channel *ch = device_get_softc(request->parent); - struct ata_device *atadev = device_get_softc(request->dev); /* select device */ - ATA_IDX_OUTB(ch, ATA_DRIVE, ATA_D_IBM | ATA_D_LBA | ATA_DEV(atadev->unit)); + ATA_IDX_OUTB(ch, ATA_DRIVE, ATA_D_IBM | ATA_D_LBA | ATA_DEV(request->unit)); /* ready to issue command ? */ - if (ata_wait(ch, atadev, 0) < 0) { - device_printf(request->dev, "timeout waiting to issue command\n"); + if (ata_wait(ch, request->unit, 0) < 0) { + device_printf(request->parent, "timeout waiting to issue command\n"); return -1; } /* enable interrupt */ ATA_IDX_OUTB(ch, ATA_CONTROL, ATA_A_4BIT); if (request->flags & ATA_R_ATAPI) { int timeout = 5000; + int res; /* issue packet command to controller */ if (request->flags & ATA_R_DMA) { ATA_IDX_OUTB(ch, ATA_FEATURE, ATA_F_DMA); ATA_IDX_OUTB(ch, ATA_CYL_LSB, 0); ATA_IDX_OUTB(ch, ATA_CYL_MSB, 0); } else { ATA_IDX_OUTB(ch, ATA_FEATURE, 0); ATA_IDX_OUTB(ch, ATA_CYL_LSB, request->transfersize); ATA_IDX_OUTB(ch, ATA_CYL_MSB, request->transfersize >> 8); } ATA_IDX_OUTB(ch, ATA_COMMAND, ATA_PACKET_CMD); /* command interrupt device ? just return and wait for interrupt */ - if ((atadev->param.config & ATA_DRQ_MASK) == ATA_DRQ_INTR) + if (request->flags & ATA_R_ATAPI_INTR) return 0; + /* command processed ? */ + res = ata_wait(ch, request->unit, 0); + if (res != 0) { + if (res < 0) + device_printf(request->parent, "timeout waiting for PACKET command\n"); + return (-1); + } /* wait for ready to write ATAPI command block */ while (timeout--) { int reason = ATA_IDX_INB(ch, ATA_IREASON); int status = ATA_IDX_INB(ch, 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) { - device_printf(request->dev, "timeout waiting for ATAPI ready\n"); + device_printf(request->parent, "timeout waiting for ATAPI ready\n"); request->result = EIO; return -1; } /* this seems to be needed for some (slow) devices */ DELAY(10); /* output command block */ ATA_IDX_OUTSW_STRM(ch, ATA_DATA, (int16_t *)request->u.atapi.ccb, - (atadev->param.config & ATA_PROTO_MASK) == - ATA_PROTO_ATAPI_12 ? 6 : 8); + (request->flags & ATA_R_ATAPI16) ? 8 : 6); } else { ch->hw.tf_write(request); /* issue command to controller */ ATA_IDX_OUTB(ch, ATA_COMMAND, request->u.ata.command); } return 0; } static void ata_tf_read(struct ata_request *request) { struct ata_channel *ch = device_get_softc(request->parent); - struct ata_device *atadev = device_get_softc(request->dev); - if (atadev->flags & ATA_D_48BIT_ACTIVE) { + if (request->flags & ATA_R_48BIT) { ATA_IDX_OUTB(ch, ATA_CONTROL, ATA_A_4BIT | ATA_A_HOB); request->u.ata.count = (ATA_IDX_INB(ch, ATA_COUNT) << 8); request->u.ata.lba = ((u_int64_t)(ATA_IDX_INB(ch, ATA_SECTOR)) << 24) | ((u_int64_t)(ATA_IDX_INB(ch, ATA_CYL_LSB)) << 32) | ((u_int64_t)(ATA_IDX_INB(ch, ATA_CYL_MSB)) << 40); ATA_IDX_OUTB(ch, ATA_CONTROL, ATA_A_4BIT); request->u.ata.count |= ATA_IDX_INB(ch, ATA_COUNT); request->u.ata.lba |= (ATA_IDX_INB(ch, ATA_SECTOR) | (ATA_IDX_INB(ch, ATA_CYL_LSB) << 8) | (ATA_IDX_INB(ch, ATA_CYL_MSB) << 16)); } else { request->u.ata.count = ATA_IDX_INB(ch, ATA_COUNT); request->u.ata.lba = ATA_IDX_INB(ch, ATA_SECTOR) | (ATA_IDX_INB(ch, ATA_CYL_LSB) << 8) | (ATA_IDX_INB(ch, ATA_CYL_MSB) << 16) | ((ATA_IDX_INB(ch, ATA_DRIVE) & 0xf) << 24); } } static void ata_tf_write(struct ata_request *request) { struct ata_channel *ch = device_get_softc(request->parent); struct ata_device *atadev = device_get_softc(request->dev); - if (atadev->flags & ATA_D_48BIT_ACTIVE) { + if (request->flags & ATA_R_48BIT) { ATA_IDX_OUTB(ch, ATA_FEATURE, request->u.ata.feature >> 8); ATA_IDX_OUTB(ch, ATA_FEATURE, request->u.ata.feature); ATA_IDX_OUTB(ch, ATA_COUNT, request->u.ata.count >> 8); ATA_IDX_OUTB(ch, ATA_COUNT, request->u.ata.count); ATA_IDX_OUTB(ch, ATA_SECTOR, request->u.ata.lba >> 24); ATA_IDX_OUTB(ch, ATA_SECTOR, request->u.ata.lba); ATA_IDX_OUTB(ch, ATA_CYL_LSB, request->u.ata.lba >> 32); ATA_IDX_OUTB(ch, ATA_CYL_LSB, request->u.ata.lba >> 8); ATA_IDX_OUTB(ch, ATA_CYL_MSB, request->u.ata.lba >> 40); ATA_IDX_OUTB(ch, ATA_CYL_MSB, request->u.ata.lba >> 16); - ATA_IDX_OUTB(ch, ATA_DRIVE, ATA_D_LBA | ATA_DEV(atadev->unit)); + ATA_IDX_OUTB(ch, ATA_DRIVE, ATA_D_LBA | ATA_DEV(request->unit)); } else { ATA_IDX_OUTB(ch, ATA_FEATURE, request->u.ata.feature); ATA_IDX_OUTB(ch, ATA_COUNT, request->u.ata.count); if (atadev->flags & ATA_D_USE_CHS) { int heads, sectors; if (atadev->param.atavalid & ATA_FLAG_54_58) { heads = atadev->param.current_heads; sectors = atadev->param.current_sectors; } else { heads = atadev->param.heads; sectors = atadev->param.sectors; } ATA_IDX_OUTB(ch, ATA_SECTOR, (request->u.ata.lba % sectors)+1); ATA_IDX_OUTB(ch, ATA_CYL_LSB, (request->u.ata.lba / (sectors * heads))); ATA_IDX_OUTB(ch, ATA_CYL_MSB, (request->u.ata.lba / (sectors * heads)) >> 8); - ATA_IDX_OUTB(ch, ATA_DRIVE, ATA_D_IBM | ATA_DEV(atadev->unit) | + ATA_IDX_OUTB(ch, ATA_DRIVE, ATA_D_IBM | ATA_DEV(request->unit) | (((request->u.ata.lba% (sectors * heads)) / sectors) & 0xf)); } else { ATA_IDX_OUTB(ch, ATA_SECTOR, request->u.ata.lba); ATA_IDX_OUTB(ch, ATA_CYL_LSB, request->u.ata.lba >> 8); ATA_IDX_OUTB(ch, ATA_CYL_MSB, request->u.ata.lba >> 16); ATA_IDX_OUTB(ch, ATA_DRIVE, - ATA_D_IBM | ATA_D_LBA | ATA_DEV(atadev->unit) | + ATA_D_IBM | ATA_D_LBA | ATA_DEV(request->unit) | ((request->u.ata.lba >> 24) & 0x0f)); } } } static void ata_pio_read(struct ata_request *request, int length) { struct ata_channel *ch = device_get_softc(request->parent); int size = min(request->transfersize, length); 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) { - device_printf(request->dev, "WARNING - %s read data overrun %d>%d\n", + device_printf(request->parent, "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) { struct ata_channel *ch = device_get_softc(request->parent); int size = min(request->transfersize, length); 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) { - device_printf(request->dev, "WARNING - %s write data underrun %d>%d\n", + device_printf(request->parent, "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 9a0af1cf55c0..4440bdea292f 100644 --- a/sys/dev/ata/ata-pci.c +++ b/sys/dev/ata/ata-pci.c @@ -1,867 +1,867 @@ /*- * Copyright (c) 1998 - 2008 Søren Schmidt * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer, * without modification, immediately at the beginning of the file. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * 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. */ #include __FBSDID("$FreeBSD$"); #include "opt_ata.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* local vars */ static MALLOC_DEFINE(M_ATAPCI, "ata_pci", "ATA driver PCI"); /* misc defines */ #define IOMASK 0xfffffffc /* local prototypes */ static int ata_generic_chipinit(device_t dev); static void ata_generic_setmode(device_t dev, int mode); /* * generic PCI ATA device probe */ int ata_pci_probe(device_t dev) { struct ata_pci_controller *ctlr = device_get_softc(dev); char buffer[64]; /* is this a storage class device ? */ if (pci_get_class(dev) != PCIC_STORAGE) return (ENXIO); /* is this an IDE/ATA type device ? */ if (pci_get_subclass(dev) != PCIS_STORAGE_IDE) return (ENXIO); sprintf(buffer, "%s ATA controller", ata_pcivendor2str(dev)); device_set_desc_copy(dev, buffer); ctlr->chipinit = ata_generic_chipinit; /* we are a low priority handler */ return (BUS_PROBE_GENERIC); } int ata_pci_attach(device_t dev) { struct ata_pci_controller *ctlr = device_get_softc(dev); device_t child; u_int32_t cmd; int unit; /* do chipset specific setups only needed once */ ctlr->legacy = ata_legacy(dev); if (ctlr->legacy || pci_read_config(dev, PCIR_BAR(2), 4) & IOMASK) ctlr->channels = 2; else ctlr->channels = 1; ctlr->ichannels = -1; ctlr->ch_attach = ata_pci_ch_attach; ctlr->ch_detach = ata_pci_ch_detach; ctlr->dev = dev; /* if needed try to enable busmastering */ cmd = pci_read_config(dev, PCIR_COMMAND, 2); if (!(cmd & PCIM_CMD_BUSMASTEREN)) { pci_write_config(dev, PCIR_COMMAND, cmd | PCIM_CMD_BUSMASTEREN, 2); cmd = pci_read_config(dev, PCIR_COMMAND, 2); } /* if busmastering mode "stuck" use it */ if ((cmd & PCIM_CMD_BUSMASTEREN) == PCIM_CMD_BUSMASTEREN) { ctlr->r_type1 = SYS_RES_IOPORT; ctlr->r_rid1 = ATA_BMADDR_RID; ctlr->r_res1 = bus_alloc_resource_any(dev, ctlr->r_type1, &ctlr->r_rid1, RF_ACTIVE); } if (ctlr->chipinit(dev)) return ENXIO; /* attach all channels on this controller */ for (unit = 0; unit < ctlr->channels; unit++) { if ((ctlr->ichannels & (1 << unit)) == 0) continue; child = device_add_child(dev, "ata", ((unit == 0 || unit == 1) && ctlr->legacy) ? unit : devclass_find_free_unit(ata_devclass, 2)); if (child == NULL) device_printf(dev, "failed to add ata child device\n"); else device_set_ivars(child, (void *)(intptr_t)unit); } bus_generic_attach(dev); return 0; } int ata_pci_detach(device_t dev) { struct ata_pci_controller *ctlr = device_get_softc(dev); device_t *children; int nchildren, i; /* detach & delete all children */ if (!device_get_children(dev, &children, &nchildren)) { for (i = 0; i < nchildren; i++) device_delete_child(dev, children[i]); free(children, M_TEMP); } if (ctlr->r_irq) { bus_teardown_intr(dev, ctlr->r_irq, ctlr->handle); bus_release_resource(dev, SYS_RES_IRQ, ctlr->r_irq_rid, ctlr->r_irq); if (ctlr->r_irq_rid != ATA_IRQ_RID) pci_release_msi(dev); } if (ctlr->r_res2) bus_release_resource(dev, ctlr->r_type2, ctlr->r_rid2, ctlr->r_res2); if (ctlr->r_res1) bus_release_resource(dev, ctlr->r_type1, ctlr->r_rid1, ctlr->r_res1); return 0; } int ata_pci_suspend(device_t dev) { struct ata_pci_controller *ctlr = device_get_softc(dev); int error = 0; bus_generic_suspend(dev); if (ctlr->suspend) error = ctlr->suspend(dev); return error; } int ata_pci_resume(device_t dev) { struct ata_pci_controller *ctlr = device_get_softc(dev); int error = 0; if (ctlr->resume) error = ctlr->resume(dev); bus_generic_resume(dev); return error; } struct resource * ata_pci_alloc_resource(device_t dev, device_t child, int type, int *rid, u_long start, u_long end, u_long count, u_int flags) { struct ata_pci_controller *controller = device_get_softc(dev); int unit = ((struct ata_channel *)device_get_softc(child))->unit; struct resource *res = NULL; int myrid; if (type == SYS_RES_IOPORT) { switch (*rid) { case ATA_IOADDR_RID: if (controller->legacy) { start = (unit ? ATA_SECONDARY : ATA_PRIMARY); count = ATA_IOSIZE; end = start + count - 1; } myrid = PCIR_BAR(0) + (unit << 3); res = BUS_ALLOC_RESOURCE(device_get_parent(dev), dev, SYS_RES_IOPORT, &myrid, start, end, count, flags); break; case ATA_CTLADDR_RID: if (controller->legacy) { start = (unit ? ATA_SECONDARY : ATA_PRIMARY) + ATA_CTLOFFSET; count = ATA_CTLIOSIZE; end = start + count - 1; } myrid = PCIR_BAR(1) + (unit << 3); res = BUS_ALLOC_RESOURCE(device_get_parent(dev), dev, SYS_RES_IOPORT, &myrid, start, end, count, flags); break; } } if (type == SYS_RES_IRQ && *rid == ATA_IRQ_RID) { if (controller->legacy) { int irq = (unit == 0 ? 14 : 15); res = BUS_ALLOC_RESOURCE(device_get_parent(dev), child, SYS_RES_IRQ, rid, irq, irq, 1, flags); } else res = controller->r_irq; } return res; } int ata_pci_release_resource(device_t dev, device_t child, int type, int rid, struct resource *r) { struct ata_pci_controller *controller = device_get_softc(dev); int unit = ((struct ata_channel *)device_get_softc(child))->unit; if (type == SYS_RES_IOPORT) { switch (rid) { case ATA_IOADDR_RID: return BUS_RELEASE_RESOURCE(device_get_parent(dev), dev, SYS_RES_IOPORT, PCIR_BAR(0) + (unit << 3), r); break; case ATA_CTLADDR_RID: return BUS_RELEASE_RESOURCE(device_get_parent(dev), dev, SYS_RES_IOPORT, PCIR_BAR(1) + (unit << 3), r); break; default: return ENOENT; } } if (type == SYS_RES_IRQ) { if (rid != ATA_IRQ_RID) return ENOENT; if (controller->legacy) { return BUS_RELEASE_RESOURCE(device_get_parent(dev), child, SYS_RES_IRQ, rid, r); } else return 0; } return EINVAL; } int ata_pci_setup_intr(device_t dev, device_t child, struct resource *irq, int flags, driver_filter_t *filter, driver_intr_t *function, void *argument, void **cookiep) { struct ata_pci_controller *controller = device_get_softc(dev); if (controller->legacy) { return BUS_SETUP_INTR(device_get_parent(dev), child, irq, flags, filter, function, argument, cookiep); } else { struct ata_pci_controller *controller = device_get_softc(dev); int unit = ((struct ata_channel *)device_get_softc(child))->unit; if (filter != NULL) { printf("ata-pci.c: we cannot use a filter here\n"); return (EINVAL); } controller->interrupt[unit].function = function; controller->interrupt[unit].argument = argument; *cookiep = controller; return 0; } } int ata_pci_teardown_intr(device_t dev, device_t child, struct resource *irq, void *cookie) { struct ata_pci_controller *controller = device_get_softc(dev); if (controller->legacy) { return BUS_TEARDOWN_INTR(device_get_parent(dev), child, irq, cookie); } else { struct ata_pci_controller *controller = device_get_softc(dev); int unit = ((struct ata_channel *)device_get_softc(child))->unit; controller->interrupt[unit].function = NULL; controller->interrupt[unit].argument = NULL; return 0; } } static void ata_generic_setmode(device_t dev, int mode) { struct ata_device *atadev = device_get_softc(dev); mode = ata_limit_mode(dev, mode, ATA_UDMA2); mode = ata_check_80pin(dev, mode); if (!ata_controlcmd(dev, ATA_SETFEATURES, ATA_SF_SETXFER, 0, mode)) atadev->mode = mode; } static int ata_generic_chipinit(device_t dev) { struct ata_pci_controller *ctlr = device_get_softc(dev); if (ata_setup_interrupt(dev, ata_generic_intr)) return ENXIO; ctlr->setmode = ata_generic_setmode; return 0; } int ata_pci_ch_attach(device_t dev) { struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev)); struct ata_channel *ch = device_get_softc(dev); struct resource *io = NULL, *ctlio = NULL; int i, rid; rid = ATA_IOADDR_RID; if (!(io = bus_alloc_resource_any(dev, SYS_RES_IOPORT, &rid, RF_ACTIVE))) return ENXIO; rid = ATA_CTLADDR_RID; if (!(ctlio = bus_alloc_resource_any(dev, SYS_RES_IOPORT, &rid,RF_ACTIVE))){ bus_release_resource(dev, SYS_RES_IOPORT, ATA_IOADDR_RID, io); return ENXIO; } ata_pci_dmainit(dev); for (i = ATA_DATA; i <= ATA_COMMAND; i ++) { ch->r_io[i].res = io; ch->r_io[i].offset = i; } ch->r_io[ATA_CONTROL].res = ctlio; ch->r_io[ATA_CONTROL].offset = ctlr->legacy ? 0 : 2; ch->r_io[ATA_IDX_ADDR].res = io; ata_default_registers(dev); if (ctlr->r_res1) { for (i = ATA_BMCMD_PORT; i <= ATA_BMDTP_PORT; i++) { ch->r_io[i].res = ctlr->r_res1; ch->r_io[i].offset = (i - ATA_BMCMD_PORT) + (ch->unit*ATA_BMIOSIZE); } } ata_pci_hw(dev); return 0; } int ata_pci_ch_detach(device_t dev) { struct ata_channel *ch = device_get_softc(dev); ata_pci_dmafini(dev); bus_release_resource(dev, SYS_RES_IOPORT, ATA_CTLADDR_RID, ch->r_io[ATA_CONTROL].res); bus_release_resource(dev, SYS_RES_IOPORT, ATA_IOADDR_RID, ch->r_io[ATA_IDX_ADDR].res); return (0); } int ata_pci_status(device_t dev) { struct ata_pci_controller *controller = device_get_softc(device_get_parent(dev)); struct ata_channel *ch = device_get_softc(dev); if ((dumping || !controller->legacy) && ((ch->flags & ATA_ALWAYS_DMASTAT) || (ch->dma.flags & ATA_DMA_ACTIVE))) { int bmstat = ATA_IDX_INB(ch, ATA_BMSTAT_PORT) & ATA_BMSTAT_MASK; if ((bmstat & (ATA_BMSTAT_ACTIVE | ATA_BMSTAT_INTERRUPT)) != ATA_BMSTAT_INTERRUPT) return 0; ATA_IDX_OUTB(ch, ATA_BMSTAT_PORT, bmstat & ~ATA_BMSTAT_ERROR); DELAY(1); } if (ATA_IDX_INB(ch, ATA_ALTSTAT) & ATA_S_BUSY) { DELAY(100); if (ATA_IDX_INB(ch, ATA_ALTSTAT) & ATA_S_BUSY) return 0; } return 1; } void ata_pci_hw(device_t dev) { struct ata_channel *ch = device_get_softc(dev); ata_generic_hw(dev); ch->hw.status = ata_pci_status; } static int ata_pci_dmastart(struct ata_request *request) { struct ata_channel *ch = device_get_softc(request->parent); ATA_DEBUG_RQ(request, "dmastart"); 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, request->dma->sg_bus); ch->dma.flags |= ATA_DMA_ACTIVE; ATA_IDX_OUTB(ch, ATA_BMCMD_PORT, (ATA_IDX_INB(ch, ATA_BMCMD_PORT) & ~ATA_BMCMD_WRITE_READ) | ((request->flags & ATA_R_READ) ? ATA_BMCMD_WRITE_READ : 0)| ATA_BMCMD_START_STOP); return 0; } static int ata_pci_dmastop(struct ata_request *request) { struct ata_channel *ch = device_get_softc(request->parent); int error; ATA_DEBUG_RQ(request, "dmastop"); ATA_IDX_OUTB(ch, ATA_BMCMD_PORT, ATA_IDX_INB(ch, ATA_BMCMD_PORT) & ~ATA_BMCMD_START_STOP); ch->dma.flags &= ~ATA_DMA_ACTIVE; error = ATA_IDX_INB(ch, ATA_BMSTAT_PORT) & ATA_BMSTAT_MASK; ATA_IDX_OUTB(ch, ATA_BMSTAT_PORT, ATA_BMSTAT_INTERRUPT | ATA_BMSTAT_ERROR); return error; } static void ata_pci_dmareset(device_t dev) { struct ata_channel *ch = device_get_softc(dev); struct ata_request *request; ATA_IDX_OUTB(ch, ATA_BMCMD_PORT, ATA_IDX_INB(ch, ATA_BMCMD_PORT) & ~ATA_BMCMD_START_STOP); ch->dma.flags &= ~ATA_DMA_ACTIVE; ATA_IDX_OUTB(ch, ATA_BMSTAT_PORT, ATA_BMSTAT_INTERRUPT | ATA_BMSTAT_ERROR); if ((request = ch->running)) { - device_printf(request->dev, "DMA reset calling unload\n"); + device_printf(dev, "DMA reset calling unload\n"); ch->dma.unload(request); } } void ata_pci_dmainit(device_t dev) { struct ata_channel *ch = device_get_softc(dev); ata_dmainit(dev); ch->dma.start = ata_pci_dmastart; ch->dma.stop = ata_pci_dmastop; ch->dma.reset = ata_pci_dmareset; } void ata_pci_dmafini(device_t dev) { ata_dmafini(dev); } static device_method_t ata_pci_methods[] = { /* device interface */ DEVMETHOD(device_probe, ata_pci_probe), DEVMETHOD(device_attach, ata_pci_attach), DEVMETHOD(device_detach, ata_pci_detach), DEVMETHOD(device_suspend, ata_pci_suspend), DEVMETHOD(device_resume, ata_pci_resume), DEVMETHOD(device_shutdown, bus_generic_shutdown), /* bus methods */ DEVMETHOD(bus_alloc_resource, ata_pci_alloc_resource), DEVMETHOD(bus_release_resource, ata_pci_release_resource), DEVMETHOD(bus_activate_resource, bus_generic_activate_resource), DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), DEVMETHOD(bus_setup_intr, ata_pci_setup_intr), DEVMETHOD(bus_teardown_intr, ata_pci_teardown_intr), { 0, 0 } }; devclass_t ata_pci_devclass; static driver_t ata_pci_driver = { "atapci", ata_pci_methods, sizeof(struct ata_pci_controller), }; DRIVER_MODULE(atapci, pci, ata_pci_driver, ata_pci_devclass, 0, 0); MODULE_VERSION(atapci, 1); MODULE_DEPEND(atapci, ata, 1, 1, 1); static int ata_pcichannel_probe(device_t dev) { char buffer[32]; sprintf(buffer, "ATA channel %d", (int)(intptr_t)device_get_ivars(dev)); device_set_desc_copy(dev, buffer); return ata_probe(dev); } static int ata_pcichannel_attach(device_t dev) { struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev)); struct ata_channel *ch = device_get_softc(dev); int error; if (ch->attached) return (0); ch->attached = 1; ch->unit = (intptr_t)device_get_ivars(dev); resource_int_value(device_get_name(dev), device_get_unit(dev), "pm_level", &ch->pm_level); if ((error = ctlr->ch_attach(dev))) return error; return ata_attach(dev); } static int ata_pcichannel_detach(device_t dev) { struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev)); struct ata_channel *ch = device_get_softc(dev); int error; if (!ch->attached) return (0); ch->attached = 0; if ((error = ata_detach(dev))) return error; if (ctlr->ch_detach) return (ctlr->ch_detach(dev)); return (0); } static int ata_pcichannel_suspend(device_t dev) { struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev)); struct ata_channel *ch = device_get_softc(dev); int error; if (!ch->attached) return (0); if ((error = ata_suspend(dev))) return (error); if (ctlr->ch_suspend != NULL && (error = ctlr->ch_suspend(dev))) return (error); return (0); } static int ata_pcichannel_resume(device_t dev) { struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev)); struct ata_channel *ch = device_get_softc(dev); int error; if (!ch->attached) return (0); if (ctlr->ch_resume != NULL && (error = ctlr->ch_resume(dev))) return (error); return ata_resume(dev); } static int ata_pcichannel_locking(device_t dev, int mode) { struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev)); struct ata_channel *ch = device_get_softc(dev); if (ctlr->locking) return ctlr->locking(dev, mode); else return ch->unit; } static void ata_pcichannel_reset(device_t dev) { struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev)); struct ata_channel *ch = device_get_softc(dev); /* if DMA engine present reset it */ if (ch->dma.reset) ch->dma.reset(dev); /* reset the controller HW */ if (ctlr->reset) ctlr->reset(dev); else ata_generic_reset(dev); } static void ata_pcichannel_setmode(device_t parent, device_t dev) { struct ata_pci_controller *ctlr = device_get_softc(GRANDPARENT(dev)); struct ata_device *atadev = device_get_softc(dev); int mode = atadev->mode; ctlr->setmode(dev, ATA_PIO_MAX); if (mode >= ATA_DMA) ctlr->setmode(dev, mode); } static device_method_t ata_pcichannel_methods[] = { /* device interface */ DEVMETHOD(device_probe, ata_pcichannel_probe), DEVMETHOD(device_attach, ata_pcichannel_attach), DEVMETHOD(device_detach, ata_pcichannel_detach), DEVMETHOD(device_shutdown, bus_generic_shutdown), DEVMETHOD(device_suspend, ata_pcichannel_suspend), DEVMETHOD(device_resume, ata_pcichannel_resume), /* ATA methods */ DEVMETHOD(ata_setmode, ata_pcichannel_setmode), DEVMETHOD(ata_locking, ata_pcichannel_locking), DEVMETHOD(ata_reset, ata_pcichannel_reset), { 0, 0 } }; driver_t ata_pcichannel_driver = { "ata", ata_pcichannel_methods, sizeof(struct ata_channel), }; DRIVER_MODULE(ata, atapci, ata_pcichannel_driver, ata_devclass, 0, 0); /* * misc support fucntions */ int ata_legacy(device_t dev) { return (((pci_read_config(dev, PCIR_PROGIF, 1)&PCIP_STORAGE_IDE_MASTERDEV)&& ((pci_read_config(dev, PCIR_PROGIF, 1) & (PCIP_STORAGE_IDE_MODEPRIM | PCIP_STORAGE_IDE_MODESEC)) != (PCIP_STORAGE_IDE_MODEPRIM | PCIP_STORAGE_IDE_MODESEC))) || (!pci_read_config(dev, PCIR_BAR(0), 4) && !pci_read_config(dev, PCIR_BAR(1), 4) && !pci_read_config(dev, PCIR_BAR(2), 4) && !pci_read_config(dev, PCIR_BAR(3), 4) && !pci_read_config(dev, PCIR_BAR(5), 4))); } void ata_generic_intr(void *data) { struct ata_pci_controller *ctlr = data; struct ata_channel *ch; int unit; for (unit = 0; unit < ctlr->channels; unit++) { if ((ch = ctlr->interrupt[unit].argument)) ctlr->interrupt[unit].function(ch); } } int ata_setup_interrupt(device_t dev, void *intr_func) { struct ata_pci_controller *ctlr = device_get_softc(dev); int i, msi = 0; if (!ctlr->legacy) { if (resource_int_value(device_get_name(dev), device_get_unit(dev), "msi", &i) == 0 && i != 0) msi = 1; if (msi && pci_msi_count(dev) > 0 && pci_alloc_msi(dev, &msi) == 0) { ctlr->r_irq_rid = 0x1; } else { ctlr->r_irq_rid = ATA_IRQ_RID; } if (!(ctlr->r_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &ctlr->r_irq_rid, RF_SHAREABLE | RF_ACTIVE))) { device_printf(dev, "unable to map interrupt\n"); return ENXIO; } if ((bus_setup_intr(dev, ctlr->r_irq, ATA_INTR_FLAGS, NULL, intr_func, ctlr, &ctlr->handle))) { /* SOS XXX release r_irq */ device_printf(dev, "unable to setup interrupt\n"); return ENXIO; } } return 0; } void ata_set_desc(device_t dev) { struct ata_pci_controller *ctlr = device_get_softc(dev); char buffer[128]; sprintf(buffer, "%s %s %s controller", ata_pcivendor2str(dev), ctlr->chip->text, ata_mode2str(ctlr->chip->max_dma)); device_set_desc_copy(dev, buffer); } struct ata_chip_id * ata_match_chip(device_t dev, struct ata_chip_id *index) { uint32_t devid; uint8_t revid; devid = pci_get_devid(dev); revid = pci_get_revid(dev); while (index->chipid != 0) { if (devid == index->chipid && revid >= index->chiprev) return (index); index++; } return (NULL); } struct ata_chip_id * ata_find_chip(device_t dev, struct ata_chip_id *index, int slot) { struct ata_chip_id *idx; device_t *children; int nchildren, i; uint8_t s; if (device_get_children(device_get_parent(dev), &children, &nchildren)) return (NULL); for (i = 0; i < nchildren; i++) { s = pci_get_slot(children[i]); if ((slot >= 0 && s == slot) || (slot < 0 && s <= -slot)) { idx = ata_match_chip(children[i], index); if (idx != NULL) { free(children, M_TEMP); return (idx); } } } free(children, M_TEMP); return (NULL); } void ata_print_cable(device_t dev, u_int8_t *who) { device_printf(dev, "DMA limited to UDMA33, %s found non-ATA66 cable\n", who); } int ata_check_80pin(device_t dev, int mode) { struct ata_device *atadev = device_get_softc(dev); if (!ata_dma_check_80pin) { if (bootverbose) device_printf(dev, "Skipping 80pin cable check\n"); return mode; } if (mode > ATA_UDMA2 && !(atadev->param.hwres & ATA_CABLE_ID)) { ata_print_cable(dev, "device"); mode = ATA_UDMA2; } return mode; } char * ata_pcivendor2str(device_t dev) { switch (pci_get_vendor(dev)) { case ATA_ACARD_ID: return "Acard"; case ATA_ACER_LABS_ID: return "AcerLabs"; case ATA_AMD_ID: return "AMD"; case ATA_ADAPTEC_ID: return "Adaptec"; case ATA_ATI_ID: return "ATI"; case ATA_CYRIX_ID: return "Cyrix"; case ATA_CYPRESS_ID: return "Cypress"; case ATA_HIGHPOINT_ID: return "HighPoint"; case ATA_INTEL_ID: return "Intel"; case ATA_ITE_ID: return "ITE"; case ATA_JMICRON_ID: return "JMicron"; case ATA_MARVELL_ID: return "Marvell"; case ATA_NATIONAL_ID: return "National"; case ATA_NETCELL_ID: return "Netcell"; case ATA_NVIDIA_ID: return "nVidia"; case ATA_PROMISE_ID: return "Promise"; case ATA_SERVERWORKS_ID: return "ServerWorks"; case ATA_SILICON_IMAGE_ID: return "SiI"; case ATA_SIS_ID: return "SiS"; case ATA_VIA_ID: return "VIA"; case ATA_CENATEK_ID: return "Cenatek"; case ATA_MICRON_ID: return "Micron"; default: return "Generic"; } } 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-queue.c b/sys/dev/ata/ata-queue.c index c0eb558e717b..eeb7a1a48055 100644 --- a/sys/dev/ata/ata-queue.c +++ b/sys/dev/ata/ata-queue.c @@ -1,785 +1,793 @@ /*- * Copyright (c) 1998 - 2008 Søren Schmidt * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer, * without modification, immediately at the beginning of the file. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * 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. */ #include __FBSDID("$FreeBSD$"); #include "opt_ata.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* prototypes */ static void ata_completed(void *, int); static void ata_sort_queue(struct ata_channel *ch, struct ata_request *request); static char *ata_skey2str(u_int8_t); void ata_queue_request(struct ata_request *request) { struct ata_channel *ch; + struct ata_device *atadev = device_get_softc(request->dev); /* treat request as virgin (this might be an ATA_R_REQUEUE) */ request->result = request->status = request->error = 0; - /* check that the device is still valid */ + /* Prepare paramers required by low-level code. */ + request->unit = atadev->unit; if (!(request->parent = device_get_parent(request->dev))) { request->result = ENXIO; if (request->callback) (request->callback)(request); return; } + if ((atadev->param.config & ATA_PROTO_MASK) == ATA_PROTO_ATAPI_16) + request->flags |= ATA_R_ATAPI16; + if ((atadev->param.config & ATA_DRQ_MASK) == ATA_DRQ_INTR) + request->flags |= ATA_R_ATAPI_INTR; + if ((request->flags & ATA_R_ATAPI) == 0) + ata_modify_if_48bit(request); ch = device_get_softc(request->parent); callout_init_mtx(&request->callout, &ch->state_mtx, CALLOUT_RETURNUNLOCKED); if (!request->callback && !(request->flags & ATA_R_REQUEUE)) sema_init(&request->done, 0, "ATA request done"); /* in ATA_STALL_QUEUE state we call HW directly */ if ((ch->state & ATA_STALL_QUEUE) && (request->flags & ATA_R_CONTROL)) { mtx_lock(&ch->state_mtx); ch->running = request; if (ch->hw.begin_transaction(request) == ATA_OP_FINISHED) { ch->running = NULL; if (!request->callback) sema_destroy(&request->done); mtx_unlock(&ch->state_mtx); return; } mtx_unlock(&ch->state_mtx); } /* otherwise put request on the locked queue at the specified location */ else { mtx_lock(&ch->queue_mtx); if (request->flags & ATA_R_AT_HEAD) TAILQ_INSERT_HEAD(&ch->ata_queue, request, chain); else if (request->flags & ATA_R_ORDERED) ata_sort_queue(ch, request); else TAILQ_INSERT_TAIL(&ch->ata_queue, request, chain); mtx_unlock(&ch->queue_mtx); ATA_DEBUG_RQ(request, "queued"); ata_start(ch->dev); } /* if this is a requeued request callback/sleep we're done */ if (request->flags & ATA_R_REQUEUE) return; /* if this is not a callback wait until request is completed */ if (!request->callback) { ATA_DEBUG_RQ(request, "wait for completion"); if (!dumping && sema_timedwait(&request->done, request->timeout * hz * 4)) { device_printf(request->dev, "WARNING - %s taskqueue timeout " "- completing request directly\n", ata_cmd2str(request)); request->flags |= ATA_R_DANGER1; ata_completed(request, 0); } sema_destroy(&request->done); } } int ata_controlcmd(device_t dev, u_int8_t command, u_int16_t feature, u_int64_t lba, u_int16_t count) { struct ata_device *atadev = device_get_softc(dev); struct ata_request *request = ata_alloc_request(); int error = ENOMEM; if (request) { request->dev = dev; 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; if (atadev->spindown_state) { device_printf(dev, "request while spun down, starting.\n"); atadev->spindown_state = 0; request->timeout = 31; } else { request->timeout = 10; } request->retries = 0; ata_queue_request(request); error = request->result; ata_free_request(request); } return error; } int ata_atapicmd(device_t dev, u_int8_t *ccb, caddr_t data, int count, int flags, int timeout) { struct ata_request *request = ata_alloc_request(); int error = ENOMEM; if (request) { request->dev = dev; bcopy(ccb, request->u.atapi.ccb, 16); request->data = data; request->bytecount = count; request->transfersize = min(request->bytecount, 65534); request->flags = flags | ATA_R_ATAPI; request->timeout = timeout; request->retries = 0; ata_queue_request(request); error = request->result; ata_free_request(request); } return error; } void ata_start(device_t dev) { struct ata_channel *ch = device_get_softc(dev); struct ata_request *request; struct ata_composite *cptr; int dependencies = 0; /* if we have a request on the queue try to get it running */ mtx_lock(&ch->queue_mtx); if ((request = TAILQ_FIRST(&ch->ata_queue))) { /* we need the locking function to get the lock for this channel */ if (ATA_LOCKING(dev, ATA_LF_LOCK) == ch->unit) { /* check for composite dependencies */ if ((cptr = request->composite)) { mtx_lock(&cptr->lock); if ((request->flags & ATA_R_WRITE) && (cptr->wr_depend & cptr->rd_done) != cptr->wr_depend) { dependencies = 1; } mtx_unlock(&cptr->lock); } /* check we are in the right state and has no dependencies */ mtx_lock(&ch->state_mtx); if (ch->state == ATA_IDLE && !dependencies) { ATA_DEBUG_RQ(request, "starting"); TAILQ_REMOVE(&ch->ata_queue, request, chain); ch->running = request; ch->state = ATA_ACTIVE; /* if we are the freezing point release it */ if (ch->freezepoint == request) ch->freezepoint = NULL; if (ch->hw.begin_transaction(request) == ATA_OP_FINISHED) { ch->running = NULL; ch->state = ATA_IDLE; mtx_unlock(&ch->state_mtx); mtx_unlock(&ch->queue_mtx); ATA_LOCKING(dev, ATA_LF_UNLOCK); ata_finish(request); return; } } mtx_unlock(&ch->state_mtx); } } mtx_unlock(&ch->queue_mtx); if (dumping) { while (ch->running) { ata_interrupt(ch); DELAY(10); } } } void ata_finish(struct ata_request *request) { struct ata_channel *ch = device_get_softc(request->parent); /* * if in ATA_STALL_QUEUE state or request has ATA_R_DIRECT flags set * we need to call ata_complete() directly here (no taskqueue involvement) */ if (dumping || (ch->state & ATA_STALL_QUEUE) || (request->flags & ATA_R_DIRECT)) { ATA_DEBUG_RQ(request, "finish directly"); ata_completed(request, 0); } else { /* put request on the proper taskqueue for completion */ if (request->bio && !(request->flags & (ATA_R_THREAD | ATA_R_TIMEOUT))){ ATA_DEBUG_RQ(request, "finish bio_taskqueue"); bio_taskqueue(request->bio, (bio_task_t *)ata_completed, request); } else { TASK_INIT(&request->task, 0, ata_completed, request); ATA_DEBUG_RQ(request, "finish taskqueue_swi"); taskqueue_enqueue(taskqueue_swi, &request->task); } } } static void ata_completed(void *context, int dummy) { struct ata_request *request = (struct ata_request *)context; struct ata_channel *ch = device_get_softc(request->parent); struct ata_device *atadev = device_get_softc(request->dev); struct ata_composite *composite; if (request->flags & ATA_R_DANGER2) { device_printf(request->dev, "WARNING - %s freeing taskqueue zombie request\n", ata_cmd2str(request)); request->flags &= ~(ATA_R_DANGER1 | ATA_R_DANGER2); ata_free_request(request); return; } if (request->flags & ATA_R_DANGER1) request->flags |= ATA_R_DANGER2; ATA_DEBUG_RQ(request, "completed entered"); /* if we had a timeout, reinit channel and deal with the falldown */ if (request->flags & ATA_R_TIMEOUT) { /* * if the channel is still present and * reinit succeeds and * the device doesn't get detached and * there are retries left we reinject this request */ if (ch && !ata_reinit(ch->dev) && !request->result && (request->retries-- > 0)) { if (!(request->flags & ATA_R_QUIET)) { device_printf(request->dev, "TIMEOUT - %s retrying (%d retr%s left)", ata_cmd2str(request), request->retries, request->retries == 1 ? "y" : "ies"); if (!(request->flags & (ATA_R_ATAPI | ATA_R_CONTROL))) printf(" LBA=%ju", request->u.ata.lba); printf("\n"); } request->flags &= ~(ATA_R_TIMEOUT | ATA_R_DEBUG); request->flags |= (ATA_R_AT_HEAD | ATA_R_REQUEUE); ATA_DEBUG_RQ(request, "completed reinject"); ata_queue_request(request); return; } /* ran out of good intentions so finish with error */ if (!request->result) { if (!(request->flags & ATA_R_QUIET)) { if (request->dev) { device_printf(request->dev, "FAILURE - %s timed out", ata_cmd2str(request)); if (!(request->flags & (ATA_R_ATAPI | ATA_R_CONTROL))) printf(" LBA=%ju", request->u.ata.lba); printf("\n"); } } request->result = EIO; } } else if (!(request->flags & ATA_R_ATAPI) ){ /* if this is a soft ECC error warn about it */ /* XXX SOS we could do WARF here */ if ((request->status & (ATA_S_CORR | ATA_S_ERROR)) == ATA_S_CORR) { device_printf(request->dev, "WARNING - %s soft error (ECC corrected)", ata_cmd2str(request)); if (!(request->flags & (ATA_R_ATAPI | ATA_R_CONTROL))) printf(" LBA=%ju", request->u.ata.lba); printf("\n"); } /* if this is a UDMA CRC error we reinject if there are retries left */ if (request->flags & ATA_R_DMA && request->error & ATA_E_ICRC) { if (request->retries-- > 0) { device_printf(request->dev, "WARNING - %s UDMA ICRC error (retrying request)", ata_cmd2str(request)); if (!(request->flags & (ATA_R_ATAPI | ATA_R_CONTROL))) printf(" LBA=%ju", request->u.ata.lba); printf("\n"); request->flags |= (ATA_R_AT_HEAD | ATA_R_REQUEUE); ata_queue_request(request); return; } } } switch (request->flags & ATA_R_ATAPI) { /* ATA errors */ default: if (!request->result && request->status & ATA_S_ERROR) { if (!(request->flags & ATA_R_QUIET)) { device_printf(request->dev, "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->dma && (request->dma->status & ATA_BMSTAT_ERROR)) printf(" dma=0x%02x", request->dma->status); if (!(request->flags & (ATA_R_ATAPI | ATA_R_CONTROL))) printf(" LBA=%ju", request->u.ata.lba); printf("\n"); } request->result = EIO; } break; /* ATAPI errors */ case ATA_R_ATAPI: /* skip if result already set */ if (request->result) break; /* if we have a sensekey -> request sense from device */ if ((request->error & ATA_E_ATAPI_SENSE_MASK) && (request->u.atapi.ccb[0] != ATAPI_REQUEST_SENSE)) { static u_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 }; request->u.atapi.saved_cmd = request->u.atapi.ccb[0]; bcopy(ccb, request->u.atapi.ccb, 16); request->data = (caddr_t)&request->u.atapi.sense; request->bytecount = sizeof(struct atapi_sense); request->donecount = 0; request->transfersize = sizeof(struct atapi_sense); request->timeout = 10; request->flags &= (ATA_R_ATAPI | ATA_R_QUIET | ATA_R_DEBUG); request->flags |= (ATA_R_READ | ATA_R_AT_HEAD | ATA_R_REQUEUE); ATA_DEBUG_RQ(request, "autoissue request sense"); ata_queue_request(request); return; } switch (request->u.atapi.sense.key & ATA_SENSE_KEY_MASK) { case ATA_SENSE_RECOVERED_ERROR: device_printf(request->dev, "WARNING - %s recovered error\n", ata_cmd2str(request)); /* FALLTHROUGH */ case ATA_SENSE_NO_SENSE: request->result = 0; break; case ATA_SENSE_NOT_READY: request->result = EBUSY; break; case ATA_SENSE_UNIT_ATTENTION: atadev->flags |= ATA_D_MEDIA_CHANGED; request->result = EIO; break; default: request->result = EIO; if (request->flags & ATA_R_QUIET) break; device_printf(request->dev, "FAILURE - %s %s asc=0x%02x ascq=0x%02x ", ata_cmd2str(request), ata_skey2str( (request->u.atapi.sense.key & ATA_SENSE_KEY_MASK)), request->u.atapi.sense.asc, request->u.atapi.sense.ascq); if (request->u.atapi.sense.specific & ATA_SENSE_SPEC_VALID) printf("sks=0x%02x 0x%02x 0x%02x\n", request->u.atapi.sense.specific & ATA_SENSE_SPEC_MASK, request->u.atapi.sense.specific1, request->u.atapi.sense.specific2); else printf("\n"); } if (!request->result && (request->u.atapi.sense.key & ATA_SENSE_KEY_MASK || request->error)) request->result = EIO; } ATA_DEBUG_RQ(request, "completed callback/wakeup"); /* if we are part of a composite operation we need to maintain progress */ if ((composite = request->composite)) { int index = 0; mtx_lock(&composite->lock); /* update whats done */ if (request->flags & ATA_R_READ) composite->rd_done |= (1 << request->this); if (request->flags & ATA_R_WRITE) composite->wr_done |= (1 << request->this); /* find ready to go dependencies */ if (composite->wr_depend && (composite->rd_done & composite->wr_depend)==composite->wr_depend && (composite->wr_needed & (~composite->wr_done))) { index = composite->wr_needed & ~composite->wr_done; } mtx_unlock(&composite->lock); /* if we have any ready candidates kick them off */ if (index) { int bit; for (bit = 0; bit < MAX_COMPOSITES; bit++) { if (index & (1 << bit)) ata_start(device_get_parent(composite->request[bit]->dev)); } } } /* get results back to the initiator for this request */ if (request->callback) (request->callback)(request); else sema_post(&request->done); /* only call ata_start if channel is present */ if (ch) ata_start(ch->dev); } void ata_timeout(struct ata_request *request) { struct ata_channel *ch = device_get_softc(request->parent); //request->flags |= ATA_R_DEBUG; ATA_DEBUG_RQ(request, "timeout"); /* * if we have an ATA_ACTIVE request running, we flag the request * ATA_R_TIMEOUT so ata_finish will handle it correctly * also NULL out the running request so we wont loose * the race with an eventual interrupt arriving late */ if (ch->state == ATA_ACTIVE) { request->flags |= ATA_R_TIMEOUT; mtx_unlock(&ch->state_mtx); ATA_LOCKING(ch->dev, ATA_LF_UNLOCK); if (ch->dma.unload) ch->dma.unload(request); ata_finish(request); } else { mtx_unlock(&ch->state_mtx); } } void ata_fail_requests(device_t dev) { struct ata_channel *ch = device_get_softc(device_get_parent(dev)); struct ata_request *request, *tmp; TAILQ_HEAD(, ata_request) fail_requests; TAILQ_INIT(&fail_requests); /* grap all channel locks to avoid races */ mtx_lock(&ch->queue_mtx); mtx_lock(&ch->state_mtx); /* do we have any running request to care about ? */ if ((request = ch->running) && (!dev || request->dev == dev)) { callout_stop(&request->callout); ch->running = NULL; request->result = ENXIO; TAILQ_INSERT_TAIL(&fail_requests, request, chain); } /* fail all requests queued on this channel for device dev if !NULL */ TAILQ_FOREACH_SAFE(request, &ch->ata_queue, chain, tmp) { if (!dev || request->dev == dev) { TAILQ_REMOVE(&ch->ata_queue, request, chain); request->result = ENXIO; TAILQ_INSERT_TAIL(&fail_requests, request, chain); } } mtx_unlock(&ch->state_mtx); mtx_unlock(&ch->queue_mtx); /* finish up all requests collected above */ TAILQ_FOREACH_SAFE(request, &fail_requests, chain, tmp) { TAILQ_REMOVE(&fail_requests, request, chain); ata_finish(request); } } /* * Rudely drop all requests queued to the channel of specified device. * XXX: The requests are leaked, use only in fatal case. */ void ata_drop_requests(device_t dev) { struct ata_channel *ch = device_get_softc(device_get_parent(dev)); struct ata_request *request, *tmp; mtx_lock(&ch->queue_mtx); TAILQ_FOREACH_SAFE(request, &ch->ata_queue, chain, tmp) { TAILQ_REMOVE(&ch->ata_queue, request, chain); request->result = ENXIO; } mtx_unlock(&ch->queue_mtx); } static u_int64_t ata_get_lba(struct ata_request *request) { if (request->flags & ATA_R_ATAPI) { switch (request->u.atapi.ccb[0]) { case ATAPI_READ_BIG: case ATAPI_WRITE_BIG: case ATAPI_READ_CD: return (request->u.atapi.ccb[5]) | (request->u.atapi.ccb[4]<<8) | (request->u.atapi.ccb[3]<<16)|(request->u.atapi.ccb[2]<<24); case ATAPI_READ: case ATAPI_WRITE: return (request->u.atapi.ccb[4]) | (request->u.atapi.ccb[3]<<8) | (request->u.atapi.ccb[2]<<16); default: return 0; } } else return request->u.ata.lba; } static void ata_sort_queue(struct ata_channel *ch, struct ata_request *request) { struct ata_request *this, *next; this = TAILQ_FIRST(&ch->ata_queue); /* if the queue is empty just insert */ if (!this) { if (request->composite) ch->freezepoint = request; TAILQ_INSERT_TAIL(&ch->ata_queue, request, chain); return; } /* dont sort frozen parts of the queue */ if (ch->freezepoint) this = ch->freezepoint; /* if position is less than head we add after tipping point */ if (ata_get_lba(request) < ata_get_lba(this)) { while ((next = TAILQ_NEXT(this, chain))) { /* have we reached the tipping point */ if (ata_get_lba(next) < ata_get_lba(this)) { /* sort the insert */ do { if (ata_get_lba(request) < ata_get_lba(next)) break; this = next; } while ((next = TAILQ_NEXT(this, chain))); break; } this = next; } } /* we are after head so sort the insert before tipping point */ else { while ((next = TAILQ_NEXT(this, chain))) { if (ata_get_lba(next) < ata_get_lba(this) || ata_get_lba(request) < ata_get_lba(next)) break; this = next; } } if (request->composite) ch->freezepoint = request; TAILQ_INSERT_AFTER(&ch->ata_queue, this, request, chain); } char * ata_cmd2str(struct ata_request *request) { static char buffer[20]; if (request->flags & ATA_R_ATAPI) { switch (request->u.atapi.sense.key ? request->u.atapi.saved_cmd : 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 0x12: return ("INQUIRY"); 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 0x96: return ("SERVICE_ACTION_IN"); 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 ("DEVICE_RESET"); case 0x20: return ("READ"); case 0x24: return ("READ48"); case 0x25: return ("READ_DMA48"); case 0x26: return ("READ_DMA_QUEUED48"); case 0x27: return ("READ_NATIVE_MAX_ADDRESS48"); 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 0x37: return ("SET_MAX_ADDRESS48"); case 0x39: return ("WRITE_MUL48"); case 0x70: return ("SEEK"); case 0xa0: return ("PACKET_CMD"); case 0xa1: return ("ATAPI_IDENTIFY"); case 0xa2: return ("SERVICE"); case 0xb0: return ("SMART"); case 0xc0: return ("CFA ERASE"); 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: switch (request->u.ata.feature) { case 0x03: return ("SETFEATURES SET TRANSFER MODE"); case 0x02: return ("SETFEATURES ENABLE WCACHE"); case 0x82: return ("SETFEATURES DISABLE WCACHE"); case 0xaa: return ("SETFEATURES ENABLE RCACHE"); case 0x55: return ("SETFEATURES DISABLE RCACHE"); } sprintf(buffer, "SETFEATURES 0x%02x", request->u.ata.feature); return buffer; case 0xf5: return ("SECURITY_FREE_LOCK"); case 0xf8: return ("READ_NATIVE_MAX_ADDRESS"); case 0xf9: return ("SET_MAX_ADDRESS"); } } sprintf(buffer, "unknown CMD (0x%02x)", request->u.ata.command); return buffer; } static char * ata_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/ata-sata.c b/sys/dev/ata/ata-sata.c index b00bf01e5085..5f5daa48f3f4 100644 --- a/sys/dev/ata/ata-sata.c +++ b/sys/dev/ata/ata-sata.c @@ -1,374 +1,369 @@ /*- * Copyright (c) 1998 - 2008 Søren Schmidt * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer, * without modification, immediately at the beginning of the file. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * 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. */ #include __FBSDID("$FreeBSD$"); #include "opt_ata.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include void ata_sata_phy_check_events(device_t dev) { struct ata_channel *ch = device_get_softc(dev); u_int32_t error = ATA_IDX_INL(ch, ATA_SERROR); /* clear error bits/interrupt */ ATA_IDX_OUTL(ch, ATA_SERROR, error); /* if we have a connection event deal with it */ if ((error & ATA_SE_PHY_CHANGED) && (ch->pm_level == 0)) { if (bootverbose) { u_int32_t status = ATA_IDX_INL(ch, ATA_SSTATUS); if (((status & ATA_SS_CONWELL_MASK) == ATA_SS_CONWELL_GEN1) || ((status & ATA_SS_CONWELL_MASK) == ATA_SS_CONWELL_GEN2)) { device_printf(dev, "CONNECT requested\n"); } else device_printf(dev, "DISCONNECT requested\n"); } taskqueue_enqueue(taskqueue_thread, &ch->conntask); } } int ata_sata_scr_read(struct ata_channel *ch, int port, int reg, uint32_t *val) { int r; if (port < 0) { *val = ATA_IDX_INL(ch, reg); return (0); } else { switch (reg) { case ATA_SSTATUS: r = 0; break; case ATA_SERROR: r = 1; break; case ATA_SCONTROL: r = 2; break; default: return (EINVAL); } return (ch->hw.pm_read(ch->dev, port, r, val)); } } int ata_sata_scr_write(struct ata_channel *ch, int port, int reg, uint32_t val) { int r; if (port < 0) { ATA_IDX_OUTL(ch, reg, val); return (0); } else { switch (reg) { case ATA_SERROR: r = 1; break; case ATA_SCONTROL: r = 2; break; default: return (EINVAL); } return (ch->hw.pm_write(ch->dev, port, r, val)); } } static int ata_sata_connect(struct ata_channel *ch, int port) { u_int32_t status; int timeout; /* wait up to 1 second for "connect well" */ for (timeout = 0; timeout < 100 ; timeout++) { if (ata_sata_scr_read(ch, port, ATA_SSTATUS, &status)) return (0); if ((status & ATA_SS_CONWELL_MASK) == ATA_SS_CONWELL_GEN1 || (status & ATA_SS_CONWELL_MASK) == ATA_SS_CONWELL_GEN2) break; ata_udelay(10000); } if (timeout >= 100) { if (bootverbose) { if (port < 0) { device_printf(ch->dev, "SATA connect timeout status=%08x\n", status); } else { device_printf(ch->dev, "p%d: SATA connect timeout status=%08x\n", port, status); } } return 0; } if (bootverbose) { if (port < 0) { device_printf(ch->dev, "SATA connect time=%dms status=%08x\n", timeout * 10, status); } else { device_printf(ch->dev, "p%d: SATA connect time=%dms status=%08x\n", port, timeout * 10, status); } } /* clear SATA error register */ ata_sata_scr_write(ch, port, ATA_SERROR, 0xffffffff); return 1; } int ata_sata_phy_reset(device_t dev, int port, int quick) { struct ata_channel *ch = device_get_softc(dev); int loop, retry; uint32_t val; if (quick) { if (ata_sata_scr_read(ch, port, ATA_SCONTROL, &val)) return (0); if ((val & ATA_SC_DET_MASK) == ATA_SC_DET_IDLE) return ata_sata_connect(ch, port); } if (bootverbose) { if (port < 0) { device_printf(dev, "hardware reset ...\n"); } else { device_printf(dev, "p%d: hardware reset ...\n", port); } } for (retry = 0; retry < 10; retry++) { for (loop = 0; loop < 10; loop++) { if (ata_sata_scr_write(ch, port, ATA_SCONTROL, ATA_SC_DET_RESET)) return (0); ata_udelay(100); if (ata_sata_scr_read(ch, port, ATA_SCONTROL, &val)) return (0); if ((val & ATA_SC_DET_MASK) == ATA_SC_DET_RESET) break; } ata_udelay(5000); for (loop = 0; loop < 10; loop++) { if (ata_sata_scr_write(ch, port, ATA_SCONTROL, ATA_SC_DET_IDLE | ((ch->pm_level > 0) ? 0 : ATA_SC_IPM_DIS_PARTIAL | ATA_SC_IPM_DIS_SLUMBER))) return (0); ata_udelay(100); if (ata_sata_scr_read(ch, port, ATA_SCONTROL, &val)) return (0); if ((val & ATA_SC_DET_MASK) == 0) return ata_sata_connect(ch, port); } } return 0; } void ata_sata_setmode(device_t dev, int mode) { struct ata_device *atadev = device_get_softc(dev); /* * if we detect that the device isn't a real SATA device we limit * the transfer mode to UDMA5/ATA100. * this works around the problems some devices has with the * Marvell 88SX8030 SATA->PATA converters and UDMA6/ATA133. */ if (atadev->param.satacapabilities != 0x0000 && atadev->param.satacapabilities != 0xffff) { struct ata_channel *ch = device_get_softc(device_get_parent(dev)); /* on some drives we need to set the transfer mode */ ata_controlcmd(dev, ATA_SETFEATURES, ATA_SF_SETXFER, 0, ata_limit_mode(dev, mode, ATA_UDMA6)); /* query SATA STATUS for the speed */ if (ch->r_io[ATA_SSTATUS].res && ((ATA_IDX_INL(ch, ATA_SSTATUS) & ATA_SS_CONWELL_MASK) == ATA_SS_CONWELL_GEN2)) atadev->mode = ATA_SA300; else atadev->mode = ATA_SA150; } else { mode = ata_limit_mode(dev, mode, ATA_UDMA5); if (!ata_controlcmd(dev, ATA_SETFEATURES, ATA_SF_SETXFER, 0, mode)) atadev->mode = mode; } } int ata_request2fis_h2d(struct ata_request *request, u_int8_t *fis) { - struct ata_device *atadev = device_get_softc(request->dev); if (request->flags & ATA_R_ATAPI) { fis[0] = 0x27; /* host to device */ - fis[1] = 0x80 | (atadev->unit & 0x0f); + fis[1] = 0x80 | (request->unit & 0x0f); fis[2] = ATA_PACKET_CMD; if (request->flags & (ATA_R_READ | ATA_R_WRITE)) fis[3] = ATA_F_DMA; else { fis[5] = request->transfersize; fis[6] = request->transfersize >> 8; } fis[7] = ATA_D_LBA; fis[15] = ATA_A_4BIT; return 20; } else { - ata_modify_if_48bit(request); fis[0] = 0x27; /* host to device */ - fis[1] = 0x80 | (atadev->unit & 0x0f); + fis[1] = 0x80 | (request->unit & 0x0f); fis[2] = request->u.ata.command; fis[3] = request->u.ata.feature; fis[4] = request->u.ata.lba; fis[5] = request->u.ata.lba >> 8; fis[6] = request->u.ata.lba >> 16; fis[7] = ATA_D_LBA; - if (!(atadev->flags & ATA_D_48BIT_ACTIVE)) + if (!(request->flags & ATA_R_48BIT)) fis[7] |= (ATA_D_IBM | (request->u.ata.lba >> 24 & 0x0f)); fis[8] = request->u.ata.lba >> 24; fis[9] = request->u.ata.lba >> 32; fis[10] = request->u.ata.lba >> 40; fis[11] = request->u.ata.feature >> 8; fis[12] = request->u.ata.count; fis[13] = request->u.ata.count >> 8; fis[15] = ATA_A_4BIT; return 20; } return 0; } void ata_pm_identify(device_t dev) { struct ata_channel *ch = device_get_softc(dev); u_int32_t pm_chipid, pm_revision, pm_ports; int port; /* get PM vendor & product data */ if (ch->hw.pm_read(dev, ATA_PM, 0, &pm_chipid)) { device_printf(dev, "error getting PM vendor data\n"); return; } /* get PM revision data */ if (ch->hw.pm_read(dev, ATA_PM, 1, &pm_revision)) { device_printf(dev, "error getting PM revison data\n"); return; } /* get number of HW ports on the PM */ if (ch->hw.pm_read(dev, ATA_PM, 2, &pm_ports)) { device_printf(dev, "error getting PM port info\n"); return; } pm_ports &= 0x0000000f; /* chip specific quirks */ switch (pm_chipid) { case 0x37261095: /* This PM declares 6 ports, while only 5 of them are real. * Port 5 is enclosure management bridge port, which has implementation * problems, causing probe faults. Hide it for now. */ device_printf(dev, "SiI 3726 (rev=%x) Port Multiplier with %d (5) ports\n", pm_revision, pm_ports); pm_ports = 5; break; case 0x47261095: /* This PM declares 7 ports, while only 5 of them are real. * Port 5 is some fake "Config Disk" with 640 sectors size, * port 6 is enclosure management bridge port. * Both fake ports has implementation problems, causing * probe faults. Hide them for now. */ device_printf(dev, "SiI 4726 (rev=%x) Port Multiplier with %d (5) ports\n", pm_revision, pm_ports); pm_ports = 5; break; default: device_printf(dev, "Port Multiplier (id=%08x rev=%x) with %d ports\n", pm_chipid, pm_revision, pm_ports); } - /* realloc space for needed DMA slots */ - ch->dma.dma_slots = pm_ports; - /* reset all ports and register if anything connected */ for (port=0; port < pm_ports; port++) { u_int32_t signature; if (!ata_sata_phy_reset(dev, port, 1)) continue; /* * XXX: I have no idea how to properly wait for PMP port hardreset * completion. Without this delay soft reset does not completes * successfully. */ DELAY(1000000); signature = ch->hw.softreset(dev, port); if (bootverbose) device_printf(dev, "p%d: SIGNATURE=%08x\n", port, signature); /* figure out whats there */ switch (signature >> 16) { case 0x0000: ch->devices |= (ATA_ATA_MASTER << port); continue; case 0xeb14: ch->devices |= (ATA_ATAPI_MASTER << port); continue; } } } diff --git a/sys/dev/ata/chipsets/ata-ahci.c b/sys/dev/ata/chipsets/ata-ahci.c index 79544bb85546..9e3f9af94b66 100644 --- a/sys/dev/ata/chipsets/ata-ahci.c +++ b/sys/dev/ata/chipsets/ata-ahci.c @@ -1,933 +1,926 @@ /*- * Copyright (c) 1998 - 2008 Søren Schmidt * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer, * without modification, immediately at the beginning of the file. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * 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. */ #include __FBSDID("$FreeBSD$"); #include "opt_ata.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* local prototypes */ static int ata_ahci_suspend(device_t dev); static int ata_ahci_status(device_t dev); static int ata_ahci_begin_transaction(struct ata_request *request); static int ata_ahci_end_transaction(struct ata_request *request); static int ata_ahci_pm_read(device_t dev, int port, int reg, u_int32_t *result); static int ata_ahci_pm_write(device_t dev, int port, int reg, u_int32_t result); static int ata_ahci_hardreset(device_t dev, int port, uint32_t *signature); static u_int32_t ata_ahci_softreset(device_t dev, int port); static void ata_ahci_dmasetprd(void *xsc, bus_dma_segment_t *segs, int nsegs, int error); static int ata_ahci_setup_fis(struct ata_ahci_cmd_tab *ctp, struct ata_request *equest); static void ata_ahci_dmainit(device_t dev); static void ata_ahci_start(device_t dev); static void ata_ahci_stop(device_t dev); static void ata_ahci_clo(device_t dev); static void ata_ahci_start_fr(device_t dev); static void ata_ahci_stop_fr(device_t dev); /* * AHCI v1.x compliant SATA chipset support functions */ static int ata_ahci_probe(device_t dev) { struct ata_pci_controller *ctlr = device_get_softc(dev); char buffer[64]; /* is this a possible AHCI candidate ? */ if (pci_get_class(dev) != PCIC_STORAGE || pci_get_subclass(dev) != PCIS_STORAGE_SATA) return (ENXIO); /* is this PCI device flagged as an AHCI compliant chip ? */ if (pci_get_progif(dev) != PCIP_STORAGE_SATA_AHCI_1_0) return (ENXIO); if (bootverbose) sprintf(buffer, "%s (ID=%08x) AHCI controller", ata_pcivendor2str(dev), pci_get_devid(dev)); else sprintf(buffer, "%s AHCI controller", ata_pcivendor2str(dev)); device_set_desc_copy(dev, buffer); ctlr->chipinit = ata_ahci_chipinit; return (BUS_PROBE_GENERIC); } int ata_ahci_chipinit(device_t dev) { struct ata_pci_controller *ctlr = device_get_softc(dev); int error, speed; u_int32_t caps, version; /* if we have a memory BAR(5) we are likely on an AHCI part */ ctlr->r_type2 = SYS_RES_MEMORY; ctlr->r_rid2 = PCIR_BAR(5); if (!(ctlr->r_res2 = bus_alloc_resource_any(dev, ctlr->r_type2, &ctlr->r_rid2, RF_ACTIVE))) return ENXIO; /* setup interrupt delivery if not done allready by a vendor driver */ if (!ctlr->r_irq) { if (ata_setup_interrupt(dev, ata_generic_intr)) { bus_release_resource(dev, ctlr->r_type2, ctlr->r_rid2, ctlr->r_res2); return ENXIO; } } else device_printf(dev, "AHCI called from vendor specific driver\n"); /* reset controller */ if ((error = ata_ahci_ctlr_reset(dev)) != 0) { bus_release_resource(dev, ctlr->r_type2, ctlr->r_rid2, ctlr->r_res2); return (error); }; /* get the number of HW channels */ ctlr->ichannels = ATA_INL(ctlr->r_res2, ATA_AHCI_PI); ctlr->channels = MAX(flsl(ctlr->ichannels), (ATA_INL(ctlr->r_res2, ATA_AHCI_CAP) & ATA_AHCI_CAP_NPMASK) + 1); ctlr->reset = ata_ahci_reset; ctlr->ch_attach = ata_ahci_ch_attach; ctlr->ch_detach = ata_ahci_ch_detach; ctlr->ch_suspend = ata_ahci_ch_suspend; ctlr->ch_resume = ata_ahci_ch_resume; ctlr->setmode = ata_sata_setmode; ctlr->suspend = ata_ahci_suspend; ctlr->resume = ata_ahci_ctlr_reset; /* announce we support the HW */ version = ATA_INL(ctlr->r_res2, ATA_AHCI_VS); caps = ATA_INL(ctlr->r_res2, ATA_AHCI_CAP); speed = (caps & ATA_AHCI_CAP_ISS) >> ATA_AHCI_CAP_ISS_SHIFT; device_printf(dev, "AHCI v%x.%02x controller with %d %sGbps ports, PM %s\n", ((version >> 20) & 0xf0) + ((version >> 16) & 0x0f), ((version >> 4) & 0xf0) + (version & 0x0f), (caps & ATA_AHCI_CAP_NPMASK) + 1, ((speed == 1) ? "1.5":((speed == 2) ? "3": ((speed == 3) ? "6":"?"))), (caps & ATA_AHCI_CAP_SPM) ? "supported" : "not supported"); if (bootverbose) { device_printf(dev, "Caps:%s%s%s%s%s%s%s%s %sGbps", (caps & ATA_AHCI_CAP_64BIT) ? " 64bit":"", (caps & ATA_AHCI_CAP_SNCQ) ? " NCQ":"", (caps & ATA_AHCI_CAP_SSNTF) ? " SNTF":"", (caps & ATA_AHCI_CAP_SMPS) ? " MPS":"", (caps & ATA_AHCI_CAP_SSS) ? " SS":"", (caps & ATA_AHCI_CAP_SALP) ? " ALP":"", (caps & ATA_AHCI_CAP_SAL) ? " AL":"", (caps & ATA_AHCI_CAP_SCLO) ? " CLO":"", ((speed == 1) ? "1.5":((speed == 2) ? "3": ((speed == 3) ? "6":"?")))); printf("%s%s%s%s%s%s %dcmd%s%s%s %dports\n", (caps & ATA_AHCI_CAP_SAM) ? " AM":"", (caps & ATA_AHCI_CAP_SPM) ? " PM":"", (caps & ATA_AHCI_CAP_FBSS) ? " FBS":"", (caps & ATA_AHCI_CAP_PMD) ? " PMD":"", (caps & ATA_AHCI_CAP_SSC) ? " SSC":"", (caps & ATA_AHCI_CAP_PSC) ? " PSC":"", ((caps & ATA_AHCI_CAP_NCS) >> ATA_AHCI_CAP_NCS_SHIFT) + 1, (caps & ATA_AHCI_CAP_CCCS) ? " CCC":"", (caps & ATA_AHCI_CAP_EMS) ? " EM":"", (caps & ATA_AHCI_CAP_SXS) ? " eSATA":"", (caps & ATA_AHCI_CAP_NPMASK) + 1); } return 0; } int ata_ahci_ctlr_reset(device_t dev) { struct ata_pci_controller *ctlr = device_get_softc(dev); int timeout; /* enable AHCI mode */ ATA_OUTL(ctlr->r_res2, ATA_AHCI_GHC, ATA_AHCI_GHC_AE); /* reset AHCI controller */ ATA_OUTL(ctlr->r_res2, ATA_AHCI_GHC, ATA_AHCI_GHC_AE|ATA_AHCI_GHC_HR); for (timeout = 1000; timeout > 0; timeout--) { DELAY(1000); if ((ATA_INL(ctlr->r_res2, ATA_AHCI_GHC) & ATA_AHCI_GHC_HR) == 0) break; } if (timeout == 0) { device_printf(dev, "AHCI controller reset failure\n"); return ENXIO; } /* reenable AHCI mode */ ATA_OUTL(ctlr->r_res2, ATA_AHCI_GHC, ATA_AHCI_GHC_AE); /* clear interrupts */ ATA_OUTL(ctlr->r_res2, ATA_AHCI_IS, ATA_INL(ctlr->r_res2, ATA_AHCI_IS)); /* enable AHCI interrupts */ ATA_OUTL(ctlr->r_res2, ATA_AHCI_GHC, ATA_INL(ctlr->r_res2, ATA_AHCI_GHC) | ATA_AHCI_GHC_IE); return 0; } static int ata_ahci_suspend(device_t dev) { struct ata_pci_controller *ctlr = device_get_softc(dev); /* disable interupts so the state change(s) doesn't trigger */ ATA_OUTL(ctlr->r_res2, ATA_AHCI_GHC, ATA_INL(ctlr->r_res2, ATA_AHCI_GHC) & (~ATA_AHCI_GHC_IE)); return 0; } int ata_ahci_ch_attach(device_t dev) { struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev)); struct ata_channel *ch = device_get_softc(dev); int offset = ch->unit << 7; ata_ahci_dmainit(dev); /* set the SATA resources */ ch->r_io[ATA_SSTATUS].res = ctlr->r_res2; ch->r_io[ATA_SSTATUS].offset = ATA_AHCI_P_SSTS + offset; ch->r_io[ATA_SERROR].res = ctlr->r_res2; ch->r_io[ATA_SERROR].offset = ATA_AHCI_P_SERR + offset; ch->r_io[ATA_SCONTROL].res = ctlr->r_res2; ch->r_io[ATA_SCONTROL].offset = ATA_AHCI_P_SCTL + offset; ch->r_io[ATA_SACTIVE].res = ctlr->r_res2; ch->r_io[ATA_SACTIVE].offset = ATA_AHCI_P_SACT + offset; ch->hw.status = ata_ahci_status; ch->hw.begin_transaction = ata_ahci_begin_transaction; ch->hw.end_transaction = ata_ahci_end_transaction; ch->hw.command = NULL; /* not used here */ ch->hw.softreset = ata_ahci_softreset; ch->hw.pm_read = ata_ahci_pm_read; ch->hw.pm_write = ata_ahci_pm_write; ata_ahci_ch_resume(dev); return 0; } int ata_ahci_ch_detach(device_t dev) { ata_ahci_ch_suspend(dev); ata_dmafini(dev); return (0); } int ata_ahci_ch_suspend(device_t dev) { struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev)); struct ata_channel *ch = device_get_softc(dev); int offset = ch->unit << 7; /* Disable port interrupts. */ ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_IE + offset, 0); /* Reset command register. */ ata_ahci_stop(dev); ata_ahci_stop_fr(dev); ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_CMD + offset, 0); /* Allow everything including partial and slumber modes. */ ATA_IDX_OUTL(ch, ATA_SCONTROL, 0); /* Request slumber mode transition and give some time to get there. */ ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_CMD + offset, ATA_AHCI_P_CMD_SLUMBER); DELAY(100); /* Disable PHY. */ ATA_IDX_OUTL(ch, ATA_SCONTROL, ATA_SC_DET_DISABLE); return (0); } int ata_ahci_ch_resume(device_t dev) { struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev)); struct ata_channel *ch = device_get_softc(dev); uint64_t work; int offset = ch->unit << 7; /* Disable port interrupts */ ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_IE + offset, 0); /* setup work areas */ work = ch->dma.work_bus + ATA_AHCI_CL_OFFSET; ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_CLB + offset, work & 0xffffffff); ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_CLBU + offset, work >> 32); work = ch->dma.work_bus + ATA_AHCI_FB_OFFSET; ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_FB + offset, work & 0xffffffff); ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_FBU + offset, work >> 32); /* activate the channel and power/spin up device */ ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_CMD + offset, (ATA_AHCI_P_CMD_ACTIVE | ATA_AHCI_P_CMD_POD | ATA_AHCI_P_CMD_SUD | ((ch->pm_level > 1) ? ATA_AHCI_P_CMD_ALPE : 0) | ((ch->pm_level > 2) ? ATA_AHCI_P_CMD_ASP : 0 ))); ata_ahci_start_fr(dev); ata_ahci_start(dev); return (0); } static int ata_ahci_status(device_t dev) { struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev)); struct ata_channel *ch = device_get_softc(dev); u_int32_t action = ATA_INL(ctlr->r_res2, ATA_AHCI_IS); int offset = ch->unit << 7; #define ATA_AHCI_STATBITS \ (ATA_AHCI_P_IX_IF|ATA_AHCI_P_IX_HBD|ATA_AHCI_P_IX_HBF|ATA_AHCI_P_IX_TFE) if (action & (1 << ch->unit)) { u_int32_t istatus = ATA_INL(ctlr->r_res2, ATA_AHCI_P_IS + offset); u_int32_t cstatus = ATA_INL(ctlr->r_res2, ATA_AHCI_P_CI + offset); /* clear interrupt(s) */ ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_IS + offset, istatus); ATA_OUTL(ctlr->r_res2, ATA_AHCI_IS, 1 << ch->unit); /* do we have any PHY events ? */ if (istatus & (ATA_AHCI_P_IX_PRC | ATA_AHCI_P_IX_PC)) ata_sata_phy_check_events(dev); /* do we have a potentially hanging engine to take care of? */ /* XXX SOS what todo on NCQ */ if ((istatus & ATA_AHCI_STATBITS) && (cstatus & 1)) { u_int32_t cmd = ATA_INL(ctlr->r_res2, ATA_AHCI_P_CMD + offset); int timeout = 0; /* kill off all activity on this channel */ ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_CMD + offset, cmd & ~(ATA_AHCI_P_CMD_FRE | ATA_AHCI_P_CMD_ST)); /* XXX SOS this is not entirely wrong */ do { DELAY(1000); if (timeout++ > 1000) { device_printf(dev, "stopping AHCI engine failed\n"); break; } } while (ATA_INL(ctlr->r_res2, ATA_AHCI_P_CMD + offset) & ATA_AHCI_P_CMD_CR); /* start operations on this channel */ ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_CMD + offset, cmd | (ATA_AHCI_P_CMD_FRE | ATA_AHCI_P_CMD_ST)); return 1; } else /* XXX SOS what todo on NCQ */ return (!(cstatus & 1)); } return 0; } /* must be called with ATA channel locked and state_mtx held */ static int ata_ahci_begin_transaction(struct ata_request *request) { - struct ata_pci_controller *ctlr=device_get_softc(GRANDPARENT(request->dev)); + struct ata_pci_controller *ctlr=device_get_softc(device_get_parent(request->parent)); struct ata_channel *ch = device_get_softc(request->parent); - struct ata_device *atadev = device_get_softc(request->dev); struct ata_ahci_cmd_tab *ctp; struct ata_ahci_cmd_list *clp; int offset = ch->unit << 7; - int port = atadev->unit & 0x0f; + int port = request->unit & 0x0f; int entries = 0; int fis_size; /* get a piece of the workspace for this request */ ctp = (struct ata_ahci_cmd_tab *) - (ch->dma.work + ATA_AHCI_CT_OFFSET + (ATA_AHCI_CT_SIZE*request->tag)); + (ch->dma.work + ATA_AHCI_CT_OFFSET); /* setup the FIS for this request */ if (!(fis_size = ata_ahci_setup_fis(ctp, request))) { - device_printf(request->dev, "setting up SATA FIS failed\n"); + device_printf(request->parent, "setting up SATA FIS failed\n"); request->result = EIO; return ATA_OP_FINISHED; } /* if request moves data setup and load SG list */ if (request->flags & (ATA_R_READ | ATA_R_WRITE)) { if (ch->dma.load(request, ctp->prd_tab, &entries)) { - device_printf(request->dev, "setting up DMA failed\n"); + device_printf(request->parent, "setting up DMA failed\n"); request->result = EIO; return ATA_OP_FINISHED; } } /* setup the command list entry */ clp = (struct ata_ahci_cmd_list *) - (ch->dma.work + ATA_AHCI_CL_OFFSET + (ATA_AHCI_CL_SIZE*request->tag)); + (ch->dma.work + ATA_AHCI_CL_OFFSET); clp->prd_length = entries; clp->cmd_flags = (request->flags & ATA_R_WRITE ? ATA_AHCI_CMD_WRITE : 0) | (request->flags & ATA_R_ATAPI ? (ATA_AHCI_CMD_ATAPI | ATA_AHCI_CMD_PREFETCH) : 0) | (fis_size / sizeof(u_int32_t)) | (port << 12); clp->bytecount = 0; - clp->cmd_table_phys = htole64(ch->dma.work_bus + ATA_AHCI_CT_OFFSET + - (ATA_AHCI_CT_SIZE * request->tag)); - - /* clear eventual ACTIVE bit */ - ATA_IDX_OUTL(ch, ATA_SACTIVE, - ATA_IDX_INL(ch, ATA_SACTIVE) & (1 << request->tag)); + clp->cmd_table_phys = htole64(ch->dma.work_bus + ATA_AHCI_CT_OFFSET); /* set command type bit */ if (request->flags & ATA_R_ATAPI) ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_CMD + offset, ATA_INL(ctlr->r_res2, ATA_AHCI_P_CMD + offset) | ATA_AHCI_P_CMD_ATAPI); else ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_CMD + offset, ATA_INL(ctlr->r_res2, ATA_AHCI_P_CMD + offset) & ~ATA_AHCI_P_CMD_ATAPI); /* issue command to controller */ - ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_CI + offset, (1 << request->tag)); + ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_CI + offset, 1); if (!(request->flags & ATA_R_ATAPI)) { /* device reset doesn't interrupt */ if (request->u.ata.command == ATA_DEVICE_RESET) { u_int32_t tf_data; int timeout = 1000000; do { DELAY(10); tf_data = ATA_INL(ctlr->r_res2, ATA_AHCI_P_TFD + (ch->unit<<7)); } while ((tf_data & ATA_S_BUSY) && timeout--); if (bootverbose) device_printf(ch->dev, "device_reset timeout=%dus\n", (1000000-timeout)*10); request->status = tf_data; if (request->status & ATA_S_ERROR) request->error = tf_data >> 8; return ATA_OP_FINISHED; } } /* start the timeout */ callout_reset(&request->callout, request->timeout * hz, (timeout_t*)ata_timeout, request); return ATA_OP_CONTINUES; } /* must be called with ATA channel locked and state_mtx held */ static int ata_ahci_end_transaction(struct ata_request *request) { - struct ata_pci_controller *ctlr=device_get_softc(GRANDPARENT(request->dev)); + struct ata_pci_controller *ctlr=device_get_softc(device_get_parent(request->parent)); struct ata_channel *ch = device_get_softc(request->parent); struct ata_ahci_cmd_list *clp; u_int32_t tf_data; int offset = ch->unit << 7; /* kill the timeout */ callout_stop(&request->callout); /* get status */ tf_data = ATA_INL(ctlr->r_res2, ATA_AHCI_P_TFD + offset); request->status = tf_data; /* if error status get details */ if (request->status & ATA_S_ERROR) request->error = tf_data >> 8; /* on control commands read back registers to the request struct */ if (request->flags & ATA_R_CONTROL) { - struct ata_device *atadev = device_get_softc(request->dev); u_int8_t *fis = ch->dma.work + ATA_AHCI_FB_OFFSET + 0x40; request->u.ata.count = fis[12] | ((u_int16_t)fis[13] << 8); request->u.ata.lba = fis[4] | ((u_int64_t)fis[5] << 8) | ((u_int64_t)fis[6] << 16); - if (atadev->flags & ATA_D_48BIT_ACTIVE) + if (request->flags & ATA_R_48BIT) request->u.ata.lba |= ((u_int64_t)fis[8] << 24) | ((u_int64_t)fis[9] << 32) | ((u_int64_t)fis[10] << 40); else request->u.ata.lba |= ((u_int64_t)(fis[7] & 0x0f) << 24); } /* record how much data we actually moved */ clp = (struct ata_ahci_cmd_list *) - (ch->dma.work + ATA_AHCI_CL_OFFSET + (ATA_AHCI_CL_SIZE*request->tag)); + (ch->dma.work + ATA_AHCI_CL_OFFSET); request->donecount = clp->bytecount; /* release SG list etc */ ch->dma.unload(request); return ATA_OP_FINISHED; } static int ata_ahci_issue_cmd(device_t dev, u_int16_t flags, int timeout) { struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev)); struct ata_channel *ch = device_get_softc(dev); struct ata_ahci_cmd_list *clp = (struct ata_ahci_cmd_list *)(ch->dma.work + ATA_AHCI_CL_OFFSET); struct ata_ahci_cmd_tab *ctp = (struct ata_ahci_cmd_tab *)(ch->dma.work + ATA_AHCI_CT_OFFSET); u_int32_t status = 0; int offset = ch->unit << 7; int port = (ctp->cfis[1] & 0x0f); int count; clp->prd_length = 0; clp->cmd_flags = (20 / sizeof(u_int32_t)) | flags | (port << 12); clp->bytecount = 0; clp->cmd_table_phys = htole64(ch->dma.work_bus + ATA_AHCI_CT_OFFSET); /* issue command to controller */ ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_CI + offset, 1); /* poll for command finished */ for (count = 0; count < timeout; count++) { DELAY(1000); if (!((status = ATA_INL(ctlr->r_res2, ATA_AHCI_P_CI + offset)) & 1)) break; } /* clear interrupts */ ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_IS + offset, ATA_INL(ctlr->r_res2, ATA_AHCI_P_IS + offset)); if (timeout && (count >= timeout)) { if (bootverbose) { device_printf(dev, "ahci_issue_cmd timeout: %d of %dms, status=%08x\n", count, timeout, status); } return EIO; } return 0; } static int ata_ahci_pm_read(device_t dev, int port, int reg, u_int32_t *result) { struct ata_channel *ch = device_get_softc(dev); struct ata_ahci_cmd_tab *ctp = (struct ata_ahci_cmd_tab *)(ch->dma.work + ATA_AHCI_CT_OFFSET); u_int8_t *fis = ch->dma.work + ATA_AHCI_FB_OFFSET + 0x40; bzero(ctp->cfis, 64); ctp->cfis[0] = 0x27; /* host to device */ ctp->cfis[1] = 0x8f; /* command FIS to PM port */ ctp->cfis[2] = ATA_READ_PM; ctp->cfis[3] = reg; ctp->cfis[7] = port | ATA_D_LBA; ctp->cfis[15] = ATA_A_4BIT; if (ata_ahci_issue_cmd(dev, 0, 10)) { device_printf(dev, "error reading PM port\n"); return EIO; } *result = fis[12] | (fis[4] << 8) | (fis[5] << 16) | (fis[6] << 24); return 0; } static int ata_ahci_pm_write(device_t dev, int port, int reg, u_int32_t value) { struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev)); struct ata_channel *ch = device_get_softc(dev); struct ata_ahci_cmd_tab *ctp = (struct ata_ahci_cmd_tab *)(ch->dma.work + ATA_AHCI_CT_OFFSET); int offset = ch->unit << 7; bzero(ctp->cfis, 64); ctp->cfis[0] = 0x27; /* host to device */ ctp->cfis[1] = 0x8f; /* command FIS to PM port */ ctp->cfis[2] = ATA_WRITE_PM; ctp->cfis[3] = reg; ctp->cfis[7] = port | ATA_D_LBA; ctp->cfis[12] = value & 0xff; ctp->cfis[4] = (value >> 8) & 0xff;; ctp->cfis[5] = (value >> 16) & 0xff;; ctp->cfis[6] = (value >> 24) & 0xff;; ctp->cfis[15] = ATA_A_4BIT; if (ata_ahci_issue_cmd(dev, 0, 100)) { device_printf(dev, "error writing PM port\n"); return ATA_E_ABORT; } return (ATA_INL(ctlr->r_res2, ATA_AHCI_P_TFD + offset) >> 8) & 0xff; } static void ata_ahci_stop(device_t dev) { struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev)); struct ata_channel *ch = device_get_softc(dev); u_int32_t cmd; int offset = ch->unit << 7; int timeout; /* kill off all activity on this channel */ cmd = ATA_INL(ctlr->r_res2, ATA_AHCI_P_CMD + offset); ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_CMD + offset, cmd & ~ATA_AHCI_P_CMD_ST); /* XXX SOS this is not entirely wrong */ timeout = 0; do { DELAY(1000); if (timeout++ > 1000) { device_printf(dev, "stopping AHCI engine failed\n"); break; } } while (ATA_INL(ctlr->r_res2, ATA_AHCI_P_CMD + offset) & ATA_AHCI_P_CMD_CR); } static void ata_ahci_clo(device_t dev) { struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev)); struct ata_channel *ch = device_get_softc(dev); u_int32_t cmd; int offset = ch->unit << 7; int timeout; /* issue Command List Override if supported */ if (ATA_INL(ctlr->r_res2, ATA_AHCI_CAP) & ATA_AHCI_CAP_SCLO) { cmd = ATA_INL(ctlr->r_res2, ATA_AHCI_P_CMD + offset); cmd |= ATA_AHCI_P_CMD_CLO; ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_CMD + offset, cmd); timeout = 0; do { DELAY(1000); if (timeout++ > 1000) { device_printf(dev, "executing CLO failed\n"); break; } } while (ATA_INL(ctlr->r_res2, ATA_AHCI_P_CMD+offset)&ATA_AHCI_P_CMD_CLO); } } static void ata_ahci_start(device_t dev) { struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev)); struct ata_channel *ch = device_get_softc(dev); u_int32_t cmd; int offset = ch->unit << 7; /* clear SATA error register */ ATA_IDX_OUTL(ch, ATA_SERROR, ATA_IDX_INL(ch, ATA_SERROR)); /* clear any interrupts pending on this channel */ ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_IS + offset, ATA_INL(ctlr->r_res2, ATA_AHCI_P_IS + offset)); /* start operations on this channel */ cmd = ATA_INL(ctlr->r_res2, ATA_AHCI_P_CMD + offset); ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_CMD + offset, cmd | ATA_AHCI_P_CMD_ST | (ch->devices & ATA_PORTMULTIPLIER ? ATA_AHCI_P_CMD_PMA : 0)); } static void ata_ahci_stop_fr(device_t dev) { struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev)); struct ata_channel *ch = device_get_softc(dev); u_int32_t cmd; int offset = ch->unit << 7; int timeout; /* kill off all activity on this channel */ cmd = ATA_INL(ctlr->r_res2, ATA_AHCI_P_CMD + offset); ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_CMD + offset, cmd & ~ATA_AHCI_P_CMD_FRE); timeout = 0; do { DELAY(1000); if (timeout++ > 1000) { device_printf(dev, "stopping AHCI FR engine failed\n"); break; } } while (ATA_INL(ctlr->r_res2, ATA_AHCI_P_CMD + offset) & ATA_AHCI_P_CMD_FR); } static void ata_ahci_start_fr(device_t dev) { struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev)); struct ata_channel *ch = device_get_softc(dev); u_int32_t cmd; int offset = ch->unit << 7; /* start FIS reception on this channel */ cmd = ATA_INL(ctlr->r_res2, ATA_AHCI_P_CMD + offset); ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_CMD + offset, cmd | ATA_AHCI_P_CMD_FRE); } static int ata_ahci_wait_ready(device_t dev, int t) { struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev)); struct ata_channel *ch = device_get_softc(dev); int offset = ch->unit << 7; int timeout = 0; uint32_t val; while ((val = ATA_INL(ctlr->r_res2, ATA_AHCI_P_TFD + offset)) & (ATA_S_BUSY | ATA_S_DRQ)) { DELAY(1000); if (timeout++ > t) { device_printf(dev, "port is not ready (timeout %dms) tfd = %08x\n", t, val); return (EBUSY); } } if (bootverbose) device_printf(dev, "ready wait time=%dms\n", timeout); return (0); } static int ata_ahci_hardreset(device_t dev, int port, uint32_t *signature) { struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev)); struct ata_channel *ch = device_get_softc(dev); int offset = ch->unit << 7; *signature = 0xffffffff; ata_ahci_stop(dev); /* Reset port */ if (!ata_sata_phy_reset(dev, port, 0)) return (ENOENT); /* Wait for clearing busy status. */ if (ata_ahci_wait_ready(dev, 10000)) { device_printf(dev, "hardware reset timeout\n"); return (EBUSY); } *signature = ATA_INL(ctlr->r_res2, ATA_AHCI_P_SIG + offset); ata_ahci_start(dev); return (0); } static u_int32_t ata_ahci_softreset(device_t dev, int port) { struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev)); struct ata_channel *ch = device_get_softc(dev); int offset = ch->unit << 7; struct ata_ahci_cmd_tab *ctp = (struct ata_ahci_cmd_tab *)(ch->dma.work + ATA_AHCI_CT_OFFSET); if (bootverbose) device_printf(dev, "software reset port %d...\n", port); /* kick controller into sane state */ ata_ahci_stop(dev); ata_ahci_clo(dev); ata_ahci_start(dev); /* pull reset active */ bzero(ctp->cfis, 64); ctp->cfis[0] = 0x27; ctp->cfis[1] = port & 0x0f; //ctp->cfis[7] = ATA_D_LBA | ATA_D_IBM; ctp->cfis[15] = (ATA_A_4BIT | ATA_A_RESET); if (ata_ahci_issue_cmd(dev, ATA_AHCI_CMD_RESET | ATA_AHCI_CMD_CLR_BUSY,100)) { device_printf(dev, "software reset set timeout\n"); return (-1); } ata_udelay(50); /* pull reset inactive -> device softreset */ bzero(ctp->cfis, 64); ctp->cfis[0] = 0x27; ctp->cfis[1] = port & 0x0f; //ctp->cfis[7] = ATA_D_LBA | ATA_D_IBM; ctp->cfis[15] = ATA_A_4BIT; ata_ahci_issue_cmd(dev, 0, 3000); if (ata_ahci_wait_ready(dev, 0)) { device_printf(dev, "software reset clear timeout\n"); return (-1); } return ATA_INL(ctlr->r_res2, ATA_AHCI_P_SIG + offset); } void ata_ahci_reset(device_t dev) { struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev)); struct ata_channel *ch = device_get_softc(dev); u_int32_t signature; int offset = ch->unit << 7; if (bootverbose) device_printf(dev, "AHCI reset...\n"); /* Disable port interrupts */ ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_IE + offset, 0); if (ata_ahci_hardreset(dev, -1, &signature)) { if (bootverbose) device_printf(dev, "AHCI reset done: phy reset found no device\n"); ch->devices = 0; /* enable wanted port interrupts */ ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_IE + offset, (ATA_AHCI_P_IX_CPD | ATA_AHCI_P_IX_PRC | ATA_AHCI_P_IX_PC)); return; } /* enable wanted port interrupts */ ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_IE + offset, (ATA_AHCI_P_IX_CPD | ATA_AHCI_P_IX_TFE | ATA_AHCI_P_IX_HBF | ATA_AHCI_P_IX_HBD | ATA_AHCI_P_IX_IF | ATA_AHCI_P_IX_OF | ((ch->pm_level == 0) ? ATA_AHCI_P_IX_PRC | ATA_AHCI_P_IX_PC : 0) | ATA_AHCI_P_IX_DP | ATA_AHCI_P_IX_UF | ATA_AHCI_P_IX_SDB | ATA_AHCI_P_IX_DS | ATA_AHCI_P_IX_PS | ATA_AHCI_P_IX_DHR)); /* only probe for PortMultiplier if HW has support */ if (ATA_INL(ctlr->r_res2, ATA_AHCI_CAP) & ATA_AHCI_CAP_SPM) { signature = ata_ahci_softreset(dev, ATA_PM); /* Workaround for some ATI chips, failing to soft-reset * when port multiplicator supported, but absent. * XXX: We can also check PxIS.IPMS==1 here to be sure. */ if (signature == 0xffffffff) signature = ata_ahci_softreset(dev, 0); } else { signature = ata_ahci_softreset(dev, 0); } if (bootverbose) device_printf(dev, "SIGNATURE: %08x\n", signature); switch (signature >> 16) { case 0x0000: ch->devices = ATA_ATA_MASTER; break; case 0x9669: ch->devices = ATA_PORTMULTIPLIER; ata_pm_identify(dev); break; case 0xeb14: ch->devices = ATA_ATAPI_MASTER; break; default: /* SOS XXX */ if (bootverbose) device_printf(dev, "Unknown signature, assuming disk device\n"); ch->devices = ATA_ATA_MASTER; } if (bootverbose) device_printf(dev, "AHCI reset done: devices=%08x\n", ch->devices); } static void ata_ahci_dmasetprd(void *xsc, bus_dma_segment_t *segs, int nsegs, int error) { struct ata_dmasetprd_args *args = xsc; struct ata_ahci_dma_prd *prd = args->dmatab; int i; if (!(args->error = error)) { for (i = 0; i < nsegs; i++) { prd[i].dba = htole64(segs[i].ds_addr); prd[i].dbc = htole32((segs[i].ds_len - 1) & ATA_AHCI_PRD_MASK); } } KASSERT(nsegs <= ATA_AHCI_DMA_ENTRIES, ("too many DMA segment entries\n")); args->nsegs = nsegs; } static void ata_ahci_dmainit(device_t dev) { struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev)); struct ata_channel *ch = device_get_softc(dev); ata_dmainit(dev); /* note start and stop are not used here */ ch->dma.setprd = ata_ahci_dmasetprd; ch->dma.max_iosize = (ATA_AHCI_DMA_ENTRIES - 1) * PAGE_SIZE; if (ATA_INL(ctlr->r_res2, ATA_AHCI_CAP) & ATA_AHCI_CAP_64BIT) ch->dma.max_address = BUS_SPACE_MAXADDR; } static int ata_ahci_setup_fis(struct ata_ahci_cmd_tab *ctp, struct ata_request *request) { bzero(ctp->cfis, 64); if (request->flags & ATA_R_ATAPI) { bzero(ctp->acmd, 32); bcopy(request->u.atapi.ccb, ctp->acmd, 16); } return ata_request2fis_h2d(request, &ctp->cfis[0]); } ATA_DECLARE_DRIVER(ata_ahci); diff --git a/sys/dev/ata/chipsets/ata-intel.c b/sys/dev/ata/chipsets/ata-intel.c index c8ed0c05c0ba..38c296b1f4bf 100644 --- a/sys/dev/ata/chipsets/ata-intel.c +++ b/sys/dev/ata/chipsets/ata-intel.c @@ -1,525 +1,525 @@ /*- * Copyright (c) 1998 - 2008 Søren Schmidt * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer, * without modification, immediately at the beginning of the file. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * 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. */ #include __FBSDID("$FreeBSD$"); #include "opt_ata.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* local prototypes */ static int ata_intel_chipinit(device_t dev); static int ata_intel_ch_attach(device_t dev); static void ata_intel_reset(device_t dev); static void ata_intel_old_setmode(device_t dev, int mode); static void ata_intel_new_setmode(device_t dev, int mode); static void ata_intel_sata_setmode(device_t dev, int mode); static int ata_intel_31244_ch_attach(device_t dev); static int ata_intel_31244_ch_detach(device_t dev); static int ata_intel_31244_status(device_t dev); static void ata_intel_31244_tf_write(struct ata_request *request); static void ata_intel_31244_reset(device_t dev); /* misc defines */ #define INTEL_AHCI 1 /* * Intel chipset support functions */ static int ata_intel_probe(device_t dev) { struct ata_pci_controller *ctlr = device_get_softc(dev); static struct ata_chip_id ids[] = {{ ATA_I82371FB, 0, 0, 2, ATA_WDMA2, "PIIX" }, { ATA_I82371SB, 0, 0, 2, ATA_WDMA2, "PIIX3" }, { ATA_I82371AB, 0, 0, 2, ATA_UDMA2, "PIIX4" }, { ATA_I82443MX, 0, 0, 2, ATA_UDMA2, "PIIX4" }, { ATA_I82451NX, 0, 0, 2, ATA_UDMA2, "PIIX4" }, { ATA_I82801AB, 0, 0, 2, ATA_UDMA2, "ICH0" }, { ATA_I82801AA, 0, 0, 2, ATA_UDMA4, "ICH" }, { ATA_I82372FB, 0, 0, 2, ATA_UDMA4, "ICH" }, { ATA_I82801BA, 0, 0, 2, ATA_UDMA5, "ICH2" }, { ATA_I82801BA_1, 0, 0, 2, ATA_UDMA5, "ICH2" }, { ATA_I82801CA, 0, 0, 2, ATA_UDMA5, "ICH3" }, { ATA_I82801CA_1, 0, 0, 2, ATA_UDMA5, "ICH3" }, { ATA_I82801DB, 0, 0, 2, ATA_UDMA5, "ICH4" }, { ATA_I82801DB_1, 0, 0, 2, ATA_UDMA5, "ICH4" }, { ATA_I82801EB, 0, 0, 2, ATA_UDMA5, "ICH5" }, { ATA_I82801EB_S1, 0, 0, 2, ATA_SA150, "ICH5" }, { ATA_I82801EB_R1, 0, 0, 2, ATA_SA150, "ICH5" }, { ATA_I6300ESB, 0, 0, 2, ATA_UDMA5, "6300ESB" }, { ATA_I6300ESB_S1, 0, 0, 2, ATA_SA150, "6300ESB" }, { ATA_I6300ESB_R1, 0, 0, 2, ATA_SA150, "6300ESB" }, { ATA_I82801FB, 0, 0, 2, ATA_UDMA5, "ICH6" }, { ATA_I82801FB_S1, 0, INTEL_AHCI, 0, ATA_SA150, "ICH6" }, { ATA_I82801FB_R1, 0, INTEL_AHCI, 0, ATA_SA150, "ICH6" }, { ATA_I82801FBM, 0, INTEL_AHCI, 0, ATA_SA150, "ICH6M" }, { ATA_I82801GB, 0, 0, 1, ATA_UDMA5, "ICH7" }, { ATA_I82801GB_S1, 0, INTEL_AHCI, 0, ATA_SA300, "ICH7" }, { ATA_I82801GB_R1, 0, INTEL_AHCI, 0, ATA_SA300, "ICH7" }, { ATA_I82801GB_AH, 0, INTEL_AHCI, 0, ATA_SA300, "ICH7" }, { ATA_I82801GBM_S1, 0, INTEL_AHCI, 0, ATA_SA150, "ICH7M" }, { ATA_I82801GBM_R1, 0, INTEL_AHCI, 0, ATA_SA150, "ICH7M" }, { ATA_I82801GBM_AH, 0, INTEL_AHCI, 0, ATA_SA150, "ICH7M" }, { ATA_I63XXESB2, 0, 0, 1, ATA_UDMA5, "63XXESB2" }, { ATA_I63XXESB2_S1, 0, INTEL_AHCI, 0, ATA_SA300, "63XXESB2" }, { ATA_I63XXESB2_S2, 0, INTEL_AHCI, 0, ATA_SA300, "63XXESB2" }, { ATA_I63XXESB2_R1, 0, INTEL_AHCI, 0, ATA_SA300, "63XXESB2" }, { ATA_I63XXESB2_R2, 0, INTEL_AHCI, 0, ATA_SA300, "63XXESB2" }, { ATA_I82801HB_S1, 0, INTEL_AHCI, 0, ATA_SA300, "ICH8" }, { ATA_I82801HB_S2, 0, INTEL_AHCI, 0, ATA_SA300, "ICH8" }, { ATA_I82801HB_R1, 0, INTEL_AHCI, 0, ATA_SA300, "ICH8" }, { ATA_I82801HB_AH4, 0, INTEL_AHCI, 0, ATA_SA300, "ICH8" }, { ATA_I82801HB_AH6, 0, INTEL_AHCI, 0, ATA_SA300, "ICH8" }, { ATA_I82801HBM, 0, 0, 1, ATA_UDMA5, "ICH8M" }, { ATA_I82801HBM_S1, 0, INTEL_AHCI, 0, ATA_SA300, "ICH8M" }, { ATA_I82801HBM_S2, 0, INTEL_AHCI, 0, ATA_SA300, "ICH8M" }, { ATA_I82801HBM_S3, 0, INTEL_AHCI, 0, ATA_SA300, "ICH8M" }, { ATA_I82801IB_S1, 0, INTEL_AHCI, 0, ATA_SA300, "ICH9" }, { ATA_I82801IB_S2, 0, INTEL_AHCI, 0, ATA_SA300, "ICH9" }, { ATA_I82801IB_AH2, 0, INTEL_AHCI, 0, ATA_SA300, "ICH9" }, { ATA_I82801IB_AH4, 0, INTEL_AHCI, 0, ATA_SA300, "ICH9" }, { ATA_I82801IB_AH6, 0, INTEL_AHCI, 0, ATA_SA300, "ICH9" }, { ATA_I82801IB_R1, 0, INTEL_AHCI, 0, ATA_SA300, "ICH9" }, { ATA_I82801JIB_S1, 0, INTEL_AHCI, 0, ATA_SA300, "ICH10" }, { ATA_I82801JIB_AH, 0, INTEL_AHCI, 0, ATA_SA300, "ICH10" }, { ATA_I82801JIB_R1, 0, INTEL_AHCI, 0, ATA_SA300, "ICH10" }, { ATA_I82801JIB_S2, 0, INTEL_AHCI, 0, ATA_SA300, "ICH10" }, { ATA_I82801JD_S1, 0, INTEL_AHCI, 0, ATA_SA300, "ICH10" }, { ATA_I82801JD_AH, 0, INTEL_AHCI, 0, ATA_SA300, "ICH10" }, { ATA_I82801JD_R1, 0, INTEL_AHCI, 0, ATA_SA300, "ICH10" }, { ATA_I82801JD_S2, 0, INTEL_AHCI, 0, ATA_SA300, "ICH10" }, { ATA_I31244, 0, 0, 2, ATA_SA150, "31244" }, { 0, 0, 0, 0, 0, 0}}; if (pci_get_vendor(dev) != ATA_INTEL_ID) return ENXIO; if (!(ctlr->chip = ata_match_chip(dev, ids))) return ENXIO; ata_set_desc(dev); ctlr->chipinit = ata_intel_chipinit; return (BUS_PROBE_DEFAULT); } static int ata_intel_chipinit(device_t dev) { struct ata_pci_controller *ctlr = device_get_softc(dev); if (ata_setup_interrupt(dev, ata_generic_intr)) return ENXIO; /* good old PIIX needs special treatment (not implemented) */ if (ctlr->chip->chipid == ATA_I82371FB) { ctlr->setmode = ata_intel_old_setmode; } /* the intel 31244 needs special care if in DPA mode */ else if (ctlr->chip->chipid == ATA_I31244) { if (pci_get_subclass(dev) != PCIS_STORAGE_IDE) { ctlr->r_type2 = SYS_RES_MEMORY; ctlr->r_rid2 = PCIR_BAR(0); if (!(ctlr->r_res2 = bus_alloc_resource_any(dev, ctlr->r_type2, &ctlr->r_rid2, RF_ACTIVE))) return ENXIO; ctlr->channels = 4; ctlr->ch_attach = ata_intel_31244_ch_attach; ctlr->ch_detach = ata_intel_31244_ch_detach; ctlr->reset = ata_intel_31244_reset; } ctlr->setmode = ata_sata_setmode; } /* non SATA intel chips goes here */ else if (ctlr->chip->max_dma < ATA_SA150) { ctlr->channels = ctlr->chip->cfg2; ctlr->ch_attach = ata_intel_ch_attach; ctlr->ch_detach = ata_pci_ch_detach; ctlr->setmode = ata_intel_new_setmode; } /* SATA parts can be either compat or AHCI */ else { /* force all ports active "the legacy way" */ pci_write_config(dev, 0x92, pci_read_config(dev, 0x92, 2) | 0x0f, 2); ctlr->ch_attach = ata_intel_ch_attach; ctlr->ch_detach = ata_pci_ch_detach; ctlr->reset = ata_intel_reset; /* * if we have AHCI capability and AHCI or RAID mode enabled * in BIOS we try for AHCI mode */ if ((ctlr->chip->cfg1 == INTEL_AHCI) && (pci_read_config(dev, 0x90, 1) & 0xc0) && (ata_ahci_chipinit(dev) != ENXIO)) return 0; /* if BAR(5) is IO it should point to SATA interface registers */ ctlr->r_type2 = SYS_RES_IOPORT; ctlr->r_rid2 = PCIR_BAR(5); if ((ctlr->r_res2 = bus_alloc_resource_any(dev, ctlr->r_type2, &ctlr->r_rid2, RF_ACTIVE))) ctlr->setmode = ata_intel_sata_setmode; else ctlr->setmode = ata_sata_setmode; } return 0; } static int ata_intel_ch_attach(device_t dev) { struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev)); struct ata_channel *ch = device_get_softc(dev); /* setup the usual register normal pci style */ if (ata_pci_ch_attach(dev)) return ENXIO; /* if r_res2 is valid it points to SATA interface registers */ if (ctlr->r_res2) { ch->r_io[ATA_IDX_ADDR].res = ctlr->r_res2; ch->r_io[ATA_IDX_ADDR].offset = 0x00; ch->r_io[ATA_IDX_DATA].res = ctlr->r_res2; ch->r_io[ATA_IDX_DATA].offset = 0x04; } ch->flags |= ATA_ALWAYS_DMASTAT; return 0; } static void ata_intel_reset(device_t dev) { device_t parent = device_get_parent(dev); struct ata_pci_controller *ctlr = device_get_softc(parent); struct ata_channel *ch = device_get_softc(dev); int mask, timeout; /* ICH6 & ICH7 in compat mode has 4 SATA ports as master/slave on 2 ch's */ if (ctlr->chip->cfg1) { mask = (0x0005 << ch->unit); } else { /* ICH5 in compat mode has SATA ports as master/slave on 1 channel */ if (pci_read_config(parent, 0x90, 1) & 0x04) mask = 0x0003; else { mask = (0x0001 << ch->unit); /* XXX SOS should be in intel_ch_attach if we grow it */ ch->flags |= ATA_NO_SLAVE; } } pci_write_config(parent, 0x92, pci_read_config(parent, 0x92, 2) & ~mask, 2); DELAY(10); pci_write_config(parent, 0x92, pci_read_config(parent, 0x92, 2) | mask, 2); /* wait up to 1 sec for "connect well" */ for (timeout = 0; timeout < 100 ; timeout++) { if (((pci_read_config(parent, 0x92, 2) & (mask << 4)) == (mask << 4)) && (ATA_IDX_INB(ch, ATA_STATUS) != 0xff)) break; ata_udelay(10000); } ata_generic_reset(dev); } static void ata_intel_old_setmode(device_t dev, int mode) { /* NOT YET */ } static void ata_intel_new_setmode(device_t dev, int mode) { device_t gparent = GRANDPARENT(dev); struct ata_pci_controller *ctlr = device_get_softc(gparent); struct ata_channel *ch = device_get_softc(device_get_parent(dev)); struct ata_device *atadev = device_get_softc(dev); int devno = (ch->unit << 1) + atadev->unit; u_int32_t reg40 = pci_read_config(gparent, 0x40, 4); u_int8_t reg44 = pci_read_config(gparent, 0x44, 1); u_int8_t reg48 = pci_read_config(gparent, 0x48, 1); u_int16_t reg4a = pci_read_config(gparent, 0x4a, 2); u_int16_t reg54 = pci_read_config(gparent, 0x54, 2); u_int32_t mask40 = 0, new40 = 0; u_int8_t mask44 = 0, new44 = 0; int error; u_int8_t timings[] = { 0x00, 0x00, 0x10, 0x21, 0x23, 0x10, 0x21, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23 }; mode = ata_limit_mode(dev, mode, ctlr->chip->max_dma); if ( mode > ATA_UDMA2 && !(reg54 & (0x10 << devno))) { ata_print_cable(dev, "controller"); mode = ATA_UDMA2; } error = ata_controlcmd(dev, ATA_SETFEATURES, ATA_SF_SETXFER, 0, mode); if (bootverbose) device_printf(dev, "%ssetting %s on %s chip\n", (error) ? "FAILURE " : "", ata_mode2str(mode), ctlr->chip->text); if (!error) { if (mode >= ATA_UDMA0) { u_int8_t utimings[] = { 0x00, 0x01, 0x10, 0x01, 0x10, 0x01, 0x10 }; pci_write_config(gparent, 0x48, reg48 | (0x0001 << devno), 2); pci_write_config(gparent, 0x4a, (reg4a & ~(0x3 << (devno << 2))) | (utimings[mode & ATA_MODE_MASK] << (devno<<2)), 2); } else { pci_write_config(gparent, 0x48, reg48 & ~(0x0001 << devno), 2); pci_write_config(gparent, 0x4a, (reg4a & ~(0x3 << (devno << 2))),2); } reg54 |= 0x0400; if (mode >= ATA_UDMA2) reg54 |= (0x1 << devno); else reg54 &= ~(0x1 << devno); if (mode >= ATA_UDMA5) reg54 |= (0x1000 << devno); else reg54 &= ~(0x1000 << devno); pci_write_config(gparent, 0x54, reg54, 2); reg40 &= ~0x00ff00ff; reg40 |= 0x40774077; if (atadev->unit == ATA_MASTER) { mask40 = 0x3300; new40 = timings[ata_mode2idx(mode)] << 8; } else { mask44 = 0x0f; new44 = ((timings[ata_mode2idx(mode)] & 0x30) >> 2) | (timings[ata_mode2idx(mode)] & 0x03); } if (ch->unit) { mask40 <<= 16; new40 <<= 16; mask44 <<= 4; new44 <<= 4; } pci_write_config(gparent, 0x40, (reg40 & ~mask40) | new40, 4); pci_write_config(gparent, 0x44, (reg44 & ~mask44) | new44, 1); atadev->mode = mode; } } static void ata_intel_sata_setmode(device_t dev, int mode) { struct ata_device *atadev = device_get_softc(dev); if (atadev->param.satacapabilities != 0x0000 && atadev->param.satacapabilities != 0xffff) { struct ata_channel *ch = device_get_softc(device_get_parent(dev)); int devno = (ch->unit << 1) + atadev->unit; /* on some drives we need to set the transfer mode */ ata_controlcmd(dev, ATA_SETFEATURES, ATA_SF_SETXFER, 0, ata_limit_mode(dev, mode, ATA_UDMA6)); /* set ATA_SSTATUS register offset */ ATA_IDX_OUTL(ch, ATA_IDX_ADDR, devno * 0x100); /* query SATA STATUS for the speed */ if ((ATA_IDX_INL(ch, ATA_IDX_DATA) & ATA_SS_CONWELL_MASK) == ATA_SS_CONWELL_GEN2) atadev->mode = ATA_SA300; else atadev->mode = ATA_SA150; } else { mode = ata_limit_mode(dev, mode, ATA_UDMA5); if (!ata_controlcmd(dev, ATA_SETFEATURES, ATA_SF_SETXFER, 0, mode)) atadev->mode = mode; } } static int ata_intel_31244_ch_attach(device_t dev) { struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev)); struct ata_channel *ch = device_get_softc(dev); int i; int ch_offset; ata_pci_dmainit(dev); ch_offset = 0x200 + ch->unit * 0x200; for (i = ATA_DATA; i < ATA_MAX_RES; i++) ch->r_io[i].res = ctlr->r_res2; /* setup ATA registers */ ch->r_io[ATA_DATA].offset = ch_offset + 0x00; ch->r_io[ATA_FEATURE].offset = ch_offset + 0x06; ch->r_io[ATA_COUNT].offset = ch_offset + 0x08; ch->r_io[ATA_SECTOR].offset = ch_offset + 0x0c; ch->r_io[ATA_CYL_LSB].offset = ch_offset + 0x10; ch->r_io[ATA_CYL_MSB].offset = ch_offset + 0x14; ch->r_io[ATA_DRIVE].offset = ch_offset + 0x18; ch->r_io[ATA_COMMAND].offset = ch_offset + 0x1d; ch->r_io[ATA_ERROR].offset = ch_offset + 0x04; ch->r_io[ATA_STATUS].offset = ch_offset + 0x1c; ch->r_io[ATA_ALTSTAT].offset = ch_offset + 0x28; ch->r_io[ATA_CONTROL].offset = ch_offset + 0x29; /* setup DMA registers */ ch->r_io[ATA_SSTATUS].offset = ch_offset + 0x100; ch->r_io[ATA_SERROR].offset = ch_offset + 0x104; ch->r_io[ATA_SCONTROL].offset = ch_offset + 0x108; /* setup SATA registers */ ch->r_io[ATA_BMCMD_PORT].offset = ch_offset + 0x70; ch->r_io[ATA_BMSTAT_PORT].offset = ch_offset + 0x72; ch->r_io[ATA_BMDTP_PORT].offset = ch_offset + 0x74; ch->flags |= ATA_NO_SLAVE; ata_pci_hw(dev); ch->hw.status = ata_intel_31244_status; ch->hw.tf_write = ata_intel_31244_tf_write; /* enable PHY state change interrupt */ ATA_OUTL(ctlr->r_res2, 0x4, ATA_INL(ctlr->r_res2, 0x04) | (0x01 << (ch->unit << 3))); return 0; } static int ata_intel_31244_ch_detach(device_t dev) { ata_pci_dmafini(dev); return (0); } static int ata_intel_31244_status(device_t dev) { /* do we have any PHY events ? */ ata_sata_phy_check_events(dev); /* any drive action to take care of ? */ return ata_pci_status(dev); } static void ata_intel_31244_tf_write(struct ata_request *request) { - struct ata_channel *ch = device_get_softc(device_get_parent(request->dev)); + struct ata_channel *ch = device_get_softc(request->parent); struct ata_device *atadev = device_get_softc(request->dev); - if (atadev->flags & ATA_D_48BIT_ACTIVE) { + if (request->flags & ATA_R_48BIT) { ATA_IDX_OUTW(ch, ATA_FEATURE, request->u.ata.feature); ATA_IDX_OUTW(ch, ATA_COUNT, request->u.ata.count); ATA_IDX_OUTW(ch, ATA_SECTOR, ((request->u.ata.lba >> 16) & 0xff00) | (request->u.ata.lba & 0x00ff)); ATA_IDX_OUTW(ch, ATA_CYL_LSB, ((request->u.ata.lba >> 24) & 0xff00) | ((request->u.ata.lba >> 8) & 0x00ff)); ATA_IDX_OUTW(ch, ATA_CYL_MSB, ((request->u.ata.lba >> 32) & 0xff00) | ((request->u.ata.lba >> 16) & 0x00ff)); - ATA_IDX_OUTW(ch, ATA_DRIVE, ATA_D_LBA | ATA_DEV(atadev->unit)); + ATA_IDX_OUTW(ch, ATA_DRIVE, ATA_D_LBA | ATA_DEV(request->unit)); } else { ATA_IDX_OUTB(ch, ATA_FEATURE, request->u.ata.feature); ATA_IDX_OUTB(ch, ATA_COUNT, request->u.ata.count); if (atadev->flags & ATA_D_USE_CHS) { int heads, sectors; if (atadev->param.atavalid & ATA_FLAG_54_58) { heads = atadev->param.current_heads; sectors = atadev->param.current_sectors; } else { heads = atadev->param.heads; sectors = atadev->param.sectors; } ATA_IDX_OUTB(ch, ATA_SECTOR, (request->u.ata.lba % sectors)+1); ATA_IDX_OUTB(ch, ATA_CYL_LSB, (request->u.ata.lba / (sectors * heads))); ATA_IDX_OUTB(ch, ATA_CYL_MSB, (request->u.ata.lba / (sectors * heads)) >> 8); - ATA_IDX_OUTB(ch, ATA_DRIVE, ATA_D_IBM | ATA_DEV(atadev->unit) | + ATA_IDX_OUTB(ch, ATA_DRIVE, ATA_D_IBM | ATA_DEV(request->unit) | (((request->u.ata.lba% (sectors * heads)) / sectors) & 0xf)); } else { ATA_IDX_OUTB(ch, ATA_SECTOR, request->u.ata.lba); ATA_IDX_OUTB(ch, ATA_CYL_LSB, request->u.ata.lba >> 8); ATA_IDX_OUTB(ch, ATA_CYL_MSB, request->u.ata.lba >> 16); ATA_IDX_OUTB(ch, ATA_DRIVE, - ATA_D_IBM | ATA_D_LBA | ATA_DEV(atadev->unit) | + ATA_D_IBM | ATA_D_LBA | ATA_DEV(request->unit) | ((request->u.ata.lba >> 24) & 0x0f)); } } } static void ata_intel_31244_reset(device_t dev) { if (ata_sata_phy_reset(dev, -1, 1)) ata_generic_reset(dev); } ATA_DECLARE_DRIVER(ata_intel); MODULE_DEPEND(ata_intel, ata_ahci, 1, 1, 1); diff --git a/sys/dev/ata/chipsets/ata-marvell.c b/sys/dev/ata/chipsets/ata-marvell.c index adf4d9893d51..dede9bb4c6db 100644 --- a/sys/dev/ata/chipsets/ata-marvell.c +++ b/sys/dev/ata/chipsets/ata-marvell.c @@ -1,598 +1,597 @@ /*- * Copyright (c) 1998 - 2008 Søren Schmidt * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer, * without modification, immediately at the beginning of the file. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * 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. */ #include __FBSDID("$FreeBSD$"); #include "opt_ata.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* local prototypes */ static int ata_marvell_pata_chipinit(device_t dev); static int ata_marvell_pata_ch_attach(device_t dev); static void ata_marvell_pata_setmode(device_t dev, int mode); static int ata_marvell_edma_ch_attach(device_t dev); static int ata_marvell_edma_ch_detach(device_t dev); static int ata_marvell_edma_status(device_t dev); static int ata_marvell_edma_begin_transaction(struct ata_request *request); static int ata_marvell_edma_end_transaction(struct ata_request *request); static void ata_marvell_edma_reset(device_t dev); static void ata_marvell_edma_dmasetprd(void *xsc, bus_dma_segment_t *segs, int nsegs, int error); static void ata_marvell_edma_dmainit(device_t dev); /* misc defines */ #define MV_50XX 50 #define MV_60XX 60 #define MV_6042 62 #define MV_7042 72 #define MV_61XX 61 /* * Marvell chipset support functions */ #define ATA_MV_HOST_BASE(ch) \ ((ch->unit & 3) * 0x0100) + (ch->unit > 3 ? 0x30000 : 0x20000) #define ATA_MV_EDMA_BASE(ch) \ ((ch->unit & 3) * 0x2000) + (ch->unit > 3 ? 0x30000 : 0x20000) struct ata_marvell_response { u_int16_t tag; u_int8_t edma_status; u_int8_t dev_status; u_int32_t timestamp; }; struct ata_marvell_dma_prdentry { u_int32_t addrlo; u_int32_t count; u_int32_t addrhi; u_int32_t reserved; }; static int ata_marvell_probe(device_t dev) { struct ata_pci_controller *ctlr = device_get_softc(dev); static struct ata_chip_id ids[] = {{ ATA_M88SX5040, 0, 4, MV_50XX, ATA_SA150, "88SX5040" }, { ATA_M88SX5041, 0, 4, MV_50XX, ATA_SA150, "88SX5041" }, { ATA_M88SX5080, 0, 8, MV_50XX, ATA_SA150, "88SX5080" }, { ATA_M88SX5081, 0, 8, MV_50XX, ATA_SA150, "88SX5081" }, { ATA_M88SX6041, 0, 4, MV_60XX, ATA_SA300, "88SX6041" }, { ATA_M88SX6042, 0, 4, MV_6042, ATA_SA300, "88SX6042" }, { ATA_M88SX6081, 0, 8, MV_60XX, ATA_SA300, "88SX6081" }, { ATA_M88SX7042, 0, 4, MV_7042, ATA_SA300, "88SX7042" }, { ATA_M88SX6101, 0, 1, MV_61XX, ATA_UDMA6, "88SX6101" }, { ATA_M88SX6121, 0, 1, MV_61XX, ATA_UDMA6, "88SX6121" }, { ATA_M88SX6145, 0, 2, MV_61XX, ATA_UDMA6, "88SX6145" }, { 0, 0, 0, 0, 0, 0}}; if (pci_get_vendor(dev) != ATA_MARVELL_ID) return ENXIO; if (!(ctlr->chip = ata_match_chip(dev, ids))) return ENXIO; ata_set_desc(dev); switch (ctlr->chip->cfg2) { case MV_50XX: case MV_60XX: case MV_6042: case MV_7042: ctlr->chipinit = ata_marvell_edma_chipinit; break; case MV_61XX: ctlr->chipinit = ata_marvell_pata_chipinit; break; } return (BUS_PROBE_DEFAULT); } static int ata_marvell_pata_chipinit(device_t dev) { struct ata_pci_controller *ctlr = device_get_softc(dev); if (ata_setup_interrupt(dev, ata_generic_intr)) return ENXIO; ctlr->ch_attach = ata_marvell_pata_ch_attach; ctlr->ch_detach = ata_pci_ch_detach; ctlr->setmode = ata_marvell_pata_setmode; ctlr->channels = ctlr->chip->cfg1; return 0; } static int ata_marvell_pata_ch_attach(device_t dev) { struct ata_channel *ch = device_get_softc(dev); /* setup the usual register normal pci style */ if (ata_pci_ch_attach(dev)) return ENXIO; /* dont use 32 bit PIO transfers */ ch->flags |= ATA_USE_16BIT; return 0; } static void ata_marvell_pata_setmode(device_t dev, int mode) { device_t gparent = GRANDPARENT(dev); struct ata_pci_controller *ctlr = device_get_softc(gparent); struct ata_device *atadev = device_get_softc(dev); mode = ata_limit_mode(dev, mode, ctlr->chip->max_dma); mode = ata_check_80pin(dev, mode); if (!ata_controlcmd(dev, ATA_SETFEATURES, ATA_SF_SETXFER, 0, mode)) atadev->mode = mode; } int ata_marvell_edma_chipinit(device_t dev) { struct ata_pci_controller *ctlr = device_get_softc(dev); if (ata_setup_interrupt(dev, ata_generic_intr)) return ENXIO; ctlr->r_type1 = SYS_RES_MEMORY; ctlr->r_rid1 = PCIR_BAR(0); if (!(ctlr->r_res1 = bus_alloc_resource_any(dev, ctlr->r_type1, &ctlr->r_rid1, RF_ACTIVE))) return ENXIO; /* mask all host controller interrupts */ ATA_OUTL(ctlr->r_res1, 0x01d64, 0x00000000); /* mask all PCI interrupts */ ATA_OUTL(ctlr->r_res1, 0x01d5c, 0x00000000); ctlr->ch_attach = ata_marvell_edma_ch_attach; ctlr->ch_detach = ata_marvell_edma_ch_detach; ctlr->reset = ata_marvell_edma_reset; ctlr->setmode = ata_sata_setmode; ctlr->channels = ctlr->chip->cfg1; /* clear host controller interrupts */ ATA_OUTL(ctlr->r_res1, 0x20014, 0x00000000); if (ctlr->chip->cfg1 > 4) ATA_OUTL(ctlr->r_res1, 0x30014, 0x00000000); /* clear PCI interrupts */ ATA_OUTL(ctlr->r_res1, 0x01d58, 0x00000000); /* unmask PCI interrupts we want */ ATA_OUTL(ctlr->r_res1, 0x01d5c, 0x007fffff); /* unmask host controller interrupts we want */ ATA_OUTL(ctlr->r_res1, 0x01d64, 0x000000ff/*HC0*/ | 0x0001fe00/*HC1*/ | /*(1<<19) | (1<<20) | (1<<21) |*/(1<<22) | (1<<24) | (0x7f << 25)); return 0; } static int ata_marvell_edma_ch_attach(device_t dev) { struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev)); struct ata_channel *ch = device_get_softc(dev); u_int64_t work; int i; ata_marvell_edma_dmainit(dev); work = ch->dma.work_bus; /* clear work area */ bzero(ch->dma.work, 1024+256); bus_dmamap_sync(ch->dma.work_tag, ch->dma.work_map, BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); /* set legacy ATA resources */ for (i = ATA_DATA; i <= ATA_COMMAND; i++) { ch->r_io[i].res = ctlr->r_res1; ch->r_io[i].offset = 0x02100 + (i << 2) + ATA_MV_EDMA_BASE(ch); } ch->r_io[ATA_CONTROL].res = ctlr->r_res1; ch->r_io[ATA_CONTROL].offset = 0x02120 + ATA_MV_EDMA_BASE(ch); ch->r_io[ATA_IDX_ADDR].res = ctlr->r_res1; ata_default_registers(dev); /* set SATA resources */ switch (ctlr->chip->cfg2) { case MV_50XX: ch->r_io[ATA_SSTATUS].res = ctlr->r_res1; ch->r_io[ATA_SSTATUS].offset = 0x00100 + ATA_MV_HOST_BASE(ch); ch->r_io[ATA_SERROR].res = ctlr->r_res1; ch->r_io[ATA_SERROR].offset = 0x00104 + ATA_MV_HOST_BASE(ch); ch->r_io[ATA_SCONTROL].res = ctlr->r_res1; ch->r_io[ATA_SCONTROL].offset = 0x00108 + ATA_MV_HOST_BASE(ch); break; case MV_60XX: case MV_6042: case MV_7042: ch->r_io[ATA_SSTATUS].res = ctlr->r_res1; ch->r_io[ATA_SSTATUS].offset = 0x02300 + ATA_MV_EDMA_BASE(ch); ch->r_io[ATA_SERROR].res = ctlr->r_res1; ch->r_io[ATA_SERROR].offset = 0x02304 + ATA_MV_EDMA_BASE(ch); ch->r_io[ATA_SCONTROL].res = ctlr->r_res1; ch->r_io[ATA_SCONTROL].offset = 0x02308 + ATA_MV_EDMA_BASE(ch); ch->r_io[ATA_SACTIVE].res = ctlr->r_res1; ch->r_io[ATA_SACTIVE].offset = 0x02350 + ATA_MV_EDMA_BASE(ch); break; } ch->flags |= ATA_NO_SLAVE; ch->flags |= ATA_USE_16BIT; /* XXX SOS needed ? */ ata_generic_hw(dev); ch->hw.begin_transaction = ata_marvell_edma_begin_transaction; ch->hw.end_transaction = ata_marvell_edma_end_transaction; ch->hw.status = ata_marvell_edma_status; /* disable the EDMA machinery */ ATA_OUTL(ctlr->r_res1, 0x02028 + ATA_MV_EDMA_BASE(ch), 0x00000002); DELAY(100000); /* SOS should poll for disabled */ /* set configuration to non-queued 128b read transfers stop on error */ ATA_OUTL(ctlr->r_res1, 0x02000 + ATA_MV_EDMA_BASE(ch), (1<<11) | (1<<13)); /* request queue base high */ ATA_OUTL(ctlr->r_res1, 0x02010 + ATA_MV_EDMA_BASE(ch), work >> 32); /* request queue in ptr */ ATA_OUTL(ctlr->r_res1, 0x02014 + ATA_MV_EDMA_BASE(ch), work & 0xffffffff); /* request queue out ptr */ ATA_OUTL(ctlr->r_res1, 0x02018 + ATA_MV_EDMA_BASE(ch), 0x0); /* response queue base high */ work += 1024; ATA_OUTL(ctlr->r_res1, 0x0201c + ATA_MV_EDMA_BASE(ch), work >> 32); /* response queue in ptr */ ATA_OUTL(ctlr->r_res1, 0x02020 + ATA_MV_EDMA_BASE(ch), 0x0); /* response queue out ptr */ ATA_OUTL(ctlr->r_res1, 0x02024 + ATA_MV_EDMA_BASE(ch), work & 0xffffffff); /* clear SATA error register */ ATA_IDX_OUTL(ch, ATA_SERROR, ATA_IDX_INL(ch, ATA_SERROR)); /* clear any outstanding error interrupts */ ATA_OUTL(ctlr->r_res1, 0x02008 + ATA_MV_EDMA_BASE(ch), 0x0); /* unmask all error interrupts */ ATA_OUTL(ctlr->r_res1, 0x0200c + ATA_MV_EDMA_BASE(ch), ~0x0); /* enable EDMA machinery */ ATA_OUTL(ctlr->r_res1, 0x02028 + ATA_MV_EDMA_BASE(ch), 0x00000001); return 0; } static int ata_marvell_edma_ch_detach(device_t dev) { struct ata_channel *ch = device_get_softc(dev); if (ch->dma.work_tag && ch->dma.work_map) bus_dmamap_sync(ch->dma.work_tag, ch->dma.work_map, BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); ata_dmafini(dev); return (0); } static int ata_marvell_edma_status(device_t dev) { struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev)); struct ata_channel *ch = device_get_softc(dev); u_int32_t cause = ATA_INL(ctlr->r_res1, 0x01d60); int shift = (ch->unit << 1) + (ch->unit > 3); if (cause & (1 << shift)) { /* clear interrupt(s) */ ATA_OUTL(ctlr->r_res1, 0x02008 + ATA_MV_EDMA_BASE(ch), 0x0); /* do we have any PHY events ? */ ata_sata_phy_check_events(dev); } /* do we have any device action ? */ return (cause & (2 << shift)); } /* must be called with ATA channel locked and state_mtx held */ static int ata_marvell_edma_begin_transaction(struct ata_request *request) { - struct ata_pci_controller *ctlr=device_get_softc(GRANDPARENT(request->dev)); + struct ata_pci_controller *ctlr=device_get_softc(device_get_parent(request->parent)); struct ata_channel *ch = device_get_softc(request->parent); u_int32_t req_in; u_int8_t *bytep; int i; int error, slot; /* only DMA R/W goes through the EMDA machine */ if (request->u.ata.command != ATA_READ_DMA && - request->u.ata.command != ATA_WRITE_DMA) { + request->u.ata.command != ATA_WRITE_DMA && + request->u.ata.command != ATA_READ_DMA48 && + request->u.ata.command != ATA_WRITE_DMA48) { /* disable the EDMA machinery */ if (ATA_INL(ctlr->r_res1, 0x02028 + ATA_MV_EDMA_BASE(ch)) & 0x00000001) ATA_OUTL(ctlr->r_res1, 0x02028 + ATA_MV_EDMA_BASE(ch), 0x00000002); return ata_begin_transaction(request); } - /* check for 48 bit access and convert if needed */ - ata_modify_if_48bit(request); - /* check sanity, setup SG list and DMA engine */ if ((error = ch->dma.load(request, NULL, NULL))) { - device_printf(request->dev, "setting up DMA failed\n"); + device_printf(request->parent, "setting up DMA failed\n"); request->result = error; return ATA_OP_FINISHED; } /* get next free request queue slot */ req_in = ATA_INL(ctlr->r_res1, 0x02014 + ATA_MV_EDMA_BASE(ch)); slot = (((req_in & ~0xfffffc00) >> 5) + 0) & 0x1f; bytep = (u_int8_t *)(ch->dma.work); bytep += (slot << 5); /* fill in this request */ le32enc(bytep + 0 * sizeof(u_int32_t), request->dma->sg_bus & 0xffffffff); le32enc(bytep + 1 * sizeof(u_int32_t), (u_int64_t)request->dma->sg_bus >> 32); if (ctlr->chip->cfg2 != MV_6042 && ctlr->chip->cfg2 != MV_7042) { le16enc(bytep + 4 * sizeof(u_int16_t), (request->flags & ATA_R_READ ? 0x01 : 0x00) | (request->tag << 1)); i = 10; bytep[i++] = (request->u.ata.count >> 8) & 0xff; bytep[i++] = 0x10 | ATA_COUNT; bytep[i++] = request->u.ata.count & 0xff; bytep[i++] = 0x10 | ATA_COUNT; bytep[i++] = (request->u.ata.lba >> 24) & 0xff; bytep[i++] = 0x10 | ATA_SECTOR; bytep[i++] = request->u.ata.lba & 0xff; bytep[i++] = 0x10 | ATA_SECTOR; bytep[i++] = (request->u.ata.lba >> 32) & 0xff; bytep[i++] = 0x10 | ATA_CYL_LSB; bytep[i++] = (request->u.ata.lba >> 8) & 0xff; bytep[i++] = 0x10 | ATA_CYL_LSB; bytep[i++] = (request->u.ata.lba >> 40) & 0xff; bytep[i++] = 0x10 | ATA_CYL_MSB; bytep[i++] = (request->u.ata.lba >> 16) & 0xff; bytep[i++] = 0x10 | ATA_CYL_MSB; bytep[i++] = ATA_D_LBA | ATA_D_IBM | ((request->u.ata.lba >> 24) & 0xf); bytep[i++] = 0x10 | ATA_DRIVE; bytep[i++] = request->u.ata.command; bytep[i++] = 0x90 | ATA_COMMAND; } else { le32enc(bytep + 2 * sizeof(u_int32_t), (request->flags & ATA_R_READ ? 0x01 : 0x00) | (request->tag << 1)); i = 16; bytep[i++] = 0; bytep[i++] = 0; bytep[i++] = request->u.ata.command; bytep[i++] = request->u.ata.feature & 0xff; bytep[i++] = request->u.ata.lba & 0xff; bytep[i++] = (request->u.ata.lba >> 8) & 0xff; bytep[i++] = (request->u.ata.lba >> 16) & 0xff; bytep[i++] = ATA_D_LBA | ATA_D_IBM | ((request->u.ata.lba >> 24) & 0x0f); bytep[i++] = (request->u.ata.lba >> 24) & 0xff; bytep[i++] = (request->u.ata.lba >> 32) & 0xff; bytep[i++] = (request->u.ata.lba >> 40) & 0xff; bytep[i++] = (request->u.ata.feature >> 8) & 0xff; bytep[i++] = request->u.ata.count & 0xff; bytep[i++] = (request->u.ata.count >> 8) & 0xff; bytep[i++] = 0; bytep[i++] = 0; } bus_dmamap_sync(ch->dma.work_tag, ch->dma.work_map, BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); /* enable EDMA machinery if needed */ if (!(ATA_INL(ctlr->r_res1, 0x02028 + ATA_MV_EDMA_BASE(ch)) & 0x00000001)) { ATA_OUTL(ctlr->r_res1, 0x02028 + ATA_MV_EDMA_BASE(ch), 0x00000001); while (!(ATA_INL(ctlr->r_res1, 0x02028 + ATA_MV_EDMA_BASE(ch)) & 0x00000001)) DELAY(10); } /* tell EDMA it has a new request */ slot = (((req_in & ~0xfffffc00) >> 5) + 1) & 0x1f; req_in &= 0xfffffc00; req_in += (slot << 5); ATA_OUTL(ctlr->r_res1, 0x02014 + ATA_MV_EDMA_BASE(ch), req_in); return ATA_OP_CONTINUES; } /* must be called with ATA channel locked and state_mtx held */ static int ata_marvell_edma_end_transaction(struct ata_request *request) { - struct ata_pci_controller *ctlr=device_get_softc(GRANDPARENT(request->dev)); + struct ata_pci_controller *ctlr=device_get_softc(device_get_parent(request->parent)); struct ata_channel *ch = device_get_softc(request->parent); int offset = (ch->unit > 3 ? 0x30014 : 0x20014); u_int32_t icr = ATA_INL(ctlr->r_res1, offset); int res; /* EDMA interrupt */ if ((icr & (0x0001 << (ch->unit & 3)))) { struct ata_marvell_response *response; u_int32_t rsp_in, rsp_out; int slot; /* stop timeout */ callout_stop(&request->callout); /* get response ptr's */ rsp_in = ATA_INL(ctlr->r_res1, 0x02020 + ATA_MV_EDMA_BASE(ch)); rsp_out = ATA_INL(ctlr->r_res1, 0x02024 + ATA_MV_EDMA_BASE(ch)); slot = (((rsp_in & ~0xffffff00) >> 3)) & 0x1f; rsp_out &= 0xffffff00; rsp_out += (slot << 3); bus_dmamap_sync(ch->dma.work_tag, ch->dma.work_map, BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); response = (struct ata_marvell_response *) (ch->dma.work + 1024 + (slot << 3)); /* record status for this request */ request->status = response->dev_status; request->error = 0; /* ack response */ ATA_OUTL(ctlr->r_res1, 0x02024 + ATA_MV_EDMA_BASE(ch), rsp_out); /* update progress */ if (!(request->status & ATA_S_ERROR) && !(request->flags & ATA_R_TIMEOUT)) request->donecount = request->bytecount; /* unload SG list */ ch->dma.unload(request); res = ATA_OP_FINISHED; } /* legacy ATA interrupt */ else { res = ata_end_transaction(request); } /* ack interrupt */ ATA_OUTL(ctlr->r_res1, offset, ~(icr & (0x0101 << (ch->unit & 3)))); return res; } static void ata_marvell_edma_reset(device_t dev) { struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev)); struct ata_channel *ch = device_get_softc(dev); /* disable the EDMA machinery */ ATA_OUTL(ctlr->r_res1, 0x02028 + ATA_MV_EDMA_BASE(ch), 0x00000002); while ((ATA_INL(ctlr->r_res1, 0x02028 + ATA_MV_EDMA_BASE(ch)) & 0x00000001)) DELAY(10); /* clear SATA error register */ ATA_IDX_OUTL(ch, ATA_SERROR, ATA_IDX_INL(ch, ATA_SERROR)); /* clear any outstanding error interrupts */ ATA_OUTL(ctlr->r_res1, 0x02008 + ATA_MV_EDMA_BASE(ch), 0x0); /* unmask all error interrupts */ ATA_OUTL(ctlr->r_res1, 0x0200c + ATA_MV_EDMA_BASE(ch), ~0x0); /* enable channel and test for devices */ if (ata_sata_phy_reset(dev, -1, 1)) ata_generic_reset(dev); /* enable EDMA machinery */ ATA_OUTL(ctlr->r_res1, 0x02028 + ATA_MV_EDMA_BASE(ch), 0x00000001); } static void ata_marvell_edma_dmasetprd(void *xsc, bus_dma_segment_t *segs, int nsegs, int error) { struct ata_dmasetprd_args *args = xsc; struct ata_marvell_dma_prdentry *prd = args->dmatab; int i; if ((args->error = error)) return; for (i = 0; i < nsegs; i++) { prd[i].addrlo = htole32(segs[i].ds_addr); prd[i].count = htole32(segs[i].ds_len); prd[i].addrhi = htole32((u_int64_t)segs[i].ds_addr >> 32); prd[i].reserved = 0; } prd[i - 1].count |= htole32(ATA_DMA_EOT); KASSERT(nsegs <= ATA_DMA_ENTRIES, ("too many DMA segment entries\n")); args->nsegs = nsegs; } static void ata_marvell_edma_dmainit(device_t dev) { struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev)); struct ata_channel *ch = device_get_softc(dev); ata_dmainit(dev); /* note start and stop are not used here */ ch->dma.setprd = ata_marvell_edma_dmasetprd; /* if 64bit support present adjust max address used */ if (ATA_INL(ctlr->r_res1, 0x00d00) & 0x00000004) ch->dma.max_address = BUS_SPACE_MAXADDR; /* chip does not reliably do 64K DMA transfers */ if (ctlr->chip->cfg2 == MV_50XX || ctlr->chip->cfg2 == MV_60XX) ch->dma.max_iosize = 64 * DEV_BSIZE; } ATA_DECLARE_DRIVER(ata_marvell); diff --git a/sys/dev/ata/chipsets/ata-promise.c b/sys/dev/ata/chipsets/ata-promise.c index 37863ce7ff25..ca3243adb74b 100644 --- a/sys/dev/ata/chipsets/ata-promise.c +++ b/sys/dev/ata/chipsets/ata-promise.c @@ -1,1245 +1,1240 @@ /*- * Copyright (c) 1998 - 2008 Søren Schmidt * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer, * without modification, immediately at the beginning of the file. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * 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. */ #include __FBSDID("$FreeBSD$"); #include "opt_ata.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* local prototypes */ static int ata_promise_chipinit(device_t dev); static int ata_promise_ch_attach(device_t dev); static int ata_promise_status(device_t dev); static int ata_promise_dmastart(struct ata_request *request); static int ata_promise_dmastop(struct ata_request *request); static void ata_promise_dmareset(device_t dev); static void ata_promise_setmode(device_t dev, int mode); static int ata_promise_tx2_ch_attach(device_t dev); static int ata_promise_tx2_status(device_t dev); static int ata_promise_mio_ch_attach(device_t dev); static int ata_promise_mio_ch_detach(device_t dev); static void ata_promise_mio_intr(void *data); static int ata_promise_mio_status(device_t dev); static int ata_promise_mio_command(struct ata_request *request); static void ata_promise_mio_reset(device_t dev); static int ata_promise_mio_pm_read(device_t dev, int port, int reg, u_int32_t *result); static int ata_promise_mio_pm_write(device_t dev, int port, int reg, u_int32_t result); static u_int32_t ata_promise_mio_softreset(device_t dev, int port); static void ata_promise_mio_dmainit(device_t dev); static void ata_promise_mio_setprd(void *xsc, bus_dma_segment_t *segs, int nsegs, int error); static void ata_promise_mio_setmode(device_t dev, int mode); static void ata_promise_sx4_intr(void *data); static int ata_promise_sx4_command(struct ata_request *request); static int ata_promise_apkt(u_int8_t *bytep, struct ata_request *request); static void ata_promise_queue_hpkt(struct ata_pci_controller *ctlr, u_int32_t hpkt); static void ata_promise_next_hpkt(struct ata_pci_controller *ctlr); /* misc defines */ #define PR_OLD 0 #define PR_NEW 1 #define PR_TX 2 #define PR_MIO 3 #define PR_TX4 0x01 #define PR_SX4X 0x02 #define PR_SX6K 0x04 #define PR_PATA 0x08 #define PR_CMBO 0x10 #define PR_CMBO2 0x20 #define PR_SATA 0x40 #define PR_SATA2 0x80 /* * Promise chipset support functions */ #define ATA_PDC_APKT_OFFSET 0x00000010 #define ATA_PDC_HPKT_OFFSET 0x00000040 #define ATA_PDC_ASG_OFFSET 0x00000080 #define ATA_PDC_LSG_OFFSET 0x000000c0 #define ATA_PDC_HSG_OFFSET 0x00000100 #define ATA_PDC_CHN_OFFSET 0x00000400 #define ATA_PDC_BUF_BASE 0x00400000 #define ATA_PDC_BUF_OFFSET 0x00100000 #define ATA_PDC_MAX_HPKT 8 #define ATA_PDC_WRITE_REG 0x00 #define ATA_PDC_WRITE_CTL 0x0e #define ATA_PDC_WRITE_END 0x08 #define ATA_PDC_WAIT_NBUSY 0x10 #define ATA_PDC_WAIT_READY 0x18 #define ATA_PDC_1B 0x20 #define ATA_PDC_2B 0x40 struct host_packet { u_int32_t addr; TAILQ_ENTRY(host_packet) chain; }; struct ata_promise_sx4 { struct mtx mtx; TAILQ_HEAD(, host_packet) queue; int busy; }; static int ata_promise_probe(device_t dev) { struct ata_pci_controller *ctlr = device_get_softc(dev); struct ata_chip_id *idx; static struct ata_chip_id ids[] = {{ ATA_PDC20246, 0, PR_OLD, 0x00, ATA_UDMA2, "PDC20246" }, { ATA_PDC20262, 0, PR_NEW, 0x00, ATA_UDMA4, "PDC20262" }, { ATA_PDC20263, 0, PR_NEW, 0x00, ATA_UDMA4, "PDC20263" }, { ATA_PDC20265, 0, PR_NEW, 0x00, ATA_UDMA5, "PDC20265" }, { ATA_PDC20267, 0, PR_NEW, 0x00, ATA_UDMA5, "PDC20267" }, { ATA_PDC20268, 0, PR_TX, PR_TX4, ATA_UDMA5, "PDC20268" }, { ATA_PDC20269, 0, PR_TX, 0x00, ATA_UDMA6, "PDC20269" }, { ATA_PDC20270, 0, PR_TX, PR_TX4, ATA_UDMA5, "PDC20270" }, { ATA_PDC20271, 0, PR_TX, 0x00, ATA_UDMA6, "PDC20271" }, { ATA_PDC20275, 0, PR_TX, 0x00, ATA_UDMA6, "PDC20275" }, { ATA_PDC20276, 0, PR_TX, PR_SX6K, ATA_UDMA6, "PDC20276" }, { ATA_PDC20277, 0, PR_TX, 0x00, ATA_UDMA6, "PDC20277" }, { ATA_PDC20318, 0, PR_MIO, PR_SATA, ATA_SA150, "PDC20318" }, { ATA_PDC20319, 0, PR_MIO, PR_SATA, ATA_SA150, "PDC20319" }, { ATA_PDC20371, 0, PR_MIO, PR_CMBO, ATA_SA150, "PDC20371" }, { ATA_PDC20375, 0, PR_MIO, PR_CMBO, ATA_SA150, "PDC20375" }, { ATA_PDC20376, 0, PR_MIO, PR_CMBO, ATA_SA150, "PDC20376" }, { ATA_PDC20377, 0, PR_MIO, PR_CMBO, ATA_SA150, "PDC20377" }, { ATA_PDC20378, 0, PR_MIO, PR_CMBO, ATA_SA150, "PDC20378" }, { ATA_PDC20379, 0, PR_MIO, PR_CMBO, ATA_SA150, "PDC20379" }, { ATA_PDC20571, 0, PR_MIO, PR_CMBO2, ATA_SA150, "PDC20571" }, { ATA_PDC20575, 0, PR_MIO, PR_CMBO2, ATA_SA150, "PDC20575" }, { ATA_PDC20579, 0, PR_MIO, PR_CMBO2, ATA_SA150, "PDC20579" }, { ATA_PDC20771, 0, PR_MIO, PR_CMBO2, ATA_SA300, "PDC20771" }, { ATA_PDC40775, 0, PR_MIO, PR_CMBO2, ATA_SA300, "PDC40775" }, { ATA_PDC20617, 0, PR_MIO, PR_PATA, ATA_UDMA6, "PDC20617" }, { ATA_PDC20618, 0, PR_MIO, PR_PATA, ATA_UDMA6, "PDC20618" }, { ATA_PDC20619, 0, PR_MIO, PR_PATA, ATA_UDMA6, "PDC20619" }, { ATA_PDC20620, 0, PR_MIO, PR_PATA, ATA_UDMA6, "PDC20620" }, { ATA_PDC20621, 0, PR_MIO, PR_SX4X, ATA_UDMA5, "PDC20621" }, { ATA_PDC20622, 0, PR_MIO, PR_SX4X, ATA_SA150, "PDC20622" }, { ATA_PDC40518, 0, PR_MIO, PR_SATA2, ATA_SA150, "PDC40518" }, { ATA_PDC40519, 0, PR_MIO, PR_SATA2, ATA_SA150, "PDC40519" }, { ATA_PDC40718, 0, PR_MIO, PR_SATA2, ATA_SA300, "PDC40718" }, { ATA_PDC40719, 0, PR_MIO, PR_SATA2, ATA_SA300, "PDC40719" }, { ATA_PDC40779, 0, PR_MIO, PR_SATA2, ATA_SA300, "PDC40779" }, { 0, 0, 0, 0, 0, 0}}; char buffer[64]; uintptr_t devid = 0; if (pci_get_vendor(dev) != ATA_PROMISE_ID) return ENXIO; if (!(idx = ata_match_chip(dev, ids))) return ENXIO; /* if we are on a SuperTrak SX6000 dont attach */ if ((idx->cfg2 & PR_SX6K) && pci_get_class(GRANDPARENT(dev))==PCIC_BRIDGE && !BUS_READ_IVAR(device_get_parent(GRANDPARENT(dev)), GRANDPARENT(dev), PCI_IVAR_DEVID, &devid) && devid == ATA_I960RM) return ENXIO; strcpy(buffer, "Promise "); strcat(buffer, idx->text); /* if we are on a FastTrak TX4, adjust the interrupt resource */ if ((idx->cfg2 & PR_TX4) && pci_get_class(GRANDPARENT(dev))==PCIC_BRIDGE && !BUS_READ_IVAR(device_get_parent(GRANDPARENT(dev)), GRANDPARENT(dev), PCI_IVAR_DEVID, &devid) && ((devid == ATA_DEC_21150) || (devid == ATA_DEC_21150_1))) { static long start = 0, end = 0; if (pci_get_slot(dev) == 1) { bus_get_resource(dev, SYS_RES_IRQ, 0, &start, &end); strcat(buffer, " (channel 0+1)"); } else if (pci_get_slot(dev) == 2 && start && end) { bus_set_resource(dev, SYS_RES_IRQ, 0, start, end); strcat(buffer, " (channel 2+3)"); } else { start = end = 0; } } sprintf(buffer, "%s %s controller", buffer, ata_mode2str(idx->max_dma)); device_set_desc_copy(dev, buffer); ctlr->chip = idx; ctlr->chipinit = ata_promise_chipinit; return (BUS_PROBE_DEFAULT); } static int ata_promise_chipinit(device_t dev) { struct ata_pci_controller *ctlr = device_get_softc(dev); int fake_reg, stat_reg; if (ata_setup_interrupt(dev, ata_generic_intr)) return ENXIO; switch (ctlr->chip->cfg1) { case PR_NEW: /* setup clocks */ ATA_OUTB(ctlr->r_res1, 0x11, ATA_INB(ctlr->r_res1, 0x11) | 0x0a); /* FALLTHROUGH */ case PR_OLD: /* enable burst mode */ ATA_OUTB(ctlr->r_res1, 0x1f, ATA_INB(ctlr->r_res1, 0x1f) | 0x01); ctlr->ch_attach = ata_promise_ch_attach; ctlr->ch_detach = ata_pci_ch_detach; ctlr->setmode = ata_promise_setmode; return 0; case PR_TX: ctlr->ch_attach = ata_promise_tx2_ch_attach; ctlr->ch_detach = ata_pci_ch_detach; ctlr->setmode = ata_promise_setmode; return 0; case PR_MIO: ctlr->r_type1 = SYS_RES_MEMORY; ctlr->r_rid1 = PCIR_BAR(4); if (!(ctlr->r_res1 = bus_alloc_resource_any(dev, ctlr->r_type1, &ctlr->r_rid1, RF_ACTIVE))) goto failnfree; ctlr->r_type2 = SYS_RES_MEMORY; ctlr->r_rid2 = PCIR_BAR(3); if (!(ctlr->r_res2 = bus_alloc_resource_any(dev, ctlr->r_type2, &ctlr->r_rid2, RF_ACTIVE))) goto failnfree; if (ctlr->chip->cfg2 == PR_SX4X) { struct ata_promise_sx4 *hpkt; u_int32_t dimm = ATA_INL(ctlr->r_res2, 0x000c0080); if (bus_teardown_intr(dev, ctlr->r_irq, ctlr->handle) || bus_setup_intr(dev, ctlr->r_irq, ATA_INTR_FLAGS, NULL, ata_promise_sx4_intr, ctlr, &ctlr->handle)) { device_printf(dev, "unable to setup interrupt\n"); goto failnfree; } /* print info about cache memory */ device_printf(dev, "DIMM size %dMB @ 0x%08x%s\n", (((dimm >> 16) & 0xff)-((dimm >> 24) & 0xff)+1) << 4, ((dimm >> 24) & 0xff), ATA_INL(ctlr->r_res2, 0x000c0088) & (1<<16) ? " ECC enabled" : "" ); /* adjust cache memory parameters */ ATA_OUTL(ctlr->r_res2, 0x000c000c, (ATA_INL(ctlr->r_res2, 0x000c000c) & 0xffff0000)); /* setup host packet controls */ hpkt = malloc(sizeof(struct ata_promise_sx4), M_TEMP, M_NOWAIT | M_ZERO); mtx_init(&hpkt->mtx, "ATA promise HPKT lock", NULL, MTX_DEF); TAILQ_INIT(&hpkt->queue); hpkt->busy = 0; ctlr->chipset_data = hpkt; ctlr->ch_attach = ata_promise_mio_ch_attach; ctlr->ch_detach = ata_promise_mio_ch_detach; ctlr->reset = ata_promise_mio_reset; ctlr->setmode = ata_promise_setmode; ctlr->channels = 4; return 0; } /* mio type controllers need an interrupt intercept */ if (bus_teardown_intr(dev, ctlr->r_irq, ctlr->handle) || bus_setup_intr(dev, ctlr->r_irq, ATA_INTR_FLAGS, NULL, ata_promise_mio_intr, ctlr, &ctlr->handle)) { device_printf(dev, "unable to setup interrupt\n"); goto failnfree; } switch (ctlr->chip->cfg2) { case PR_PATA: ctlr->channels = ((ATA_INL(ctlr->r_res2, 0x48) & 0x01) > 0) + ((ATA_INL(ctlr->r_res2, 0x48) & 0x02) > 0) + 2; goto sata150; case PR_CMBO: ctlr->channels = 3; goto sata150; case PR_SATA: ctlr->channels = 4; sata150: fake_reg = 0x60; stat_reg = 0x6c; break; case PR_CMBO2: ctlr->channels = 3; goto sataii; case PR_SATA2: default: ctlr->channels = 4; sataii: fake_reg = 0x54; stat_reg = 0x60; break; } /* prime fake interrupt register */ ATA_OUTL(ctlr->r_res2, fake_reg, 0xffffffff); /* clear SATA status and unmask interrupts */ ATA_OUTL(ctlr->r_res2, stat_reg, 0x000000ff); /* enable "long burst length" on gen2 chips */ if ((ctlr->chip->cfg2 == PR_SATA2) || (ctlr->chip->cfg2 == PR_CMBO2)) ATA_OUTL(ctlr->r_res2, 0x44, ATA_INL(ctlr->r_res2, 0x44) | 0x2000); ctlr->ch_attach = ata_promise_mio_ch_attach; ctlr->ch_detach = ata_promise_mio_ch_detach; ctlr->reset = ata_promise_mio_reset; ctlr->setmode = ata_promise_mio_setmode; return 0; } failnfree: if (ctlr->r_res2) bus_release_resource(dev, ctlr->r_type2, ctlr->r_rid2, ctlr->r_res2); if (ctlr->r_res1) bus_release_resource(dev, ctlr->r_type1, ctlr->r_rid1, ctlr->r_res1); return ENXIO; } static int ata_promise_ch_attach(device_t dev) { struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev)); struct ata_channel *ch = device_get_softc(dev); if (ata_pci_ch_attach(dev)) return ENXIO; if (ctlr->chip->cfg1 == PR_NEW) { ch->dma.start = ata_promise_dmastart; ch->dma.stop = ata_promise_dmastop; ch->dma.reset = ata_promise_dmareset; } ch->hw.status = ata_promise_status; return 0; } static int ata_promise_status(device_t dev) { struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev)); struct ata_channel *ch = device_get_softc(dev); if (ATA_INL(ctlr->r_res1, 0x1c) & (ch->unit ? 0x00004000 : 0x00000400)) { return ata_pci_status(dev); } return 0; } static int ata_promise_dmastart(struct ata_request *request) { - struct ata_pci_controller *ctlr=device_get_softc(GRANDPARENT(request->dev)); + struct ata_pci_controller *ctlr=device_get_softc(device_get_parent(request->parent)); struct ata_channel *ch = device_get_softc(request->parent); - struct ata_device *atadev = device_get_softc(request->dev); - if (atadev->flags & ATA_D_48BIT_ACTIVE) { + if (request->flags & ATA_R_48BIT) { ATA_OUTB(ctlr->r_res1, 0x11, ATA_INB(ctlr->r_res1, 0x11) | (ch->unit ? 0x08 : 0x02)); ATA_OUTL(ctlr->r_res1, ch->unit ? 0x24 : 0x20, ((request->flags & ATA_R_READ) ? 0x05000000 : 0x06000000) | (request->bytecount >> 1)); } 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, request->dma->sg_bus); ATA_IDX_OUTB(ch, ATA_BMCMD_PORT, ((request->flags & ATA_R_READ) ? ATA_BMCMD_WRITE_READ : 0) | ATA_BMCMD_START_STOP); ch->dma.flags |= ATA_DMA_ACTIVE; return 0; } static int ata_promise_dmastop(struct ata_request *request) { - struct ata_pci_controller *ctlr=device_get_softc(GRANDPARENT(request->dev)); + struct ata_pci_controller *ctlr=device_get_softc(device_get_parent(request->parent)); struct ata_channel *ch = device_get_softc(request->parent); - struct ata_device *atadev = device_get_softc(request->dev); int error; - if (atadev->flags & ATA_D_48BIT_ACTIVE) { + if (request->flags & ATA_R_48BIT) { ATA_OUTB(ctlr->r_res1, 0x11, ATA_INB(ctlr->r_res1, 0x11) & ~(ch->unit ? 0x08 : 0x02)); ATA_OUTL(ctlr->r_res1, ch->unit ? 0x24 : 0x20, 0); } error = ATA_IDX_INB(ch, ATA_BMSTAT_PORT); 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); ch->dma.flags &= ~ATA_DMA_ACTIVE; return error; } static void ata_promise_dmareset(device_t dev) { struct ata_channel *ch = device_get_softc(dev); 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); ch->flags &= ~ATA_DMA_ACTIVE; } static void ata_promise_setmode(device_t dev, int mode) { device_t gparent = GRANDPARENT(dev); struct ata_pci_controller *ctlr = device_get_softc(gparent); struct ata_channel *ch = device_get_softc(device_get_parent(dev)); struct ata_device *atadev = device_get_softc(dev); int devno = (ch->unit << 1) + atadev->unit; int error; u_int32_t timings[][2] = { /* PR_OLD PR_NEW mode */ { 0x004ff329, 0x004fff2f }, /* PIO 0 */ { 0x004fec25, 0x004ff82a }, /* PIO 1 */ { 0x004fe823, 0x004ff026 }, /* PIO 2 */ { 0x004fe622, 0x004fec24 }, /* PIO 3 */ { 0x004fe421, 0x004fe822 }, /* PIO 4 */ { 0x004567f3, 0x004acef6 }, /* MWDMA 0 */ { 0x004467f3, 0x0048cef6 }, /* MWDMA 1 */ { 0x004367f3, 0x0046cef6 }, /* MWDMA 2 */ { 0x004367f3, 0x0046cef6 }, /* UDMA 0 */ { 0x004247f3, 0x00448ef6 }, /* UDMA 1 */ { 0x004127f3, 0x00436ef6 }, /* UDMA 2 */ { 0, 0x00424ef6 }, /* UDMA 3 */ { 0, 0x004127f3 }, /* UDMA 4 */ { 0, 0x004127f3 } /* UDMA 5 */ }; mode = ata_limit_mode(dev, mode, ctlr->chip->max_dma); switch (ctlr->chip->cfg1) { case PR_OLD: case PR_NEW: if (mode > ATA_UDMA2 && (pci_read_config(gparent, 0x50, 2) & (ch->unit ? 1 << 11 : 1 << 10))) { ata_print_cable(dev, "controller"); mode = ATA_UDMA2; } if (ata_atapi(dev) && mode > ATA_PIO_MAX) mode = ata_limit_mode(dev, mode, ATA_PIO_MAX); break; case PR_TX: ATA_IDX_OUTB(ch, ATA_BMDEVSPEC_0, 0x0b); if (mode > ATA_UDMA2 && ATA_IDX_INB(ch, ATA_BMDEVSPEC_1) & 0x04) { ata_print_cable(dev, "controller"); mode = ATA_UDMA2; } break; case PR_MIO: if (mode > ATA_UDMA2 && (ATA_INL(ctlr->r_res2, (ctlr->chip->cfg2 & PR_SX4X ? 0x000c0260 : 0x0260) + (ch->unit << 7)) & 0x01000000)) { ata_print_cable(dev, "controller"); mode = ATA_UDMA2; } break; } error = ata_controlcmd(dev, ATA_SETFEATURES, ATA_SF_SETXFER, 0, mode); if (bootverbose) device_printf(dev, "%ssetting %s on %s chip\n", (error) ? "FAILURE " : "", ata_mode2str(mode), ctlr->chip->text); if (!error) { if (ctlr->chip->cfg1 < PR_TX) pci_write_config(gparent, 0x60 + (devno << 2), timings[ata_mode2idx(mode)][ctlr->chip->cfg1], 4); atadev->mode = mode; } return; } static int ata_promise_tx2_ch_attach(device_t dev) { struct ata_channel *ch = device_get_softc(dev); if (ata_pci_ch_attach(dev)) return ENXIO; ch->hw.status = ata_promise_tx2_status; return 0; } static int ata_promise_tx2_status(device_t dev) { struct ata_channel *ch = device_get_softc(dev); ATA_IDX_OUTB(ch, ATA_BMDEVSPEC_0, 0x0b); if (ATA_IDX_INB(ch, ATA_BMDEVSPEC_1) & 0x20) { return ata_pci_status(dev); } return 0; } static int ata_promise_mio_ch_attach(device_t dev) { struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev)); struct ata_channel *ch = device_get_softc(dev); int offset = (ctlr->chip->cfg2 & PR_SX4X) ? 0x000c0000 : 0; int i; ata_promise_mio_dmainit(dev); for (i = ATA_DATA; i <= ATA_COMMAND; i++) { ch->r_io[i].res = ctlr->r_res2; ch->r_io[i].offset = offset + 0x0200 + (i << 2) + (ch->unit << 7); } ch->r_io[ATA_CONTROL].res = ctlr->r_res2; ch->r_io[ATA_CONTROL].offset = offset + 0x0238 + (ch->unit << 7); ch->r_io[ATA_IDX_ADDR].res = ctlr->r_res2; ata_default_registers(dev); if ((ctlr->chip->cfg2 & (PR_SATA | PR_SATA2)) || ((ctlr->chip->cfg2 & (PR_CMBO | PR_CMBO2)) && ch->unit < 2)) { ch->r_io[ATA_SSTATUS].res = ctlr->r_res2; ch->r_io[ATA_SSTATUS].offset = 0x400 + (ch->unit << 8); ch->r_io[ATA_SERROR].res = ctlr->r_res2; ch->r_io[ATA_SERROR].offset = 0x404 + (ch->unit << 8); ch->r_io[ATA_SCONTROL].res = ctlr->r_res2; ch->r_io[ATA_SCONTROL].offset = 0x408 + (ch->unit << 8); ch->flags |= ATA_NO_SLAVE; } ch->flags |= ATA_USE_16BIT; ata_generic_hw(dev); if (ctlr->chip->cfg2 & PR_SX4X) { ch->hw.command = ata_promise_sx4_command; } else { ch->hw.command = ata_promise_mio_command; ch->hw.status = ata_promise_mio_status; ch->hw.softreset = ata_promise_mio_softreset; ch->hw.pm_read = ata_promise_mio_pm_read; ch->hw.pm_write = ata_promise_mio_pm_write; } return 0; } static int ata_promise_mio_ch_detach(device_t dev) { ata_dmafini(dev); return (0); } static void ata_promise_mio_intr(void *data) { struct ata_pci_controller *ctlr = data; struct ata_channel *ch; u_int32_t vector; int unit, fake_reg; switch (ctlr->chip->cfg2) { case PR_PATA: case PR_CMBO: case PR_SATA: fake_reg = 0x60; break; case PR_CMBO2: case PR_SATA2: default: fake_reg = 0x54; break; } /* * since reading interrupt status register on early "mio" chips * clears the status bits we cannot read it for each channel later on * in the generic interrupt routine. * store the bits in an unused register in the chip so we can read * it from there safely to get around this "feature". */ vector = ATA_INL(ctlr->r_res2, 0x040); ATA_OUTL(ctlr->r_res2, 0x040, vector); ATA_OUTL(ctlr->r_res2, fake_reg, vector); for (unit = 0; unit < ctlr->channels; unit++) { if ((ch = ctlr->interrupt[unit].argument)) ctlr->interrupt[unit].function(ch); } ATA_OUTL(ctlr->r_res2, fake_reg, 0xffffffff); } static int ata_promise_mio_status(device_t dev) { struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev)); struct ata_channel *ch = device_get_softc(dev); u_int32_t fake_reg, stat_reg, vector, status; switch (ctlr->chip->cfg2) { case PR_PATA: case PR_CMBO: case PR_SATA: fake_reg = 0x60; stat_reg = 0x6c; break; case PR_CMBO2: case PR_SATA2: default: fake_reg = 0x54; stat_reg = 0x60; break; } /* read and acknowledge interrupt */ vector = ATA_INL(ctlr->r_res2, fake_reg); /* read and clear interface status */ status = ATA_INL(ctlr->r_res2, stat_reg); ATA_OUTL(ctlr->r_res2, stat_reg, status & (0x00000011 << ch->unit)); /* check for and handle disconnect events */ if (status & (0x00000001 << ch->unit)) { if (bootverbose) device_printf(dev, "DISCONNECT requested\n"); taskqueue_enqueue(taskqueue_thread, &ch->conntask); } /* check for and handle connect events */ if (status & (0x00000010 << ch->unit)) { if (bootverbose) device_printf(dev, "CONNECT requested\n"); taskqueue_enqueue(taskqueue_thread, &ch->conntask); } /* do we have any device action ? */ return (vector & (1 << (ch->unit + 1))); } static int ata_promise_mio_command(struct ata_request *request) { - struct ata_pci_controller *ctlr=device_get_softc(GRANDPARENT(request->dev)); + struct ata_pci_controller *ctlr=device_get_softc(device_get_parent(request->parent)); struct ata_channel *ch = device_get_softc(request->parent); - struct ata_device *atadev = device_get_softc(request->dev); u_int32_t *wordp = (u_int32_t *)ch->dma.work; ATA_OUTL(ctlr->r_res2, (ch->unit + 1) << 2, 0x00000001); if ((ctlr->chip->cfg2 == PR_SATA2) || ((ctlr->chip->cfg2 == PR_CMBO2) && (ch->unit < 2))) { /* set portmultiplier port */ - ATA_OUTB(ctlr->r_res2, 0x4e8 + (ch->unit << 8), atadev->unit & 0x0f); + ATA_OUTB(ctlr->r_res2, 0x4e8 + (ch->unit << 8), request->unit & 0x0f); } /* XXX SOS add ATAPI commands support later */ switch (request->u.ata.command) { default: return ata_generic_command(request); case ATA_READ_DMA: case ATA_READ_DMA48: wordp[0] = htole32(0x04 | ((ch->unit + 1) << 16) | (0x00 << 24)); break; case ATA_WRITE_DMA: case ATA_WRITE_DMA48: wordp[0] = htole32(0x00 | ((ch->unit + 1) << 16) | (0x00 << 24)); break; } wordp[1] = htole32(request->dma->sg_bus); wordp[2] = 0; ata_promise_apkt((u_int8_t*)wordp, request); ATA_OUTL(ctlr->r_res2, 0x0240 + (ch->unit << 7), ch->dma.work_bus); return 0; } static void ata_promise_mio_reset(device_t dev) { struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev)); struct ata_channel *ch = device_get_softc(dev); struct ata_promise_sx4 *hpktp; switch (ctlr->chip->cfg2) { case PR_SX4X: /* softreset channel ATA module */ hpktp = ctlr->chipset_data; ATA_OUTL(ctlr->r_res2, 0xc0260 + (ch->unit << 7), ch->unit + 1); ata_udelay(1000); ATA_OUTL(ctlr->r_res2, 0xc0260 + (ch->unit << 7), (ATA_INL(ctlr->r_res2, 0xc0260 + (ch->unit << 7)) & ~0x00003f9f) | (ch->unit + 1)); /* softreset HOST module */ /* XXX SOS what about other outstandings */ mtx_lock(&hpktp->mtx); ATA_OUTL(ctlr->r_res2, 0xc012c, (ATA_INL(ctlr->r_res2, 0xc012c) & ~0x00000f9f) | (1 << 11)); DELAY(10); ATA_OUTL(ctlr->r_res2, 0xc012c, (ATA_INL(ctlr->r_res2, 0xc012c) & ~0x00000f9f)); hpktp->busy = 0; mtx_unlock(&hpktp->mtx); ata_generic_reset(dev); break; case PR_PATA: case PR_CMBO: case PR_SATA: if ((ctlr->chip->cfg2 == PR_SATA) || ((ctlr->chip->cfg2 == PR_CMBO) && (ch->unit < 2))) { /* mask plug/unplug intr */ ATA_OUTL(ctlr->r_res2, 0x06c, (0x00110000 << ch->unit)); } /* softreset channels ATA module */ ATA_OUTL(ctlr->r_res2, 0x0260 + (ch->unit << 7), (1 << 11)); ata_udelay(10000); ATA_OUTL(ctlr->r_res2, 0x0260 + (ch->unit << 7), (ATA_INL(ctlr->r_res2, 0x0260 + (ch->unit << 7)) & ~0x00003f9f) | (ch->unit + 1)); if ((ctlr->chip->cfg2 == PR_SATA) || ((ctlr->chip->cfg2 == PR_CMBO) && (ch->unit < 2))) { if (ata_sata_phy_reset(dev, -1, 1)) ata_generic_reset(dev); /* reset and enable plug/unplug intr */ ATA_OUTL(ctlr->r_res2, 0x06c, (0x00000011 << ch->unit)); } else ata_generic_reset(dev); break; case PR_CMBO2: case PR_SATA2: if ((ctlr->chip->cfg2 == PR_SATA2) || ((ctlr->chip->cfg2 == PR_CMBO2) && (ch->unit < 2))) { /* set portmultiplier port */ //ATA_OUTL(ctlr->r_res2, 0x4e8 + (ch->unit << 8), 0x0f); /* mask plug/unplug intr */ ATA_OUTL(ctlr->r_res2, 0x060, (0x00110000 << ch->unit)); } /* softreset channels ATA module */ ATA_OUTL(ctlr->r_res2, 0x0260 + (ch->unit << 7), (1 << 11)); ata_udelay(10000); ATA_OUTL(ctlr->r_res2, 0x0260 + (ch->unit << 7), (ATA_INL(ctlr->r_res2, 0x0260 + (ch->unit << 7)) & ~0x00003f9f) | (ch->unit + 1)); if ((ctlr->chip->cfg2 == PR_SATA2) || ((ctlr->chip->cfg2 == PR_CMBO2) && (ch->unit < 2))) { /* set PHY mode to "improved" */ ATA_OUTL(ctlr->r_res2, 0x414 + (ch->unit << 8), (ATA_INL(ctlr->r_res2, 0x414 + (ch->unit << 8)) & ~0x00000003) | 0x00000001); if (ata_sata_phy_reset(dev, -1, 1)) { u_int32_t signature = ch->hw.softreset(dev, ATA_PM); if (1 | bootverbose) device_printf(dev, "SIGNATURE: %08x\n", signature); switch (signature >> 16) { case 0x0000: ch->devices = ATA_ATA_MASTER; break; case 0x9669: ch->devices = ATA_PORTMULTIPLIER; ata_pm_identify(dev); break; case 0xeb14: ch->devices = ATA_ATAPI_MASTER; break; default: /* SOS XXX */ if (bootverbose) device_printf(dev, "No signature, assuming disk device\n"); ch->devices = ATA_ATA_MASTER; } if (bootverbose) device_printf(dev, "promise_mio_reset devices=%08x\n", ch->devices); } /* reset and enable plug/unplug intr */ ATA_OUTL(ctlr->r_res2, 0x060, (0x00000011 << ch->unit)); ///* set portmultiplier port */ ATA_OUTL(ctlr->r_res2, 0x4e8 + (ch->unit << 8), 0x00); } else ata_generic_reset(dev); break; } } static int ata_promise_mio_pm_read(device_t dev, int port, int reg, u_int32_t *result) { struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev)); struct ata_channel *ch = device_get_softc(dev); int timeout = 0; /* set portmultiplier port */ ATA_OUTB(ctlr->r_res2, 0x4e8 + (ch->unit << 8), 0x0f); ATA_IDX_OUTB(ch, ATA_FEATURE, reg); ATA_IDX_OUTB(ch, ATA_DRIVE, port); ATA_IDX_OUTB(ch, ATA_COMMAND, ATA_READ_PM); while (timeout < 1000000) { u_int8_t status = ATA_IDX_INB(ch, ATA_STATUS); if (!(status & ATA_S_BUSY)) break; timeout += 1000; DELAY(1000); } if (timeout >= 1000000) return ATA_E_ABORT; *result = ATA_IDX_INB(ch, ATA_COUNT) | (ATA_IDX_INB(ch, ATA_SECTOR) << 8) | (ATA_IDX_INB(ch, ATA_CYL_LSB) << 16) | (ATA_IDX_INB(ch, ATA_CYL_MSB) << 24); return 0; } static int ata_promise_mio_pm_write(device_t dev, int port, int reg, u_int32_t value) { struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev)); struct ata_channel *ch = device_get_softc(dev); int timeout = 0; /* set portmultiplier port */ ATA_OUTB(ctlr->r_res2, 0x4e8 + (ch->unit << 8), 0x0f); ATA_IDX_OUTB(ch, ATA_FEATURE, reg); ATA_IDX_OUTB(ch, ATA_DRIVE, port); ATA_IDX_OUTB(ch, ATA_COUNT, value & 0xff); ATA_IDX_OUTB(ch, ATA_SECTOR, (value >> 8) & 0xff); ATA_IDX_OUTB(ch, ATA_CYL_LSB, (value >> 16) & 0xff); ATA_IDX_OUTB(ch, ATA_CYL_MSB, (value >> 24) & 0xff); ATA_IDX_OUTB(ch, ATA_COMMAND, ATA_WRITE_PM); while (timeout < 1000000) { u_int8_t status = ATA_IDX_INB(ch, ATA_STATUS); if (!(status & ATA_S_BUSY)) break; timeout += 1000; DELAY(1000); } if (timeout >= 1000000) return ATA_E_ABORT; return ATA_IDX_INB(ch, ATA_ERROR); } /* must be called with ATA channel locked and state_mtx held */ static u_int32_t ata_promise_mio_softreset(device_t dev, int port) { struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev)); struct ata_channel *ch = device_get_softc(dev); int timeout; /* set portmultiplier port */ ATA_OUTB(ctlr->r_res2, 0x4e8 + (ch->unit << 8), port & 0x0f); /* softreset device on this channel */ ATA_IDX_OUTB(ch, ATA_DRIVE, ATA_D_IBM | ATA_D_LBA | ATA_DEV(ATA_MASTER)); DELAY(10); ATA_IDX_OUTB(ch, ATA_CONTROL, ATA_A_IDS | ATA_A_RESET); ata_udelay(10000); ATA_IDX_OUTB(ch, ATA_CONTROL, ATA_A_IDS); ata_udelay(150000); ATA_IDX_INB(ch, ATA_ERROR); /* wait for BUSY to go inactive */ for (timeout = 0; timeout < 100; timeout++) { u_int8_t err, stat; err = ATA_IDX_INB(ch, ATA_ERROR); stat = ATA_IDX_INB(ch, ATA_STATUS); //if (stat == err && timeout > (stat & ATA_S_BUSY ? 100 : 10)) //break; if (!(stat & ATA_S_BUSY)) { //if ((err & 0x7f) == ATA_E_ILI) { return ATA_IDX_INB(ch, ATA_COUNT) | (ATA_IDX_INB(ch, ATA_SECTOR) << 8) | (ATA_IDX_INB(ch, ATA_CYL_LSB) << 16) | (ATA_IDX_INB(ch, ATA_CYL_MSB) << 24); //} //else if (stat & 0x0f) { //stat |= ATA_S_BUSY; //} } if (!(stat & ATA_S_BUSY) || (stat == 0xff && timeout > 10)) break; ata_udelay(100000); } return -1; } static void ata_promise_mio_dmainit(device_t dev) { struct ata_channel *ch = device_get_softc(dev); ata_dmainit(dev); /* note start and stop are not used here */ ch->dma.setprd = ata_promise_mio_setprd; } #define MAXLASTSGSIZE (32 * sizeof(u_int32_t)) static void ata_promise_mio_setprd(void *xsc, bus_dma_segment_t *segs, int nsegs, int error) { struct ata_dmasetprd_args *args = xsc; struct ata_dma_prdentry *prd = args->dmatab; int i; if ((args->error = error)) return; for (i = 0; i < nsegs; i++) { prd[i].addr = htole32(segs[i].ds_addr); prd[i].count = htole32(segs[i].ds_len); } if (segs[i - 1].ds_len > MAXLASTSGSIZE) { //printf("split last SG element of %u\n", segs[i - 1].ds_len); prd[i - 1].count = htole32(segs[i - 1].ds_len - MAXLASTSGSIZE); prd[i].count = htole32(MAXLASTSGSIZE); prd[i].addr = htole32(segs[i - 1].ds_addr + (segs[i - 1].ds_len - MAXLASTSGSIZE)); nsegs++; i++; } prd[i - 1].count |= htole32(ATA_DMA_EOT); KASSERT(nsegs <= ATA_DMA_ENTRIES, ("too many DMA segment entries\n")); args->nsegs = nsegs; } static void ata_promise_mio_setmode(device_t dev, int mode) { device_t gparent = GRANDPARENT(dev); struct ata_pci_controller *ctlr = device_get_softc(gparent); struct ata_channel *ch = device_get_softc(device_get_parent(dev)); if ( (ctlr->chip->cfg2 == PR_SATA) || ((ctlr->chip->cfg2 == PR_CMBO) && (ch->unit < 2)) || (ctlr->chip->cfg2 == PR_SATA2) || ((ctlr->chip->cfg2 == PR_CMBO2) && (ch->unit < 2))) ata_sata_setmode(dev, mode); else ata_promise_setmode(dev, mode); } static void ata_promise_sx4_intr(void *data) { struct ata_pci_controller *ctlr = data; struct ata_channel *ch; u_int32_t vector = ATA_INL(ctlr->r_res2, 0x000c0480); int unit; for (unit = 0; unit < ctlr->channels; unit++) { if (vector & (1 << (unit + 1))) if ((ch = ctlr->interrupt[unit].argument)) ctlr->interrupt[unit].function(ch); if (vector & (1 << (unit + 5))) if ((ch = ctlr->interrupt[unit].argument)) ata_promise_queue_hpkt(ctlr, htole32((ch->unit * ATA_PDC_CHN_OFFSET) + ATA_PDC_HPKT_OFFSET)); if (vector & (1 << (unit + 9))) { ata_promise_next_hpkt(ctlr); if ((ch = ctlr->interrupt[unit].argument)) ctlr->interrupt[unit].function(ch); } if (vector & (1 << (unit + 13))) { ata_promise_next_hpkt(ctlr); if ((ch = ctlr->interrupt[unit].argument)) ATA_OUTL(ctlr->r_res2, 0x000c0240 + (ch->unit << 7), htole32((ch->unit * ATA_PDC_CHN_OFFSET) + ATA_PDC_APKT_OFFSET)); } } } static int ata_promise_sx4_command(struct ata_request *request) { - device_t gparent = GRANDPARENT(request->dev); + device_t gparent = device_get_parent(request->parent); struct ata_pci_controller *ctlr = device_get_softc(gparent); struct ata_channel *ch = device_get_softc(request->parent); struct ata_dma_prdentry *prd; caddr_t window = rman_get_virtual(ctlr->r_res1); u_int32_t *wordp; int i, idx, length = 0; /* XXX SOS add ATAPI commands support later */ switch (request->u.ata.command) { default: return -1; case ATA_ATA_IDENTIFY: case ATA_READ: case ATA_READ48: case ATA_READ_MUL: case ATA_READ_MUL48: case ATA_WRITE: case ATA_WRITE48: case ATA_WRITE_MUL: case ATA_WRITE_MUL48: ATA_OUTL(ctlr->r_res2, 0x000c0400 + ((ch->unit + 1) << 2), 0x00000001); return ata_generic_command(request); case ATA_SETFEATURES: case ATA_FLUSHCACHE: case ATA_FLUSHCACHE48: case ATA_SLEEP: case ATA_SET_MULTI: wordp = (u_int32_t *) (window + (ch->unit * ATA_PDC_CHN_OFFSET) + ATA_PDC_APKT_OFFSET); wordp[0] = htole32(0x08 | ((ch->unit + 1)<<16) | (0x00 << 24)); wordp[1] = 0; wordp[2] = 0; ata_promise_apkt((u_int8_t *)wordp, request); ATA_OUTL(ctlr->r_res2, 0x000c0484, 0x00000001); ATA_OUTL(ctlr->r_res2, 0x000c0400 + ((ch->unit + 1) << 2), 0x00000001); ATA_OUTL(ctlr->r_res2, 0x000c0240 + (ch->unit << 7), htole32((ch->unit * ATA_PDC_CHN_OFFSET)+ATA_PDC_APKT_OFFSET)); return 0; case ATA_READ_DMA: case ATA_READ_DMA48: case ATA_WRITE_DMA: case ATA_WRITE_DMA48: prd = request->dma->sg; wordp = (u_int32_t *) (window + (ch->unit * ATA_PDC_CHN_OFFSET) + ATA_PDC_HSG_OFFSET); i = idx = 0; do { wordp[idx++] = prd[i].addr; wordp[idx++] = prd[i].count; length += (prd[i].count & ~ATA_DMA_EOT); } while (!(prd[i++].count & ATA_DMA_EOT)); wordp = (u_int32_t *) (window + (ch->unit * ATA_PDC_CHN_OFFSET) + ATA_PDC_LSG_OFFSET); wordp[0] = htole32((ch->unit * ATA_PDC_BUF_OFFSET) + ATA_PDC_BUF_BASE); wordp[1] = htole32(request->bytecount | ATA_DMA_EOT); wordp = (u_int32_t *) (window + (ch->unit * ATA_PDC_CHN_OFFSET) + ATA_PDC_ASG_OFFSET); wordp[0] = htole32((ch->unit * ATA_PDC_BUF_OFFSET) + ATA_PDC_BUF_BASE); wordp[1] = htole32(request->bytecount | ATA_DMA_EOT); wordp = (u_int32_t *) (window + (ch->unit * ATA_PDC_CHN_OFFSET) + ATA_PDC_HPKT_OFFSET); if (request->flags & ATA_R_READ) wordp[0] = htole32(0x14 | ((ch->unit+9)<<16) | ((ch->unit+5)<<24)); if (request->flags & ATA_R_WRITE) wordp[0] = htole32(0x00 | ((ch->unit+13)<<16) | (0x00<<24)); wordp[1] = htole32((ch->unit * ATA_PDC_CHN_OFFSET)+ATA_PDC_HSG_OFFSET); wordp[2] = htole32((ch->unit * ATA_PDC_CHN_OFFSET)+ATA_PDC_LSG_OFFSET); wordp[3] = 0; wordp = (u_int32_t *) (window + (ch->unit * ATA_PDC_CHN_OFFSET) + ATA_PDC_APKT_OFFSET); if (request->flags & ATA_R_READ) wordp[0] = htole32(0x04 | ((ch->unit+5)<<16) | (0x00<<24)); if (request->flags & ATA_R_WRITE) wordp[0] = htole32(0x10 | ((ch->unit+1)<<16) | ((ch->unit+13)<<24)); wordp[1] = htole32((ch->unit * ATA_PDC_CHN_OFFSET)+ATA_PDC_ASG_OFFSET); wordp[2] = 0; ata_promise_apkt((u_int8_t *)wordp, request); ATA_OUTL(ctlr->r_res2, 0x000c0484, 0x00000001); if (request->flags & ATA_R_READ) { ATA_OUTL(ctlr->r_res2, 0x000c0400 + ((ch->unit+5)<<2), 0x00000001); ATA_OUTL(ctlr->r_res2, 0x000c0400 + ((ch->unit+9)<<2), 0x00000001); ATA_OUTL(ctlr->r_res2, 0x000c0240 + (ch->unit << 7), htole32((ch->unit * ATA_PDC_CHN_OFFSET) + ATA_PDC_APKT_OFFSET)); } if (request->flags & ATA_R_WRITE) { ATA_OUTL(ctlr->r_res2, 0x000c0400 + ((ch->unit+1)<<2), 0x00000001); ATA_OUTL(ctlr->r_res2, 0x000c0400 + ((ch->unit+13)<<2), 0x00000001); ata_promise_queue_hpkt(ctlr, htole32((ch->unit * ATA_PDC_CHN_OFFSET) + ATA_PDC_HPKT_OFFSET)); } return 0; } } static int ata_promise_apkt(u_int8_t *bytep, struct ata_request *request) { - struct ata_device *atadev = device_get_softc(request->dev); int i = 12; bytep[i++] = ATA_PDC_1B | ATA_PDC_WRITE_REG | ATA_PDC_WAIT_NBUSY|ATA_DRIVE; - bytep[i++] = ATA_D_IBM | ATA_D_LBA | ATA_DEV(atadev->unit); + bytep[i++] = ATA_D_IBM | ATA_D_LBA | ATA_DEV(request->unit); bytep[i++] = ATA_PDC_1B | ATA_PDC_WRITE_CTL; bytep[i++] = ATA_A_4BIT; - if (atadev->flags & ATA_D_48BIT_ACTIVE) { + if (request->flags & ATA_R_48BIT) { bytep[i++] = ATA_PDC_2B | ATA_PDC_WRITE_REG | ATA_FEATURE; bytep[i++] = request->u.ata.feature >> 8; bytep[i++] = request->u.ata.feature; bytep[i++] = ATA_PDC_2B | ATA_PDC_WRITE_REG | ATA_COUNT; bytep[i++] = request->u.ata.count >> 8; bytep[i++] = request->u.ata.count; bytep[i++] = ATA_PDC_2B | ATA_PDC_WRITE_REG | ATA_SECTOR; bytep[i++] = request->u.ata.lba >> 24; bytep[i++] = request->u.ata.lba; bytep[i++] = ATA_PDC_2B | ATA_PDC_WRITE_REG | ATA_CYL_LSB; bytep[i++] = request->u.ata.lba >> 32; bytep[i++] = request->u.ata.lba >> 8; bytep[i++] = ATA_PDC_2B | ATA_PDC_WRITE_REG | ATA_CYL_MSB; bytep[i++] = request->u.ata.lba >> 40; bytep[i++] = request->u.ata.lba >> 16; bytep[i++] = ATA_PDC_1B | ATA_PDC_WRITE_REG | ATA_DRIVE; - bytep[i++] = ATA_D_LBA | ATA_DEV(atadev->unit); + bytep[i++] = ATA_D_LBA | ATA_DEV(request->unit); } else { bytep[i++] = ATA_PDC_1B | ATA_PDC_WRITE_REG | ATA_FEATURE; bytep[i++] = request->u.ata.feature; bytep[i++] = ATA_PDC_1B | ATA_PDC_WRITE_REG | ATA_COUNT; bytep[i++] = request->u.ata.count; bytep[i++] = ATA_PDC_1B | ATA_PDC_WRITE_REG | ATA_SECTOR; bytep[i++] = request->u.ata.lba; bytep[i++] = ATA_PDC_1B | ATA_PDC_WRITE_REG | ATA_CYL_LSB; bytep[i++] = request->u.ata.lba >> 8; bytep[i++] = ATA_PDC_1B | ATA_PDC_WRITE_REG | ATA_CYL_MSB; bytep[i++] = request->u.ata.lba >> 16; bytep[i++] = ATA_PDC_1B | ATA_PDC_WRITE_REG | ATA_DRIVE; - bytep[i++] = (atadev->flags & ATA_D_USE_CHS ? 0 : ATA_D_LBA) | - ATA_D_IBM | ATA_DEV(atadev->unit) | + bytep[i++] = ATA_D_LBA | ATA_D_IBM | ATA_DEV(request->unit) | ((request->u.ata.lba >> 24)&0xf); } bytep[i++] = ATA_PDC_1B | ATA_PDC_WRITE_END | ATA_COMMAND; bytep[i++] = request->u.ata.command; return i; } static void ata_promise_queue_hpkt(struct ata_pci_controller *ctlr, u_int32_t hpkt) { struct ata_promise_sx4 *hpktp = ctlr->chipset_data; mtx_lock(&hpktp->mtx); if (hpktp->busy) { struct host_packet *hp = malloc(sizeof(struct host_packet), M_TEMP, M_NOWAIT | M_ZERO); hp->addr = hpkt; TAILQ_INSERT_TAIL(&hpktp->queue, hp, chain); } else { hpktp->busy = 1; ATA_OUTL(ctlr->r_res2, 0x000c0100, hpkt); } mtx_unlock(&hpktp->mtx); } static void ata_promise_next_hpkt(struct ata_pci_controller *ctlr) { struct ata_promise_sx4 *hpktp = ctlr->chipset_data; struct host_packet *hp; mtx_lock(&hpktp->mtx); if ((hp = TAILQ_FIRST(&hpktp->queue))) { TAILQ_REMOVE(&hpktp->queue, hp, chain); ATA_OUTL(ctlr->r_res2, 0x000c0100, hp->addr); free(hp, M_TEMP); } else hpktp->busy = 0; mtx_unlock(&hpktp->mtx); } ATA_DECLARE_DRIVER(ata_promise); diff --git a/sys/dev/ata/chipsets/ata-serverworks.c b/sys/dev/ata/chipsets/ata-serverworks.c index dfa01f5f80ce..886282ebb376 100644 --- a/sys/dev/ata/chipsets/ata-serverworks.c +++ b/sys/dev/ata/chipsets/ata-serverworks.c @@ -1,398 +1,397 @@ /*- * Copyright (c) 1998 - 2008 Søren Schmidt * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer, * without modification, immediately at the beginning of the file. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * 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. */ #include __FBSDID("$FreeBSD$"); #include "opt_ata.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef __powerpc__ #include #endif #include #include #include #include #include #include #include #include #include /* local prototypes */ static int ata_serverworks_chipinit(device_t dev); static int ata_serverworks_ch_attach(device_t dev); static int ata_serverworks_ch_detach(device_t dev); static void ata_serverworks_tf_read(struct ata_request *request); static void ata_serverworks_tf_write(struct ata_request *request); static void ata_serverworks_setmode(device_t dev, int mode); #ifdef __powerpc__ static int ata_serverworks_status(device_t dev); #endif /* misc defines */ #define SWKS_33 0 #define SWKS_66 1 #define SWKS_100 2 #define SWKS_MIO 3 /* * ServerWorks chipset support functions */ static int ata_serverworks_probe(device_t dev) { struct ata_pci_controller *ctlr = device_get_softc(dev); static struct ata_chip_id ids[] = {{ ATA_ROSB4, 0x00, SWKS_33, 0, ATA_UDMA2, "ROSB4" }, { ATA_CSB5, 0x92, SWKS_100, 0, ATA_UDMA5, "CSB5" }, { ATA_CSB5, 0x00, SWKS_66, 0, ATA_UDMA4, "CSB5" }, { ATA_CSB6, 0x00, SWKS_100, 0, ATA_UDMA5, "CSB6" }, { ATA_CSB6_1, 0x00, SWKS_66, 0, ATA_UDMA4, "CSB6" }, { ATA_HT1000, 0x00, SWKS_100, 0, ATA_UDMA5, "HT1000" }, { ATA_HT1000_S1, 0x00, SWKS_MIO, 4, ATA_SA150, "HT1000" }, { ATA_HT1000_S2, 0x00, SWKS_MIO, 4, ATA_SA150, "HT1000" }, { ATA_K2, 0x00, SWKS_MIO, 4, ATA_SA150, "K2" }, { ATA_FRODO4, 0x00, SWKS_MIO, 4, ATA_SA150, "Frodo4" }, { ATA_FRODO8, 0x00, SWKS_MIO, 8, ATA_SA150, "Frodo8" }, { 0, 0, 0, 0, 0, 0}}; if (pci_get_vendor(dev) != ATA_SERVERWORKS_ID) return ENXIO; if (!(ctlr->chip = ata_match_chip(dev, ids))) return ENXIO; ata_set_desc(dev); ctlr->chipinit = ata_serverworks_chipinit; return (BUS_PROBE_DEFAULT); } #ifdef __powerpc__ static int ata_serverworks_status(device_t dev) { struct ata_channel *ch = device_get_softc(dev); struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev)); /* * Check if this interrupt belongs to our channel. */ if (!(ATA_INL(ctlr->r_res2, 0x1f80) & (1 << ch->unit))) return (0); /* * We need to do a 4-byte read on the status reg before the values * will report correctly */ ATA_IDX_INL(ch,ATA_STATUS); return ata_pci_status(dev); } #endif static int ata_serverworks_chipinit(device_t dev) { struct ata_pci_controller *ctlr = device_get_softc(dev); if (ata_setup_interrupt(dev, ata_generic_intr)) return ENXIO; if (ctlr->chip->cfg1 == SWKS_MIO) { ctlr->r_type2 = SYS_RES_MEMORY; ctlr->r_rid2 = PCIR_BAR(5); if (!(ctlr->r_res2 = bus_alloc_resource_any(dev, ctlr->r_type2, &ctlr->r_rid2, RF_ACTIVE))) return ENXIO; ctlr->channels = ctlr->chip->cfg2; ctlr->ch_attach = ata_serverworks_ch_attach; ctlr->ch_detach = ata_serverworks_ch_detach; ctlr->setmode = ata_sata_setmode; return 0; } else if (ctlr->chip->cfg1 == SWKS_33) { 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 == SWKS_100) ? 0x03 : 0x02, 1); } ctlr->setmode = ata_serverworks_setmode; return 0; } static int ata_serverworks_ch_attach(device_t dev) { struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev)); struct ata_channel *ch = device_get_softc(dev); int ch_offset; int i; ata_pci_dmainit(dev); ch_offset = ch->unit * 0x100; for (i = ATA_DATA; i < ATA_MAX_RES; i++) ch->r_io[i].res = ctlr->r_res2; /* setup ATA registers */ ch->r_io[ATA_DATA].offset = ch_offset + 0x00; ch->r_io[ATA_FEATURE].offset = ch_offset + 0x04; ch->r_io[ATA_COUNT].offset = ch_offset + 0x08; ch->r_io[ATA_SECTOR].offset = ch_offset + 0x0c; ch->r_io[ATA_CYL_LSB].offset = ch_offset + 0x10; ch->r_io[ATA_CYL_MSB].offset = ch_offset + 0x14; ch->r_io[ATA_DRIVE].offset = ch_offset + 0x18; ch->r_io[ATA_COMMAND].offset = ch_offset + 0x1c; ch->r_io[ATA_CONTROL].offset = ch_offset + 0x20; ata_default_registers(dev); /* setup DMA registers */ ch->r_io[ATA_BMCMD_PORT].offset = ch_offset + 0x30; ch->r_io[ATA_BMSTAT_PORT].offset = ch_offset + 0x32; ch->r_io[ATA_BMDTP_PORT].offset = ch_offset + 0x34; /* setup SATA registers */ ch->r_io[ATA_SSTATUS].offset = ch_offset + 0x40; ch->r_io[ATA_SERROR].offset = ch_offset + 0x44; ch->r_io[ATA_SCONTROL].offset = ch_offset + 0x48; ch->flags |= ATA_NO_SLAVE; ata_pci_hw(dev); ch->hw.tf_read = ata_serverworks_tf_read; ch->hw.tf_write = ata_serverworks_tf_write; #ifdef __powerpc__ ch->hw.status = ata_serverworks_status; /* Make sure that our interrupt is edge triggered */ powerpc_config_intr(bus_get_resource_start(device_get_parent(dev), SYS_RES_IRQ, 0), INTR_TRIGGER_EDGE, INTR_POLARITY_HIGH); #endif if (ctlr->chip->chipid == ATA_K2) { /* * The revision 1 K2 SATA controller has interesting bugs. Patch them. * These magic numbers regulate interrupt delivery in the first few * cases and are pure magic in the last case. * * Values obtained from the Darwin driver. */ ATA_IDX_OUTB(ch, ATA_BMSTAT_PORT, 0x04); ATA_IDX_OUTL(ch, ATA_SERROR, 0xffffffff); ATA_IDX_OUTL(ch, ATA_SCONTROL, 0x00000300); ATA_OUTL(ctlr->r_res2, ch_offset + 0x88, 0); ATA_OUTL(ctlr->r_res2, ch_offset + 0x80, ATA_INL(ctlr->r_res2, ch_offset + 0x80) & ~0x00040000); } /* chip does not reliably do 64K DMA transfers */ ch->dma.max_iosize = 64 * DEV_BSIZE; return 0; } static int ata_serverworks_ch_detach(device_t dev) { ata_pci_dmafini(dev); return (0); } static void ata_serverworks_tf_read(struct ata_request *request) { struct ata_channel *ch = device_get_softc(request->parent); - struct ata_device *atadev = device_get_softc(request->dev); - if (atadev->flags & ATA_D_48BIT_ACTIVE) { + if (request->flags & ATA_R_48BIT) { u_int16_t temp; request->u.ata.count = ATA_IDX_INW(ch, ATA_COUNT); temp = ATA_IDX_INW(ch, ATA_SECTOR); request->u.ata.lba = (u_int64_t)(temp & 0x00ff) | ((u_int64_t)(temp & 0xff00) << 24); temp = ATA_IDX_INW(ch, ATA_CYL_LSB); request->u.ata.lba |= ((u_int64_t)(temp & 0x00ff) << 8) | ((u_int64_t)(temp & 0xff00) << 32); temp = ATA_IDX_INW(ch, ATA_CYL_MSB); request->u.ata.lba |= ((u_int64_t)(temp & 0x00ff) << 16) | ((u_int64_t)(temp & 0xff00) << 40); } else { request->u.ata.count = ATA_IDX_INW(ch, ATA_COUNT) & 0x00ff; request->u.ata.lba = (ATA_IDX_INW(ch, ATA_SECTOR) & 0x00ff) | ((ATA_IDX_INW(ch, ATA_CYL_LSB) & 0x00ff) << 8) | ((ATA_IDX_INW(ch, ATA_CYL_MSB) & 0x00ff) << 16) | ((ATA_IDX_INW(ch, ATA_DRIVE) & 0xf) << 24); } } static void ata_serverworks_tf_write(struct ata_request *request) { struct ata_channel *ch = device_get_softc(request->parent); struct ata_device *atadev = device_get_softc(request->dev); - if (atadev->flags & ATA_D_48BIT_ACTIVE) { + if (request->flags & ATA_R_48BIT) { ATA_IDX_OUTW(ch, ATA_FEATURE, request->u.ata.feature); ATA_IDX_OUTW(ch, ATA_COUNT, request->u.ata.count); ATA_IDX_OUTW(ch, ATA_SECTOR, ((request->u.ata.lba >> 16) & 0xff00) | (request->u.ata.lba & 0x00ff)); ATA_IDX_OUTW(ch, ATA_CYL_LSB, ((request->u.ata.lba >> 24) & 0xff00) | ((request->u.ata.lba >> 8) & 0x00ff)); ATA_IDX_OUTW(ch, ATA_CYL_MSB, ((request->u.ata.lba >> 32) & 0xff00) | ((request->u.ata.lba >> 16) & 0x00ff)); - ATA_IDX_OUTW(ch, ATA_DRIVE, ATA_D_LBA | ATA_DEV(atadev->unit)); + ATA_IDX_OUTW(ch, ATA_DRIVE, ATA_D_LBA | ATA_DEV(request->unit)); } else { ATA_IDX_OUTW(ch, ATA_FEATURE, request->u.ata.feature); ATA_IDX_OUTW(ch, ATA_COUNT, request->u.ata.count); if (atadev->flags & ATA_D_USE_CHS) { int heads, sectors; if (atadev->param.atavalid & ATA_FLAG_54_58) { heads = atadev->param.current_heads; sectors = atadev->param.current_sectors; } else { heads = atadev->param.heads; sectors = atadev->param.sectors; } ATA_IDX_OUTW(ch, ATA_SECTOR, (request->u.ata.lba % sectors)+1); ATA_IDX_OUTW(ch, ATA_CYL_LSB, (request->u.ata.lba / (sectors * heads))); ATA_IDX_OUTW(ch, ATA_CYL_MSB, (request->u.ata.lba / (sectors * heads)) >> 8); - ATA_IDX_OUTW(ch, ATA_DRIVE, ATA_D_IBM | ATA_DEV(atadev->unit) | + ATA_IDX_OUTW(ch, ATA_DRIVE, ATA_D_IBM | ATA_DEV(request->unit) | (((request->u.ata.lba% (sectors * heads)) / sectors) & 0xf)); } else { ATA_IDX_OUTW(ch, ATA_SECTOR, request->u.ata.lba); ATA_IDX_OUTW(ch, ATA_CYL_LSB, request->u.ata.lba >> 8); ATA_IDX_OUTW(ch, ATA_CYL_MSB, request->u.ata.lba >> 16); ATA_IDX_OUTW(ch, ATA_DRIVE, - ATA_D_IBM | ATA_D_LBA | ATA_DEV(atadev->unit) | + ATA_D_IBM | ATA_D_LBA | ATA_DEV(request->unit) | ((request->u.ata.lba >> 24) & 0x0f)); } } } static void ata_serverworks_setmode(device_t dev, int mode) { device_t gparent = GRANDPARENT(dev); struct ata_pci_controller *ctlr = device_get_softc(gparent); struct ata_channel *ch = device_get_softc(device_get_parent(dev)); struct ata_device *atadev = device_get_softc(dev); int devno = (ch->unit << 1) + atadev->unit; int offset = (devno ^ 0x01) << 3; int error; 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(dev, mode, ctlr->chip->max_dma); mode = ata_check_80pin(dev, mode); error = ata_controlcmd(dev, ATA_SETFEATURES, ATA_SF_SETXFER, 0, mode); if (bootverbose) device_printf(dev, "%ssetting %s on %s chip\n", (error) ? "FAILURE " : "", ata_mode2str(mode), ctlr->chip->text); if (!error) { if (mode >= ATA_UDMA0) { pci_write_config(gparent, 0x56, (pci_read_config(gparent, 0x56, 2) & ~(0xf << (devno << 2))) | ((mode & ATA_MODE_MASK) << (devno << 2)), 2); pci_write_config(gparent, 0x54, pci_read_config(gparent, 0x54, 1) | (0x01 << devno), 1); pci_write_config(gparent, 0x44, (pci_read_config(gparent, 0x44, 4) & ~(0xff << offset)) | (dmatimings[2] << offset), 4); } else if (mode >= ATA_WDMA0) { pci_write_config(gparent, 0x54, pci_read_config(gparent, 0x54, 1) & ~(0x01 << devno), 1); pci_write_config(gparent, 0x44, (pci_read_config(gparent, 0x44, 4) & ~(0xff << offset)) | (dmatimings[mode & ATA_MODE_MASK] << offset), 4); } else pci_write_config(gparent, 0x54, pci_read_config(gparent, 0x54, 1) & ~(0x01 << devno), 1); pci_write_config(gparent, 0x40, (pci_read_config(gparent, 0x40, 4) & ~(0xff << offset)) | (piotimings[ata_mode2idx(mode)] << offset), 4); atadev->mode = mode; } } ATA_DECLARE_DRIVER(ata_serverworks); diff --git a/sys/dev/ata/chipsets/ata-siliconimage.c b/sys/dev/ata/chipsets/ata-siliconimage.c index 232592e071a2..1ed48e487867 100644 --- a/sys/dev/ata/chipsets/ata-siliconimage.c +++ b/sys/dev/ata/chipsets/ata-siliconimage.c @@ -1,912 +1,905 @@ /*- * Copyright (c) 1998 - 2008 Søren Schmidt * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer, * without modification, immediately at the beginning of the file. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * 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. */ #include __FBSDID("$FreeBSD$"); #include "opt_ata.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* local prototypes */ static int ata_cmd_ch_attach(device_t dev); static int ata_cmd_status(device_t dev); static void ata_cmd_setmode(device_t dev, int mode); static int ata_sii_ch_attach(device_t dev); static int ata_sii_ch_detach(device_t dev); static int ata_sii_status(device_t dev); static void ata_sii_reset(device_t dev); static void ata_sii_setmode(device_t dev, int mode); static int ata_siiprb_ch_attach(device_t dev); static int ata_siiprb_ch_detach(device_t dev); static int ata_siiprb_status(device_t dev); static int ata_siiprb_begin_transaction(struct ata_request *request); static int ata_siiprb_end_transaction(struct ata_request *request); static int ata_siiprb_pm_read(device_t dev, int port, int reg, u_int32_t *result); static int ata_siiprb_pm_write(device_t dev, int port, int reg, u_int32_t result); static u_int32_t ata_siiprb_softreset(device_t dev, int port); static void ata_siiprb_reset(device_t dev); static void ata_siiprb_dmasetprd(void *xsc, bus_dma_segment_t *segs, int nsegs, int error); static void ata_siiprb_dmainit(device_t dev); /* misc defines */ #define SII_MEMIO 1 #define SII_PRBIO 2 #define SII_INTR 0x01 #define SII_SETCLK 0x02 #define SII_BUG 0x04 #define SII_4CH 0x08 /* * Silicon Image Inc. (SiI) (former CMD) chipset support functions */ static int ata_sii_probe(device_t dev) { struct ata_pci_controller *ctlr = device_get_softc(dev); static struct ata_chip_id ids[] = {{ ATA_SII3114, 0x00, SII_MEMIO, SII_4CH, ATA_SA150, "3114" }, { ATA_SII3512, 0x02, SII_MEMIO, 0, ATA_SA150, "3512" }, { ATA_SII3112, 0x02, SII_MEMIO, 0, ATA_SA150, "3112" }, { ATA_SII3112_1, 0x02, SII_MEMIO, 0, ATA_SA150, "3112" }, { ATA_SII3512, 0x00, SII_MEMIO, SII_BUG, ATA_SA150, "3512" }, { ATA_SII3112, 0x00, SII_MEMIO, SII_BUG, ATA_SA150, "3112" }, { ATA_SII3112_1, 0x00, SII_MEMIO, SII_BUG, ATA_SA150, "3112" }, { ATA_SII3124, 0x00, SII_PRBIO, SII_4CH, ATA_SA300, "3124" }, { ATA_SII3132, 0x00, SII_PRBIO, 0, ATA_SA300, "3132" }, { ATA_SII3132_1, 0x00, SII_PRBIO, 0, ATA_SA300, "3132" }, { ATA_SII3132_2, 0x00, SII_PRBIO, 0, ATA_SA300, "3132" }, { ATA_SII0680, 0x00, SII_MEMIO, SII_SETCLK, ATA_UDMA6, "680" }, { ATA_CMD649, 0x00, 0, SII_INTR, ATA_UDMA5, "(CMD) 649" }, { ATA_CMD648, 0x00, 0, SII_INTR, 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}}; if (pci_get_vendor(dev) != ATA_SILICON_IMAGE_ID) return ENXIO; if (!(ctlr->chip = ata_match_chip(dev, ids))) return ENXIO; ata_set_desc(dev); ctlr->chipinit = ata_sii_chipinit; return (BUS_PROBE_DEFAULT); } int ata_sii_chipinit(device_t dev) { struct ata_pci_controller *ctlr = device_get_softc(dev); if (ata_setup_interrupt(dev, ata_generic_intr)) return ENXIO; switch (ctlr->chip->cfg1) { case SII_PRBIO: ctlr->r_type1 = SYS_RES_MEMORY; ctlr->r_rid1 = PCIR_BAR(0); if (!(ctlr->r_res1 = bus_alloc_resource_any(dev, ctlr->r_type1, &ctlr->r_rid1, RF_ACTIVE))) return ENXIO; ctlr->r_rid2 = PCIR_BAR(2); ctlr->r_type2 = SYS_RES_MEMORY; if (!(ctlr->r_res2 = bus_alloc_resource_any(dev, ctlr->r_type2, &ctlr->r_rid2, RF_ACTIVE))){ bus_release_resource(dev, ctlr->r_type1, ctlr->r_rid1,ctlr->r_res1); return ENXIO; } ctlr->ch_attach = ata_siiprb_ch_attach; ctlr->ch_detach = ata_siiprb_ch_detach; ctlr->reset = ata_siiprb_reset; ctlr->setmode = ata_sata_setmode; ctlr->channels = (ctlr->chip->cfg2 == SII_4CH) ? 4 : 2; /* reset controller */ ATA_OUTL(ctlr->r_res1, 0x0040, 0x80000000); DELAY(10000); ATA_OUTL(ctlr->r_res1, 0x0040, 0x0000000f); break; case SII_MEMIO: ctlr->r_type2 = SYS_RES_MEMORY; ctlr->r_rid2 = PCIR_BAR(5); if (!(ctlr->r_res2 = bus_alloc_resource_any(dev, ctlr->r_type2, &ctlr->r_rid2, RF_ACTIVE))){ if (ctlr->chip->chipid != ATA_SII0680 || (pci_read_config(dev, 0x8a, 1) & 1)) return ENXIO; } if (ctlr->chip->cfg2 & SII_SETCLK) { if ((pci_read_config(dev, 0x8a, 1) & 0x30) != 0x10) pci_write_config(dev, 0x8a, (pci_read_config(dev, 0x8a, 1) & 0xcf)|0x10,1); if ((pci_read_config(dev, 0x8a, 1) & 0x30) != 0x10) device_printf(dev, "%s could not set ATA133 clock\n", ctlr->chip->text); } /* if we have 4 channels enable the second set */ if (ctlr->chip->cfg2 & SII_4CH) { ATA_OUTL(ctlr->r_res2, 0x0200, 0x00000002); ctlr->channels = 4; } /* dont block interrupts from any channel */ pci_write_config(dev, 0x48, (pci_read_config(dev, 0x48, 4) & ~0x03c00000), 4); /* enable PCI interrupt as BIOS might not */ pci_write_config(dev, 0x8a, (pci_read_config(dev, 0x8a, 1) & 0x3f), 1); if (ctlr->r_res2) { ctlr->ch_attach = ata_sii_ch_attach; ctlr->ch_detach = ata_sii_ch_detach; } if (ctlr->chip->max_dma >= ATA_SA150) { ctlr->reset = ata_sii_reset; ctlr->setmode = ata_sata_setmode; } else ctlr->setmode = ata_sii_setmode; break; default: if ((pci_read_config(dev, 0x51, 1) & 0x08) != 0x08) { device_printf(dev, "HW has secondary channel disabled\n"); ctlr->channels = 1; } /* enable interrupt as BIOS might not */ pci_write_config(dev, 0x71, 0x01, 1); ctlr->ch_attach = ata_cmd_ch_attach; ctlr->ch_detach = ata_pci_ch_detach; ctlr->setmode = ata_cmd_setmode; break; } return 0; } static int ata_cmd_ch_attach(device_t dev) { struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev)); struct ata_channel *ch = device_get_softc(dev); /* setup the usual register normal pci style */ if (ata_pci_ch_attach(dev)) return ENXIO; if (ctlr->chip->cfg2 & SII_INTR) ch->hw.status = ata_cmd_status; return 0; } static int ata_cmd_status(device_t dev) { struct ata_channel *ch = device_get_softc(dev); u_int8_t reg71; if (((reg71 = pci_read_config(device_get_parent(dev), 0x71, 1)) & (ch->unit ? 0x08 : 0x04))) { pci_write_config(device_get_parent(dev), 0x71, reg71 & ~(ch->unit ? 0x04 : 0x08), 1); return ata_pci_status(dev); } return 0; } static void ata_cmd_setmode(device_t dev, int mode) { device_t gparent = GRANDPARENT(dev); struct ata_pci_controller *ctlr = device_get_softc(gparent); struct ata_channel *ch = device_get_softc(device_get_parent(dev)); struct ata_device *atadev = device_get_softc(dev); int devno = (ch->unit << 1) + atadev->unit; int error; mode = ata_limit_mode(dev, mode, ctlr->chip->max_dma); mode = ata_check_80pin(dev, mode); error = ata_controlcmd(dev, ATA_SETFEATURES, ATA_SF_SETXFER, 0, mode); if (bootverbose) device_printf(dev, "%ssetting %s on %s chip\n", (error) ? "FAILURE " : "", ata_mode2str(mode), ctlr->chip->text); if (!error) { int treg = 0x54 + ((devno < 3) ? (devno << 1) : 7); int ureg = ch->unit ? 0x7b : 0x73; if (mode >= ATA_UDMA0) { int udmatimings[][2] = { { 0x31, 0xc2 }, { 0x21, 0x82 }, { 0x11, 0x42 }, { 0x25, 0x8a }, { 0x15, 0x4a }, { 0x05, 0x0a } }; u_int8_t umode = pci_read_config(gparent, ureg, 1); umode &= ~(atadev->unit == ATA_MASTER ? 0x35 : 0xca); umode |= udmatimings[mode & ATA_MODE_MASK][atadev->unit]; pci_write_config(gparent, ureg, umode, 1); } else if (mode >= ATA_WDMA0) { int dmatimings[] = { 0x87, 0x32, 0x3f }; pci_write_config(gparent, treg, dmatimings[mode & ATA_MODE_MASK],1); pci_write_config(gparent, ureg, pci_read_config(gparent, ureg, 1) & ~(atadev->unit == ATA_MASTER ? 0x35 : 0xca), 1); } else { int piotimings[] = { 0xa9, 0x57, 0x44, 0x32, 0x3f }; pci_write_config(gparent, treg, piotimings[(mode & ATA_MODE_MASK) - ATA_PIO0], 1); pci_write_config(gparent, ureg, pci_read_config(gparent, ureg, 1) & ~(atadev->unit == ATA_MASTER ? 0x35 : 0xca), 1); } atadev->mode = mode; } } static int ata_sii_ch_attach(device_t dev) { struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev)); struct ata_channel *ch = device_get_softc(dev); int unit01 = (ch->unit & 1), unit10 = (ch->unit & 2); int i; ata_pci_dmainit(dev); for (i = ATA_DATA; i <= ATA_COMMAND; i++) { ch->r_io[i].res = ctlr->r_res2; ch->r_io[i].offset = 0x80 + i + (unit01 << 6) + (unit10 << 8); } ch->r_io[ATA_CONTROL].res = ctlr->r_res2; ch->r_io[ATA_CONTROL].offset = 0x8a + (unit01 << 6) + (unit10 << 8); ch->r_io[ATA_IDX_ADDR].res = ctlr->r_res2; ata_default_registers(dev); ch->r_io[ATA_BMCMD_PORT].res = ctlr->r_res2; ch->r_io[ATA_BMCMD_PORT].offset = 0x00 + (unit01 << 3) + (unit10 << 8); ch->r_io[ATA_BMSTAT_PORT].res = ctlr->r_res2; ch->r_io[ATA_BMSTAT_PORT].offset = 0x02 + (unit01 << 3) + (unit10 << 8); ch->r_io[ATA_BMDTP_PORT].res = ctlr->r_res2; ch->r_io[ATA_BMDTP_PORT].offset = 0x04 + (unit01 << 3) + (unit10 << 8); if (ctlr->chip->max_dma >= ATA_SA150) { ch->r_io[ATA_SSTATUS].res = ctlr->r_res2; ch->r_io[ATA_SSTATUS].offset = 0x104 + (unit01 << 7) + (unit10 << 8); ch->r_io[ATA_SERROR].res = ctlr->r_res2; ch->r_io[ATA_SERROR].offset = 0x108 + (unit01 << 7) + (unit10 << 8); ch->r_io[ATA_SCONTROL].res = ctlr->r_res2; ch->r_io[ATA_SCONTROL].offset = 0x100 + (unit01 << 7) + (unit10 << 8); ch->flags |= ATA_NO_SLAVE; /* enable PHY state change interrupt */ ATA_OUTL(ctlr->r_res2, 0x148 + (unit01 << 7) + (unit10 << 8),(1 << 16)); } if (ctlr->chip->cfg2 & SII_BUG) { /* work around errata in early chips */ ch->dma.boundary = 8192; ch->dma.segsize = 15 * DEV_BSIZE; } ata_pci_hw(dev); ch->hw.status = ata_sii_status; return 0; } static int ata_sii_ch_detach(device_t dev) { ata_pci_dmafini(dev); return (0); } static int ata_sii_status(device_t dev) { struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev)); struct ata_channel *ch = device_get_softc(dev); int offset0 = ((ch->unit & 1) << 3) + ((ch->unit & 2) << 8); int offset1 = ((ch->unit & 1) << 6) + ((ch->unit & 2) << 8); /* do we have any PHY events ? */ if (ctlr->chip->max_dma >= ATA_SA150 && (ATA_INL(ctlr->r_res2, 0x10 + offset0) & 0x00000010)) ata_sata_phy_check_events(dev); if (ATA_INL(ctlr->r_res2, 0xa0 + offset1) & 0x00000800) return ata_pci_status(dev); else return 0; } static void ata_sii_reset(device_t dev) { if (ata_sata_phy_reset(dev, -1, 1)) ata_generic_reset(dev); } static void ata_sii_setmode(device_t dev, int mode) { device_t gparent = GRANDPARENT(dev); struct ata_pci_controller *ctlr = device_get_softc(gparent); struct ata_channel *ch = device_get_softc(device_get_parent(dev)); struct ata_device *atadev = device_get_softc(dev); int rego = (ch->unit << 4) + (atadev->unit << 1); int mreg = ch->unit ? 0x84 : 0x80; int mask = 0x03 << (atadev->unit << 2); int mval = pci_read_config(gparent, mreg, 1) & ~mask; int error; mode = ata_limit_mode(dev, mode, ctlr->chip->max_dma); if (ctlr->chip->cfg2 & SII_SETCLK) { if (mode > ATA_UDMA2 && (pci_read_config(gparent, 0x79, 1) & (ch->unit ? 0x02 : 0x01))) { ata_print_cable(dev, "controller"); mode = ATA_UDMA2; } } else mode = ata_check_80pin(dev, mode); error = ata_controlcmd(dev, ATA_SETFEATURES, ATA_SF_SETXFER, 0, mode); if (bootverbose) device_printf(dev, "%ssetting %s on %s chip\n", (error) ? "FAILURE " : "", ata_mode2str(mode), ctlr->chip->text); if (error) return; if (mode >= ATA_UDMA0) { u_int8_t udmatimings[] = { 0xf, 0xb, 0x7, 0x5, 0x3, 0x2, 0x1 }; u_int8_t ureg = 0xac + rego; pci_write_config(gparent, mreg, mval | (0x03 << (atadev->unit << 2)), 1); pci_write_config(gparent, ureg, (pci_read_config(gparent, ureg, 1) & ~0x3f) | udmatimings[mode & ATA_MODE_MASK], 1); } else if (mode >= ATA_WDMA0) { u_int8_t dreg = 0xa8 + rego; u_int16_t dmatimings[] = { 0x2208, 0x10c2, 0x10c1 }; pci_write_config(gparent, mreg, mval | (0x02 << (atadev->unit << 2)), 1); pci_write_config(gparent, dreg, dmatimings[mode & ATA_MODE_MASK], 2); } else { u_int8_t preg = 0xa4 + rego; u_int16_t piotimings[] = { 0x328a, 0x2283, 0x1104, 0x10c3, 0x10c1 }; pci_write_config(gparent, mreg, mval | (0x01 << (atadev->unit << 2)), 1); pci_write_config(gparent, preg, piotimings[mode & ATA_MODE_MASK], 2); } atadev->mode = mode; } struct ata_siiprb_dma_prdentry { u_int64_t addr; u_int32_t count; u_int32_t control; } __packed; -#define ATA_SIIPRB_DMA_ENTRIES 125 +#define ATA_SIIPRB_DMA_ENTRIES 129 struct ata_siiprb_ata_command { struct ata_siiprb_dma_prdentry prd[ATA_SIIPRB_DMA_ENTRIES]; } __packed; struct ata_siiprb_atapi_command { u_int8_t ccb[16]; struct ata_siiprb_dma_prdentry prd[ATA_SIIPRB_DMA_ENTRIES]; } __packed; struct ata_siiprb_command { u_int16_t control; u_int16_t protocol_override; u_int32_t transfer_count; u_int8_t fis[24]; union { struct ata_siiprb_ata_command ata; struct ata_siiprb_atapi_command atapi; } u; } __packed; static int ata_siiprb_ch_attach(device_t dev) { struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev)); struct ata_channel *ch = device_get_softc(dev); int offset = ch->unit * 0x2000; ata_siiprb_dmainit(dev); /* set the SATA resources */ ch->r_io[ATA_SSTATUS].res = ctlr->r_res2; ch->r_io[ATA_SSTATUS].offset = 0x1f04 + offset; ch->r_io[ATA_SERROR].res = ctlr->r_res2; ch->r_io[ATA_SERROR].offset = 0x1f08 + offset; ch->r_io[ATA_SCONTROL].res = ctlr->r_res2; ch->r_io[ATA_SCONTROL].offset = 0x1f00 + offset; ch->r_io[ATA_SACTIVE].res = ctlr->r_res2; ch->r_io[ATA_SACTIVE].offset = 0x1f0c + offset; ch->hw.status = ata_siiprb_status; ch->hw.begin_transaction = ata_siiprb_begin_transaction; ch->hw.end_transaction = ata_siiprb_end_transaction; ch->hw.command = NULL; /* not used here */ ch->hw.softreset = ata_siiprb_softreset; ch->hw.pm_read = ata_siiprb_pm_read; ch->hw.pm_write = ata_siiprb_pm_write; return 0; } static int ata_siiprb_ch_detach(device_t dev) { ata_dmafini(dev); return 0; } static int ata_siiprb_status(device_t dev) { struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev)); struct ata_channel *ch = device_get_softc(dev); u_int32_t action = ATA_INL(ctlr->r_res1, 0x0044); int offset = ch->unit * 0x2000; if (action & (1 << ch->unit)) { u_int32_t istatus = ATA_INL(ctlr->r_res2, 0x1008 + offset); /* do we have any PHY events ? */ ata_sata_phy_check_events(dev); /* clear interrupt(s) */ ATA_OUTL(ctlr->r_res2, 0x1008 + offset, istatus); /* do we have any device action ? */ return (istatus & 0x00000003); } return 0; } static int ata_siiprb_begin_transaction(struct ata_request *request) { - struct ata_pci_controller *ctlr=device_get_softc(GRANDPARENT(request->dev)); + struct ata_pci_controller *ctlr=device_get_softc(device_get_parent(request->parent)); struct ata_channel *ch = device_get_softc(request->parent); struct ata_siiprb_command *prb; struct ata_siiprb_dma_prdentry *prd; int offset = ch->unit * 0x2000; u_int64_t prb_bus; /* SOS XXX */ if (request->u.ata.command == ATA_DEVICE_RESET) { request->result = 0; return ATA_OP_FINISHED; } /* get a piece of the workspace for this request */ - prb = (struct ata_siiprb_command *) - (ch->dma.work + (sizeof(struct ata_siiprb_command) * request->tag)); + prb = (struct ata_siiprb_command *)ch->dma.work; /* clear the prb structure */ bzero(prb, sizeof(struct ata_siiprb_command)); /* setup the FIS for this request */ if (!ata_request2fis_h2d(request, &prb->fis[0])) { - device_printf(request->dev, "setting up SATA FIS failed\n"); + device_printf(request->parent, "setting up SATA FIS failed\n"); request->result = EIO; return ATA_OP_FINISHED; } /* setup transfer type */ if (request->flags & ATA_R_ATAPI) { - struct ata_device *atadev = device_get_softc(request->dev); - bcopy(request->u.atapi.ccb, prb->u.atapi.ccb, 16); - if ((atadev->param.config & ATA_PROTO_MASK) == ATA_PROTO_ATAPI_12) - ATA_OUTL(ctlr->r_res2, 0x1004 + offset, 0x00000020); - else + if (request->flags & ATA_R_ATAPI16) ATA_OUTL(ctlr->r_res2, 0x1000 + offset, 0x00000020); + else + ATA_OUTL(ctlr->r_res2, 0x1004 + offset, 0x00000020); if (request->flags & ATA_R_READ) prb->control = htole16(0x0010); if (request->flags & ATA_R_WRITE) prb->control = htole16(0x0020); prd = &prb->u.atapi.prd[0]; } else prd = &prb->u.ata.prd[0]; /* if request moves data setup and load SG list */ if (request->flags & (ATA_R_READ | ATA_R_WRITE)) { if (ch->dma.load(request, prd, NULL)) { - device_printf(request->dev, "setting up DMA failed\n"); + device_printf(request->parent, "setting up DMA failed\n"); request->result = EIO; return ATA_OP_FINISHED; } } /* activate the prb */ - prb_bus = ch->dma.work_bus + - (sizeof(struct ata_siiprb_command) * request->tag); - ATA_OUTL(ctlr->r_res2, - 0x1c00 + offset + (request->tag * sizeof(u_int64_t)), prb_bus); - ATA_OUTL(ctlr->r_res2, - 0x1c04 + offset + (request->tag * sizeof(u_int64_t)), prb_bus>>32); + prb_bus = ch->dma.work_bus; + ATA_OUTL(ctlr->r_res2, 0x1c00 + offset, prb_bus); + ATA_OUTL(ctlr->r_res2, 0x1c04 + offset, prb_bus>>32); /* start the timeout */ callout_reset(&request->callout, request->timeout * hz, (timeout_t*)ata_timeout, request); return ATA_OP_CONTINUES; } static int ata_siiprb_end_transaction(struct ata_request *request) { - struct ata_pci_controller *ctlr=device_get_softc(GRANDPARENT(request->dev)); + struct ata_pci_controller *ctlr=device_get_softc(device_get_parent(request->parent)); struct ata_channel *ch = device_get_softc(request->parent); struct ata_siiprb_command *prb; int offset = ch->unit * 0x2000; int error, timeout; /* kill the timeout */ callout_stop(&request->callout); prb = (struct ata_siiprb_command *) - ((u_int8_t *)rman_get_virtual(ctlr->r_res2)+(request->tag << 7)+offset); + ((u_int8_t *)rman_get_virtual(ctlr->r_res2) + offset); /* any controller errors flagged ? */ if ((error = ATA_INL(ctlr->r_res2, 0x1024 + offset))) { if (bootverbose) printf("ata_siiprb_end_transaction %s error=%08x\n", ata_cmd2str(request), error); /* if device error status get details */ if (error == 1 || error == 2) { request->status = prb->fis[2]; if (request->status & ATA_S_ERROR) request->error = prb->fis[3]; } /* SOS XXX handle other controller errors here */ /* initialize port */ ATA_OUTL(ctlr->r_res2, 0x1000 + offset, 0x00000004); /* poll for port ready */ for (timeout = 0; timeout < 1000; timeout++) { DELAY(1000); if (ATA_INL(ctlr->r_res2, 0x1008 + offset) & 0x00040000) break; } if (bootverbose) { if (timeout >= 1000) device_printf(ch->dev, "port initialize timeout\n"); else device_printf(ch->dev, "port initialize time=%dms\n", timeout); } } /* on control commands read back registers to the request struct */ if (request->flags & ATA_R_CONTROL) { - struct ata_device *atadev = device_get_softc(request->dev); - request->u.ata.count = prb->fis[12] | ((u_int16_t)prb->fis[13] << 8); request->u.ata.lba = prb->fis[4] | ((u_int64_t)prb->fis[5] << 8) | ((u_int64_t)prb->fis[6] << 16); - if (atadev->flags & ATA_D_48BIT_ACTIVE) + if (request->flags & ATA_R_48BIT) request->u.ata.lba |= ((u_int64_t)prb->fis[8] << 24) | ((u_int64_t)prb->fis[9] << 32) | ((u_int64_t)prb->fis[10] << 40); else request->u.ata.lba |= ((u_int64_t)(prb->fis[7] & 0x0f) << 24); } /* update progress */ if (!(request->status & ATA_S_ERROR) && !(request->flags & ATA_R_TIMEOUT)) { if (request->flags & ATA_R_READ) request->donecount = prb->transfer_count; else request->donecount = request->bytecount; } /* release SG list etc */ ch->dma.unload(request); return ATA_OP_FINISHED; } static int ata_siiprb_issue_cmd(device_t dev) { struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev)); struct ata_channel *ch = device_get_softc(dev); u_int64_t prb_bus = ch->dma.work_bus; u_int32_t status; int offset = ch->unit * 0x2000; int timeout; /* issue command to chip */ ATA_OUTL(ctlr->r_res2, 0x1c00 + offset, prb_bus); ATA_OUTL(ctlr->r_res2, 0x1c04 + offset, prb_bus >> 32); /* poll for command finished */ for (timeout = 0; timeout < 10000; timeout++) { DELAY(1000); if ((status = ATA_INL(ctlr->r_res2, 0x1008 + offset)) & 0x00010000) break; } // SOS XXX ATA_OUTL(ctlr->r_res2, 0x1008 + offset, 0x00010000); ATA_OUTL(ctlr->r_res2, 0x1008 + offset, 0x08ff08ff); if (timeout >= 1000) return EIO; if (bootverbose) device_printf(dev, "siiprb_issue_cmd time=%dms status=%08x\n", timeout, status); return 0; } static int ata_siiprb_pm_read(device_t dev, int port, int reg, u_int32_t *result) { struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev)); struct ata_channel *ch = device_get_softc(dev); struct ata_siiprb_command *prb = (struct ata_siiprb_command *)ch->dma.work; int offset = ch->unit * 0x2000; bzero(prb, sizeof(struct ata_siiprb_command)); prb->fis[0] = 0x27; /* host to device */ prb->fis[1] = 0x8f; /* command FIS to PM port */ prb->fis[2] = ATA_READ_PM; prb->fis[3] = reg; prb->fis[7] = port; if (ata_siiprb_issue_cmd(dev)) { device_printf(dev, "error reading PM port\n"); return EIO; } prb = (struct ata_siiprb_command *) ((u_int8_t *)rman_get_virtual(ctlr->r_res2) + offset); *result = prb->fis[12]|(prb->fis[4]<<8)|(prb->fis[5]<<16)|(prb->fis[6]<<24); return 0; } static int ata_siiprb_pm_write(device_t dev, int port, int reg, u_int32_t value) { struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev)); struct ata_channel *ch = device_get_softc(dev); struct ata_siiprb_command *prb = (struct ata_siiprb_command *)ch->dma.work; int offset = ch->unit * 0x2000; bzero(prb, sizeof(struct ata_siiprb_command)); prb->fis[0] = 0x27; /* host to device */ prb->fis[1] = 0x8f; /* command FIS to PM port */ prb->fis[2] = ATA_WRITE_PM; prb->fis[3] = reg; prb->fis[7] = port; prb->fis[12] = value & 0xff; prb->fis[4] = (value >> 8) & 0xff;; prb->fis[5] = (value >> 16) & 0xff;; prb->fis[6] = (value >> 24) & 0xff;; if (ata_siiprb_issue_cmd(dev)) { device_printf(dev, "error writing PM port\n"); return ATA_E_ABORT; } prb = (struct ata_siiprb_command *) ((u_int8_t *)rman_get_virtual(ctlr->r_res2) + offset); return prb->fis[3]; } static u_int32_t ata_siiprb_softreset(device_t dev, int port) { struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev)); struct ata_channel *ch = device_get_softc(dev); struct ata_siiprb_command *prb = (struct ata_siiprb_command *)ch->dma.work; u_int32_t signature; int offset = ch->unit * 0x2000; /* setup the workspace for a soft reset command */ bzero(prb, sizeof(struct ata_siiprb_command)); prb->control = htole16(0x0080); prb->fis[1] = port & 0x0f; /* issue soft reset */ if (ata_siiprb_issue_cmd(dev)) return -1; ata_udelay(150000); /* get possible signature */ prb = (struct ata_siiprb_command *) ((u_int8_t *)rman_get_virtual(ctlr->r_res2) + offset); signature=prb->fis[12]|(prb->fis[4]<<8)|(prb->fis[5]<<16)|(prb->fis[6]<<24); /* clear error bits/interrupt */ ATA_IDX_OUTL(ch, ATA_SERROR, 0xffffffff); return signature; } static void ata_siiprb_reset(device_t dev) { struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev)); struct ata_channel *ch = device_get_softc(dev); int offset = ch->unit * 0x2000; u_int32_t status, signature; int timeout; /* disable interrupts */ ATA_OUTL(ctlr->r_res2, 0x1014 + offset, 0x000000ff); /* reset channel HW */ ATA_OUTL(ctlr->r_res2, 0x1000 + offset, 0x00000001); DELAY(1000); ATA_OUTL(ctlr->r_res2, 0x1004 + offset, 0x00000001); DELAY(10000); /* poll for channel ready */ for (timeout = 0; timeout < 1000; timeout++) { if ((status = ATA_INL(ctlr->r_res2, 0x1008 + offset)) & 0x00040000) break; DELAY(1000); } if (bootverbose) { if (timeout >= 1000) device_printf(dev, "channel HW reset timeout\n"); else device_printf(dev, "channel HW reset time=%dms\n", timeout); } /* reset phy */ if (!ata_sata_phy_reset(dev, -1, 1)) { if (bootverbose) device_printf(dev, "phy reset found no device\n"); ch->devices = 0; goto finish; } /* issue soft reset */ signature = ata_siiprb_softreset(dev, ATA_PM); if (bootverbose) device_printf(dev, "SIGNATURE=%08x\n", signature); /* figure out whats there */ switch (signature >> 16) { case 0x0000: ch->devices = ATA_ATA_MASTER; break; case 0x9669: ch->devices = ATA_PORTMULTIPLIER; ATA_OUTL(ctlr->r_res2, 0x1000 + offset, 0x2000); /* enable PM support */ //SOS XXX need to clear all PM status and interrupts!!!! ata_pm_identify(dev); break; case 0xeb14: ch->devices = ATA_ATAPI_MASTER; break; default: ch->devices = 0; } if (bootverbose) device_printf(dev, "siiprb_reset devices=%08x\n", ch->devices); finish: /* clear interrupt(s) */ ATA_OUTL(ctlr->r_res2, 0x1008 + offset, 0x000008ff); /* require explicit interrupt ack */ ATA_OUTL(ctlr->r_res2, 0x1000 + offset, 0x00000008); /* 64bit mode */ ATA_OUTL(ctlr->r_res2, 0x1004 + offset, 0x00000400); /* enable interrupts wanted */ ATA_OUTL(ctlr->r_res2, 0x1010 + offset, 0x000000ff); } static void ata_siiprb_dmasetprd(void *xsc, bus_dma_segment_t *segs, int nsegs, int error) { struct ata_dmasetprd_args *args = xsc; struct ata_siiprb_dma_prdentry *prd = args->dmatab; int i; if ((args->error = error)) return; for (i = 0; i < nsegs; i++) { prd[i].addr = htole64(segs[i].ds_addr); prd[i].count = htole32(segs[i].ds_len); } prd[i - 1].control = htole32(ATA_DMA_EOT); KASSERT(nsegs <= ATA_SIIPRB_DMA_ENTRIES,("too many DMA segment entries\n")); args->nsegs = nsegs; } static void ata_siiprb_dmainit(device_t dev) { struct ata_channel *ch = device_get_softc(dev); ata_dmainit(dev); /* note start and stop are not used here */ ch->dma.setprd = ata_siiprb_dmasetprd; ch->dma.max_address = BUS_SPACE_MAXADDR; + ch->dma.max_iosize = (ATA_SIIPRB_DMA_ENTRIES - 1) * PAGE_SIZE; } ATA_DECLARE_DRIVER(ata_sii);