MFC:
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:
parent
cc52cf5ad6
commit
a3ddb94db9
@ -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 */
|
||||
|
@ -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
|
||||
|
@ -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 *)
|
||||
|
@ -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);
|
||||
|
@ -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 */
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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)
|
||||
|
Loading…
x
Reference in New Issue
Block a user