summaryrefslogtreecommitdiffstats
path: root/sys/dev
diff options
context:
space:
mode:
authorsos <sos@FreeBSD.org>2003-07-02 10:50:44 +0000
committersos <sos@FreeBSD.org>2003-07-02 10:50:44 +0000
commit50b0b9ea2f2d26323c199bc837b228b8f2c87837 (patch)
tree95c6e3e670c8a36907b5836fe67f4b0c35f18f4e /sys/dev
parentf7b1b6fb60e6beaabbb08943e9e4530ced84cabd (diff)
downloadFreeBSD-src-50b0b9ea2f2d26323c199bc837b228b8f2c87837.zip
FreeBSD-src-50b0b9ea2f2d26323c199bc837b228b8f2c87837.tar.gz
Update the SATA support code to work more correctly with
real SATA disks now that I can test it. Add support for the SiI 3112 SATA chip using memory mapped I/O. Update the support for the SiI 0680 to use the memio interface as well. Sponsored by: David Leimbach <leimy2k@mac.com> (3112 based controller) Sponsored by: FreeBSD Systems (www.FreeBSDsystems.com) (SATA disks)
Diffstat (limited to 'sys/dev')
-rw-r--r--sys/dev/ata/ata-chipset.c160
-rw-r--r--sys/dev/ata/ata-pci.c11
-rw-r--r--sys/dev/ata/ata-pci.h7
3 files changed, 121 insertions, 57 deletions
diff --git a/sys/dev/ata/ata-chipset.c b/sys/dev/ata/ata-chipset.c
index e831fce..d731265 100644
--- a/sys/dev/ata/ata-chipset.c
+++ b/sys/dev/ata/ata-chipset.c
@@ -93,6 +93,8 @@ static int ata_promise_mio_dmastop(struct ata_channel *);
static int ata_serverworks_chipinit(device_t);
static void ata_serverworks_setmode(struct ata_device *, int);
static int ata_sii_chipinit(device_t);
+static int ata_sii_mio_allocate(device_t, struct ata_channel *);
+static void ata_sii_intr(void *);
static void ata_cmd_intr(void *);
static void ata_sii_setmode(struct ata_device *, int);
static void ata_cmd_setmode(struct ata_device *, int);
@@ -838,11 +840,6 @@ ata_intel_new_setmode(struct ata_device *atadev, int mode)
mode = ata_limit_mode(atadev, mode, ctlr->chip->max_dma);
- if (mode >= ATA_SA150) {
- atadev->mode = mode;
- return;
- }
-
if (ctlr->chip->max_dma && mode > ATA_UDMA2 && !(reg54 & (0x10 << devno))) {
ata_prtdev(atadev,"DMA limited to UDMA33, non-ATA66 cable or device\n");
mode = ATA_UDMA2;
@@ -854,7 +851,10 @@ ata_intel_new_setmode(struct ata_device *atadev, int mode)
ata_prtdev(atadev, "%s setting %s on %s chip\n",
(error) ? "failed" : "success",
ata_mode2str(mode), ctlr->chip->text);
- if (!error) {
+ if (error)
+ return;
+
+ if (ctlr->chip->max_dma < ATA_SA150) {
if (mode >= ATA_UDMA0) {
pci_write_config(parent, 0x48, reg48 | (0x0001 << devno), 2);
pci_write_config(parent, 0x4a, (reg4a & ~(0x3 << (devno<<2))) |
@@ -894,8 +894,8 @@ ata_intel_new_setmode(struct ata_device *atadev, int mode)
}
pci_write_config(parent, 0x40, (reg40 & ~mask40) | new40, 4);
pci_write_config(parent, 0x44, (reg44 & ~mask44) | new44, 1);
- atadev->mode = mode;
}
+ atadev->mode = mode;
}
/*
@@ -1244,11 +1244,6 @@ ata_promise_setmode(struct ata_device *atadev, int mode)
break;
}
- if (mode >= ATA_SA150) {
- atadev->mode = mode;
- return;
- }
-
error = ata_command(atadev, ATA_C_SETFEATURES, 0, mode,
ATA_C_F_SETXFER, ATA_WAIT_READY);
if (bootverbose)
@@ -1458,11 +1453,12 @@ ata_sii_ident(device_t dev)
struct ata_pci_controller *ctlr = device_get_softc(dev);
struct ata_chip_id *idx;
static struct ata_chip_id ids[] =
- {{ ATA_SII0680, 0x00, 0, SII_SETCLK, ATA_UDMA6, "SiI 0680" },
- { ATA_CMD649, 0x00, 0, SII_INTR|SII_ENINTR, ATA_UDMA5, "CMD 649" },
- { ATA_CMD648, 0x00, 0, SII_INTR|SII_ENINTR, ATA_UDMA4, "CMD 648" },
- { ATA_CMD646, 0x07, 0, SII_ENINTR, ATA_UDMA2, "CMD 646U2" },
- { ATA_CMD646, 0x00, 0, SII_ENINTR, ATA_WDMA2, "CMD 646" },
+ {{ ATA_SII3112, 0x00, SIIMEMIO, 0, ATA_SA150, "SiI 3112" },
+ { ATA_SII0680, 0x00, SIIMEMIO, SIISETCLK, ATA_UDMA6, "SiI 0680" },
+ { ATA_CMD649, 0x00, 0, SIIINTR, ATA_UDMA5, "CMD 649" },
+ { ATA_CMD648, 0x00, 0, SIIINTR, ATA_UDMA4, "CMD 648" },
+ { ATA_CMD646, 0x07, 0, 0, ATA_UDMA2, "CMD 646U2" },
+ { ATA_CMD646, 0x00, 0, 0, ATA_WDMA2, "CMD 646" },
{ 0, 0, 0, 0, 0, 0}};
char buffer[64];
@@ -1487,38 +1483,105 @@ ata_sii_chipinit(device_t dev)
device_printf(dev, "unable to map interrupt\n");
return ENXIO;
}
- if ((bus_setup_intr(dev, ctlr->r_irq, INTR_TYPE_BIO | INTR_ENTROPY,
- ctlr->chip->cfg2 & SII_INTR ?
- ata_cmd_intr : ata_generic_intr,
- ctlr, &ctlr->handle))) {
- device_printf(dev, "unable to setup interrupt\n");
- return ENXIO;
+
+ if (ctlr->chip->cfg1 == SIIMEMIO) {
+ if ((bus_setup_intr(dev, ctlr->r_irq, INTR_TYPE_BIO | INTR_ENTROPY,
+ ata_sii_intr, ctlr, &ctlr->handle))) {
+ device_printf(dev, "unable to setup interrupt\n");
+ return ENXIO;
+ }
+ rid = 0x24;
+ if (!(ctlr->r_io2 = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid,
+ 0, ~0, 1, RF_ACTIVE)))
+ return ENXIO;
+
+ if (ctlr->chip->cfg2 & SIISETCLK) {
+ if ((pci_read_config(dev, 0x8a, 1) & 0x30) != 0x10)
+ pci_write_config(dev, 0x8a,
+ (pci_read_config(dev, 0x8a, 1) & 0x0F)|0x10,1);
+ if ((pci_read_config(dev, 0x8a, 1) & 0x30) != 0x10)
+ device_printf(dev, "%s could not set ATA133 clock\n",
+ ctlr->chip->text);
+ }
+ ctlr->allocate = ata_sii_mio_allocate;
+ ctlr->setmode = ata_sii_setmode;
}
+ else {
+ if ((bus_setup_intr(dev, ctlr->r_irq, INTR_TYPE_BIO | INTR_ENTROPY,
+ ctlr->chip->cfg2 & SIIINTR ?
+ ata_cmd_intr : ata_generic_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;
+ }
- if (ctlr->chip->cfg2 & SII_ENINTR)
+ /* enable interrupt as BIOS might not */
pci_write_config(dev, 0x71, 0x01, 1);
- if (ctlr->chip->cfg2 & SII_SETCLK) {
- if ((pci_read_config(dev, 0x8a, 1) & 0x30) != 0x10)
- pci_write_config(dev, 0x8a,
- (pci_read_config(dev, 0x8a, 1) & 0x0F) | 0x10, 1);
- if ((pci_read_config(dev, 0x8a, 1) & 0x30) != 0x10)
- device_printf(dev, "%s could not set ATA133 clock\n",
- ctlr->chip->text);
- ctlr->setmode = ata_sii_setmode;
+ ctlr->setmode = ata_cmd_setmode;
}
- else
- ctlr->setmode = ata_cmd_setmode;
+ return 0;
+}
- if ((pci_read_config(dev, 0x51, 1) & 0x08) != 0x08) {
- device_printf(dev, "secondary channel disabled\n");
- ctlr->channels = 1;
- }
+static int
+ata_sii_mio_allocate(device_t dev, struct ata_channel *ch)
+{
+ struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev));
+ int i;
+ for (i = ATA_DATA; i <= ATA_STATUS; i++) {
+ ch->r_io[i].res = ctlr->r_io2;
+ ch->r_io[i].offset = 0x80 + i + (ch->unit << 6);
+ }
+ ch->r_io[ATA_ALTSTAT].res = ctlr->r_io2;
+ ch->r_io[ATA_ALTSTAT].offset = 0x8a + (ch->unit << 6);
+ ch->r_io[ATA_BMCMD_PORT].res = ctlr->r_io2;
+ ch->r_io[ATA_BMCMD_PORT].offset = 0x00 + (ch->unit << 3);
+ ch->r_io[ATA_BMSTAT_PORT].res = ctlr->r_io2;
+ ch->r_io[ATA_BMSTAT_PORT].offset = 0x02 + (ch->unit << 3);
+ ch->r_io[ATA_BMDTP_PORT].res = ctlr->r_io2;
+ ch->r_io[ATA_BMDTP_PORT].offset = 0x04 + (ch->unit << 3);
+ ch->r_io[ATA_BMDEVSPEC_0].res = ctlr->r_io2;
+ ch->r_io[ATA_BMDEVSPEC_0].offset = 0xa1 + (ch->unit << 6);
+ ch->r_io[ATA_IDX_ADDR].res = ctlr->r_io2;
+
+ if (ctlr->chip->max_dma >= ATA_SA150)
+ ch->flags |= ATA_NO_SLAVE;
+ ctlr->dmainit(ch);
return 0;
}
static void
+ata_sii_intr(void *data)
+{
+ struct ata_pci_controller *ctlr = data;
+ struct ata_channel *ch;
+ u_int8_t dmastat;
+ int unit;
+
+ /* implement this as a toggle instead to balance load XXX */
+ for (unit = 0; unit < 2; unit++) {
+ if (!(ch = ctlr->interrupt[unit].argument))
+ continue;
+ if (ATA_IDX_INB(ch, ATA_BMDEVSPEC_0) & 0x08) {
+ if (ch->dma->flags & ATA_DMA_ACTIVE) {
+ if (!((dmastat = (ATA_IDX_INB(ch, ATA_BMSTAT_PORT) &
+ ATA_BMSTAT_MASK)) & ATA_BMSTAT_INTERRUPT))
+ continue;
+ ATA_IDX_OUTB(ch, ATA_BMSTAT_PORT, dmastat|ATA_BMSTAT_INTERRUPT);
+ DELAY(1);
+ }
+ ctlr->interrupt[unit].function(ch);
+ }
+ }
+}
+
+static void
ata_cmd_intr(void *data)
{
struct ata_pci_controller *ctlr = data;
@@ -1551,7 +1614,7 @@ ata_sii_setmode(struct ata_device *atadev, int mode)
{
device_t parent = device_get_parent(atadev->channel->dev);
struct ata_pci_controller *ctlr = device_get_softc(parent);
- int devno = (atadev->channel->unit << 4) + (ATA_DEV(atadev->unit) << 1);
+ int rego = (atadev->channel->unit << 4) + (ATA_DEV(atadev->unit) << 1);
int mreg = atadev->channel->unit ? 0x84 : 0x80;
int mask = 0x03 << (ATA_DEV(atadev->unit) << 2);
int mval = pci_read_config(parent, mreg, 1) & ~mask;
@@ -1559,7 +1622,8 @@ ata_sii_setmode(struct ata_device *atadev, int mode)
mode = ata_limit_mode(atadev, mode, ctlr->chip->max_dma);
- mode = ata_check_80pin(atadev, mode);
+ if (ctlr->chip->max_dma < ATA_SA150)
+ mode = ata_check_80pin(atadev, mode);
error = ata_command(atadev, ATA_C_SETFEATURES, 0, mode,
ATA_C_F_SETXFER, ATA_WAIT_READY);
@@ -1567,20 +1631,24 @@ ata_sii_setmode(struct ata_device *atadev, int mode)
ata_prtdev(atadev, "%s setting %s on %s chip\n",
(error) ? "failed" : "success",
ata_mode2str(mode), ctlr->chip->text);
- if (!error) {
+
+ if (error)
+ return;
+
+ if (ctlr->chip->max_dma < ATA_SA150) {
if (mode >= ATA_UDMA0) {
u_int8_t udmatimings[] = { 0xf, 0xb, 0x7, 0x5, 0x3, 0x2, 0x1 };
- u_int8_t ureg = 0xac + devno;
+ u_int8_t ureg = 0xac + rego;
pci_write_config(parent, mreg,
mval | (0x03 << (ATA_DEV(atadev->unit) << 2)), 1);
pci_write_config(parent, ureg,
- (pci_read_config(parent, ureg, 1) & 0x3f) |
+ (pci_read_config(parent, ureg, 1) & ~0x3f) |
udmatimings[mode & ATA_MODE_MASK], 1);
}
else if (mode >= ATA_WDMA0) {
- u_int8_t dreg = 0xa8 + devno;
+ u_int8_t dreg = 0xa8 + rego;
u_int16_t dmatimings[] = { 0x2208, 0x10c2, 0x10c1 };
pci_write_config(parent, mreg,
@@ -1589,15 +1657,15 @@ ata_sii_setmode(struct ata_device *atadev, int mode)
}
else {
- u_int8_t preg = 0xa4 + devno;
+ u_int8_t preg = 0xa4 + rego;
u_int16_t piotimings[] = { 0x328a, 0x2283, 0x1104, 0x10c3, 0x10c1 };
pci_write_config(parent, mreg,
mval | (0x01 << (ATA_DEV(atadev->unit) << 2)), 1);
pci_write_config(parent, preg, piotimings[mode & ATA_MODE_MASK], 2);
}
- atadev->mode = mode;
}
+ atadev->mode = mode;
}
static void
diff --git a/sys/dev/ata/ata-pci.c b/sys/dev/ata/ata-pci.c
index 2eddd9d..7027da7 100644
--- a/sys/dev/ata/ata-pci.c
+++ b/sys/dev/ata/ata-pci.c
@@ -152,18 +152,13 @@ ata_pci_attach(device_t dev)
cmd = pci_read_config(dev, PCIR_COMMAND, 2);
}
#endif
- /* is busmastering supported and configured ? */
+ /* if busmastering configured get the I/O resource */
if ((cmd & PCIM_CMD_BUSMASTEREN) == PCIM_CMD_BUSMASTEREN) {
int rid = ATA_BMADDR_RID;
- if (!ctlr->r_io2) {
- if (!(ctlr->r_io1 = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid,
- 0, ~0, 1, RF_ACTIVE)))
- device_printf(dev, "Busmastering DMA not configured\n");
- }
+ ctlr->r_io1 = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid,
+ 0, ~0, 1, RF_ACTIVE);
}
- else
- device_printf(dev, "Busmastering DMA not supported\n");
ctlr->chipinit(dev);
diff --git a/sys/dev/ata/ata-pci.h b/sys/dev/ata/ata-pci.h
index acad8e7..9cb19ca 100644
--- a/sys/dev/ata/ata-pci.h
+++ b/sys/dev/ata/ata-pci.h
@@ -154,6 +154,7 @@ struct ata_pci_controller {
#define ATA_SILICON_IMAGE_ID 0x1095
#define ATA_SII0680 0x06801095
+#define ATA_SII3112 0x31121095
#define ATA_CMD646 0x06461095
#define ATA_CMD648 0x06481095
#define ATA_CMD649 0x06491095
@@ -242,9 +243,9 @@ struct ata_pci_controller {
#define SWKS66 1
#define SWKS100 2
-#define SII_INTR 0x01
-#define SII_SETCLK 0x02
-#define SII_ENINTR 0x04
+#define SIIMEMIO 1
+#define SIIINTR 0x01
+#define SIISETCLK 0x02
#define SIS_SOUTH 1
#define SIS133NEW 2
OpenPOWER on IntegriCloud