Add support for the JMicron JMB363 dual SATA + single PATA controller.
	Add r/w support for JMicron ATA RAID metadata.
	Add a reset of the AHCI machinery to the ICH6/ICH7 support.
	Unbreak Promise SATAII/150 controllers caused by the DMA dump changes.
	Unbreak DMA dump on Intel 31224.

Approved by:	re@ (scottl)
This commit is contained in:
sos 2006-02-19 15:18:23 +00:00
parent cc52cf5ad6
commit a3ddb94db9
7 changed files with 541 additions and 118 deletions

View File

@ -542,8 +542,8 @@ ata_boot_attach(void)
/* release the hook that got us here, we are only needed once during boot */
if (ata_delayed_attach) {
config_intrhook_disestablish(ata_delayed_attach);
ata_delayed_attach = NULL;
free(ata_delayed_attach, M_TEMP);
ata_delayed_attach = NULL;
}
mtx_unlock(&Giant); /* newbus suckage dealt with, release Giant */

View File

@ -413,7 +413,6 @@ struct ata_device {
struct ata_params param; /* ata param structure */
int mode; /* current transfermode */
u_int32_t max_iosize; /* max IO size */
int cmd; /* last cmd executed */
int flags;
#define ATA_D_USE_CHS 0x0001
#define ATA_D_MEDIA_CHANGED 0x0002

View File

@ -100,6 +100,10 @@ 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_jmicron_chipinit(device_t dev);
static int ata_jmicron_allocate(device_t dev);
static void ata_jmicron_reset(device_t dev);
static void ata_jmicron_dmainit(device_t dev);
static void ata_jmicron_setmode(device_t dev, int mode);
static int ata_marvell_chipinit(device_t dev);
static int ata_marvell_allocate(device_t dev);
static int ata_marvell_status(device_t dev);
@ -1658,6 +1662,18 @@ ata_intel_chipinit(device_t dev)
RF_ACTIVE))) {
/* is AHCI or RAID mode enabled in BIOS ? */
if (pci_read_config(dev, 0x90, 1) & 0xc0) {
/* reset AHCI controller */
ATA_OUTL(ctlr->r_res2, ATA_AHCI_GHC,
ATA_INL(ctlr->r_res2, ATA_AHCI_GHC) | ATA_AHCI_GHC_HR);
DELAY(1000000);
if (ATA_INL(ctlr->r_res2, ATA_AHCI_GHC) & ATA_AHCI_GHC_HR) {
bus_release_resource(dev, ctlr->r_type2,
ctlr->r_rid2, ctlr->r_res2);
device_printf(dev, "AHCI controller reset failure\n");
return ENXIO;
}
/* enable AHCI mode */
ATA_OUTL(ctlr->r_res2, ATA_AHCI_GHC, ATA_AHCI_GHC_AE);
@ -1897,7 +1913,7 @@ ata_intel_31244_status(device_t dev)
}
/* any drive action to take care of ? */
return 1;
return ata_pci_status(dev);
}
static int
@ -2053,6 +2069,7 @@ ata_jmicron_ident(device_t dev)
struct ata_chip_id *idx;
static struct ata_chip_id ids[] =
{{ ATA_JMB360, 0, 0, 0, ATA_SA300, "JMB360" },
{ ATA_JMB363, 0, 1, 0, ATA_SA300, "JMB363" },
{ 0, 0, 0, 0, 0, 0}};
char buffer[64];
@ -2075,51 +2092,112 @@ ata_jmicron_chipinit(device_t dev)
if (ata_setup_interrupt(dev))
return ENXIO;
/* set controller configuration to a setup we support */
pci_write_config(dev, 0x40, 0x80c0a131, 4);
ctlr->allocate = ata_jmicron_allocate;
ctlr->reset = ata_jmicron_reset;
ctlr->dmainit = ata_jmicron_dmainit;
ctlr->setmode = ata_jmicron_setmode;
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)))
return ENXIO;
if ((ctlr->r_res2 = bus_alloc_resource_any(dev, ctlr->r_type2,
&ctlr->r_rid2, RF_ACTIVE))) {
/* reset AHCI controller */
ATA_OUTL(ctlr->r_res2, ATA_AHCI_GHC,
ATA_INL(ctlr->r_res2, ATA_AHCI_GHC) | ATA_AHCI_GHC_HR);
DELAY(1000000);
if (ATA_INL(ctlr->r_res2, ATA_AHCI_GHC) & ATA_AHCI_GHC_HR) {
bus_release_resource(dev, ctlr->r_type2, ctlr->r_rid2,ctlr->r_res2);
device_printf(dev, "AHCI controller reset failure\n");
return ENXIO;
}
/* enable AHCI mode */
ATA_OUTL(ctlr->r_res2, ATA_AHCI_GHC,
ATA_INL(ctlr->r_res2, ATA_AHCI_GHC) | ATA_AHCI_GHC_AE);
/* enable AHCI mode */
pci_write_config(dev, 0x41, 0xa1, 1);
/* get the number of HW channels */
ctlr->channels =
(ATA_INL(ctlr->r_res2, ATA_AHCI_CAP) & ATA_AHCI_NPMASK) + 1;
/* reset AHCI controller */
ATA_OUTL(ctlr->r_res2, ATA_AHCI_GHC,
ATA_INL(ctlr->r_res2, ATA_AHCI_GHC) | ATA_AHCI_GHC_HR);
DELAY(1000000);
if (ATA_INL(ctlr->r_res2, ATA_AHCI_GHC) & ATA_AHCI_GHC_HR) {
bus_release_resource(dev, ctlr->r_type2, ctlr->r_rid2, ctlr->r_res2);
device_printf(dev, "AHCI controller reset failure\n");
return ENXIO;
/* clear interrupts */
ATA_OUTL(ctlr->r_res2, ATA_AHCI_IS, ATA_INL(ctlr->r_res2, ATA_AHCI_IS));
/* enable AHCI interrupts */
ATA_OUTL(ctlr->r_res2, ATA_AHCI_GHC,
ATA_INL(ctlr->r_res2, ATA_AHCI_GHC) | ATA_AHCI_GHC_IE);
/* enable PCI interrupt */
pci_write_config(dev, PCIR_COMMAND,
pci_read_config(dev, PCIR_COMMAND, 2) & ~0x0400, 2);
}
/* enable AHCI mode */
ATA_OUTL(ctlr->r_res2, ATA_AHCI_GHC,
ATA_INL(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;
ctlr->allocate = ata_ahci_allocate;
ctlr->reset = ata_ahci_reset;
ctlr->dmainit = ata_ahci_dmainit;
ctlr->setmode = ata_sata_setmode;
/* clear interrupts */
ATA_OUTL(ctlr->r_res2, ATA_AHCI_IS, ATA_INL(ctlr->r_res2, ATA_AHCI_IS));
/* enable AHCI interrupts */
ATA_OUTL(ctlr->r_res2, ATA_AHCI_GHC,
ATA_INL(ctlr->r_res2, ATA_AHCI_GHC) | ATA_AHCI_GHC_IE);
/* enable PCI interrupt */
pci_write_config(dev, PCIR_COMMAND,
pci_read_config(dev, PCIR_COMMAND, 2) & ~0x0400, 2);
/* add in PATA channel(s) */
ctlr->channels += ctlr->chip->cfg1;
return 0;
}
static int
ata_jmicron_allocate(device_t dev)
{
struct ata_channel *ch = device_get_softc(dev);
int error;
if (ch->unit >= 2) {
ch->unit -= 2;
error = ata_pci_allocate(dev);
ch->unit += 2;
}
else
error = ata_ahci_allocate(dev);
return error;
}
static void
ata_jmicron_reset(device_t dev)
{
struct ata_channel *ch = device_get_softc(dev);
if (ch->unit >= 2)
ata_generic_reset(dev);
else
ata_ahci_reset(dev);
}
static void
ata_jmicron_dmainit(device_t dev)
{
struct ata_channel *ch = device_get_softc(dev);
if (ch->unit >= 2)
ata_pci_dmainit(dev);
else
ata_ahci_dmainit(dev);
}
static void
ata_jmicron_setmode(device_t dev, int mode)
{
struct ata_channel *ch = device_get_softc(device_get_parent(dev));
if (ch->unit >= 2) {
struct ata_device *atadev = device_get_softc(dev);
/* check for 80pin cable present */
if (pci_read_config(dev, 0x40, 1) & 0x08)
mode = ata_limit_mode(dev, mode, ATA_UDMA2);
else
mode = ata_limit_mode(dev, mode, ATA_UDMA6);
if (!ata_controlcmd(dev, ATA_SETFEATURES, ATA_SF_SETXFER, 0, mode))
atadev->mode = mode;
}
else
ata_sata_setmode(dev, mode);
}
/*
* Marvell chipset support functions
@ -2861,10 +2939,10 @@ ata_promise_ident(device_t dev)
{ ATA_PDC20377, 0, PRMIO, PRCMBO, ATA_SA150, "PDC20377" },
{ ATA_PDC20378, 0, PRMIO, PRCMBO, ATA_SA150, "PDC20378" },
{ ATA_PDC20379, 0, PRMIO, PRCMBO, ATA_SA150, "PDC20379" },
{ ATA_PDC20571, 0, PRMIO, PRSATA2, ATA_SA150, "PDC20571" },
{ ATA_PDC20571, 0, PRMIO, PRCMBO2, ATA_SA150, "PDC20571" },
{ ATA_PDC20575, 0, PRMIO, PRCMBO2, ATA_SA150, "PDC20575" },
{ ATA_PDC20579, 0, PRMIO, PRCMBO2, ATA_SA150, "PDC20579" },
{ ATA_PDC20771, 0, PRMIO, PRSATA2, ATA_SA300, "PDC20771" },
{ ATA_PDC20771, 0, PRMIO, PRCMBO2, ATA_SA300, "PDC20771" },
{ ATA_PDC40775, 0, PRMIO, PRCMBO2, ATA_SA300, "PDC40775" },
{ ATA_PDC20617, 0, PRMIO, PRPATA, ATA_UDMA6, "PDC20617" },
{ ATA_PDC20618, 0, PRMIO, PRPATA, ATA_UDMA6, "PDC20618" },
@ -2925,6 +3003,7 @@ static int
ata_promise_chipinit(device_t dev)
{
struct ata_pci_controller *ctlr = device_get_softc(dev);
int fake_reg, stat_reg;
if (ata_setup_interrupt(dev))
return ENXIO;
@ -2962,8 +3041,7 @@ ata_promise_chipinit(device_t dev)
&ctlr->r_rid2, RF_ACTIVE)))
goto failnfree;
switch (ctlr->chip->cfg2) {
case PRSX4X: {
if (ctlr->chip->cfg2 == PRSX4X) {
struct ata_promise_sx4 *hpkt;
u_int32_t dimm = ATA_INL(ctlr->r_res2, 0x000c0080);
@ -2998,58 +3076,55 @@ ata_promise_chipinit(device_t dev)
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) ||
}
/* mio type controllers need an interrupt intercept */
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);
}
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;
goto sata150;
case PRCMBO:
ctlr->channels = 3;
goto sata150;
case PRSATA:
ctlr->channels = 4;
sata150:
fake_reg = 0x60;
stat_reg = 0x6c;
break;
case PRCMBO2:
ctlr->channels = 3;
goto sataii;
case PRSATA2:
default:
ctlr->channels = 4;
sataii:
fake_reg = 0x54;
stat_reg = 0x60;
break;
}
/* prime fake interrupt register */
ATA_OUTL(ctlr->r_res2, fake_reg, 0xffffffff);
/* clear SATA status */
ATA_OUTL(ctlr->r_res2, stat_reg, 0x000000ff);
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;
return 0;
case PRCMBO:
ATA_OUTL(ctlr->r_res2, 0x06c, 0x000000ff);
ctlr->channels = ((ATA_INL(ctlr->r_res2, 0x48) & 0x02) > 0) + 3;
return 0;
case PRSATA:
ATA_OUTL(ctlr->r_res2, 0x06c, 0x000000ff);
ctlr->channels = 4;
return 0;
case PRCMBO2:
ATA_OUTL(ctlr->r_res2, 0x060, 0x000000ff);
ctlr->channels = 3;
return 0;
case PRSATA2:
ATA_OUTL(ctlr->r_res2, 0x060, 0x000000ff);
ctlr->channels = 4;
return 0;
}
return 0;
}
failnfree:
@ -3297,7 +3372,21 @@ ata_promise_mio_intr(void *data)
{
struct ata_pci_controller *ctlr = data;
struct ata_channel *ch;
int unit;
u_int32_t vector;
int unit, fake_reg;
switch (ctlr->chip->cfg2) {
case PRPATA:
case PRCMBO:
case PRSATA:
fake_reg = 0x60;
break;
case PRCMBO2:
case PRSATA2:
default:
fake_reg = 0x54;
break;
}
/*
* since reading interrupt status register on early "mio" chips
@ -3306,13 +3395,16 @@ ata_promise_mio_intr(void *data)
* 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));
vector = ATA_INL(ctlr->r_res2, 0x040);
ATA_OUTL(ctlr->r_res2, 0x040, vector);
ATA_OUTL(ctlr->r_res2, fake_reg, vector);
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);
ATA_OUTL(ctlr->r_res2, fake_reg, 0xffffffff);
}
static int
@ -3321,37 +3413,30 @@ 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;
u_int32_t fake_reg, stat_reg, vector, status;
switch (ctlr->chip->cfg2) {
case PRPATA:
case PRSATA:
case PRCMBO:
/* read and acknowledge interrupt */
vector = ATA_INL(ctlr->r_res2, 0x0060);
/* read and clear interface status */
status = ATA_INL(ctlr->r_res2, 0x006c);
ATA_OUTL(ctlr->r_res2, 0x006c, status & (0x00000011 << ch->unit));
case PRSATA:
fake_reg = 0x60;
stat_reg = 0x6c;
break;
case PRCMBO2:
case PRSATA2:
case PRCMBO2:
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, 0x0060);
ATA_OUTL(ctlr->r_res2, 0x0060, status & (0x00000011 << ch->unit));
critical_exit();
break;
default:
return 0;
fake_reg = 0x54;
stat_reg = 0x60;
break;
}
/* read and acknowledge interrupt */
vector = ATA_INL(ctlr->r_res2, fake_reg);
/* read and clear interface status */
status = ATA_INL(ctlr->r_res2, stat_reg);
ATA_OUTL(ctlr->r_res2, stat_reg, status & (0x00000011 << ch->unit));
/* check for and handle disconnect events */
if ((status & (0x00000001 << ch->unit)) &&
(tp = (struct ata_connect_task *)

View File

@ -34,6 +34,7 @@ __FBSDID("$FreeBSD$");
#include <sys/module.h>
#include <sys/ata.h>
#include <sys/bus.h>
#include <sys/conf.h>
#include <sys/malloc.h>
#include <sys/sema.h>
#include <sys/taskqueue.h>
@ -58,9 +59,6 @@ static MALLOC_DEFINE(M_ATAPCI, "ata_pci", "ATA driver PCI");
#define IOMASK 0xfffffffc
#define ATA_PROBE_OK -10
/* prototypes */
static void ata_pci_dmainit(device_t);
int
ata_legacy(device_t dev)
{
@ -443,7 +441,7 @@ ata_pci_status(device_t dev)
{
struct ata_channel *ch = device_get_softc(dev);
if (!ata_legacy(device_get_parent(dev)) &&
if ((dumping || !ata_legacy(device_get_parent(dev))) &&
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;
@ -504,7 +502,7 @@ ata_pci_dmareset(device_t dev)
ch->dma->unload(dev);
}
static void
void
ata_pci_dmainit(device_t dev)
{
struct ata_channel *ch = device_get_softc(dev);

View File

@ -161,6 +161,7 @@ struct ata_connect_task {
#define ATA_JMICRON_ID 0x197b
#define ATA_JMB360 0x2360197b
#define ATA_JMB363 0x2363197b
#define ATA_MARVELL_ID 0x11ab
#define ATA_M88SX5040 0x504011ab
@ -401,6 +402,7 @@ int ata_pci_setup_intr(device_t dev, device_t child, struct resource *irq, int f
int ata_pci_allocate(device_t dev);
void ata_pci_hw(device_t dev);
int ata_pci_status(device_t dev);
void ata_pci_dmainit(device_t);
/* global prototypes ata-chipset.c */

View File

@ -71,6 +71,8 @@ static int ata_raid_hptv3_read_meta(device_t dev, struct ar_softc **raidp);
static int ata_raid_intel_read_meta(device_t dev, struct ar_softc **raidp);
static int ata_raid_intel_write_meta(struct ar_softc *rdp);
static int ata_raid_ite_read_meta(device_t dev, struct ar_softc **raidp);
static int ata_raid_jmicron_read_meta(device_t dev, struct ar_softc **raidp);
static int ata_raid_jmicron_write_meta(struct ar_softc *rdp);
static int ata_raid_lsiv2_read_meta(device_t dev, struct ar_softc **raidp);
static int ata_raid_lsiv3_read_meta(device_t dev, struct ar_softc **raidp);
static int ata_raid_nvidia_read_meta(device_t dev, struct ar_softc **raidp);
@ -95,6 +97,7 @@ static void ata_raid_hptv2_print_meta(struct hptv2_raid_conf *meta);
static void ata_raid_hptv3_print_meta(struct hptv3_raid_conf *meta);
static void ata_raid_intel_print_meta(struct intel_raid_conf *meta);
static void ata_raid_ite_print_meta(struct ite_raid_conf *meta);
static void ata_raid_jmicron_print_meta(struct jmicron_raid_conf *meta);
static void ata_raid_lsiv2_print_meta(struct lsiv2_raid_conf *meta);
static void ata_raid_lsiv3_print_meta(struct lsiv3_raid_conf *meta);
static void ata_raid_nvidia_print_meta(struct nvidia_raid_conf *meta);
@ -937,6 +940,11 @@ ata_raid_create(struct ata_ioc_raid_config *config)
rdp->disks[disk].sectors = ITE_LBA(rdp->disks[disk].dev);
break;
case ATA_JMICRON_ID:
ctlr = AR_F_JMICRON_RAID;
rdp->disks[disk].sectors = JMICRON_LBA(rdp->disks[disk].dev);
break;
case 0: /* XXX SOS cover up for bug in our PCI code */
case ATA_PROMISE_ID:
ctlr = AR_F_PROMISE_RAID;
@ -1072,6 +1080,10 @@ ata_raid_create(struct ata_ioc_raid_config *config)
rdp->interleave = min(max(2, rdp->interleave), 128); /*+*/
break;
case AR_F_JMICRON_RAID:
rdp->interleave = min(max(8, rdp->interleave), 256); /*+*/
break;
case AR_F_LSIV2_RAID:
rdp->interleave = min(max(2, rdp->interleave), 4096);
break;
@ -1274,6 +1286,11 @@ ata_raid_read_metadata(device_t subdisk)
return 0;
break;
case ATA_JMICRON_ID:
if (ata_raid_jmicron_read_meta(subdisk, ata_raid_arrays))
return 0;
break;
case ATA_NVIDIA_ID:
if (ata_raid_nvidia_read_meta(subdisk, ata_raid_arrays))
return 0;
@ -1339,6 +1356,9 @@ ata_raid_write_metadata(struct ar_softc *rdp)
case AR_F_INTEL_RAID:
return ata_raid_intel_write_meta(rdp);
case AR_F_JMICRON_RAID:
return ata_raid_jmicron_write_meta(rdp);
case AR_F_SIS_RAID:
return ata_raid_sis_write_meta(rdp);
@ -1410,6 +1430,11 @@ ata_raid_wipe_metadata(struct ar_softc *rdp)
size = sizeof(struct ite_raid_conf);
break;
case AR_F_JMICRON_RAID:
lba = JMICRON_LBA(rdp->disks[disk].dev);
size = sizeof(struct jmicron_raid_conf);
break;
case AR_F_LSIV2_RAID:
lba = LSIV2_LBA(rdp->disks[disk].dev);
size = sizeof(struct lsiv2_raid_conf);
@ -2392,6 +2417,231 @@ ite_out:
return retval;
}
/* JMicron Technology Corp Metadata */
static int
ata_raid_jmicron_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 jmicron_raid_conf *meta;
struct ar_softc *raid = NULL;
u_int16_t checksum, *ptr;
u_int64_t disk_size;
int count, array, disk, total_disks, retval = 0;
if (!(meta = (struct jmicron_raid_conf *)
malloc(sizeof(struct jmicron_raid_conf), M_AR, M_NOWAIT | M_ZERO)))
return ENOMEM;
if (ata_raid_rw(parent, JMICRON_LBA(parent),
meta, sizeof(struct jmicron_raid_conf), ATA_R_READ)) {
if (testing || bootverbose)
device_printf(parent,
"JMicron read metadata failed\n");
}
/* check for JMicron signature */
if (strncmp(meta->signature, JMICRON_MAGIC, 2)) {
if (testing || bootverbose)
device_printf(parent, "JMicron check1 failed\n");
goto jmicron_out;
}
/* calculate checksum and compare for valid */
for (checksum = 0, ptr = (u_int16_t *)meta, count = 0; count < 64; count++)
checksum += *ptr++;
if (checksum) {
if (testing || bootverbose)
device_printf(parent, "JMicron check2 failed\n");
goto jmicron_out;
}
if (testing || bootverbose)
ata_raid_jmicron_print_meta(meta);
/* now convert JMicron meta into our generic form */
for (array = 0; array < MAX_ARRAYS; array++) {
jmicron_next:
if (!raidp[array]) {
raidp[array] =
(struct ar_softc *)malloc(sizeof(struct ar_softc), M_AR,
M_NOWAIT | M_ZERO);
if (!raidp[array]) {
device_printf(parent, "failed to allocate metadata storage\n");
goto jmicron_out;
}
}
raid = raidp[array];
if (raid->format && (raid->format != AR_F_JMICRON_RAID))
continue;
for (total_disks = 0, disk = 0; disk < JM_MAX_DISKS; disk++) {
if (meta->disks[disk]) {
if (raid->format == AR_F_JMICRON_RAID) {
if (bcmp(&meta->disks[disk],
raid->disks[disk].serial, sizeof(u_int32_t))) {
array++;
goto jmicron_next;
}
}
else
bcopy(&meta->disks[disk],
raid->disks[disk].serial, sizeof(u_int32_t));
total_disks++;
}
}
/* handle spares XXX SOS */
switch (meta->type) {
case JM_T_RAID0:
raid->type = AR_T_RAID0;
raid->width = total_disks;
break;
case JM_T_RAID1:
raid->type = AR_T_RAID1;
raid->width = 1;
break;
case JM_T_RAID01:
raid->type = AR_T_RAID01;
raid->width = total_disks / 2;
break;
case JM_T_RAID5:
raid->type = AR_T_RAID5;
raid->width = total_disks;
break;
case JM_T_JBOD:
raid->type = AR_T_SPAN;
raid->width = 1;
break;
default:
device_printf(parent,
"JMicron unknown RAID type 0x%02x\n", meta->type);
free(raidp[array], M_AR);
raidp[array] = NULL;
goto jmicron_out;
}
disk_size = (meta->disk_sectors_high << 16) + meta->disk_sectors_low;
raid->format = AR_F_JMICRON_RAID;
strncpy(raid->name, meta->name, sizeof(meta->name));
raid->generation = 0;
raid->interleave = 2 << meta->stripe_shift;
raid->total_disks = total_disks;
raid->total_sectors = disk_size * (raid->width-(raid->type==AR_RAID5));
raid->heads = 255;
raid->sectors = 63;
raid->cylinders = raid->total_sectors / (63 * 255);
raid->offset_sectors = meta->offset * 16;
raid->rebuild_lba = 0;
raid->lun = array;
for (disk = 0; disk < raid->total_disks; disk++) {
if (meta->disks[disk] == meta->disk_id) {
raid->disks[disk].dev = parent;
raid->disks[disk].sectors = disk_size;
raid->disks[disk].flags =
(AR_DF_ONLINE | AR_DF_PRESENT | AR_DF_ASSIGNED);
ars->raid[raid->volume] = raid;
ars->disk_number[raid->volume] = disk;
retval = 1;
break;
}
}
break;
}
jmicron_out:
free(meta, M_AR);
return retval;
}
static int
ata_raid_jmicron_write_meta(struct ar_softc *rdp)
{
struct jmicron_raid_conf *meta;
u_int64_t disk_sectors;
int disk, error = 0;
if (!(meta = (struct jmicron_raid_conf *)
malloc(sizeof(struct jmicron_raid_conf), M_AR, M_NOWAIT | M_ZERO))) {
printf("ar%d: failed to allocate metadata storage\n", rdp->lun);
return ENOMEM;
}
rdp->generation++;
switch (rdp->type) {
case AR_T_JBOD:
meta->type = JM_T_JBOD;
break;
case AR_T_RAID0:
meta->type = JM_T_RAID0;
break;
case AR_T_RAID1:
meta->type = JM_T_RAID1;
break;
case AR_T_RAID5:
meta->type = JM_T_RAID5;
break;
case AR_T_RAID01:
meta->type = JM_T_RAID01;
break;
default:
free(meta, M_AR);
return ENODEV;
}
bcopy(JMICRON_MAGIC, meta->signature, sizeof(JMICRON_MAGIC));
meta->version = JMICRON_VERSION;
meta->offset = rdp->offset_sectors / 16;
disk_sectors = rdp->total_sectors / (rdp->width - (rdp->type == AR_RAID5));
meta->disk_sectors_low = disk_sectors & 0xffff;
meta->disk_sectors_high = disk_sectors >> 16;
strncpy(meta->name, rdp->name, sizeof(meta->name));
meta->stripe_shift = ffs(rdp->interleave) - 2;
for (disk = 0; disk < rdp->total_disks; disk++) {
if (rdp->disks[disk].serial[0])
bcopy(rdp->disks[disk].serial,&meta->disks[disk],sizeof(u_int32_t));
else
meta->disks[disk] = (u_int32_t)(uintptr_t)rdp->disks[disk].dev;
}
for (disk = 0; disk < rdp->total_disks; disk++) {
if (rdp->disks[disk].dev) {
u_int16_t checksum = 0, *ptr;
int count;
meta->disk_id = meta->disks[disk];
meta->checksum = 0;
for (ptr = (u_int16_t *)meta, count = 0; count < 64; count++)
checksum += *ptr++;
meta->checksum -= checksum;
if (testing || bootverbose)
ata_raid_jmicron_print_meta(meta);
if (ata_raid_rw(rdp->disks[disk].dev,
JMICRON_LBA(rdp->disks[disk].dev),
meta, sizeof(struct jmicron_raid_conf),
ATA_R_WRITE | ATA_R_DIRECT)) {
device_printf(rdp->disks[disk].dev, "write metadata failed\n");
error = EIO;
}
}
}
/* handle spares XXX SOS */
free(meta, M_AR);
return error;
}
/* LSILogic V2 MegaRAID Metadata */
static int
ata_raid_lsiv2_read_meta(device_t dev, struct ar_softc **raidp)
@ -3600,6 +3850,7 @@ via_out:
free(meta, M_AR);
return retval;
}
static int
ata_raid_via_write_meta(struct ar_softc *rdp)
{
@ -3931,6 +4182,7 @@ ata_raid_format(struct ar_softc *rdp)
case AR_F_HPTV3_RAID: return "HighPoint v3 RocketRAID";
case AR_F_INTEL_RAID: return "Intel MatrixRAID";
case AR_F_ITE_RAID: return "Integrated Technology Express";
case AR_F_JMICRON_RAID: return "JMicron Technology Corp";
case AR_F_LSIV2_RAID: return "LSILogic v2 MegaRAID";
case AR_F_LSIV3_RAID: return "LSILogic v3 MegaRAID";
case AR_F_NVIDIA_RAID: return "nVidia MediaShield";
@ -4300,6 +4552,48 @@ ata_raid_ite_print_meta(struct ite_raid_conf *meta)
printf("=================================================\n");
}
static char *
ata_raid_jmicron_type(int type)
{
static char buffer[16];
switch (type) {
case JM_T_RAID0: return "RAID0";
case JM_T_RAID1: return "RAID1";
case JM_T_RAID01: return "RAID0+1";
case JM_T_JBOD: return "JBOD";
case JM_T_RAID5: return "RAID5";
default: sprintf(buffer, "UNKNOWN 0x%02x", type);
return buffer;
}
}
static void
ata_raid_jmicron_print_meta(struct jmicron_raid_conf *meta)
{
int i;
printf("***** ATA JMicron Technology Corp Metadata ******\n");
printf("signature %.2s\n", meta->signature);
printf("version 0x%04x\n", meta->version);
printf("checksum 0x%04x\n", meta->checksum);
printf("disk_id 0x%08x\n", meta->disk_id);
printf("offset 0x%08x\n", meta->offset);
printf("disk_sectors_low 0x%08x\n", meta->disk_sectors_low);
printf("disk_sectors_high 0x%08x\n", meta->disk_sectors_high);
printf("name %.16s\n", meta->name);
printf("type %s\n", ata_raid_jmicron_type(meta->type));
printf("stripe_shift %d\n", meta->stripe_shift);
printf("flags 0x%04x\n", meta->flags);
printf("spare:\n");
for (i=0; i < 2 && meta->spare[i]; i++)
printf(" %d 0x%08x\n", i, meta->spare[i]);
printf("disks:\n");
for (i=0; i < 8 && meta->disks[i]; i++)
printf(" %d 0x%08x\n", i, meta->disks[i]);
printf("=================================================\n");
}
static char *
ata_raid_lsiv2_type(int type)
{

View File

@ -68,13 +68,14 @@ struct ar_softc {
#define AR_F_HPTV3_RAID 0x0008
#define AR_F_INTEL_RAID 0x0010
#define AR_F_ITE_RAID 0x0020
#define AR_F_LSIV2_RAID 0x0040
#define AR_F_LSIV3_RAID 0x0080
#define AR_F_NVIDIA_RAID 0x0100
#define AR_F_PROMISE_RAID 0x0200
#define AR_F_SII_RAID 0x0400
#define AR_F_SIS_RAID 0x0800
#define AR_F_VIA_RAID 0x1000
#define AR_F_JMICRON_RAID 0x0040
#define AR_F_LSIV2_RAID 0x0080
#define AR_F_LSIV3_RAID 0x0100
#define AR_F_NVIDIA_RAID 0x0200
#define AR_F_PROMISE_RAID 0x0400
#define AR_F_SII_RAID 0x0800
#define AR_F_SIS_RAID 0x1000
#define AR_F_VIA_RAID 0x2000
#define AR_F_FORMAT_MASK 0x1fff
u_int generation;
@ -398,6 +399,50 @@ struct ite_raid_conf {
} __packed;
/* JMicron Technology Corp Metadata */
#define JMICRON_LBA(dev) \
(((struct ad_softc *)device_get_ivars(dev))->total_secs - 1)
#define JM_MAX_DISKS 8
struct jmicron_raid_conf {
u_int8_t signature[2];
#define JMICRON_MAGIC "JM"
u_int16_t version;
#define JMICRON_VERSION 0x0001
u_int16_t checksum;
u_int8_t filler_1[10];
u_int32_t disk_id;
u_int32_t offset;
u_int32_t disk_sectors_high;
u_int16_t disk_sectors_low;
u_int8_t filler_2[2];
u_int8_t name[16];
u_int8_t type;
#define JM_T_RAID0 0
#define JM_T_RAID1 1
#define JM_T_RAID01 2
#define JM_T_JBOD 3
#define JM_T_RAID5 5
u_int8_t stripe_shift;
u_int16_t flags;
#define JM_F_READY 0x0001
#define JM_F_BOOTABLE 0x0002
#define JM_F_BAD 0x0004
#define JM_F_ACTIVE 0c0010
#define JM_F_UNSYNC 0c0020
#define JM_F_NEWEST 0c0040
u_int8_t filler_3[4];
u_int32_t spare[2];
u_int32_t disks[JM_MAX_DISKS];
u_int8_t filler_4[32];
u_int8_t filler_5[384];
};
/* LSILogic V2 MegaRAID Metadata */
#define LSIV2_LBA(dev) \
(((struct ad_softc *)device_get_ivars(dev))->total_secs - 1)