From ddaf7697090a37929abc368d5cb46fb866df787f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=B8ren=20Schmidt?= Date: Fri, 2 Dec 2005 10:13:53 +0000 Subject: [PATCH] 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 --- sys/dev/ata/ata-chipset.c | 152 ++++++++++++++++++++------------------ sys/dev/ata/ata-pci.h | 1 + sys/dev/ata/ata-raid.c | 51 ++++++++----- sys/dev/ata/ata-raid.h | 3 +- 4 files changed, 119 insertions(+), 88 deletions(-) diff --git a/sys/dev/ata/ata-chipset.c b/sys/dev/ata/ata-chipset.c index f7b2f962115a..3421f3c7b098 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); + + ctlr->reset = ata_intel_reset; + + /* 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; + } + + /* enable AHCI mode */ + ATA_OUTL(ctlr->r_res2, ATA_AHCI_GHC, ATA_AHCI_GHC_AE); + + /* get the number of HW channels */ + ctlr->channels = (ATA_INL(ctlr->r_res2, ATA_AHCI_CAP) & + ATA_AHCI_NPMASK) + 1; + + /* 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 } - - /* force all ports active "the legacy way" */ - pci_write_config(dev, 0x92, pci_read_config(dev, 0x92, 2) | 0x0f,2); - - /* enable AHCI mode */ - ATA_OUTL(ctlr->r_res2, ATA_AHCI_GHC, ATA_AHCI_GHC_AE); - - /* get the number of HW channels */ - ctlr->channels = (ATA_INL(ctlr->r_res2, ATA_AHCI_CAP) & - ATA_AHCI_NPMASK) + 1; - - /* 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; - } - else { - ctlr->reset = ata_intel_reset; } 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 b09afcbcd899..dc557688d495 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 e9d2f22080a5..ad269238b33e 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 8c0bb7f1005d..55ecbf5f8bf3 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];