summaryrefslogtreecommitdiffstats
path: root/sys/dev
diff options
context:
space:
mode:
authorsos <sos@FreeBSD.org>2005-12-02 10:13:53 +0000
committersos <sos@FreeBSD.org>2005-12-02 10:13:53 +0000
commit52c5335529dad823a6f9c13e176d0ee1fb630268 (patch)
tree59f21a7abd1395d6cc273e382b2f18ebfeca6e76 /sys/dev
parentc85c22d1294af9b307862f718fe4258e7bf63e0b (diff)
downloadFreeBSD-src-52c5335529dad823a6f9c13e176d0ee1fb630268.zip
FreeBSD-src-52c5335529dad823a6f9c13e176d0ee1fb630268.tar.gz
Update the ICH7 support so it deals better with chips without AHCI.
Update Intel MatrixRAID support to be able to pick up RAID0+1 (RAID10) and RAID5 arrays without panic'ing. This has the side effect of now also supporting multiple volumes on MatrixRAID's now I have the metadata better understood.. HW sponsored by: Mullet Scandinavia AB
Diffstat (limited to 'sys/dev')
-rw-r--r--sys/dev/ata/ata-chipset.c144
-rw-r--r--sys/dev/ata/ata-pci.h1
-rw-r--r--sys/dev/ata/ata-raid.c51
-rw-r--r--sys/dev/ata/ata-raid.h3
4 files changed, 115 insertions, 84 deletions
diff --git a/sys/dev/ata/ata-chipset.c b/sys/dev/ata/ata-chipset.c
index f7b2f96..3421f3c 100644
--- a/sys/dev/ata/ata-chipset.c
+++ b/sys/dev/ata/ata-chipset.c
@@ -211,7 +211,6 @@ ata_generic_setmode(device_t dev, int mode)
static void
ata_sata_setmode(device_t dev, int mode)
{
- struct ata_pci_controller *ctlr = device_get_softc(GRANDPARENT(dev));
struct ata_device *atadev = device_get_softc(dev);
/*
@@ -224,7 +223,8 @@ ata_sata_setmode(device_t dev, int mode)
atadev->param.satacapabilities != 0xffff) {
if (!ata_controlcmd(dev, ATA_SETFEATURES, ATA_SF_SETXFER, 0,
ata_limit_mode(dev, mode, ATA_UDMA6)))
- atadev->mode = ctlr->chip->max_dma;
+ /* XXX SOS we should query SATA STATUS for the speed */
+ atadev->mode = ATA_SA150;
}
else {
mode = ata_limit_mode(dev, mode, ATA_UDMA5);
@@ -1545,36 +1545,36 @@ ata_intel_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_I82371FB, 0, 0, 0x00, ATA_WDMA2, "Intel PIIX" },
- { ATA_I82371SB, 0, 0, 0x00, ATA_WDMA2, "Intel PIIX3" },
- { ATA_I82371AB, 0, 0, 0x00, ATA_UDMA2, "Intel PIIX4" },
- { ATA_I82443MX, 0, 0, 0x00, ATA_UDMA2, "Intel PIIX4" },
- { ATA_I82451NX, 0, 0, 0x00, ATA_UDMA2, "Intel PIIX4" },
- { ATA_I82801AB, 0, 0, 0x00, ATA_UDMA2, "Intel ICH0" },
- { ATA_I82801AA, 0, 0, 0x00, ATA_UDMA4, "Intel ICH" },
- { ATA_I82372FB, 0, 0, 0x00, ATA_UDMA4, "Intel ICH" },
- { ATA_I82801BA, 0, 0, 0x00, ATA_UDMA5, "Intel ICH2" },
- { ATA_I82801BA_1, 0, 0, 0x00, ATA_UDMA5, "Intel ICH2" },
- { ATA_I82801CA, 0, 0, 0x00, ATA_UDMA5, "Intel ICH3" },
- { ATA_I82801CA_1, 0, 0, 0x00, ATA_UDMA5, "Intel ICH3" },
- { ATA_I82801DB, 0, 0, 0x00, ATA_UDMA5, "Intel ICH4" },
- { ATA_I82801DB_1, 0, 0, 0x00, ATA_UDMA5, "Intel ICH4" },
- { ATA_I82801EB, 0, 0, 0x00, ATA_UDMA5, "Intel ICH5" },
- { ATA_I82801EB_S1, 0, 0, 0x00, ATA_SA150, "Intel ICH5" },
- { ATA_I82801EB_R1, 0, 0, 0x00, ATA_SA150, "Intel ICH5" },
- { ATA_I6300ESB, 0, 0, 0x00, ATA_UDMA5, "Intel 6300ESB" },
- { ATA_I6300ESB_S1, 0, 0, 0x00, ATA_SA150, "Intel 6300ESB" },
- { ATA_I6300ESB_R1, 0, 0, 0x00, ATA_SA150, "Intel 6300ESB" },
- { ATA_I82801FB, 0, 0, 0x00, ATA_UDMA5, "Intel ICH6" },
- { ATA_I82801FB_S1, 0, 0, 0x00, ATA_SA150, "Intel ICH6" },
- { ATA_I82801FB_R1, 0, 0, 0x00, ATA_SA150, "Intel ICH6" },
- { ATA_I82801FB_M, 0, 0, 0x00, ATA_SA150, "Intel ICH6" },
- { ATA_I82801GB, 0, 0, 0x00, ATA_UDMA5, "Intel ICH7" },
- { ATA_I82801GB_S1, 0, 0, 0x00, ATA_SA150, "Intel ICH7" },
- { ATA_I82801GB_R1, 0, 0, 0x00, ATA_SA150, "Intel ICH7" },
- { ATA_I82801GB_M, 0, 0, 0x00, ATA_SA150, "Intel ICH7" },
- { ATA_I82801GB_AH, 0, 0, 0x00, ATA_SA150, "Intel ICH7" },
- { ATA_I31244, 0, 0, 0x00, ATA_SA150, "Intel 31244" },
+ {{ ATA_I82371FB, 0, 0, 0x00, ATA_WDMA2, "Intel PIIX" },
+ { ATA_I82371SB, 0, 0, 0x00, ATA_WDMA2, "Intel PIIX3" },
+ { ATA_I82371AB, 0, 0, 0x00, ATA_UDMA2, "Intel PIIX4" },
+ { ATA_I82443MX, 0, 0, 0x00, ATA_UDMA2, "Intel PIIX4" },
+ { ATA_I82451NX, 0, 0, 0x00, ATA_UDMA2, "Intel PIIX4" },
+ { ATA_I82801AB, 0, 0, 0x00, ATA_UDMA2, "Intel ICH0" },
+ { ATA_I82801AA, 0, 0, 0x00, ATA_UDMA4, "Intel ICH" },
+ { ATA_I82372FB, 0, 0, 0x00, ATA_UDMA4, "Intel ICH" },
+ { ATA_I82801BA, 0, 0, 0x00, ATA_UDMA5, "Intel ICH2" },
+ { ATA_I82801BA_1, 0, 0, 0x00, ATA_UDMA5, "Intel ICH2" },
+ { ATA_I82801CA, 0, 0, 0x00, ATA_UDMA5, "Intel ICH3" },
+ { ATA_I82801CA_1, 0, 0, 0x00, ATA_UDMA5, "Intel ICH3" },
+ { ATA_I82801DB, 0, 0, 0x00, ATA_UDMA5, "Intel ICH4" },
+ { ATA_I82801DB_1, 0, 0, 0x00, ATA_UDMA5, "Intel ICH4" },
+ { ATA_I82801EB, 0, 0, 0x00, ATA_UDMA5, "Intel ICH5" },
+ { ATA_I82801EB_S1, 0, 0, 0x00, ATA_SA150, "Intel ICH5" },
+ { ATA_I82801EB_R1, 0, 0, 0x00, ATA_SA150, "Intel ICH5" },
+ { ATA_I6300ESB, 0, 0, 0x00, ATA_UDMA5, "Intel 6300ESB" },
+ { ATA_I6300ESB_S1, 0, 0, 0x00, ATA_SA150, "Intel 6300ESB" },
+ { ATA_I6300ESB_R1, 0, 0, 0x00, ATA_SA150, "Intel 6300ESB" },
+ { ATA_I82801FB, 0, 0, 0x00, ATA_UDMA5, "Intel ICH6" },
+ { ATA_I82801FB_S1, 0, AHCI, 0x00, ATA_SA150, "Intel ICH6" },
+ { ATA_I82801FB_R1, 0, AHCI, 0x00, ATA_SA150, "Intel ICH6" },
+ { ATA_I82801FB_M, 0, AHCI, 0x00, ATA_SA150, "Intel ICH6" },
+ { ATA_I82801GB, 0, 0, 0x00, ATA_UDMA5, "Intel ICH7" },
+ { ATA_I82801GB_S1, 0, AHCI, 0x00, ATA_SA300, "Intel ICH7" },
+ { ATA_I82801GB_R1, 0, AHCI, 0x00, ATA_SA300, "Intel ICH7" },
+ { ATA_I82801GB_M, 0, AHCI, 0x00, ATA_SA300, "Intel ICH7" },
+ { ATA_I82801GB_AH, 0, AHCI, 0x00, ATA_SA300, "Intel ICH7" },
+ { ATA_I31244, 0, 0, 0x00, ATA_SA150, "Intel 31244" },
{ 0, 0, 0, 0, 0, 0}};
char buffer[64];
@@ -1642,40 +1642,54 @@ ata_intel_chipinit(device_t dev)
/* SATA parts can be either compat or AHCI */
else {
- /* if we have BAR(5) as a memory resource we should use AHCI mode */
- ctlr->r_type2 = SYS_RES_MEMORY;
- ctlr->r_rid2 = PCIR_BAR(5);
- if ((ctlr->r_res2 = bus_alloc_resource_any(dev, ctlr->r_type2,
- &ctlr->r_rid2, RF_ACTIVE))) {
- if (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;
- }
+ /* force all ports active "the legacy way" */
+ pci_write_config(dev, 0x92, pci_read_config(dev, 0x92, 2) | 0x0f,2);
- /* force all ports active "the legacy way" */
- pci_write_config(dev, 0x92, pci_read_config(dev, 0x92, 2) | 0x0f,2);
+ ctlr->reset = ata_intel_reset;
- /* enable AHCI mode */
- ATA_OUTL(ctlr->r_res2, ATA_AHCI_GHC, ATA_AHCI_GHC_AE);
+ /* if we have AHCI capability and BAR(5) as a memory resource */
+ if (ctlr->chip->cfg1 == AHCI) {
+ ctlr->r_type2 = SYS_RES_MEMORY;
+ ctlr->r_rid2 = PCIR_BAR(5);
+ if ((ctlr->r_res2 = bus_alloc_resource_any(dev, ctlr->r_type2,
+ &ctlr->r_rid2,
+ RF_ACTIVE))) {
+ /* 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;
+ }
- /* get the number of HW channels */
- ctlr->channels = (ATA_INL(ctlr->r_res2, ATA_AHCI_CAP) &
- ATA_AHCI_NPMASK) + 1;
+ /* enable AHCI mode */
+ ATA_OUTL(ctlr->r_res2, ATA_AHCI_GHC, ATA_AHCI_GHC_AE);
- /* enable AHCI interrupts */
- ATA_OUTL(ctlr->r_res2, ATA_AHCI_GHC,
- ATA_INL(ctlr->r_res2, ATA_AHCI_GHC) | ATA_AHCI_GHC_IE);
+ /* get the number of HW channels */
+ ctlr->channels = (ATA_INL(ctlr->r_res2, ATA_AHCI_CAP) &
+ ATA_AHCI_NPMASK) + 1;
- ctlr->reset = ata_ahci_reset;
- ctlr->dmainit = ata_ahci_dmainit;
- ctlr->allocate = ata_ahci_allocate;
- }
- else {
- ctlr->reset = ata_intel_reset;
+ /* enable AHCI interrupts */
+ ATA_OUTL(ctlr->r_res2, ATA_AHCI_GHC,
+ ATA_INL(ctlr->r_res2, ATA_AHCI_GHC) |
+ ATA_AHCI_GHC_IE);
+ ctlr->reset = ata_ahci_reset;
+ ctlr->dmainit = ata_ahci_dmainit;
+ ctlr->allocate = ata_ahci_allocate;
+ }
+#if 0
+ else {
+ /* enable SATA registers in compat mode */
+ pci_write_config(dev, 0x94,
+ pci_read_config(dev, 0x94, 4) | 1 << 9, 4);
+ }
+#endif
+ }
}
ctlr->setmode = ata_sata_setmode;
+
+ /* enable PCI interrupt */
pci_write_config(dev, PCIR_COMMAND,
pci_read_config(dev, PCIR_COMMAND, 2) & ~0x0400, 2);
}
@@ -1845,10 +1859,8 @@ ata_intel_reset(device_t dev)
struct ata_channel *ch = device_get_softc(dev);
int mask, timeout;
- /* ICH6 has 4 SATA ports as master/slave on 2 channels so deal with pairs */
- if (ctlr->chip->chipid == ATA_I82801FB_S1 ||
- ctlr->chip->chipid == ATA_I82801FB_R1 ||
- ctlr->chip->chipid == ATA_I82801FB_M) {
+ /* ICH6 & ICH7 in compat mode has 4 SATA ports as master/slave on 2 ch's */
+ if (ctlr->chip->cfg1) {
mask = (0x0005 << ch->unit);
}
else {
@@ -1857,7 +1869,7 @@ ata_intel_reset(device_t dev)
mask = 0x0003;
else {
mask = (0x0001 << ch->unit);
- /* XXX SOS should be in intel_allocate when we grow it */
+ /* XXX SOS should be in intel_allocate if we grow it */
ch->flags |= ATA_NO_SLAVE;
}
}
@@ -2177,8 +2189,8 @@ ata_nvidia_ident(device_t dev)
{ ATA_NFORCE3_MCP_S1, 0, 0, NV4OFF, ATA_SA150, "nVidia nForce3 MCP" },
{ ATA_NFORCE3_MCP_S2, 0, 0, NV4OFF, ATA_SA150, "nVidia nForce3 MCP" },
{ ATA_NFORCE4, 0, AMDNVIDIA, NVIDIA, ATA_UDMA6, "nVidia nForce4" },
- { ATA_NFORCE4_S1, 0, 0, NV4OFF, ATA_SA150, "nVidia nForce4" },
- { ATA_NFORCE4_S2, 0, 0, NV4OFF, ATA_SA150, "nVidia nForce4" },
+ { ATA_NFORCE4_S1, 0, 0, NV4OFF, ATA_SA300, "nVidia nForce4" },
+ { ATA_NFORCE4_S2, 0, 0, NV4OFF, ATA_SA300, "nVidia nForce4" },
{ 0, 0, 0, 0, 0, 0}};
char buffer[64];
diff --git a/sys/dev/ata/ata-pci.h b/sys/dev/ata/ata-pci.h
index b09afcb..dc55768 100644
--- a/sys/dev/ata/ata-pci.h
+++ b/sys/dev/ata/ata-pci.h
@@ -307,6 +307,7 @@ struct ata_connect_task {
#define ATA_VIA6421 0x32491106
/* chipset setup related defines */
+#define AHCI 1
#define ATPOLD 1
#define ALIOLD 0x01
diff --git a/sys/dev/ata/ata-raid.c b/sys/dev/ata/ata-raid.c
index e9d2f22..ad26923 100644
--- a/sys/dev/ata/ata-raid.c
+++ b/sys/dev/ata/ata-raid.c
@@ -1830,20 +1830,25 @@ ata_raid_intel_read_meta(device_t dev, struct ar_softc **raidp)
struct ata_raid_subdisk *ars = device_get_softc(dev);
device_t parent = device_get_parent(dev);
struct intel_raid_conf *meta;
+ struct intel_raid_mapping *map;
struct ar_softc *raid = NULL;
u_int32_t checksum, *ptr;
- int array, count, disk, retval = 0;
+ int array, count, disk, volume = 1, retval = 0;
+ char *tmp;
if (!(meta = (struct intel_raid_conf *)
- malloc(1024, M_AR, M_NOWAIT | M_ZERO)))
+ malloc(1536, M_AR, M_NOWAIT | M_ZERO)))
return ENOMEM;
- if (ata_raid_rw(parent, INTEL_LBA(parent),
- meta, 1024, ATA_R_READ)) {
+ if (ata_raid_rw(parent, INTEL_LBA(parent), meta, 1024, ATA_R_READ)) {
if (testing || bootverbose)
device_printf(parent, "Intel read metadata failed\n");
goto intel_out;
}
+ tmp = (char *)meta;
+ bcopy(tmp, tmp+1024, 512);
+ bcopy(tmp+512, tmp, 1024);
+ bzero(tmp+1024, 512);
/* check if this is a Intel RAID struct */
if (strncmp(meta->intel_id, INTEL_MAGIC, strlen(INTEL_MAGIC))) {
@@ -1851,23 +1856,23 @@ ata_raid_intel_read_meta(device_t dev, struct ar_softc **raidp)
device_printf(parent, "Intel check1 failed\n");
goto intel_out;
}
+
for (checksum = 0, ptr = (u_int32_t *)meta, count = 0;
count < (meta->config_size / sizeof(u_int32_t)); count++) {
checksum += *ptr++;
}
-
-/* XXX SOS needs to be fixed */
-device_printf(parent, "Intel calc=%08x meta=%08x\n", checksum, meta->checksum);
-
+ checksum -= meta->checksum;
if (checksum != meta->checksum) {
if (testing || bootverbose)
device_printf(parent, "Intel check2 failed\n");
- //goto intel_out;
+ goto intel_out;
}
if (testing || bootverbose)
ata_raid_intel_print_meta(meta);
+ map = (struct intel_raid_mapping *)&meta->disk[meta->total_disks];
+
/* now convert Intel metadata into our generic form */
for (array = 0; array < MAX_ARRAYS; array++) {
if (!raidp[array]) {
@@ -1889,13 +1894,9 @@ device_printf(parent, "Intel calc=%08x meta=%08x\n", checksum, meta->checksum);
/*
* update our knowledge about the array config based on generation
- * we only grap the first volume description (yet) since the
- * BIOS'n I have access to puts crap into the following ones
+ * NOTE: there can be multiple volumes on a disk set
*/
if (!meta->generation || meta->generation > raid->generation) {
- struct intel_raid_mapping *map =
- (struct intel_raid_mapping *)&meta->disk[meta->total_disks];
-
switch (map->type) {
case INTEL_T_RAID0:
raid->type = AR_T_RAID0;
@@ -1903,10 +1904,18 @@ device_printf(parent, "Intel calc=%08x meta=%08x\n", checksum, meta->checksum);
break;
case INTEL_T_RAID1:
- raid->type = AR_T_RAID1;
+ if (map->total_disks == 4)
+ raid->type = AR_T_RAID01;
+ else
+ raid->type = AR_T_RAID1;
raid->width = map->total_disks / 2;
break;
+ case INTEL_T_RAID5:
+ raid->type = AR_T_RAID5;
+ raid->width = map->total_disks;
+ break;
+
default:
device_printf(parent, "Intel unknown RAID type 0x%02x\n",
map->type);
@@ -1976,8 +1985,15 @@ device_printf(parent, "Intel calc=%08x meta=%08x\n", checksum, meta->checksum);
}
}
}
- if (retval)
+ if (retval) {
+ if (volume < meta->total_volumes) {
+ map = (struct intel_raid_mapping *)
+ &map->disk_idx[map->total_disks];
+ volume++;
+ continue;
+ }
break;
+ }
}
intel_out:
@@ -3724,6 +3740,7 @@ ata_raid_intel_type(int type)
switch (type) {
case INTEL_T_RAID0: return "RAID0";
case INTEL_T_RAID1: return "RAID1";
+ case INTEL_T_RAID5: return "RAID5";
default: sprintf(buffer, "UNKNOWN 0x%02x", type);
return buffer;
}
@@ -3767,7 +3784,7 @@ ata_raid_intel_print_meta(struct intel_raid_conf *meta)
for (i = 0; i < map->total_disks; i++ ) {
printf(" disk %d at disk_idx 0x%08x\n", i, map->disk_idx[i]);
}
- map = (struct intel_raid_mapping *)&map->disk_idx[i];
+ map = (struct intel_raid_mapping *)&map->disk_idx[map->total_disks];
}
printf("=================================================\n");
}
diff --git a/sys/dev/ata/ata-raid.h b/sys/dev/ata/ata-raid.h
index 8c0bb7f..55ecbf5 100644
--- a/sys/dev/ata/ata-raid.h
+++ b/sys/dev/ata/ata-raid.h
@@ -281,7 +281,7 @@ struct hptv3_raid_conf {
/* Intel MatrixRAID Metadata */
#define INTEL_LBA(dev) \
- (((struct ad_softc *)device_get_ivars(dev))->total_secs - 2)
+ (((struct ad_softc *)device_get_ivars(dev))->total_secs - 3)
struct intel_raid_conf {
u_int8_t intel_id[24];
@@ -332,6 +332,7 @@ struct intel_raid_mapping {
u_int8_t type;
#define INTEL_T_RAID0 0x00
#define INTEL_T_RAID1 0x01
+#define INTEL_T_RAID5 0x05
u_int8_t total_disks;
u_int8_t dummy_2[3];
OpenPOWER on IntegriCloud