From f5f55db308e8649cb397a6c406a0c40eabc9ad27 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=B8ren=20Schmidt?= Date: Wed, 18 Jan 2006 09:14:55 +0000 Subject: [PATCH] Add support for using DMA on dump, greatly speeds up the dump process. Add dump support in ataraid. --- sys/dev/ata/ata-all.c | 21 +- sys/dev/ata/ata-all.h | 5 + sys/dev/ata/ata-chipset.c | 2409 +++++++++++++++++------------------- sys/dev/ata/ata-disk.c | 48 +- sys/dev/ata/ata-lowlevel.c | 24 +- sys/dev/ata/ata-pci.c | 37 +- sys/dev/ata/ata-pci.h | 4 +- sys/dev/ata/ata-queue.c | 13 +- sys/dev/ata/ata-raid.c | 33 +- 9 files changed, 1263 insertions(+), 1331 deletions(-) diff --git a/sys/dev/ata/ata-all.c b/sys/dev/ata/ata-all.c index 2a802f1fba2..12dcfb61a7d 100644 --- a/sys/dev/ata/ata-all.c +++ b/sys/dev/ata/ata-all.c @@ -63,7 +63,6 @@ static struct cdevsw ata_cdevsw = { }; /* prototypes */ -static void ata_interrupt(void *); static void ata_boot_attach(void); static device_t ata_add_child(device_t, struct ata_device *, int); static int ata_getparam(struct ata_device *, int); @@ -139,7 +138,7 @@ ata_attach(device_t dev) return ENXIO; } if ((error = bus_setup_intr(dev, ch->r_irq, ATA_INTR_FLAGS, - ata_interrupt, ch, &ch->ih))) { + (driver_intr_t *)ata_interrupt, ch, &ch->ih))) { device_printf(dev, "unable to setup interrupt\n"); return error; } @@ -317,7 +316,7 @@ ata_resume(device_t dev) return error; } -static void +int ata_interrupt(void *data) { struct ata_channel *ch = (struct ata_channel *)data; @@ -325,20 +324,17 @@ ata_interrupt(void *data) 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"); - /* ignore interrupt if device is busy */ - if (ATA_IDX_INB(ch, ATA_ALTSTAT) & ATA_S_BUSY) { - DELAY(100); - if (ATA_IDX_INB(ch, ATA_ALTSTAT) & ATA_S_BUSY) - break; - } - - /* check for the right state */ + /* safetycheck for the right state */ if (ch->state != ATA_ACTIVE && ch->state != ATA_STALL_QUEUE) { device_printf(request->dev, "interrupt on idle channel ignored\n"); break; @@ -355,10 +351,11 @@ ata_interrupt(void *data) mtx_unlock(&ch->state_mtx); ATA_LOCKING(ch->dev, ATA_LF_UNLOCK); ata_finish(request); - return; + return 1; } } while (0); mtx_unlock(&ch->state_mtx); + return 0; } /* diff --git a/sys/dev/ata/ata-all.h b/sys/dev/ata/ata-all.h index b02f7d6a048..0e5d0524098 100644 --- a/sys/dev/ata/ata-all.h +++ b/sys/dev/ata/ata-all.h @@ -470,6 +470,7 @@ struct ata_dma { /* structure holding lowlevel functions */ struct ata_lowlevel { + 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); @@ -495,6 +496,7 @@ struct ata_channel { #define ATA_USE_16BIT 0x02 #define ATA_ATAPI_DMA_RO 0x04 #define ATA_NO_48BIT_DMA 0x08 +#define ATA_ALWAYS_DMASTAT 0x10 int devices; /* what is present */ #define ATA_ATA_MASTER 0x01 @@ -534,6 +536,7 @@ int ata_detach(device_t dev); int ata_reinit(device_t dev); int ata_suspend(device_t dev); int ata_resume(device_t dev); +int ata_interrupt(void *data); int ata_device_ioctl(device_t dev, u_long cmd, caddr_t data); int ata_identify(device_t dev); void ata_default_registers(device_t dev); @@ -558,6 +561,8 @@ 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); diff --git a/sys/dev/ata/ata-chipset.c b/sys/dev/ata/ata-chipset.c index cb0ac6d8218..2570c6b11d8 100644 --- a/sys/dev/ata/ata-chipset.c +++ b/sys/dev/ata/ata-chipset.c @@ -51,22 +51,25 @@ __FBSDID("$FreeBSD$"); #include /* local prototypes */ +/* ata-chipset.c */ static int ata_generic_chipinit(device_t dev); static void ata_generic_intr(void *data); static void ata_generic_setmode(device_t dev, int mode); -static void ata_sata_setmode(device_t dev, int mode); -static int ata_sata_connect(struct ata_channel *ch); static void ata_sata_phy_enable(struct ata_channel *ch); static void ata_sata_phy_event(void *context, int dummy); +static int ata_sata_connect(struct ata_channel *ch); +static void ata_sata_setmode(device_t dev, int mode); static int ata_ahci_allocate(device_t dev); -static int ata_ahci_setup_fis(u_int8_t *fis, struct ata_request *request); +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 void ata_ahci_intr(void *data); static void ata_ahci_reset(device_t dev); +static void ata_ahci_dmasetprd(void *xsc, bus_dma_segment_t *segs, int nsegs, int error); static void ata_ahci_dmainit(device_t dev); +static int ata_ahci_setup_fis(u_int8_t *fis, struct ata_request *request); static int ata_acard_chipinit(device_t dev); -static void ata_acard_intr(void *data); +static int ata_acard_allocate(device_t dev); +static int ata_acard_status(device_t dev); static void ata_acard_850_setmode(device_t dev, int mode); static void ata_acard_86X_setmode(device_t dev, int mode); static int ata_ali_chipinit(device_t dev); @@ -82,60 +85,66 @@ static void ata_cyrix_setmode(device_t dev, int mode); static int ata_cypress_chipinit(device_t dev); static void ata_cypress_setmode(device_t dev, int mode); static int ata_highpoint_chipinit(device_t dev); -static void ata_highpoint_intr(void *data); +static int ata_highpoint_allocate(device_t dev); static void ata_highpoint_setmode(device_t dev, int mode); static int ata_highpoint_check_80pin(device_t dev, int mode); static int ata_intel_chipinit(device_t dev); -static int ata_intel_31244_allocate(device_t dev); -static void ata_intel_31244_intr(void *data); -static void ata_intel_31244_reset(device_t dev); -static int ata_intel_31244_command(struct ata_request *request); -static void ata_intel_intr(void *data); +static int ata_intel_allocate(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 int ata_intel_31244_allocate(device_t dev); +static int ata_intel_31244_status(device_t dev); +static int ata_intel_31244_command(struct ata_request *request); +static void ata_intel_31244_reset(device_t dev); static int ata_ite_chipinit(device_t dev); static void ata_ite_setmode(device_t dev, int mode); static int ata_marvell_chipinit(device_t dev); static int ata_marvell_allocate(device_t dev); -static void ata_marvell_intr(void *data); -static void ata_marvell_dmainit(device_t dev); -static int ata_marvell_command(struct ata_request *request); +static int ata_marvell_status(device_t dev); +static int ata_marvell_begin_transaction(struct ata_request *request); +static int ata_marvell_end_transaction(struct ata_request *request); static void ata_marvell_reset(device_t dev); +static void ata_marvell_dmasetprd(void *xsc, bus_dma_segment_t *segs, int nsegs, int error); +static void ata_marvell_dmainit(device_t dev); static int ata_national_chipinit(device_t dev); static void ata_national_setmode(device_t dev, int mode); static int ata_nvidia_chipinit(device_t dev); static int ata_nvidia_allocate(device_t dev); -static void ata_nvidia_intr(void *data); +static int ata_nvidia_status(device_t dev); static void ata_nvidia_reset(device_t dev); static int ata_promise_chipinit(device_t dev); +static int ata_promise_allocate(device_t dev); +static int ata_promise_status(device_t dev); +static int ata_promise_dmastart(device_t dev); +static int ata_promise_dmastop(device_t dev); +static void ata_promise_dmareset(device_t dev); +static void ata_promise_dmainit(device_t dev); +static void ata_promise_setmode(device_t dev, int mode); +static int ata_promise_tx2_allocate(device_t dev); +static int ata_promise_tx2_status(device_t dev); static int ata_promise_mio_allocate(device_t dev); static void ata_promise_mio_intr(void *data); -static void ata_promise_sx4_intr(void *data); -static void ata_promise_mio_dmainit(device_t dev); -static void ata_promise_mio_reset(device_t dev); +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 void ata_promise_mio_dmainit(device_t dev); +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); -static void ata_promise_tx2_intr(void *data); -static void ata_promise_old_intr(void *data); -static int ata_promise_new_dmastart(device_t dev); -static int ata_promise_new_dmastop(device_t dev); -static void ata_promise_new_dmareset(device_t dev); -static void ata_promise_new_dmainit(device_t dev); -static void ata_promise_setmode(device_t dev, int mode); static int ata_serverworks_chipinit(device_t dev); static void ata_serverworks_setmode(device_t dev, int mode); static int ata_sii_chipinit(device_t dev); +static int ata_cmd_allocate(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_allocate(device_t dev); -static void ata_sii_intr(void *data); -static void ata_cmd_intr(void *data); -static void ata_cmd_old_intr(void *data); +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 void ata_cmd_setmode(device_t dev, int mode); static int ata_sis_chipinit(device_t dev); static int ata_sis_allocate(device_t dev); static void ata_sis_reset(device_t dev); @@ -145,6 +154,7 @@ static int ata_via_allocate(device_t dev); static void ata_via_reset(device_t dev); static void ata_via_southbridge_fixup(device_t dev); static void ata_via_family_setmode(device_t dev, int mode); +static struct ata_chip_id *ata_match_chip(device_t dev, struct ata_chip_id *index); static struct ata_chip_id *ata_find_chip(device_t dev, struct ata_chip_id *index, int slot); static int ata_setup_interrupt(device_t dev); static int ata_serialize(device_t dev, int flags); @@ -154,7 +164,9 @@ static int ata_check_80pin(device_t dev, int mode); static int ata_mode2idx(int mode); -/* generic or unknown ATA chipset support functions */ +/* + * generic ATA support functions + */ int ata_generic_ident(device_t dev) { @@ -184,18 +196,8 @@ ata_generic_intr(void *data) int unit; for (unit = 0; unit < ctlr->channels; unit++) { - if (!(ch = ctlr->interrupt[unit].argument)) - continue; - if (ch->dma && (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) - continue; - ATA_IDX_OUTB(ch, ATA_BMSTAT_PORT, bmstat & ~ATA_BMSTAT_ERROR); - DELAY(1); - } - ctlr->interrupt[unit].function(ch); + if ((ch = ctlr->interrupt[unit].argument)) + ctlr->interrupt[unit].function(ch); } } @@ -211,32 +213,71 @@ ata_generic_setmode(device_t dev, int mode) } -/* SATA support functions */ +/* + * SATA support functions + */ static void -ata_sata_setmode(device_t dev, int mode) +ata_sata_phy_enable(struct ata_channel *ch) { - struct ata_device *atadev = device_get_softc(dev); + int loop, retry; - /* - * 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) { - if (!ata_controlcmd(dev, ATA_SETFEATURES, ATA_SF_SETXFER, 0, - ata_limit_mode(dev, mode, ATA_UDMA6))) - /* XXX SOS we should query SATA STATUS for the speed */ - atadev->mode = ATA_SA150; + if ((ATA_IDX_INL(ch, ATA_SCONTROL) & ATA_SC_DET_MASK) == ATA_SC_DET_IDLE) { + ata_sata_connect(ch); + return; } - else { - mode = ata_limit_mode(dev, mode, ATA_UDMA5); - if (!ata_controlcmd(dev, ATA_SETFEATURES, ATA_SF_SETXFER, 0, mode)) - atadev->mode = mode; + + for (retry = 0; retry < 10; retry++) { + for (loop = 0; loop < 10; loop++) { + ATA_IDX_OUTL(ch, ATA_SCONTROL, ATA_SC_DET_RESET); + ata_udelay(100); + if ((ATA_IDX_INL(ch, ATA_SCONTROL) & + ATA_SC_DET_MASK) == ATA_SC_DET_RESET) + break; + } + ata_udelay(5000); + for (loop = 0; loop < 10; loop++) { + ATA_IDX_OUTL(ch, ATA_SCONTROL, ATA_SC_DET_IDLE); + ata_udelay(100); + if ((ATA_IDX_INL(ch, ATA_SCONTROL) & ATA_SC_DET_MASK) == 0) { + ata_sata_connect(ch); + return; + } + } } } +static void +ata_sata_phy_event(void *context, int dummy) +{ + struct ata_connect_task *tp = (struct ata_connect_task *)context; + struct ata_channel *ch = device_get_softc(tp->dev); + device_t *children; + int nchildren, i; + + mtx_lock(&Giant); /* newbus suckage it needs Giant */ + if (tp->action == ATA_C_ATTACH) { + if (bootverbose) + device_printf(tp->dev, "CONNECTED\n"); + ata_sata_connect(ch); + ata_identify(tp->dev); + } + if (tp->action == ATA_C_DETACH) { + if (!device_get_children(tp->dev, &children, &nchildren)) { + for (i = 0; i < nchildren; i++) + if (children[i]) + device_delete_child(tp->dev, children[i]); + free(children, M_TEMP); + } + mtx_lock(&ch->state_mtx); + ch->state = ATA_IDLE; + mtx_unlock(&ch->state_mtx); + if (bootverbose) + device_printf(tp->dev, "DISCONNECTED\n"); + } + mtx_unlock(&Giant); /* suckage code dealt with, release Giant */ + free(tp, M_ATA); +} + static int ata_sata_connect(struct ata_channel *ch) { @@ -285,65 +326,30 @@ ata_sata_connect(struct ata_channel *ch) } static void -ata_sata_phy_enable(struct ata_channel *ch) +ata_sata_setmode(device_t dev, int mode) { - int loop, retry; + struct ata_device *atadev = device_get_softc(dev); - if ((ATA_IDX_INL(ch, ATA_SCONTROL) & ATA_SC_DET_MASK) == ATA_SC_DET_IDLE) { - ata_sata_connect(ch); - return; + /* + * 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) { + if (!ata_controlcmd(dev, ATA_SETFEATURES, ATA_SF_SETXFER, 0, + ata_limit_mode(dev, mode, ATA_UDMA6))) + /* XXX SOS we should query SATA STATUS for the speed */ + atadev->mode = ATA_SA150; } - - for (retry = 0; retry < 10; retry++) { - for (loop = 0; loop < 10; loop++) { - ATA_IDX_OUTL(ch, ATA_SCONTROL, ATA_SC_DET_RESET); - ata_udelay(100); - if ((ATA_IDX_INL(ch, ATA_SCONTROL) & - ATA_SC_DET_MASK) == ATA_SC_DET_RESET) - break; - } - ata_udelay(5000); - for (loop = 0; loop < 10; loop++) { - ATA_IDX_OUTL(ch, ATA_SCONTROL, ATA_SC_DET_IDLE); - ata_udelay(100); - if ((ATA_IDX_INL(ch, ATA_SCONTROL) & ATA_SC_DET_MASK) == 0) { - ata_sata_connect(ch); - return; - } - } + else { + mode = ata_limit_mode(dev, mode, ATA_UDMA5); + if (!ata_controlcmd(dev, ATA_SETFEATURES, ATA_SF_SETXFER, 0, mode)) + atadev->mode = mode; } } -static void -ata_sata_phy_event(void *context, int dummy) -{ - struct ata_connect_task *tp = (struct ata_connect_task *)context; - struct ata_channel *ch = device_get_softc(tp->dev); - device_t *children; - int nchildren, i; - - mtx_lock(&Giant); /* newbus suckage it needs Giant */ - if (tp->action == ATA_C_ATTACH) { - device_printf(tp->dev, "CONNECTED\n"); - ata_sata_connect(ch); - ata_identify(tp->dev); - } - if (tp->action == ATA_C_DETACH) { - if (!device_get_children(tp->dev, &children, &nchildren)) { - for (i = 0; i < nchildren; i++) - if (children[i]) - device_delete_child(tp->dev, children[i]); - free(children, M_TEMP); - } - mtx_lock(&ch->state_mtx); - ch->state = ATA_IDLE; - mtx_unlock(&ch->state_mtx); - device_printf(tp->dev, "DISCONNECTED\n"); - } - mtx_unlock(&Giant); /* suckage code dealt with, release Giant */ - free(tp, M_ATA); -} - /* * AHCI v1.0 compliant SATA chipset support functions @@ -378,7 +384,7 @@ ata_ahci_allocate(device_t dev) struct ata_channel *ch = device_get_softc(dev); int offset = (ch->unit << 7); - /* XXX SOS this is a hack to satisfy various legacy cruft */ + /* setup legacy cruft we need */ ch->r_io[ATA_CYL_LSB].res = ctlr->r_res2; ch->r_io[ATA_CYL_LSB].offset = ATA_AHCI_P_SIG + 1 + offset; ch->r_io[ATA_CYL_MSB].res = ctlr->r_res2; @@ -398,6 +404,7 @@ ata_ahci_allocate(device_t dev) 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 */ @@ -427,43 +434,68 @@ ata_ahci_allocate(device_t dev) } static int -ata_ahci_setup_fis(u_int8_t *fis, struct ata_request *request) +ata_ahci_status(device_t dev) { - struct ata_device *atadev = device_get_softc(request->dev); - int idx = 0; + struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev)); + struct ata_channel *ch = device_get_softc(dev); + struct ata_connect_task *tp; + u_int32_t action, status, error, issued; + int offset = (ch->unit << 7); + int tag = 0; - /* XXX SOS add ATAPI commands support later */ - ata_modify_if_48bit(request); + action = ATA_INL(ctlr->r_res2, ATA_AHCI_IS) & (1 << ch->unit); - fis[idx++] = 0x27; /* host to device */ - fis[idx++] = 0x80; /* command FIS (note PM goes here) */ - fis[idx++] = request->u.ata.command; - fis[idx++] = request->u.ata.feature; + if (action) { + error = ATA_INL(ctlr->r_res2, ATA_AHCI_P_SERR + offset); + status = ATA_INL(ctlr->r_res2, ATA_AHCI_P_IS + offset); + issued = ATA_INL(ctlr->r_res2, ATA_AHCI_P_CI + offset); + ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_SERR + offset, error); + ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_IS + offset, status); - fis[idx++] = request->u.ata.lba; - fis[idx++] = request->u.ata.lba >> 8; - fis[idx++] = request->u.ata.lba >> 16; - fis[idx] = ATA_D_LBA | atadev->unit; - if (atadev->flags & ATA_D_48BIT_ACTIVE) - idx++; - else - fis[idx++] |= (request->u.ata.lba >> 24 & 0x0f); + /* do we have cold connect surprise */ + if (status & ATA_AHCI_P_IX_CPD) { + printf("ata_ahci_intr status=%08x error=%08x issued=%08x\n", + status, error, issued); + } - fis[idx++] = request->u.ata.lba >> 24; - fis[idx++] = request->u.ata.lba >> 32; - fis[idx++] = request->u.ata.lba >> 40; - fis[idx++] = request->u.ata.feature >> 8; + /* check for and handle connect events */ + if (((status & (ATA_AHCI_P_IX_PRC | ATA_AHCI_P_IX_PC)) == + ATA_AHCI_P_IX_PC) && + (tp = (struct ata_connect_task *) + malloc(sizeof(struct ata_connect_task), + M_ATA, M_NOWAIT | M_ZERO))) { - fis[idx++] = request->u.ata.count; - fis[idx++] = request->u.ata.count >> 8; - fis[idx++] = 0x00; - fis[idx++] = ATA_A_4BIT; + if (bootverbose) + device_printf(ch->dev, "CONNECT requested\n"); + tp->action = ATA_C_ATTACH; + tp->dev = ch->dev; + TASK_INIT(&tp->task, 0, ata_sata_phy_event, tp); + taskqueue_enqueue(taskqueue_thread, &tp->task); + } - fis[idx++] = 0x00; - fis[idx++] = 0x00; - fis[idx++] = 0x00; - fis[idx++] = 0x00; - return idx; + /* check for and handle disconnect events */ + if (((status & (ATA_AHCI_P_IX_PRC | ATA_AHCI_P_IX_PC)) == + ATA_AHCI_P_IX_PRC) && + (tp = (struct ata_connect_task *) + malloc(sizeof(struct ata_connect_task), + M_ATA, M_NOWAIT | M_ZERO))) { + + if (bootverbose) + device_printf(ch->dev, "DISCONNECT requested\n"); + tp->action = ATA_C_DETACH; + tp->dev = ch->dev; + TASK_INIT(&tp->task, 0, ata_sata_phy_event, tp); + taskqueue_enqueue(taskqueue_thread, &tp->task); + } + + /* clear interrupt */ + ATA_OUTL(ctlr->r_res2, ATA_AHCI_IS, action); + + /* do we have any device action ? */ + if (!(issued & (1 << tag))) + return 1; + } + return 0; } /* must be called with ATA channel locked and state_mtx held */ @@ -555,72 +587,6 @@ ata_ahci_end_transaction(struct ata_request *request) return ATA_OP_FINISHED; } -static void -ata_ahci_intr(void *data) -{ - struct ata_pci_controller *ctlr = data; - struct ata_channel *ch; - u_int32_t port, status, error, issued; - int unit; - int tag = 0; - - port = ATA_INL(ctlr->r_res2, ATA_AHCI_IS); - - for (unit = 0; unit < ctlr->channels; unit++) { - if (port & (1 << unit)) { - if ((ch = ctlr->interrupt[unit].argument)) { - struct ata_connect_task *tp; - int offset = (ch->unit << 7); - - error = ATA_INL(ctlr->r_res2, ATA_AHCI_P_SERR + offset); - status = ATA_INL(ctlr->r_res2, ATA_AHCI_P_IS + offset); - issued = ATA_INL(ctlr->r_res2, ATA_AHCI_P_CI + offset); - ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_SERR + offset, error); - ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_IS + offset, status); - - /* do we have cold connect surprise */ - if (status & ATA_AHCI_P_IX_CPD) { - printf("ata_ahci_intr status=%08x error=%08x issued=%08x\n", - status, error, issued); - } - - /* check for and handle connect events */ - if (((status & (ATA_AHCI_P_IX_PRC | ATA_AHCI_P_IX_PC)) == - ATA_AHCI_P_IX_PC) && - (tp = (struct ata_connect_task *) - malloc(sizeof(struct ata_connect_task), - M_ATA, M_NOWAIT | M_ZERO))) { - - device_printf(ch->dev, "CONNECT requested\n"); - tp->action = ATA_C_ATTACH; - tp->dev = ch->dev; - TASK_INIT(&tp->task, 0, ata_sata_phy_event, tp); - taskqueue_enqueue(taskqueue_thread, &tp->task); - } - - /* check for and handle disconnect events */ - if (((status & (ATA_AHCI_P_IX_PRC | ATA_AHCI_P_IX_PC)) == - ATA_AHCI_P_IX_PRC) && - (tp = (struct ata_connect_task *) - malloc(sizeof(struct ata_connect_task), - M_ATA, M_NOWAIT | M_ZERO))) { - - device_printf(ch->dev, "DISCONNECT requested\n"); - tp->action = ATA_C_DETACH; - tp->dev = ch->dev; - TASK_INIT(&tp->task, 0, ata_sata_phy_event, tp); - taskqueue_enqueue(taskqueue_thread, &tp->task); - } - - /* any drive action to take care of ? */ - if (!(issued & (1<interrupt[unit].function(ch); - } - } - } - ATA_OUTL(ctlr->r_res2, ATA_AHCI_IS, port); -} - static void ata_ahci_reset(device_t dev) { @@ -681,6 +647,46 @@ ata_ahci_dmainit(device_t dev) } } +static int +ata_ahci_setup_fis(u_int8_t *fis, struct ata_request *request) +{ + struct ata_device *atadev = device_get_softc(request->dev); + int idx = 0; + + /* XXX SOS add ATAPI commands support later */ + ata_modify_if_48bit(request); + + fis[idx++] = 0x27; /* host to device */ + fis[idx++] = 0x80; /* command FIS (note PM goes here) */ + fis[idx++] = request->u.ata.command; + fis[idx++] = request->u.ata.feature; + + fis[idx++] = request->u.ata.lba; + fis[idx++] = request->u.ata.lba >> 8; + fis[idx++] = request->u.ata.lba >> 16; + fis[idx] = ATA_D_LBA | atadev->unit; + if (atadev->flags & ATA_D_48BIT_ACTIVE) + idx++; + else + fis[idx++] |= (request->u.ata.lba >> 24 & 0x0f); + + fis[idx++] = request->u.ata.lba >> 24; + fis[idx++] = request->u.ata.lba >> 32; + fis[idx++] = request->u.ata.lba >> 40; + fis[idx++] = request->u.ata.feature >> 8; + + fis[idx++] = request->u.ata.count; + fis[idx++] = request->u.ata.count >> 8; + fis[idx++] = 0x00; + fis[idx++] = ATA_A_4BIT; + + fis[idx++] = 0x00; + fis[idx++] = 0x00; + fis[idx++] = 0x00; + fis[idx++] = 0x00; + return idx; +} + /* * Acard chipset support functions @@ -714,18 +720,11 @@ static int ata_acard_chipinit(device_t dev) { struct ata_pci_controller *ctlr = device_get_softc(dev); - int rid = ATA_IRQ_RID; - if (!(ctlr->r_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, - RF_SHAREABLE | RF_ACTIVE))) { - device_printf(dev, "unable to map interrupt\n"); + if (ata_setup_interrupt(dev)) return ENXIO; - } - if ((bus_setup_intr(dev, ctlr->r_irq, ATA_INTR_FLAGS, - ata_acard_intr, ctlr, &ctlr->handle))) { - device_printf(dev, "unable to setup interrupt\n"); - return ENXIO; - } + + ctlr->allocate = ata_acard_allocate; if (ctlr->chip->cfg1 == ATPOLD) { ctlr->setmode = ata_acard_850_setmode; ctlr->locking = ata_serialize; @@ -735,33 +734,46 @@ ata_acard_chipinit(device_t dev) return 0; } -static void -ata_acard_intr(void *data) +static int +ata_acard_allocate(device_t dev) { - struct ata_pci_controller *ctlr = data; - struct ata_channel *ch; - int unit; + struct ata_channel *ch = device_get_softc(dev); - for (unit = 0; unit < ctlr->channels; unit++) { - if (!(ch = ctlr->interrupt[unit].argument)) - continue; - if (ctlr->chip->cfg1 == ATPOLD && - ATA_LOCKING(ch->dev, ATA_LF_WHICH) != unit) - continue; - if (ch->dma && (ch->dma->flags & ATA_DMA_ACTIVE)) { - int bmstat = ATA_IDX_INB(ch, ATA_BMSTAT_PORT) & ATA_BMSTAT_MASK; + /* setup the usual register normal pci style */ + if (ata_pci_allocate(dev)) + return ENXIO; - if ((bmstat & (ATA_BMSTAT_ACTIVE | ATA_BMSTAT_INTERRUPT)) != - ATA_BMSTAT_INTERRUPT) - continue; - ATA_IDX_OUTB(ch, ATA_BMSTAT_PORT, bmstat & ~ATA_BMSTAT_ERROR); - DELAY(1); - ATA_IDX_OUTB(ch, ATA_BMCMD_PORT, - ATA_IDX_INB(ch, ATA_BMCMD_PORT)&~ATA_BMCMD_START_STOP); - DELAY(1); - } - ctlr->interrupt[unit].function(ch); + ch->hw.status = ata_acard_status; + return 0; +} + +static int +ata_acard_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 (ctlr->chip->cfg1 == ATPOLD && + ATA_LOCKING(ch->dev, ATA_LF_WHICH) != ch->unit) + return 0; + if (ch->dma && (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); + ATA_IDX_OUTB(ch, ATA_BMCMD_PORT, + ATA_IDX_INB(ch, ATA_BMCMD_PORT)&~ATA_BMCMD_START_STOP); + 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; } static void @@ -903,8 +915,8 @@ ata_ali_chipinit(device_t dev) device_printf(dev, "using PIO transfers above 137GB as workaround for " "48bit DMA access bug, expect reduced performance\n"); - ctlr->reset = ata_ali_reset; ctlr->allocate = ata_ali_allocate; + ctlr->reset = ata_ali_reset; ctlr->setmode = ata_ali_setmode; break; @@ -973,7 +985,7 @@ ata_ali_sata_allocate(device_t dev) ch->flags |= ATA_NO_SLAVE; /* XXX SOS PHY handling awkward in ALI chip not supported yet */ - ata_generic_hw(dev); + ata_pci_hw(dev); return 0; } @@ -1407,18 +1419,9 @@ static int ata_highpoint_chipinit(device_t dev) { struct ata_pci_controller *ctlr = device_get_softc(dev); - int rid = ATA_IRQ_RID; - if (!(ctlr->r_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, - RF_SHAREABLE | RF_ACTIVE))) { - device_printf(dev, "unable to map interrupt\n"); + if (ata_setup_interrupt(dev)) return ENXIO; - } - if ((bus_setup_intr(dev, ctlr->r_irq, ATA_INTR_FLAGS, - ata_highpoint_intr, ctlr, &ctlr->handle))) { - device_printf(dev, "unable to setup interrupt\n"); - return ENXIO; - } if (ctlr->chip->cfg2 == HPTOLD) { /* disable interrupt prediction */ @@ -1439,31 +1442,22 @@ ata_highpoint_chipinit(device_t dev) pci_write_config(dev, 0x5b, (pci_read_config(dev, 0x5b, 1) & 0x01) | 0x20, 1); } + ctlr->allocate = ata_highpoint_allocate; ctlr->setmode = ata_highpoint_setmode; return 0; } -static void -ata_highpoint_intr(void *data) +static int +ata_highpoint_allocate(device_t dev) { - struct ata_pci_controller *ctlr = data; - struct ata_channel *ch; - int unit; + struct ata_channel *ch = device_get_softc(dev); - for (unit = 0; unit < ctlr->channels; unit++) { - if (!(ch = ctlr->interrupt[unit].argument)) - continue; - if (ch->dma) { - int bmstat = ATA_IDX_INB(ch, ATA_BMSTAT_PORT) & ATA_BMSTAT_MASK; + /* setup the usual register normal pci style */ + if (ata_pci_allocate(dev)) + return ENXIO; - if ((bmstat & (ATA_BMSTAT_ACTIVE | ATA_BMSTAT_INTERRUPT)) != - ATA_BMSTAT_INTERRUPT) - continue; - ATA_IDX_OUTB(ch, ATA_BMSTAT_PORT, bmstat & ~ATA_BMSTAT_ERROR); - DELAY(1); - } - ctlr->interrupt[unit].function(ch); - } + ch->flags |= ATA_ALWAYS_DMASTAT; + return 0; } static void @@ -1603,20 +1597,9 @@ static int ata_intel_chipinit(device_t dev) { struct ata_pci_controller *ctlr = device_get_softc(dev); - int rid = ATA_IRQ_RID; - if (!ata_legacy(dev)) { - if (!(ctlr->r_irq = bus_alloc_resource_any(dev, SYS_RES_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, - ata_intel_intr, ctlr, &ctlr->handle))) { - device_printf(dev, "unable to setup interrupt\n"); - return ENXIO; - } - } + if (ata_setup_interrupt(dev)) + return ENXIO; /* good old PIIX needs special treatment (not implemented) */ if (ctlr->chip->chipid == ATA_I82371FB) { @@ -1632,22 +1615,16 @@ ata_intel_chipinit(device_t dev) &ctlr->r_rid2, RF_ACTIVE))) return ENXIO; - - if (bus_teardown_intr(dev, ctlr->r_irq, ctlr->handle) || - bus_setup_intr(dev, ctlr->r_irq, ATA_INTR_FLAGS, - ata_intel_31244_intr, ctlr, &ctlr->handle)) { - device_printf(dev, "unable to setup interrupt\n"); - return ENXIO; - } ctlr->channels = 4; - ctlr->reset = ata_intel_31244_reset; ctlr->allocate = ata_intel_31244_allocate; + 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->allocate = ata_intel_allocate; ctlr->setmode = ata_intel_new_setmode; } @@ -1656,6 +1633,7 @@ ata_intel_chipinit(device_t dev) /* force all ports active "the legacy way" */ pci_write_config(dev, 0x92, pci_read_config(dev, 0x92, 2) | 0x0f,2); + ctlr->allocate = ata_intel_allocate; ctlr->reset = ata_intel_reset; /* if we have AHCI capability and BAR(5) as a memory resource */ @@ -1667,13 +1645,6 @@ ata_intel_chipinit(device_t dev) RF_ACTIVE))) { /* is AHCI or RAID mode enabled in BIOS ? */ if (pci_read_config(dev, 0x90, 1) & 0xc0) { - if (bus_teardown_intr(dev, ctlr->r_irq, ctlr->handle) || - bus_setup_intr(dev, ctlr->r_irq, ATA_INTR_FLAGS, - ata_ahci_intr, ctlr, &ctlr->handle)) { - device_printf(dev, "unable to setup interrupt\n"); - return ENXIO; - } - /* enable AHCI mode */ ATA_OUTL(ctlr->r_res2, ATA_AHCI_GHC, ATA_AHCI_GHC_AE); @@ -1685,9 +1656,9 @@ ata_intel_chipinit(device_t dev) ATA_OUTL(ctlr->r_res2, ATA_AHCI_GHC, ATA_INL(ctlr->r_res2, ATA_AHCI_GHC) | ATA_AHCI_GHC_IE); + ctlr->allocate = ata_ahci_allocate; ctlr->reset = ata_ahci_reset; ctlr->dmainit = ata_ahci_dmainit; - ctlr->allocate = ata_ahci_allocate; } } } @@ -1701,160 +1672,18 @@ ata_intel_chipinit(device_t dev) } static int -ata_intel_31244_allocate(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; - - ch_offset = 0x200 + ch->unit * 0x200; - - for (i = ATA_DATA; i < ATA_MAX_RES; i++) - ch->r_io[i].res = ctlr->r_res2; - 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; - 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; - 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_generic_hw(dev); - ch->hw.command = ata_intel_31244_command; - - /* enable PHY state change interrupt */ - ATA_OUTL(ctlr->r_res2, 0x4, - ATA_INL(ctlr->r_res2, 0x04) | (0x01 << (ch->unit << 3))); - return 0; -} - -static void -ata_intel_31244_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)) - continue; - - /* check for PHY related interrupts on SATA capable HW */ - if (ctlr->chip->max_dma >= ATA_SA150) { - u_int32_t status = ATA_IDX_INL(ch, ATA_SSTATUS); - u_int32_t error = ATA_IDX_INL(ch, ATA_SERROR); - struct ata_connect_task *tp; - - if (error) { - /* 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) && - (tp = (struct ata_connect_task *) - malloc(sizeof(struct ata_connect_task), - M_ATA, M_NOWAIT | M_ZERO))) { - - if ((status & ATA_SS_CONWELL_MASK) == ATA_SS_CONWELL_GEN1) { - device_printf(ch->dev, "CONNECT requested\n"); - tp->action = ATA_C_ATTACH; - } - else { - device_printf(ch->dev, "DISCONNECT requested\n"); - tp->action = ATA_C_DETACH; - } - tp->dev = ch->dev; - TASK_INIT(&tp->task, 0, ata_sata_phy_event, tp); - taskqueue_enqueue(taskqueue_thread, &tp->task); - } - } - } - - /* any drive action to take care of ? */ - if (ch->dma && (ch->dma->flags & ATA_DMA_ACTIVE)) { - int bmstat = ATA_IDX_INB(ch, ATA_BMSTAT_PORT) & ATA_BMSTAT_MASK; - - if (!(bmstat & ATA_BMSTAT_INTERRUPT)) - continue; - ATA_IDX_OUTB(ch, ATA_BMSTAT_PORT, bmstat & ~ATA_BMSTAT_ERROR); - DELAY(1); - } - ctlr->interrupt[unit].function(ch); - } -} - -static void -ata_intel_31244_reset(device_t dev) +ata_intel_allocate(device_t dev) { struct ata_channel *ch = device_get_softc(dev); - ata_sata_phy_enable(ch); -} - -static int -ata_intel_31244_command(struct ata_request *request) -{ - struct ata_channel *ch = device_get_softc(device_get_parent(request->dev)); - struct ata_device *atadev = device_get_softc(request->dev); - u_int64_t lba; - - if (!(atadev->flags & ATA_D_48BIT_ACTIVE)) - return (ata_generic_command(request)); - - lba = request->u.ata.lba; - ATA_IDX_OUTB(ch, ATA_DRIVE, ATA_D_IBM | ATA_D_LBA | atadev->unit); - /* enable interrupt */ - ATA_IDX_OUTB(ch, ATA_CONTROL, ATA_A_4BIT); - 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, ((lba >> 16) & 0xff00) | (lba & 0x00ff)); - ATA_IDX_OUTW(ch, ATA_CYL_LSB, ((lba >> 24) & 0xff00) | - ((lba >> 8) & 0x00ff)); - ATA_IDX_OUTW(ch, ATA_CYL_MSB, ((lba >> 32) & 0xff00) | - ((lba >> 16) & 0x00ff)); - - /* issue command to controller */ - ATA_IDX_OUTB(ch, ATA_COMMAND, request->u.ata.command); + /* setup the usual register normal pci style */ + if (ata_pci_allocate(dev)) + return ENXIO; + ch->flags |= ATA_ALWAYS_DMASTAT; return 0; } -static void -ata_intel_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)) - continue; - if (ch->dma) { - int bmstat = ATA_IDX_INB(ch, ATA_BMSTAT_PORT) & ATA_BMSTAT_MASK; - - if ((bmstat & (ATA_BMSTAT_ACTIVE | ATA_BMSTAT_INTERRUPT)) != - ATA_BMSTAT_INTERRUPT) - continue; - ATA_IDX_OUTB(ch, ATA_BMSTAT_PORT, bmstat & ~ATA_BMSTAT_ERROR); - DELAY(1); - } - ctlr->interrupt[unit].function(ch); - } -} - static void ata_intel_reset(device_t dev) { @@ -1977,6 +1806,123 @@ ata_intel_new_setmode(device_t dev, int mode) atadev->mode = mode; } +static int +ata_intel_31244_allocate(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; + + ch_offset = 0x200 + ch->unit * 0x200; + + for (i = ATA_DATA; i < ATA_MAX_RES; i++) + ch->r_io[i].res = ctlr->r_res2; + 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; + 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; + 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.command = ata_intel_31244_command; + + /* 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_status(device_t dev) +{ + struct ata_channel *ch = device_get_softc(dev); + u_int32_t status = ATA_IDX_INL(ch, ATA_SSTATUS); + u_int32_t error = ATA_IDX_INL(ch, ATA_SERROR); + struct ata_connect_task *tp; + + /* check for PHY related interrupts on SATA capable HW */ + if (error) { + /* 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) && + (tp = (struct ata_connect_task *) + malloc(sizeof(struct ata_connect_task), + M_ATA, M_NOWAIT | M_ZERO))) { + + if ((status & ATA_SS_CONWELL_MASK) == ATA_SS_CONWELL_GEN1) { + if (bootverbose) + device_printf(ch->dev, "CONNECT requested\n"); + tp->action = ATA_C_ATTACH; + } + else { + if (bootverbose) + device_printf(ch->dev, "DISCONNECT requested\n"); + tp->action = ATA_C_DETACH; + } + tp->dev = ch->dev; + TASK_INIT(&tp->task, 0, ata_sata_phy_event, tp); + taskqueue_enqueue(taskqueue_thread, &tp->task); + } + } + + /* any drive action to take care of ? */ + return 1; +} + +static int +ata_intel_31244_command(struct ata_request *request) +{ + struct ata_channel *ch = device_get_softc(device_get_parent(request->dev)); + struct ata_device *atadev = device_get_softc(request->dev); + u_int64_t lba; + + if (!(atadev->flags & ATA_D_48BIT_ACTIVE)) + return (ata_generic_command(request)); + + lba = request->u.ata.lba; + ATA_IDX_OUTB(ch, ATA_DRIVE, ATA_D_IBM | ATA_D_LBA | atadev->unit); + /* enable interrupt */ + ATA_IDX_OUTB(ch, ATA_CONTROL, ATA_A_4BIT); + 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, ((lba >> 16) & 0xff00) | (lba & 0x00ff)); + ATA_IDX_OUTW(ch, ATA_CYL_LSB, ((lba >> 24) & 0xff00) | + ((lba >> 8) & 0x00ff)); + ATA_IDX_OUTW(ch, ATA_CYL_MSB, ((lba >> 32) & 0xff00) | + ((lba >> 16) & 0x00ff)); + + /* issue command to controller */ + ATA_IDX_OUTB(ch, ATA_COMMAND, request->u.ata.command); + + return 0; +} + +static void +ata_intel_31244_reset(device_t dev) +{ + struct ata_channel *ch = device_get_softc(dev); + + ata_sata_phy_enable(ch); +} + /* * Integrated Technology Express Inc. (ITE) chipset support functions @@ -2092,6 +2038,20 @@ ata_ite_setmode(device_t dev, int mode) #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; +}; + int ata_marvell_ident(device_t dev) { @@ -2122,13 +2082,9 @@ static int ata_marvell_chipinit(device_t dev) { struct ata_pci_controller *ctlr = device_get_softc(dev); - int rid = ATA_IRQ_RID; - if (!(ctlr->r_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, - RF_SHAREABLE | RF_ACTIVE))) { - device_printf(dev, "unable to map interrupt\n"); + if (ata_setup_interrupt(dev)) return ENXIO; - } ctlr->r_type1 = SYS_RES_MEMORY; ctlr->r_rid1 = PCIR_BAR(0); @@ -2142,18 +2098,12 @@ ata_marvell_chipinit(device_t dev) /* mask all PCI interrupts */ ATA_OUTL(ctlr->r_res1, 0x01d5c, 0x00000000); + ctlr->allocate = ata_marvell_allocate; ctlr->reset = ata_marvell_reset; ctlr->dmainit = ata_marvell_dmainit; - ctlr->allocate = ata_marvell_allocate; ctlr->setmode = ata_sata_setmode; ctlr->channels = ctlr->chip->cfg1; - if ((bus_setup_intr(dev, ctlr->r_irq, ATA_INTR_FLAGS, - ata_marvell_intr, ctlr, &ctlr->handle))) { - device_printf(dev, "unable to setup interrupt\n"); - return ENXIO; - } - /* clear host controller interrupts */ ATA_OUTL(ctlr->r_res1, 0x20014, 0x00000000); if (ctlr->chip->cfg1 > 4) @@ -2217,7 +2167,9 @@ ata_marvell_allocate(device_t dev) ch->flags |= ATA_NO_SLAVE; ch->flags |= ATA_USE_16BIT; /* XXX SOS needed ? */ ata_generic_hw(dev); - ch->hw.command = ata_marvell_command; + ch->hw.begin_transaction = ata_marvell_begin_transaction; + ch->hw.end_transaction = ata_marvell_end_transaction; + ch->hw.status = ata_marvell_status; /* disable the EDMA machinery */ ATA_OUTL(ctlr->r_res1, 0x02028 + ATA_MV_EDMA_BASE(ch), 0x00000002); @@ -2259,195 +2211,62 @@ ata_marvell_allocate(device_t dev) return 0; } -struct ata_marvell_response { - u_int16_t tag; - u_int8_t edma_status; - u_int8_t dev_status; - u_int32_t timestamp; -}; - -static void -ata_marvell_intr(void *data) -{ - struct ata_pci_controller *ctlr = data; - struct ata_channel *ch; - struct ata_request *request; - struct ata_marvell_response *response; - u_int32_t cause, icr = 0; - int unit; - - /* get main interrupt cause register contents to save time below */ - cause = ATA_INL(ctlr->r_res1, 0x01d60); - - for (unit = 0; unit < ctlr->channels; unit++) { - int shift = (unit << 1) + (unit >= 4); - - if (!(ch = ctlr->interrupt[unit].argument)) - continue; - - mtx_lock(&ch->state_mtx); - if (unit == 0) { - icr = ATA_INL(ctlr->r_res1, 0x20014); - ATA_OUTL(ctlr->r_res1, 0x20014, ~icr); - } - if (unit == 4) { - icr = ATA_INL(ctlr->r_res1, 0x30014); - ATA_OUTL(ctlr->r_res1, 0x30014, ~icr); - } - - /* do we have any errors flagged ? */ - if (cause & (1 << shift)) { - struct ata_connect_task *tp; - u_int32_t error = - ATA_INL(ctlr->r_res1, 0x02008 + ATA_MV_EDMA_BASE(ch)); - - /* check for and handle disconnect events */ - if ((error & 0x00000008) && - (tp = (struct ata_connect_task *) - malloc(sizeof(struct ata_connect_task), - M_ATA, M_NOWAIT | M_ZERO))) { - - if (bootverbose) - device_printf(ch->dev, "DISCONNECT requested\n"); - tp->action = ATA_C_DETACH; - tp->dev = ch->dev; - TASK_INIT(&tp->task, 0, ata_sata_phy_event, tp); - taskqueue_enqueue(taskqueue_thread, &tp->task); - } - - /* check for and handle connect events */ - if ((error & 0x00000010) && - (tp = (struct ata_connect_task *) - malloc(sizeof(struct ata_connect_task), - M_ATA, M_NOWAIT | M_ZERO))) { - - if (bootverbose) - device_printf(ch->dev, "CONNECT requested\n"); - tp->action = ATA_C_ATTACH; - tp->dev = ch->dev; - TASK_INIT(&tp->task, 0, ata_sata_phy_event, tp); - taskqueue_enqueue(taskqueue_thread, &tp->task); - } - - /* 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); - } - - /* EDMA interrupt */ - if ((icr & (0x0001 << (unit & 3))) && (request = ch->running)) { - u_int32_t rsp_in, rsp_out; - int slot; - - request->dmastat = ch->dma->stop(request->dev); - ch->dma->unload(ch->dev); - 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); - response = (struct ata_marvell_response *) - (u_int8_t *)(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; - - /* finish up this request */ - 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); - } - - /* legacy ATA interrupt */ - else if (icr & (0x0100 << (unit & 3))) { - mtx_unlock(&ch->state_mtx); - ctlr->interrupt[unit].function(ch); - } - - /* no device action to handle */ - else { - mtx_unlock(&ch->state_mtx); - } - } -} - -struct ata_marvell_dma_prdentry { - u_int32_t addrlo; - u_int32_t count; - u_int32_t addrhi; - u_int32_t reserved; -}; - -static void -ata_marvell_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].addrhi = 0; - prd[i].count = htole32(segs[i].ds_len); - } - prd[i - 1].count |= htole32(ATA_DMA_EOT); -} - static int -ata_marvell_dmastart(device_t dev) -{ - struct ata_channel *ch = device_get_softc(device_get_parent(dev)); - - ch->flags |= ATA_DMA_ACTIVE; - return 0; -} - -static int -ata_marvell_dmastop(device_t dev) -{ - struct ata_channel *ch = device_get_softc(device_get_parent(dev)); - - ch->flags &= ~ATA_DMA_ACTIVE; - - /* get status XXX SOS */ - return 0; -} - -static void -ata_marvell_dmainit(device_t dev) +ata_marvell_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); - ata_dmainit(dev); - if (ch->dma) { - ch->dma->start = ata_marvell_dmastart; - ch->dma->stop = ata_marvell_dmastop; - ch->dma->setprd = ata_marvell_dmasetprd; + /* do we have any errors flagged ? */ + if (cause & (1 << shift)) { + struct ata_connect_task *tp; + u_int32_t error = + ATA_INL(ctlr->r_res1, 0x02008 + ATA_MV_EDMA_BASE(ch)); + + /* check for and handle disconnect events */ + if ((error & 0x00000008) && + (tp = (struct ata_connect_task *) + malloc(sizeof(struct ata_connect_task), + M_ATA, M_NOWAIT | M_ZERO))) { + + if (bootverbose) + device_printf(ch->dev, "DISCONNECT requested\n"); + tp->action = ATA_C_DETACH; + tp->dev = ch->dev; + TASK_INIT(&tp->task, 0, ata_sata_phy_event, tp); + taskqueue_enqueue(taskqueue_thread, &tp->task); + } + + /* check for and handle connect events */ + if ((error & 0x00000010) && + (tp = (struct ata_connect_task *) + malloc(sizeof(struct ata_connect_task), + M_ATA, M_NOWAIT | M_ZERO))) { + + if (bootverbose) + device_printf(ch->dev, "CONNECT requested\n"); + tp->action = ATA_C_ATTACH; + tp->dev = ch->dev; + TASK_INIT(&tp->task, 0, ata_sata_phy_event, tp); + taskqueue_enqueue(taskqueue_thread, &tp->task); + } + + /* 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); } + + /* 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_command(struct ata_request *request) +ata_marvell_begin_transaction(struct ata_request *request) { struct ata_pci_controller *ctlr=device_get_softc(GRANDPARENT(request->dev)); struct ata_channel *ch = device_get_softc(device_get_parent(request->dev)); @@ -2456,18 +2275,28 @@ ata_marvell_command(struct ata_request *request) u_int16_t *wordp; u_int32_t *quadp; int i, tag = 0x07; - int slot; + int dummy, error, slot; /* only DMA R/W goes through the EMDA machine */ if (request->u.ata.command != ATA_READ_DMA && - request->u.ata.command != ATA_READ_DMA48 && - request->u.ata.command != ATA_WRITE_DMA && - request->u.ata.command != ATA_WRITE_DMA48) { + request->u.ata.command != ATA_WRITE_DMA) { /* 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_generic_command(request); + 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(ch->dev, request->data, request->bytecount, + request->flags & ATA_R_READ, ch->dma->sg, + &dummy))) { + device_printf(request->dev, "setting up DMA failed\n"); + request->result = error; + return ATA_OP_FINISHED; } /* get next free request queue slot */ @@ -2506,6 +2335,7 @@ ata_marvell_command(struct ata_request *request) 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; @@ -2523,7 +2353,62 @@ ata_marvell_command(struct ata_request *request) req_in += (slot << 5); ATA_OUTL(ctlr->r_res1, 0x02014 + ATA_MV_EDMA_BASE(ch), req_in); - return 0; + return ATA_OP_CONTINUES; +} + +/* must be called with ATA channel locked and state_mtx held */ +static int +ata_marvell_end_transaction(struct ata_request *request) +{ + struct ata_pci_controller *ctlr=device_get_softc(GRANDPARENT(request->dev)); + struct ata_channel *ch = device_get_softc(device_get_parent(request->dev)); + 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; + + /* unload SG list */ + ch->dma->unload(ch->dev); + + /* 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); + response = (struct ata_marvell_response *) + (int8_t *)(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; + 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 @@ -2553,6 +2438,36 @@ ata_marvell_reset(device_t dev) ATA_OUTL(ctlr->r_res1, 0x02028 + ATA_MV_EDMA_BASE(ch), 0x00000001); } +static void +ata_marvell_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].addrhi = 0; + prd[i].count = htole32(segs[i].ds_len); + } + prd[i - 1].count |= htole32(ATA_DMA_EOT); +} + +static void +ata_marvell_dmainit(device_t dev) +{ + struct ata_channel *ch = device_get_softc(dev); + + ata_dmainit(dev); + if (ch->dma) { + /* note start and stop are not used here */ + ch->dma->setprd = ata_marvell_dmasetprd; + } +} + /* * National chipset support functions @@ -2571,28 +2486,14 @@ ata_national_ident(device_t dev) return ENXIO; } -static device_t nat_host = NULL; - static int ata_national_chipinit(device_t dev) { struct ata_pci_controller *ctlr = device_get_softc(dev); - device_t *children; - int nchildren, i; if (ata_setup_interrupt(dev)) return ENXIO; - /* locate the ISA part in the southbridge and enable UDMA33 */ - if (!device_get_children(device_get_parent(dev), &children,&nchildren)){ - for (i = 0; i < nchildren; i++) { - if (pci_get_devid(children[i]) == 0x0510100b) { - nat_host = children[i]; - break; - } - } - free(children, M_TEMP); - } ctlr->setmode = ata_national_setmode; return 0; } @@ -2704,12 +2605,8 @@ ata_nvidia_chipinit(device_t dev) &ctlr->r_rid2, RF_ACTIVE))) { int offset = ctlr->chip->cfg2 & NV4OFF ? 0x0440 : 0x0010; - if (bus_teardown_intr(dev, ctlr->r_irq, ctlr->handle) || - bus_setup_intr(dev, ctlr->r_irq, ATA_INTR_FLAGS, - ata_nvidia_intr, ctlr, &ctlr->handle)) { - device_printf(dev, "unable to setup interrupt\n"); - return ENXIO; - } + ctlr->allocate = ata_nvidia_allocate; + ctlr->reset = ata_nvidia_reset; /* enable control access */ pci_write_config(dev, 0x50, pci_read_config(dev, 0x50, 1) | 0x04,1); @@ -2724,8 +2621,6 @@ ata_nvidia_chipinit(device_t dev) pci_write_config(dev, PCIR_COMMAND, pci_read_config(dev, PCIR_COMMAND, 2) & ~0x0400,2); - ctlr->allocate = ata_nvidia_allocate; - ctlr->reset = ata_nvidia_reset; } ctlr->setmode = ata_sata_setmode; } @@ -2753,75 +2648,59 @@ ata_nvidia_allocate(device_t dev) ch->r_io[ATA_SERROR].offset = 0x04 + (ch->unit << 6); ch->r_io[ATA_SCONTROL].res = ctlr->r_res2; ch->r_io[ATA_SCONTROL].offset = 0x08 + (ch->unit << 6); + + ch->hw.status = ata_nvidia_status; ch->flags |= ATA_NO_SLAVE; return 0; } -static void -ata_nvidia_intr(void *data) +static int +ata_nvidia_status(device_t dev) { - struct ata_pci_controller *ctlr = data; - struct ata_channel *ch; + 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 & NV4OFF ? 0x0440 : 0x0010; + struct ata_connect_task *tp; + int shift = ch->unit << 2; u_int8_t status; - int unit; /* get interrupt status */ status = ATA_INB(ctlr->r_res2, offset); - /* clear interrupt status */ - ATA_OUTB(ctlr->r_res2, offset, 0xff); + /* check for and handle connect events */ + if (((status & (0x0c << shift)) == (0x04 << shift)) && + (tp = (struct ata_connect_task *) + malloc(sizeof(struct ata_connect_task), + M_ATA, M_NOWAIT | M_ZERO))) { - for (unit = 0; unit < ctlr->channels; unit++) { - if ((ch = ctlr->interrupt[unit].argument)) { - struct ata_connect_task *tp; - int maskshift = ch->unit << 2; - - /* clear error status */ - ATA_IDX_OUTL(ch, ATA_SERROR, ATA_IDX_INL(ch, ATA_SERROR)); - - /* check for and handle connect events */ - if (((status & (0x0c << maskshift)) == (0x04 << maskshift)) && - (tp = (struct ata_connect_task *) - malloc(sizeof(struct ata_connect_task), - M_ATA, M_NOWAIT | M_ZERO))) { - - device_printf(ch->dev, "CONNECT requested\n"); - tp->action = ATA_C_ATTACH; - tp->dev = ch->dev; - TASK_INIT(&tp->task, 0, ata_sata_phy_event, tp); - taskqueue_enqueue(taskqueue_thread, &tp->task); - } - - /* check for and handle disconnect events */ - if ((status & (0x08 << maskshift)) && - (tp = (struct ata_connect_task *) - malloc(sizeof(struct ata_connect_task), - M_ATA, M_NOWAIT | M_ZERO))) { - - device_printf(ch->dev, "DISCONNECT requested\n"); - tp->action = ATA_C_DETACH; - tp->dev = ch->dev; - TASK_INIT(&tp->task, 0, ata_sata_phy_event, tp); - taskqueue_enqueue(taskqueue_thread, &tp->task); - } - - /* any drive action to take care of ? */ - if (status & (0x01 << maskshift)) { - if (ch->dma && (ch->dma->flags & ATA_DMA_ACTIVE)) { - int bmstat = - ATA_IDX_INB(ch, ATA_BMSTAT_PORT) & ATA_BMSTAT_MASK; - - if (!(bmstat & ATA_BMSTAT_INTERRUPT)) - continue; - ATA_IDX_OUTB(ch, ATA_BMSTAT_PORT, bmstat&~ATA_BMSTAT_ERROR); - DELAY(1); - } - ctlr->interrupt[unit].function(ch); - } - } + if (bootverbose) + device_printf(ch->dev, "CONNECT requested\n"); + tp->action = ATA_C_ATTACH; + tp->dev = ch->dev; + TASK_INIT(&tp->task, 0, ata_sata_phy_event, tp); + taskqueue_enqueue(taskqueue_thread, &tp->task); } + + /* check for and handle disconnect events */ + if ((status & (0x08 << shift)) && + (tp = (struct ata_connect_task *) + malloc(sizeof(struct ata_connect_task), + M_ATA, M_NOWAIT | M_ZERO))) { + + if (bootverbose) + device_printf(ch->dev, "DISCONNECT requested\n"); + tp->action = ATA_C_DETACH; + tp->dev = ch->dev; + TASK_INIT(&tp->task, 0, ata_sata_phy_event, tp); + taskqueue_enqueue(taskqueue_thread, &tp->task); + } + + /* clear interrupt status */ + ATA_OUTB(ctlr->r_res2, offset, (0x0f << shift)); + + /* do we have any device action ? */ + return (status & (0x01 << shift)); } static void @@ -2952,74 +2831,54 @@ static int ata_promise_chipinit(device_t dev) { struct ata_pci_controller *ctlr = device_get_softc(dev); - int rid = ATA_IRQ_RID; - if (!(ctlr->r_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, - RF_SHAREABLE | RF_ACTIVE))) { - device_printf(dev, "unable to map interrupt\n"); + if (ata_setup_interrupt(dev)) return ENXIO; - } - - if (ctlr->chip->max_dma >= ATA_SA150) - ctlr->setmode = ata_sata_setmode; - else - ctlr->setmode = ata_promise_setmode; switch (ctlr->chip->cfg1) { case PRNEW: /* setup clocks */ ATA_OUTB(ctlr->r_res1, 0x11, ATA_INB(ctlr->r_res1, 0x11) | 0x0a); - ctlr->dmainit = ata_promise_new_dmainit; + ctlr->dmainit = ata_promise_dmainit; /* FALLTHROUGH */ case PROLD: /* enable burst mode */ ATA_OUTB(ctlr->r_res1, 0x1f, ATA_INB(ctlr->r_res1, 0x1f) | 0x01); - - if ((bus_setup_intr(dev, ctlr->r_irq, ATA_INTR_FLAGS, - ata_promise_old_intr, ctlr, &ctlr->handle))) { - device_printf(dev, "unable to setup interrupt\n"); - return ENXIO; - } - break; + ctlr->allocate = ata_promise_allocate; + ctlr->setmode = ata_promise_setmode; + return 0; case PRTX: - if ((bus_setup_intr(dev, ctlr->r_irq, ATA_INTR_FLAGS, - ata_promise_tx2_intr, ctlr, &ctlr->handle))) { - device_printf(dev, "unable to setup interrupt\n"); - return ENXIO; - } - break; + ctlr->allocate = ata_promise_tx2_allocate; + ctlr->setmode = ata_promise_setmode; + return 0; case PRMIO: 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))) - return ENXIO; + 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))){ - bus_release_resource(dev, ctlr->r_type1, ctlr->r_rid1,ctlr->r_res1); - return ENXIO; - } - ctlr->reset = ata_promise_mio_reset; - ctlr->dmainit = ata_promise_mio_dmainit; - ctlr->allocate = ata_promise_mio_allocate; + &ctlr->r_rid2, RF_ACTIVE))) + goto failnfree; - if (ctlr->chip->cfg2 == PRSX4X) { + switch (ctlr->chip->cfg2) { + case PRSX4X: { struct ata_promise_sx4 *hpkt; u_int32_t dimm = ATA_INL(ctlr->r_res2, 0x000c0080); - if ((bus_setup_intr(dev, ctlr->r_irq, ATA_INTR_FLAGS, - ata_promise_sx4_intr, ctlr, &ctlr->handle))) { - device_printf(dev, "unable to setup interrupt\n"); - /* XXX SOS release resources */ - return ENXIO; - } + if (bus_teardown_intr(dev, ctlr->r_irq, ctlr->handle) || + bus_setup_intr(dev, ctlr->r_irq, ATA_INTR_FLAGS, + 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", @@ -3037,52 +2896,265 @@ ata_promise_chipinit(device_t dev) M_TEMP, M_NOWAIT | M_ZERO); mtx_init(&hpkt->mtx, "ATA promise HPKT lock", NULL, MTX_DEF); TAILQ_INIT(&hpkt->queue); - hpkt->busy = 0; //hpkt->head = hpkt->tail = 0; + hpkt->busy = 0; device_set_ivars(dev, hpkt); + ctlr->allocate = ata_promise_mio_allocate; + ctlr->reset = ata_promise_mio_reset; + ctlr->dmainit = ata_promise_mio_dmainit; + ctlr->setmode = ata_promise_setmode; ctlr->channels = 4; return 0; + } + case PRPATA: + case PRCMBO: + case PRSATA: + /* + * older "mio" type controllers need an interrupt intercept + * function to compensate for the "reset on read" type interrupt + * status register they have. + */ + if (bus_teardown_intr(dev, ctlr->r_irq, ctlr->handle) || + bus_setup_intr(dev, ctlr->r_irq, ATA_INTR_FLAGS, + ata_promise_mio_intr, ctlr, &ctlr->handle)) { + device_printf(dev, "unable to setup interrupt\n"); + goto failnfree; + } + /* prime fake interrupt register */ + ATA_OUTL(ctlr->r_res2, 0x060, 0xffffffff); + break; } - if ((bus_setup_intr(dev, ctlr->r_irq, ATA_INTR_FLAGS, - ata_promise_mio_intr, ctlr, &ctlr->handle))) { - device_printf(dev, "unable to setup interrupt\n"); - /* XXX SOS release resources */ - return ENXIO; - } + + ctlr->allocate = ata_promise_mio_allocate; + ctlr->reset = ata_promise_mio_reset; + ctlr->dmainit = ata_promise_mio_dmainit; + ctlr->setmode = ata_promise_mio_setmode; switch (ctlr->chip->cfg2) { case PRPATA: ctlr->channels = ((ATA_INL(ctlr->r_res2, 0x48) & 0x01) > 0) + ((ATA_INL(ctlr->r_res2, 0x48) & 0x02) > 0) + 2; - break; + return 0; case PRCMBO: ATA_OUTL(ctlr->r_res2, 0x06c, 0x000000ff); ctlr->channels = ((ATA_INL(ctlr->r_res2, 0x48) & 0x02) > 0) + 3; - break; + return 0; case PRSATA: ATA_OUTL(ctlr->r_res2, 0x06c, 0x000000ff); ctlr->channels = 4; - break; + return 0; case PRCMBO2: ATA_OUTL(ctlr->r_res2, 0x060, 0x000000ff); ctlr->channels = 3; - break; + return 0; case PRSATA2: ATA_OUTL(ctlr->r_res2, 0x060, 0x000000ff); ctlr->channels = 4; - break; - - default: - /* XXX SOS release resources */ - return ENXIO; + return 0; } - default: - /* XXX SOS release resources */ + } + +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_allocate(device_t dev) +{ + struct ata_channel *ch = device_get_softc(dev); + + if (ata_pci_allocate(dev)) return ENXIO; + + 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(device_t dev) +{ + struct ata_pci_controller *ctlr = device_get_softc(GRANDPARENT(dev)); + struct ata_channel *ch = device_get_softc(device_get_parent(dev)); + struct ata_device *atadev = device_get_softc(dev); + + if (atadev->flags & ATA_D_48BIT_ACTIVE) { + 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, + ((ch->dma->flags & ATA_DMA_READ) ? 0x05000000 : 0x06000000) | + (ch->dma->cur_iosize >> 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, ch->dma->sg_bus); + ATA_IDX_OUTB(ch, ATA_BMCMD_PORT, + ((ch->dma->flags & ATA_DMA_READ) ? ATA_BMCMD_WRITE_READ : 0) | + ATA_BMCMD_START_STOP); + ch->flags |= ATA_DMA_ACTIVE; + return 0; +} + +static int +ata_promise_dmastop(device_t dev) +{ + struct ata_pci_controller *ctlr = device_get_softc(GRANDPARENT(dev)); + struct ata_channel *ch = device_get_softc(device_get_parent(dev)); + struct ata_device *atadev = device_get_softc(dev); + int error; + + if (atadev->flags & ATA_D_48BIT_ACTIVE) { + 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->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_dmainit(device_t dev) +{ + struct ata_channel *ch = device_get_softc(dev); + + ata_dmainit(dev); + if (ch->dma) { + ch->dma->start = ata_promise_dmastart; + ch->dma->stop = ata_promise_dmastop; + ch->dma->reset = ata_promise_dmareset; + } +} + +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) + ATA_DEV(atadev->unit); + int error; + u_int32_t timings[][2] = { + /* PROLD PRNEW 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 PROLD: + case PRNEW: + 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 PRTX: + 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 PRMIO: + if (mode > ATA_UDMA2 && + (ATA_INL(ctlr->r_res2, + (ctlr->chip->cfg2 & PRSX4X ? 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 < PRTX) + pci_write_config(gparent, 0x60 + (devno << 2), + timings[ata_mode2idx(mode)][ctlr->chip->cfg1], 4); + atadev->mode = mode; + } + return; +} + +static int +ata_promise_tx2_allocate(device_t dev) +{ + struct ata_channel *ch = device_get_softc(dev); + + if (ata_pci_allocate(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; } @@ -3116,10 +3188,13 @@ ata_promise_mio_allocate(device_t dev) ch->flags |= ATA_USE_16BIT; ata_generic_hw(dev); - if (offset) + if (ctlr->chip->cfg2 & PRSX4X) { ch->hw.command = ata_promise_sx4_command; - else + } + else { ch->hw.command = ata_promise_mio_command; + ch->hw.status = ata_promise_mio_status; + } return 0; } @@ -3128,114 +3203,123 @@ ata_promise_mio_intr(void *data) { struct ata_pci_controller *ctlr = data; struct ata_channel *ch; - u_int32_t vector = 0, status = 0; int unit; + /* + * 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". + */ + ATA_OUTL(ctlr->r_res2, 0x060, ATA_INL(ctlr->r_res2, 0x040)); + + for (unit = 0; unit < ctlr->channels; unit++) { + if ((ch = ctlr->interrupt[unit].argument)) + ctlr->interrupt[unit].function(ch); + } + ATA_OUTL(ctlr->r_res2, 0x060, 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); + struct ata_connect_task *tp; + u_int32_t vector, status; + switch (ctlr->chip->cfg2) { + case PRPATA: case PRSATA: case PRCMBO: - /* read and acknowledge interrupt(s) */ - vector = ATA_INL(ctlr->r_res2, 0x040); + /* read and acknowledge interrupt */ + vector = ATA_INL(ctlr->r_res2, 0x0060); /* read and clear interface status */ - status = ATA_INL(ctlr->r_res2, 0x06c); - ATA_OUTL(ctlr->r_res2, 0x06c, status & 0x000000ff); + status = ATA_INL(ctlr->r_res2, 0x006c); + ATA_OUTL(ctlr->r_res2, 0x006c, status & (0x00000011 << ch->unit)); break; case PRSATA2: case PRCMBO2: - /* read and acknowledge interrupt(s) */ - vector = ATA_INL(ctlr->r_res2, 0x040); - ATA_OUTL(ctlr->r_res2, 0x040, vector & 0x0000ffff); +critical_enter(); + /* read and acknowledge interrupt */ + vector = ATA_INL(ctlr->r_res2, 0x0040); + ATA_OUTL(ctlr->r_res2, 0x0040, (1 << (ch->unit + 1))); /* read and clear interface status */ - status = ATA_INL(ctlr->r_res2, 0x060); - ATA_OUTL(ctlr->r_res2, 0x060, status & 0x000000ff); + status = ATA_INL(ctlr->r_res2, 0x0060); + ATA_OUTL(ctlr->r_res2, 0x0060, status & (0x00000011 << ch->unit)); +critical_exit(); + break; + + default: + return 0; + } + + /* check for and handle disconnect events */ + if ((status & (0x00000001 << ch->unit)) && + (tp = (struct ata_connect_task *) + malloc(sizeof(struct ata_connect_task), + M_ATA, M_NOWAIT | M_ZERO))) { + + if (bootverbose) + device_printf(ch->dev, "DISCONNECT requested\n"); + tp->action = ATA_C_DETACH; + tp->dev = ch->dev; + TASK_INIT(&tp->task, 0, ata_sata_phy_event, tp); + taskqueue_enqueue(taskqueue_thread, &tp->task); + } + + /* check for and handle connect events */ + if ((status & (0x00000010 << ch->unit)) && + (tp = (struct ata_connect_task *) + malloc(sizeof(struct ata_connect_task), + M_ATA, M_NOWAIT | M_ZERO))) { + + if (bootverbose) + device_printf(ch->dev, "CONNECT requested\n"); + tp->action = ATA_C_ATTACH; + tp->dev = ch->dev; + TASK_INIT(&tp->task, 0, ata_sata_phy_event, tp); + taskqueue_enqueue(taskqueue_thread, &tp->task); + } + + /* 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_channel *ch = device_get_softc(device_get_parent(request->dev)); + u_int32_t *wordp = (u_int32_t *)ch->dma->work; + + ATA_OUTL(ctlr->r_res2, (ch->unit + 1) << 2, 0x00000001); + + /* 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(ch->dma->sg_bus); + wordp[2] = 0; + ata_promise_apkt((u_int8_t*)wordp, request); - for (unit = 0; unit < ctlr->channels; unit++) { - - if ((ch = ctlr->interrupt[unit].argument)) { - struct ata_connect_task *tp; - - /* check for and handle disconnect events */ - if ((status & (0x00000001 << unit)) && - (tp = (struct ata_connect_task *) - malloc(sizeof(struct ata_connect_task), - M_ATA, M_NOWAIT | M_ZERO))) { - - if (bootverbose) - device_printf(ch->dev, "DISCONNECT requested\n"); - tp->action = ATA_C_DETACH; - tp->dev = ch->dev; - TASK_INIT(&tp->task, 0, ata_sata_phy_event, tp); - taskqueue_enqueue(taskqueue_thread, &tp->task); - } - - /* check for and handle connect events */ - if ((status & (0x00000010 << unit)) && - (tp = (struct ata_connect_task *) - malloc(sizeof(struct ata_connect_task), - M_ATA, M_NOWAIT | M_ZERO))) { - - if (bootverbose) - device_printf(ch->dev, "CONNECT requested\n"); - tp->action = ATA_C_ATTACH; - tp->dev = ch->dev; - TASK_INIT(&tp->task, 0, ata_sata_phy_event, tp); - taskqueue_enqueue(taskqueue_thread, &tp->task); - } - - /* active interrupt(s) need to call the interrupt handler */ - if (vector & (1 << (unit + 1))) - if ((ch = ctlr->interrupt[unit].argument)) - ctlr->interrupt[unit].function(ch); - } - } -} - -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 void -ata_promise_mio_dmainit(device_t dev) -{ - struct ata_channel *ch = device_get_softc(dev); - - ata_dmainit(dev); - if (ch->dma) { - /* note start and stop are not used here */ - } + ATA_OUTL(ctlr->r_res2, 0x0240 + (ch->unit << 7), ch->dma->work_bus); + return 0; } static void @@ -3268,6 +3352,7 @@ ata_promise_mio_reset(device_t dev) ata_generic_reset(dev); break; + case PRPATA: case PRCMBO: case PRSATA: if ((ctlr->chip->cfg2 == PRSATA) || @@ -3337,36 +3422,59 @@ ata_promise_mio_reset(device_t dev) } } -static int -ata_promise_mio_command(struct ata_request *request) +static void +ata_promise_mio_dmainit(device_t dev) { - struct ata_pci_controller *ctlr=device_get_softc(GRANDPARENT(request->dev)); - struct ata_channel *ch = device_get_softc(device_get_parent(request->dev)); - u_int32_t *wordp = (u_int32_t *)ch->dma->work; + /* note start and stop are not used here */ + ata_dmainit(dev); +} - ATA_OUTL(ctlr->r_res2, (ch->unit + 1) << 2, 0x00000001); +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)); - /* XXX SOS add ATAPI commands support later */ - switch (request->u.ata.command) { - default: - return ata_generic_command(request); + if ( (ctlr->chip->cfg2 == PRSATA) || + ((ctlr->chip->cfg2 == PRCMBO) && (ch->unit < 2)) || + (ctlr->chip->cfg2 == PRSATA2) || + ((ctlr->chip->cfg2 == PRCMBO2) && (ch->unit < 2))) + ata_sata_setmode(dev, mode); + else + ata_promise_setmode(dev, mode); +} - case ATA_READ_DMA: - case ATA_READ_DMA48: - wordp[0] = htole32(0x04 | ((ch->unit + 1) << 16) | (0x00 << 24)); - break; +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; - case ATA_WRITE_DMA: - case ATA_WRITE_DMA48: - wordp[0] = htole32(0x00 | ((ch->unit + 1) << 16) | (0x00 << 24)); - break; + 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)); + } } - wordp[1] = htole32(ch->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 int @@ -3561,202 +3669,6 @@ ata_promise_next_hpkt(struct ata_pci_controller *ctlr) mtx_unlock(&hpktp->mtx); } -static void -ata_promise_tx2_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)) - continue; - ATA_IDX_OUTB(ch, ATA_BMDEVSPEC_0, 0x0b); - if (ATA_IDX_INB(ch, ATA_BMDEVSPEC_1) & 0x20) { - if (ch->dma && (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) - continue; - ATA_IDX_OUTB(ch, ATA_BMSTAT_PORT, bmstat & ~ATA_BMSTAT_ERROR); - DELAY(1); - } - ctlr->interrupt[unit].function(ch); - } - } -} - -static void -ata_promise_old_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)) - continue; - if (ATA_INL(ctlr->r_res1, 0x1c) & (ch->unit ? 0x00004000 : 0x00000400)){ - if (ch->dma && (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) - continue; - ATA_IDX_OUTB(ch, ATA_BMSTAT_PORT, bmstat & ~ATA_BMSTAT_ERROR); - DELAY(1); - } - ctlr->interrupt[unit].function(ch); - } - } -} - -static int -ata_promise_new_dmastart(device_t dev) -{ - struct ata_pci_controller *ctlr = device_get_softc(GRANDPARENT(dev)); - struct ata_channel *ch = device_get_softc(device_get_parent(dev)); - struct ata_device *atadev = device_get_softc(dev); - - if (atadev->flags & ATA_D_48BIT_ACTIVE) { - 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, - ((ch->dma->flags & ATA_DMA_READ) ? 0x05000000 : 0x06000000) | - (ch->dma->cur_iosize >> 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, ch->dma->sg_bus); - ATA_IDX_OUTB(ch, ATA_BMCMD_PORT, - ((ch->dma->flags & ATA_DMA_READ) ? ATA_BMCMD_WRITE_READ : 0) | - ATA_BMCMD_START_STOP); - ch->flags |= ATA_DMA_ACTIVE; - return 0; -} - -static int -ata_promise_new_dmastop(device_t dev) -{ - struct ata_pci_controller *ctlr = device_get_softc(GRANDPARENT(dev)); - struct ata_channel *ch = device_get_softc(device_get_parent(dev)); - struct ata_device *atadev = device_get_softc(dev); - int error; - - if (atadev->flags & ATA_D_48BIT_ACTIVE) { - 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->flags &= ~ATA_DMA_ACTIVE; - return error; -} - -static void -ata_promise_new_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_new_dmainit(device_t dev) -{ - struct ata_channel *ch = device_get_softc(dev); - - ata_dmainit(dev); - if (ch->dma) { - ch->dma->start = ata_promise_new_dmastart; - ch->dma->stop = ata_promise_new_dmastop; - ch->dma->reset = ata_promise_new_dmareset; - } -} - -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) + ATA_DEV(atadev->unit); - int error; - u_int32_t timings[][2] = { - /* PROLD PRNEW 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 PROLD: - case PRNEW: - 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 PRTX: - 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 PRMIO: - if (mode > ATA_UDMA2 && - (ATA_INL(ctlr->r_res2, - (ctlr->chip->cfg2 & PRSX4X ? 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 < PRTX) - pci_write_config(gparent, 0x60 + (devno << 2), - timings[ata_mode2idx(mode)][ctlr->chip->cfg1], 4); - atadev->mode = mode; - } - return; -} - /* * ServerWorks chipset support functions @@ -3919,21 +3831,11 @@ static int ata_sii_chipinit(device_t dev) { struct ata_pci_controller *ctlr = device_get_softc(dev); - int rid = ATA_IRQ_RID; - if (!(ctlr->r_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, - RF_SHAREABLE | RF_ACTIVE))) { - device_printf(dev, "unable to map interrupt\n"); + if (ata_setup_interrupt(dev)) return ENXIO; - } if (ctlr->chip->cfg1 == SIIMEMIO) { - if ((bus_setup_intr(dev, ctlr->r_irq, ATA_INTR_FLAGS, - ata_sii_intr, ctlr, &ctlr->handle))) { - device_printf(dev, "unable to setup interrupt\n"); - return ENXIO; - } - ctlr->r_type2 = SYS_RES_MEMORY; ctlr->r_rid2 = PCIR_BAR(5); if (!(ctlr->r_res2 = bus_alloc_resource_any(dev, ctlr->r_type2, @@ -3971,14 +3873,6 @@ ata_sii_chipinit(device_t dev) ctlr->setmode = ata_sii_setmode; } else { - if ((bus_setup_intr(dev, ctlr->r_irq, ATA_INTR_FLAGS, - ctlr->chip->cfg2 & SIIINTR ? - ata_cmd_intr : ata_cmd_old_intr, - ctlr, &ctlr->handle))) { - device_printf(dev, "unable to setup interrupt\n"); - return ENXIO; - } - if ((pci_read_config(dev, 0x51, 1) & 0x08) != 0x08) { device_printf(dev, "HW has secondary channel disabled\n"); ctlr->channels = 1; @@ -3987,11 +3881,99 @@ ata_sii_chipinit(device_t dev) /* enable interrupt as BIOS might not */ pci_write_config(dev, 0x71, 0x01, 1); + ctlr->allocate = ata_cmd_allocate; ctlr->setmode = ata_cmd_setmode; } return 0; } +static int +ata_cmd_allocate(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_allocate(dev)) + return ENXIO; + ata_pci_allocate(dev); + + if (ctlr->chip->cfg2 & SIIINTR) + 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(ch->dev), 0x71, 1)) & + (ch->unit ? 0x08 : 0x04))) { + pci_write_config(device_get_parent(ch->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) + ATA_DEV(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][ATA_DEV(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_allocate(device_t dev) { @@ -4036,118 +4018,55 @@ ata_sii_allocate(device_t dev) ch->dma->segsize = 15 * DEV_BSIZE; } - ata_generic_hw(dev); + ata_pci_hw(dev); + ch->hw.status = ata_sii_status; return 0; } -static void -ata_sii_intr(void *data) +static int +ata_sii_status(device_t dev) { - struct ata_pci_controller *ctlr = data; - struct ata_channel *ch; - int unit; + struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev)); + struct ata_channel *ch = device_get_softc(dev); - for (unit = 0; unit < ctlr->channels; unit++) { - if (!(ch = ctlr->interrupt[unit].argument)) - continue; + /* check for PHY related interrupts on SATA capable HW */ + if (ctlr->chip->max_dma >= ATA_SA150) { + u_int32_t status = ATA_IDX_INL(ch, ATA_SSTATUS); + u_int32_t error = ATA_IDX_INL(ch, ATA_SERROR); + struct ata_connect_task *tp; - /* check for PHY related interrupts on SATA capable HW */ - if (ctlr->chip->max_dma >= ATA_SA150) { - u_int32_t status = ATA_IDX_INL(ch, ATA_SSTATUS); - u_int32_t error = ATA_IDX_INL(ch, ATA_SERROR); - struct ata_connect_task *tp; + if (error) { + /* clear error bits/interrupt */ + ATA_IDX_OUTL(ch, ATA_SERROR, error); - if (error) { - /* 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) && + (tp = (struct ata_connect_task *) + malloc(sizeof(struct ata_connect_task), + M_ATA, M_NOWAIT | M_ZERO))) { - /* if we have a connection event deal with it */ - if ((error & ATA_SE_PHY_CHANGED) && - (tp = (struct ata_connect_task *) - malloc(sizeof(struct ata_connect_task), - M_ATA, M_NOWAIT | M_ZERO))) { - - if ((status & ATA_SS_CONWELL_MASK) == ATA_SS_CONWELL_GEN1) { + if ((status & ATA_SS_CONWELL_MASK) == ATA_SS_CONWELL_GEN1) { + if (bootverbose) device_printf(ch->dev, "CONNECT requested\n"); - tp->action = ATA_C_ATTACH; - } - else { - device_printf(ch->dev, "DISCONNECT requested\n"); - tp->action = ATA_C_DETACH; - } - tp->dev = ch->dev; - TASK_INIT(&tp->task, 0, ata_sata_phy_event, tp); - taskqueue_enqueue(taskqueue_thread, &tp->task); + tp->action = ATA_C_ATTACH; } + else { + if (bootverbose) + device_printf(ch->dev, "DISCONNECT requested\n"); + tp->action = ATA_C_DETACH; + } + tp->dev = ch->dev; + TASK_INIT(&tp->task, 0, ata_sata_phy_event, tp); + taskqueue_enqueue(taskqueue_thread, &tp->task); } } - - /* any drive action to take care of ? */ - if (ATA_IDX_INB(ch, ATA_BMDEVSPEC_0) & 0x08) { - if (ch->dma && (ch->dma->flags & ATA_DMA_ACTIVE)) { - int bmstat = ATA_IDX_INB(ch, ATA_BMSTAT_PORT) & ATA_BMSTAT_MASK; - - if (!(bmstat & ATA_BMSTAT_INTERRUPT)) - continue; - ATA_IDX_OUTB(ch, ATA_BMSTAT_PORT, bmstat & ~ATA_BMSTAT_ERROR); - DELAY(1); - } - ctlr->interrupt[unit].function(ch); - } - } -} -static void -ata_cmd_intr(void *data) -{ - struct ata_pci_controller *ctlr = data; - struct ata_channel *ch; - u_int8_t reg71; - int unit; - - for (unit = 0; unit < ctlr->channels; unit++) { - if (!(ch = ctlr->interrupt[unit].argument)) - continue; - if (((reg71 = pci_read_config(device_get_parent(ch->dev), 0x71, 1)) & - (ch->unit ? 0x08 : 0x04))) { - pci_write_config(device_get_parent(ch->dev), 0x71, - reg71 & ~(ch->unit ? 0x04 : 0x08), 1); - if (ch->dma && (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) - continue; - ATA_IDX_OUTB(ch, ATA_BMSTAT_PORT, bmstat & ~ATA_BMSTAT_ERROR); - DELAY(1); - } - ctlr->interrupt[unit].function(ch); - } - } -} - -static void -ata_cmd_old_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)) - continue; - if (ch->dma && (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) - continue; - ATA_IDX_OUTB(ch, ATA_BMSTAT_PORT, bmstat & ~ATA_BMSTAT_ERROR); - DELAY(1); - } - ctlr->interrupt[unit].function(ch); - } + /* any drive action to take care of ? */ + if (ATA_IDX_INB(ch, ATA_BMDEVSPEC_0) & 0x08) + return ata_pci_status(dev); + else + return 0; } static void @@ -4238,61 +4157,6 @@ ata_sii_setmode(device_t dev, int mode) atadev->mode = mode; } -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) + ATA_DEV(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][ATA_DEV(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; - } -} - /* * Silicon Integrated Systems Corp. (SiS) chipset support functions @@ -4661,9 +4525,10 @@ ata_via_allocate(device_t dev) ch->r_io[i].res = ctlr->r_res1; ch->r_io[i].offset = i - ATA_BMCMD_PORT; } - ata_generic_hw(dev); + ata_pci_hw(dev); } else { + /* setup the usual register normal pci style */ if (ata_pci_allocate(dev)) return ENXIO; } @@ -4774,7 +4639,7 @@ ata_via_family_setmode(device_t dev, int mode) /* misc functions */ -struct ata_chip_id * +static struct ata_chip_id * ata_match_chip(device_t dev, struct ata_chip_id *index) { while (index->chipid != 0) { diff --git a/sys/dev/ata/ata-disk.c b/sys/dev/ata/ata-disk.c index 3965f14de06..17749626f3b 100644 --- a/sys/dev/ata/ata-disk.c +++ b/sys/dev/ata/ata-disk.c @@ -289,45 +289,23 @@ ad_ioctl(struct disk *disk, u_long cmd, void *data, int flag, struct thread *td) static int ad_dump(void *arg, void *virtual, vm_offset_t physical, - off_t offset, size_t length) + off_t offset, size_t length) { struct disk *dp = arg; - device_t dev = dp->d_drv1; - struct ata_device *atadev = device_get_softc(dev); - struct ad_softc *adp = device_get_ivars(dev); - struct ata_channel *ch = device_get_softc(device_get_parent(dev)); - struct ata_request request; + struct bio bp; - if (!adp) - return ENXIO; + /* length zero is special and really means flush buffers to media */ + if (!length) + return ata_controlcmd(dp->d_drv1, ATA_FLUSHCACHE, 0, 0, 0); - bzero(&request, sizeof(struct ata_request)); - request.dev = dev; - - if (length) { - request.data = virtual; - request.bytecount = length; - request.transfersize = min(length, atadev->max_iosize); - request.flags = ATA_R_WRITE; - if (atadev->max_iosize > DEV_BSIZE) - request.u.ata.command = ATA_WRITE_MUL; - else - request.u.ata.command = ATA_WRITE; - request.u.ata.lba = offset / DEV_BSIZE; - request.u.ata.count = request.bytecount / DEV_BSIZE; - } - else { - request.u.ata.command = ATA_FLUSHCACHE; - request.flags = ATA_R_CONTROL; - } - if (ch->hw.begin_transaction(&request) == ATA_OP_CONTINUES) { - do { - DELAY(20); - } while (ch->hw.end_transaction(&request) == ATA_OP_CONTINUES); - } - if (request.status & ATA_S_ERROR) - return EIO; - return 0; + bzero(&bp, sizeof(struct bio)); + bp.bio_disk = dp; + bp.bio_pblkno = offset / DEV_BSIZE; + bp.bio_bcount = length; + bp.bio_data = virtual; + bp.bio_cmd = BIO_WRITE; + ad_strategy(&bp); + return bp.bio_error; } static void diff --git a/sys/dev/ata/ata-lowlevel.c b/sys/dev/ata/ata-lowlevel.c index cca8cc89950..0d50ccf0b51 100644 --- a/sys/dev/ata/ata-lowlevel.c +++ b/sys/dev/ata/ata-lowlevel.c @@ -46,8 +46,7 @@ __FBSDID("$FreeBSD$"); #include /* prototypes */ -static int ata_begin_transaction(struct ata_request *); -static int ata_end_transaction(struct ata_request *); +static int ata_generic_status(device_t dev); static int ata_wait(struct ata_channel *ch, struct ata_device *, u_int8_t); static void ata_pio_read(struct ata_request *, int); static void ata_pio_write(struct ata_request *, int); @@ -62,11 +61,12 @@ ata_generic_hw(device_t dev) ch->hw.begin_transaction = ata_begin_transaction; ch->hw.end_transaction = ata_end_transaction; + ch->hw.status = ata_generic_status; ch->hw.command = ata_generic_command; } /* must be called with ATA channel locked and state_mtx held */ -static int +int ata_begin_transaction(struct ata_request *request) { struct ata_channel *ch = device_get_softc(device_get_parent(request->dev)); @@ -220,7 +220,7 @@ begin_continue: } /* must be called with ATA channel locked and state_mtx held */ -static int +int ata_end_transaction(struct ata_request *request) { struct ata_channel *ch = device_get_softc(device_get_parent(request->dev)); @@ -470,7 +470,7 @@ end_continue: return ATA_OP_CONTINUES; } -/* must be called with ATA channel locked */ +/* must be called with ATA channel locked and state_mtx held */ void ata_generic_reset(device_t dev) { @@ -605,6 +605,20 @@ ata_generic_reset(device_t dev) "\20\4ATAPI_SLAVE\3ATAPI_MASTER\2ATA_SLAVE\1ATA_MASTER"); } +/* 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) { diff --git a/sys/dev/ata/ata-pci.c b/sys/dev/ata/ata-pci.c index acde1800a00..5fa4d557586 100644 --- a/sys/dev/ata/ata-pci.c +++ b/sys/dev/ata/ata-pci.c @@ -203,7 +203,8 @@ ata_pci_attach(device_t dev) RF_ACTIVE); } - ctlr->chipinit(dev); + if (ctlr->chipinit(dev)) + return ENXIO; /* attach all channels on this controller */ for (unit = 0; unit < ctlr->channels; unit++) { @@ -420,10 +421,42 @@ ata_pci_allocate(device_t dev) } } - ata_generic_hw(dev); + ata_pci_hw(dev); return 0; } +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; +} + +int +ata_pci_status(device_t dev) +{ + struct ata_channel *ch = device_get_softc(dev); + + if (ch->dma && ((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; +} + static int ata_pci_dmastart(device_t dev) { diff --git a/sys/dev/ata/ata-pci.h b/sys/dev/ata/ata-pci.h index 14ce850659d..dbef07a779f 100644 --- a/sys/dev/ata/ata-pci.h +++ b/sys/dev/ata/ata-pci.h @@ -392,6 +392,9 @@ int ata_pci_release_resource(device_t dev, device_t child, int type, int rid, st int ata_pci_setup_intr(device_t dev, device_t child, struct resource *irq, int flags, driver_intr_t *function, void *argument, void **cookiep); int ata_pci_teardown_intr(device_t dev, device_t child, struct resource *irq, void *cookie); int ata_pci_allocate(device_t dev); +void ata_pci_hw(device_t dev); +int ata_pci_status(device_t dev); + /* global prototypes ata-chipset.c */ int ata_generic_ident(device_t); @@ -413,7 +416,6 @@ int ata_sii_ident(device_t); int ata_sis_ident(device_t); int ata_via_ident(device_t); int ata_legacy(device_t); -struct ata_chip_id *ata_match_chip(device_t, struct ata_chip_id *); /* global prototypes ata-dma.c */ void ata_dmainit(device_t); diff --git a/sys/dev/ata/ata-queue.c b/sys/dev/ata/ata-queue.c index 3d6d6b24241..37a2f67a22a 100644 --- a/sys/dev/ata/ata-queue.c +++ b/sys/dev/ata/ata-queue.c @@ -94,7 +94,8 @@ ata_queue_request(struct ata_request *request) /* if this is not a callback wait until request is completed */ if (!request->callback) { ATA_DEBUG_RQ(request, "wait for completition"); - while (sema_timedwait(&request->done, request->timeout * hz * 4)) { + while (!dumping && + sema_timedwait(&request->done, request->timeout * hz * 4)) { device_printf(request->dev, "req=%p %s semaphore timeout !! DANGER Will Robinson !!\n", request, ata_cmd2str(request)); @@ -200,6 +201,13 @@ ata_start(device_t dev) ata_finish(request); return; } + if (dumping) { + mtx_unlock(&ch->state_mtx); + mtx_unlock(&ch->queue_mtx); + while (!ata_interrupt(ch)) + DELAY(10); + return; + } } mtx_unlock(&ch->state_mtx); } @@ -216,7 +224,8 @@ ata_finish(struct ata_request *request) * 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 ((ch->state & ATA_STALL_QUEUE) || (request->flags & ATA_R_DIRECT)) { + if (dumping || + (ch->state & ATA_STALL_QUEUE) || (request->flags & ATA_R_DIRECT)) { ATA_DEBUG_RQ(request, "finish directly"); ata_completed(request, 0); } diff --git a/sys/dev/ata/ata-raid.c b/sys/dev/ata/ata-raid.c index bcc636c6d7e..7580ab71ed0 100644 --- a/sys/dev/ata/ata-raid.c +++ b/sys/dev/ata/ata-raid.c @@ -111,7 +111,7 @@ static int testing = 0; /* device structures */ static disk_strategy_t ata_raid_strategy; -//static dumper_t ata_raid_dump; +static dumper_t ata_raid_dump; static void ata_raid_attach(struct ar_softc *rdp, int writeback) @@ -134,7 +134,7 @@ ata_raid_attach(struct ar_softc *rdp, int writeback) buffer[0] = '\0'; rdp->disk = disk_alloc(); rdp->disk->d_strategy = ata_raid_strategy; - //rdp->disk->d_dump = ata_raid_dump; + rdp->disk->d_dump = ata_raid_dump; rdp->disk->d_name = "ar"; rdp->disk->d_sectorsize = DEV_BSIZE; rdp->disk->d_mediasize = (off_t)rdp->total_sectors * DEV_BSIZE; @@ -751,6 +751,35 @@ ata_raid_done(struct ata_request *request) ata_free_request(request); } +static int +ata_raid_dump(void *arg, void *virtual, vm_offset_t physical, + off_t offset, size_t length) +{ + struct disk *dp = arg; + struct ar_softc *rdp = dp->d_drv1; + struct bio bp; + + /* length zero is special and really means flush buffers to media */ + if (!length) { + int disk, error; + + for (disk = 0, error = 0; disk < rdp->total_disks; disk++) + if (rdp->disks[disk].dev) + error |= ata_controlcmd(rdp->disks[disk].dev, + ATA_FLUSHCACHE, 0, 0, 0); + return (error ? EIO : 0); + } + + bzero(&bp, sizeof(struct bio)); + bp.bio_disk = dp; + bp.bio_pblkno = offset / DEV_BSIZE; + bp.bio_bcount = length; + bp.bio_data = virtual; + bp.bio_cmd = BIO_WRITE; + ata_raid_strategy(&bp); + return bp.bio_error; +} + static void ata_raid_config_changed(struct ar_softc *rdp, int writeback) {