ata-dma.c revision 45554
145095Ssos/*- 245095Ssos * Copyright (c) 1998,1999 S�ren Schmidt 345095Ssos * All rights reserved. 445095Ssos * 545095Ssos * Redistribution and use in source and binary forms, with or without 645095Ssos * modification, are permitted provided that the following conditions 745095Ssos * are met: 845095Ssos * 1. Redistributions of source code must retain the above copyright 945095Ssos * notice, this list of conditions and the following disclaimer, 1045095Ssos * without modification, immediately at the beginning of the file. 1145095Ssos * 2. Redistributions in binary form must reproduce the above copyright 1245095Ssos * notice, this list of conditions and the following disclaimer in the 1345095Ssos * documentation and/or other materials provided with the distribution. 1445095Ssos * 3. The name of the author may not be used to endorse or promote products 1545095Ssos * derived from this software without specific prior written permission. 1645095Ssos * 1745095Ssos * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 1845095Ssos * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 1945095Ssos * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 2045095Ssos * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 2145095Ssos * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 2245095Ssos * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 2345095Ssos * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 2445095Ssos * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 2545095Ssos * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 2645095Ssos * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2745095Ssos * 2845554Ssos * $Id: ata-dma.c,v 1.3 1999/03/30 13:09:47 sos Exp $ 2945095Ssos */ 3045095Ssos 3145095Ssos#include "ata.h" 3245150Ssos#include "pci.h" 3345095Ssos#if NATA > 0 3445095Ssos#include <sys/param.h> 3545095Ssos#include <sys/systm.h> 3645095Ssos#include <sys/kernel.h> 3745095Ssos#include <sys/buf.h> 3845095Ssos#include <sys/malloc.h> 3945095Ssos#include <vm/vm.h> 4045095Ssos#include <vm/pmap.h> 4145095Ssos#include <pci/pcivar.h> 4245095Ssos#include <pci/pcireg.h> 4345095Ssos#include <dev/ata/ata-all.h> 4445095Ssos 4545095Ssos/* misc defines */ 4645095Ssos#define MIN(a,b) ((a)>(b)?(b):(a)) 4745095Ssos 4845150Ssos#if NPCI > 0 4945150Ssos 5045095Ssosint32_t 5145095Ssosata_dmainit(struct ata_softc *scp, int32_t device, 5245095Ssos int32_t apiomode, int32_t wdmamode, int32_t udmamode) 5345095Ssos{ 5445095Ssos int32_t type, devno, error; 5545095Ssos void *dmatab; 5645095Ssos 5745095Ssos if (!scp->bmaddr) 5845095Ssos return -1; 5945095Ssos#ifdef ATA_DEBUGDMA 6045095Ssos printf("ata%d: dmainit: ioaddr=0x%x altioaddr=0x%x, bmaddr=0x%x\n", 6145095Ssos scp->lun, scp->ioaddr, scp->altioaddr, scp->bmaddr); 6245095Ssos#endif 6345095Ssos 6445095Ssos if (!(dmatab = malloc(PAGE_SIZE, M_DEVBUF, M_NOWAIT))) 6545095Ssos return -1; 6645095Ssos 6745095Ssos if (((int)dmatab>>PAGE_SHIFT)^(((int)dmatab+PAGE_SIZE-1)>>PAGE_SHIFT)) { 6845095Ssos printf("ata_dmainit: dmatab crosses page boundary, no DMA\n"); 6945095Ssos free(dmatab, M_DEVBUF); 7045095Ssos return -1; 7145095Ssos } 7245095Ssos scp->dmatab[device ? 1 : 0] = dmatab; 7345095Ssos 7445095Ssos type = pci_conf_read(scp->tag, PCI_ID_REG); 7545095Ssos 7645095Ssos switch(type) { 7745095Ssos 7845095Ssos case 0x71118086: /* Intel PIIX4 */ 7945095Ssos if (udmamode >= 2) { 8045095Ssos int32_t mask48, new48; 8145095Ssos 8245095Ssos printf("ata%d: %s: settting up UDMA2 mode on PIIX4 chip ", 8345095Ssos scp->lun, (device) ? "slave" : "master"); 8445095Ssos error = ata_command(scp, device, ATA_C_SETFEATURES, 0, 0, 0, 8545095Ssos ATA_UDMA2, ATA_C_FEA_SETXFER, ATA_WAIT_INTR); 8645095Ssos if (error) { 8745095Ssos printf("failed\n"); 8845095Ssos break; 8945095Ssos } 9045095Ssos printf("OK\n"); 9145554Ssos devno = (scp->unit << 1) + (device ? 1 : 0); 9245095Ssos mask48 = (1 << devno) + (3 << (16 + (devno << 2))); 9345095Ssos new48 = (1 << devno) + (2 << (16 + (devno << 2))); 9445095Ssos pci_conf_write(scp->tag, 0x48, 9545095Ssos (pci_conf_read(scp->tag, 0x48) & ~mask48) | new48); 9645095Ssos return 0; 9745095Ssos } 9845095Ssos /* FALLTHROUGH */ 9945095Ssos 10045095Ssos case 0x70108086: /* Intel PIIX3 */ 10145095Ssos if (wdmamode >= 2 && apiomode >= 4) { 10245095Ssos int32_t mask40, new40, mask44, new44; 10345095Ssos 10445095Ssos /* if SITRE not set doit for both channels */ 10545095Ssos if (!((pci_conf_read(scp->tag, 0x40) >> (scp->unit<<8)) & 0x4000)) { 10645095Ssos new40 = pci_conf_read(scp->tag, 0x40); 10745095Ssos new44 = pci_conf_read(scp->tag, 0x44); 10845095Ssos if (!(new40 & 0x00004000)) { 10945095Ssos new44 &= ~0x0000000f; 11045095Ssos new44 |= ((new40&0x00003000)>>10)|((new40&0x00000300)>>8); 11145095Ssos } 11245095Ssos if (!(new40 & 0x40000000)) { 11345095Ssos new44 &= ~0x000000f0; 11445095Ssos new44 |= ((new40&0x30000000)>>22)|((new40&0x03000000)>>20); 11545095Ssos } 11645095Ssos new40 |= 0x40004000; 11745095Ssos pci_conf_write(scp->tag, 0x40, new40); 11845095Ssos pci_conf_write(scp->tag, 0x44, new44); 11945095Ssos } 12045095Ssos printf("ata%d: %s: settting up WDMA2 mode on PIIX3/4 chip ", 12145095Ssos scp->lun, (device) ? "slave" : "master"); 12245095Ssos error = ata_command(scp, device, ATA_C_SETFEATURES, 0, 0, 0, 12345095Ssos ATA_WDMA2, ATA_C_FEA_SETXFER, ATA_WAIT_INTR); 12445095Ssos if (error) { 12545095Ssos printf("failed\n"); 12645095Ssos break; 12745095Ssos } 12845095Ssos printf("OK\n"); 12945095Ssos if (device == ATA_MASTER) { 13045095Ssos mask40 = 0x0000330f; 13145095Ssos new40 = 0x00002307; 13245095Ssos mask44 = 0; 13345095Ssos new44 = 0; 13445095Ssos } else { 13545095Ssos mask40 = 0x000000f0; 13645095Ssos new40 = 0x00000070; 13745095Ssos mask44 = 0x0000000f; 13845095Ssos new44 = 0x0000000b; 13945095Ssos } 14045095Ssos if (scp->unit) { 14145095Ssos mask40 <<= 16; 14245095Ssos new40 <<= 16; 14345095Ssos mask44 <<= 4; 14445095Ssos new44 <<= 4; 14545095Ssos } 14645095Ssos pci_conf_write(scp->tag, 0x40, 14745095Ssos (pci_conf_read(scp->tag, 0x40) & ~mask40) | new40); 14845095Ssos pci_conf_write(scp->tag, 0x44, 14945095Ssos (pci_conf_read(scp->tag, 0x44) & ~mask44) | new44); 15045095Ssos return 0; 15145095Ssos } 15245095Ssos break; 15345095Ssos 15445095Ssos case 0x12308086: /* Intel PIIX */ 15545095Ssos /* probably not worth the trouble */ 15645095Ssos break; 15745095Ssos 15845095Ssos case 0x4d33105a: /* Promise Ultra/33 / FastTrack controllers */ 15945554Ssos devno = (scp->unit << 1) + (device ? 1 : 0); 16045095Ssos if (udmamode >=2) { 16145095Ssos printf("ata%d: %s: settting up UDMA2 mode on Promise chip ", 16245095Ssos scp->lun, (device) ? "slave" : "master"); 16345095Ssos error = ata_command(scp, device, ATA_C_SETFEATURES, 0, 0, 0, 16445095Ssos ATA_UDMA2, ATA_C_FEA_SETXFER, ATA_WAIT_INTR); 16545095Ssos if (error) { 16645095Ssos printf("failed\n"); 16745095Ssos break; 16845095Ssos } 16945095Ssos printf("OK\n"); 17045116Ssos pci_conf_write(scp->tag, 0x60 + (devno << 2), 0x004127f3); 17145116Ssos return 0; 17245095Ssos } 17345095Ssos else if (wdmamode >= 2 && apiomode >= 4) { 17445095Ssos printf("ata%d: %s: settting up WDMA2 mode on Promise chip ", 17545095Ssos scp->lun, (device) ? "slave" : "master"); 17645095Ssos error = ata_command(scp, device, ATA_C_SETFEATURES, 0, 0, 0, 17745095Ssos ATA_WDMA2, ATA_C_FEA_SETXFER, ATA_WAIT_INTR); 17845095Ssos if (error) { 17945095Ssos printf("failed\n"); 18045095Ssos break; 18145095Ssos } 18245095Ssos printf("OK\n"); 18345116Ssos pci_conf_write(scp->tag, 0x60 + (devno << 2), 0x004367f3); 18445116Ssos return 0; 18545095Ssos } 18645095Ssos else { 18745095Ssos printf("ata%d: %s: settting up PIO mode on Promise chip OK\n", 18845095Ssos scp->lun, (device) ? "slave" : "master"); 18945116Ssos pci_conf_write(scp->tag, 0x60 + (devno << 2), 0x004fe924); 19045095Ssos } 19145095Ssos break; 19245095Ssos 19345095Ssos case 0x522910b9: /* AcerLabs Aladdin IV/V */ 19445095Ssos if (udmamode >=2) { 19545095Ssos int32_t word54 = pci_conf_read(scp->tag, 0x54); 19645095Ssos 19745095Ssos printf("ata%d: %s: settting up UDMA2 mode on Aladdin chip ", 19845095Ssos scp->lun, (device) ? "slave" : "master"); 19945095Ssos error = ata_command(scp, device, ATA_C_SETFEATURES, 0, 0, 0, 20045095Ssos ATA_UDMA2, ATA_C_FEA_SETXFER, ATA_WAIT_INTR); 20145095Ssos if (error) { 20245095Ssos printf("failed\n"); 20345095Ssos break; 20445095Ssos } 20545095Ssos printf("OK\n"); 20645095Ssos word54 |= 0x5555; 20745095Ssos word54 |= (0x0000000A << (16 + (scp->unit << 3) + (device << 2))); 20845095Ssos pci_conf_write(scp->tag, 0x54, word54); 20945095Ssos return 0; 21045095Ssos 21145095Ssos } 21245095Ssos else if (wdmamode >= 2 && apiomode >= 4) { 21345095Ssos printf("ata%d: %s: settting up WDMA2 mode on Aladdin chip ", 21445095Ssos scp->lun, (device) ? "slave" : "master"); 21545095Ssos error = ata_command(scp, device, ATA_C_SETFEATURES, 0, 0, 0, 21645095Ssos ATA_WDMA2, ATA_C_FEA_SETXFER, ATA_WAIT_INTR); 21745095Ssos if (error) { 21845095Ssos printf("failed\n"); 21945095Ssos break; 22045095Ssos } 22145095Ssos printf("OK\n"); 22245095Ssos return 0; 22345095Ssos } 22445095Ssos break; 22545095Ssos 22645095Ssos default: /* well, we have no support for this, but try anyways */ 22745095Ssos if ((wdmamode >= 2 && apiomode >= 4) || udmamode >= 2) { 22845095Ssos printf("ata%d: %s: settting up generic WDMA2 mode ", 22945095Ssos scp->lun, (device) ? "slave" : "master"); 23045095Ssos error = ata_command(scp, device, ATA_C_SETFEATURES, 0, 0, 0, 23145095Ssos ATA_WDMA2, ATA_C_FEA_SETXFER, ATA_WAIT_INTR); 23245095Ssos if (error) { 23345095Ssos printf("failed\n"); 23445095Ssos break; 23545095Ssos } 23645095Ssos printf("OK\n"); 23745095Ssos return 0; 23845095Ssos } 23945095Ssos } 24045095Ssos free(dmatab, M_DEVBUF); 24145095Ssos return -1; 24245095Ssos} 24345095Ssos 24445095Ssosint32_t 24545095Ssosata_dmasetup(struct ata_softc *scp, int32_t device, 24645095Ssos int8_t *data, int32_t count, int32_t flags) 24745095Ssos{ 24845095Ssos struct ata_dmaentry *dmatab; 24945095Ssos u_int32_t dma_count, dma_base; 25045095Ssos int32_t i = 0; 25145095Ssos 25245095Ssos#ifdef ATA_DEBUGDMA 25345095Ssos printf("ata%d: dmasetup\n", scp->lun); 25445095Ssos#endif 25545095Ssos if (((u_int32_t)data & 1) || (count & 1)) 25645095Ssos return -1; 25745095Ssos 25845095Ssos if (!count) { 25945095Ssos printf("ata%d: zero length DMA transfer attempt on %s\n", 26045095Ssos scp->lun, (device ? "slave" : "master")); 26145095Ssos return -1; 26245095Ssos } 26345095Ssos 26445095Ssos dmatab = scp->dmatab[device ? 1 : 0]; 26545095Ssos dma_base = vtophys(data); 26645095Ssos dma_count = MIN(count, (PAGE_SIZE - ((u_int32_t)data & PAGE_MASK))); 26745095Ssos data += dma_count; 26845095Ssos count -= dma_count; 26945095Ssos 27045095Ssos while (count) { 27145095Ssos dmatab[i].base = dma_base; 27245095Ssos dmatab[i].count = (dma_count & 0xffff); 27345095Ssos i++; 27445095Ssos if (i >= ATA_DMA_ENTRIES) { 27545095Ssos printf("ata%d: too many segments in DMA table for %s\n", 27645095Ssos scp->lun, (device ? "slave" : "master")); 27745095Ssos return -1; 27845095Ssos } 27945095Ssos dma_base = vtophys(data); 28045095Ssos dma_count = MIN(count, PAGE_SIZE); 28145095Ssos data += MIN(count, PAGE_SIZE); 28245095Ssos count -= MIN(count, PAGE_SIZE); 28345095Ssos } 28445095Ssos#ifdef ATA_DEBUGDMA 28545095Ssosprintf("ata_dmasetup: base=%08x count%08x\n", 28645095Ssos dma_base, dma_count); 28745095Ssos#endif 28845095Ssos dmatab[i].base = dma_base; 28945095Ssos dmatab[i].count = (dma_count & 0xffff) | ATA_DMA_EOT; 29045095Ssos 29145095Ssos outl(scp->bmaddr + ATA_BMDTP_PORT, vtophys(dmatab)); 29245095Ssos#ifdef ATA_DEBUGDMA 29345095Ssosprintf("dmatab=%08x %08x\n", vtophys(dmatab), inl(scp->bmaddr+ATA_BMDTP_PORT)); 29445095Ssos#endif 29545095Ssos outb(scp->bmaddr + ATA_BMCMD_PORT, flags ? ATA_BMCMD_WRITE_READ:0); 29645095Ssos outb(scp->bmaddr + ATA_BMSTAT_PORT, (inb(scp->bmaddr + ATA_BMSTAT_PORT) | 29745095Ssos (ATA_BMSTAT_INTERRUPT | ATA_BMSTAT_ERROR))); 29845095Ssos return 0; 29945095Ssos} 30045095Ssos 30145095Ssosvoid 30245095Ssosata_dmastart(struct ata_softc *scp, int32_t device) 30345095Ssos{ 30445095Ssos#ifdef ATA_DEBUGDMA 30545095Ssos printf("ata%d: dmastart\n", scp->lun); 30645095Ssos#endif 30745095Ssos outb(scp->bmaddr + ATA_BMCMD_PORT, 30845095Ssos inb(scp->bmaddr + ATA_BMCMD_PORT) | ATA_BMCMD_START_STOP); 30945095Ssos} 31045095Ssos 31145095Ssosint32_t 31245095Ssosata_dmadone(struct ata_softc *scp, int32_t device) 31345095Ssos{ 31445095Ssos#ifdef ATA_DEBUGDMA 31545095Ssos printf("ata%d: dmadone\n", scp->lun); 31645095Ssos#endif 31745095Ssos outb(scp->bmaddr + ATA_BMCMD_PORT, 31845095Ssos inb(scp->bmaddr + ATA_BMCMD_PORT) & ~ATA_BMCMD_START_STOP); 31945095Ssos return inb(scp->bmaddr + ATA_BMSTAT_PORT) & ATA_BMSTAT_MASK; 32045095Ssos} 32145095Ssos 32245095Ssosint32_t 32345095Ssosata_dmastatus(struct ata_softc *scp, int32_t device) 32445095Ssos{ 32545095Ssos#ifdef ATA_DEBUGDMA 32645095Ssos printf("ata%d: dmastatus\n", scp->lun); 32745095Ssos#endif 32845095Ssos return inb(scp->bmaddr + ATA_BMSTAT_PORT) & ATA_BMSTAT_MASK; 32945095Ssos} 33045095Ssos 33145095Ssos#else /* NPCI > 0 */ 33245095Ssos 33345095Ssosint32_t 33445095Ssosata_dmainit(struct ata_softc *scp, int32_t device, 33545095Ssos int32_t piomode, int32_t wdmamode, int32_t udmamode) 33645095Ssos{ 33745095Ssos return -1; 33845095Ssos} 33945095Ssos 34045095Ssosint32_t 34145095Ssosata_dmasetup(struct ata_softc *scp, int32_t device, 34245095Ssos int8_t *data, int32_t count, int32_t flags) 34345095Ssos{ 34445095Ssos return -1; 34545095Ssos} 34645095Ssos 34745095Ssosvoid 34845095Ssosata_dmastart(struct ata_softc *scp, int32_t device) 34945095Ssos{ 35045095Ssos} 35145095Ssos 35245095Ssosint32_t 35345095Ssosata_dmadone(struct ata_softc *scp, int32_t device) 35445095Ssos{ 35545095Ssos return -1; 35645095Ssos} 35745095Ssos 35845095Ssosint32_t 35945095Ssosata_dmastatus(struct ata_softc *scp, int32_t device) 36045095Ssos{ 36145095Ssos return -1; 36245095Ssos} 36345095Ssos 36445095Ssos#endif /* NPCI > 0 */ 36545095Ssos#endif /* NATA > 0 */ 366