summaryrefslogtreecommitdiffstats
path: root/sys/dev/ata
diff options
context:
space:
mode:
authorsos <sos@FreeBSD.org>2007-03-08 16:39:25 +0000
committersos <sos@FreeBSD.org>2007-03-08 16:39:25 +0000
commit54f0b44b6e4933df7ddbe02349fe2c9cd93a21f5 (patch)
treee4686663b4edd3a9ab4fad87f566a7ad5cad1478 /sys/dev/ata
parent428a375b20f0af97722089874e08b6e7ef2142f8 (diff)
downloadFreeBSD-src-54f0b44b6e4933df7ddbe02349fe2c9cd93a21f5.zip
FreeBSD-src-54f0b44b6e4933df7ddbe02349fe2c9cd93a21f5.tar.gz
Cleanup the channel/phy reset code.
Diffstat (limited to 'sys/dev/ata')
-rw-r--r--sys/dev/ata/ata-all.h1
-rw-r--r--sys/dev/ata/ata-chipset.c272
2 files changed, 144 insertions, 129 deletions
diff --git a/sys/dev/ata/ata-all.h b/sys/dev/ata/ata-all.h
index d721f7e..2b410a0 100644
--- a/sys/dev/ata/ata-all.h
+++ b/sys/dev/ata/ata-all.h
@@ -491,6 +491,7 @@ struct ata_channel {
#define ATA_ATA_SLAVE 0x02
#define ATA_ATAPI_MASTER 0x04
#define ATA_ATAPI_SLAVE 0x08
+#define ATA_PORTMULTIPLIER 0x10
struct mtx state_mtx; /* state lock */
int state; /* ATA channel state */
diff --git a/sys/dev/ata/ata-chipset.c b/sys/dev/ata/ata-chipset.c
index 61199f4..e53bd1f 100644
--- a/sys/dev/ata/ata-chipset.c
+++ b/sys/dev/ata/ata-chipset.c
@@ -55,10 +55,11 @@ __FBSDID("$FreeBSD$");
static int ata_generic_chipinit(device_t dev);
static void ata_generic_intr(void *data);
static void ata_generic_setmode(device_t dev, int mode);
-static void ata_sata_phy_reset(device_t dev);
+static int ata_sata_phy_reset(device_t dev);
static void ata_sata_phy_event(void *context, int dummy);
static int ata_sata_connect(struct ata_channel *ch);
static void ata_sata_setmode(device_t dev, int mode);
+static int ata_request2fis_h2d(struct ata_request *request, u_int8_t *fis);
static int ata_ahci_chipinit(device_t dev);
static int ata_ahci_allocate(device_t dev);
static int ata_ahci_status(device_t dev);
@@ -97,6 +98,7 @@ static void ata_intel_new_setmode(device_t dev, int mode);
static int ata_intel_31244_allocate(device_t dev);
static int ata_intel_31244_status(device_t dev);
static int ata_intel_31244_command(struct ata_request *request);
+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);
@@ -122,6 +124,7 @@ static int ata_netcell_allocate(device_t dev);
static int ata_nvidia_chipinit(device_t dev);
static int ata_nvidia_allocate(device_t dev);
static int ata_nvidia_status(device_t dev);
+static void ata_nvidia_reset(device_t dev);
static int ata_promise_chipinit(device_t dev);
static int ata_promise_allocate(device_t dev);
static int ata_promise_status(device_t dev);
@@ -157,6 +160,7 @@ static void ata_sii_reset(device_t dev);
static void ata_sii_setmode(device_t dev, int mode);
static int ata_sis_chipinit(device_t dev);
static int ata_sis_allocate(device_t dev);
+static void ata_sis_reset(device_t dev);
static void ata_sis_setmode(device_t dev, int mode);
static int ata_via_chipinit(device_t dev);
static int ata_via_allocate(device_t dev);
@@ -227,39 +231,6 @@ ata_generic_setmode(device_t dev, int mode)
* SATA support functions
*/
static void
-ata_sata_phy_reset(device_t dev)
-{
- struct ata_channel *ch = device_get_softc(dev);
- int loop, retry;
-
- if ((ATA_IDX_INL(ch, ATA_SCONTROL) & ATA_SC_DET_MASK) == ATA_SC_DET_IDLE) {
- ata_sata_connect(ch);
- return;
- }
-
- for (retry = 0; retry < 10; retry++) {
- for (loop = 0; loop < 10; loop++) {
- ATA_IDX_OUTL(ch, ATA_SCONTROL, ATA_SC_DET_RESET);
- ata_udelay(100);
- if ((ATA_IDX_INL(ch, ATA_SCONTROL) &
- ATA_SC_DET_MASK) == ATA_SC_DET_RESET)
- break;
- }
- ata_udelay(5000);
- for (loop = 0; loop < 10; loop++) {
- ATA_IDX_OUTL(ch, ATA_SCONTROL, ATA_SC_DET_IDLE |
- ATA_SC_IPM_DIS_PARTIAL |
- ATA_SC_IPM_DIS_SLUMBER);
- ata_udelay(100);
- if ((ATA_IDX_INL(ch, ATA_SCONTROL) & ATA_SC_DET_MASK) == 0) {
- ata_sata_connect(ch);
- return;
- }
- }
- }
-}
-
-static void
ata_sata_phy_event(void *context, int dummy)
{
struct ata_connect_task *tp = (struct ata_connect_task *)context;
@@ -271,7 +242,7 @@ ata_sata_phy_event(void *context, int dummy)
if (tp->action == ATA_C_ATTACH) {
if (bootverbose)
device_printf(tp->dev, "CONNECTED\n");
- ata_sata_connect(ch);
+ ATA_RESET(tp->dev);
ata_identify(tp->dev);
}
if (tp->action == ATA_C_DETACH) {
@@ -292,6 +263,36 @@ ata_sata_phy_event(void *context, int dummy)
}
static int
+ata_sata_phy_reset(device_t dev)
+{
+ struct ata_channel *ch = device_get_softc(dev);
+ int loop, retry;
+
+ if ((ATA_IDX_INL(ch, ATA_SCONTROL) & ATA_SC_DET_MASK) == ATA_SC_DET_IDLE)
+ return ata_sata_connect(ch);
+
+ for (retry = 0; retry < 10; retry++) {
+ for (loop = 0; loop < 10; loop++) {
+ ATA_IDX_OUTL(ch, ATA_SCONTROL, ATA_SC_DET_RESET);
+ ata_udelay(100);
+ if ((ATA_IDX_INL(ch, ATA_SCONTROL) &
+ ATA_SC_DET_MASK) == ATA_SC_DET_RESET)
+ break;
+ }
+ ata_udelay(5000);
+ for (loop = 0; loop < 10; loop++) {
+ ATA_IDX_OUTL(ch, ATA_SCONTROL, ATA_SC_DET_IDLE |
+ ATA_SC_IPM_DIS_PARTIAL |
+ ATA_SC_IPM_DIS_SLUMBER);
+ ata_udelay(100);
+ if ((ATA_IDX_INL(ch, ATA_SCONTROL) & ATA_SC_DET_MASK) == 0)
+ return ata_sata_connect(ch);
+ }
+ }
+ return 0;
+}
+
+static int
ata_sata_connect(struct ata_channel *ch)
{
u_int32_t status;
@@ -310,37 +311,12 @@ ata_sata_connect(struct ata_channel *ch)
device_printf(ch->dev, "SATA connect status=%08x\n", status);
return 0;
}
+ if (bootverbose)
+ device_printf(ch->dev, "SATA connect time=%dms\n", timeout * 10);
/* clear SATA error register */
ATA_IDX_OUTL(ch, ATA_SERROR, ATA_IDX_INL(ch, ATA_SERROR));
- /* poll 31 seconds for device ready */
- /* XXX SOS 10 secs for now as I have little patience */
- for (timeout = 0; timeout < 1000; timeout++) {
- if (ATA_IDX_INB(ch, ATA_STATUS) & ATA_S_BUSY)
- DELAY(10000);
- else
- break;
- }
- if (bootverbose)
- device_printf(ch->dev, "SATA connect ready time=%dms\n", timeout * 10);
-
- /* if we have legacy resources an old fashioned reset might be needed */
- if (ch->r_io[ATA_DATA].res)
- ata_generic_reset(ch->dev);
-
- /* register device type from signature */
- ch->devices = 0;
- if (timeout < 1000) {
- if ((ATA_IDX_INB(ch, ATA_CYL_LSB) == ATAPI_MAGIC_LSB) &&
- (ATA_IDX_INB(ch, ATA_CYL_MSB) == ATAPI_MAGIC_MSB))
- ch->devices = ATA_ATAPI_MASTER;
- else
- ch->devices = ATA_ATA_MASTER;
- }
- if (bootverbose)
- device_printf(ch->dev, "sata_connect devices=0x%b\n",
- ch->devices, "\20\3ATAPI_MASTER\1ATA_MASTER");
return 1;
}
@@ -378,6 +354,49 @@ ata_sata_setmode(device_t dev, int mode)
}
}
+static int
+ata_request2fis_h2d(struct ata_request *request, u_int8_t *fis)
+{
+ struct ata_device *atadev = device_get_softc(request->dev);
+
+ if (request->flags & ATA_R_ATAPI) {
+ fis[0] = 0x27; /* host to device */
+ fis[1] = 0x80; /* command FIS (note PM goes here) */
+ fis[2] = ATA_PACKET_CMD;
+ if (request->flags & ATA_R_DMA)
+ fis[3] = ATA_F_DMA;
+ else {
+ fis[5] = request->transfersize;
+ fis[6] = request->transfersize >> 8;
+ }
+ fis[7] = ATA_D_LBA | atadev->unit;
+ fis[15] = ATA_A_4BIT;
+ return 20;
+ }
+ else {
+ ata_modify_if_48bit(request);
+ fis[0] = 0x27; /* host to device */
+ fis[1] = 0x80; /* command FIS (note PM goes here) */
+ fis[2] = request->u.ata.command;
+ fis[3] = request->u.ata.feature;
+ fis[4] = request->u.ata.lba;
+ fis[5] = request->u.ata.lba >> 8;
+ fis[6] = request->u.ata.lba >> 16;
+ fis[7] = ATA_D_LBA | atadev->unit;
+ if (!(atadev->flags & ATA_D_48BIT_ACTIVE))
+ fis[7] |= (request->u.ata.lba >> 24 & 0x0f);
+ fis[8] = request->u.ata.lba >> 24;
+ fis[9] = request->u.ata.lba >> 32;
+ fis[10] = request->u.ata.lba >> 40;
+ fis[11] = request->u.ata.feature >> 8;
+ fis[12] = request->u.ata.count;
+ fis[13] = request->u.ata.count >> 8;
+ fis[15] = ATA_A_4BIT;
+ return 20;
+ }
+ return 0;
+}
+
/*
* AHCI v1.x compliant SATA chipset support functions
@@ -440,17 +459,6 @@ ata_ahci_allocate(device_t dev)
struct ata_channel *ch = device_get_softc(dev);
int offset = ch->unit << 7;
- /* setup legacy cruft we need */
- ch->r_io[ATA_DATA].res = NULL;
- ch->r_io[ATA_CYL_LSB].res = ctlr->r_res2;
- ch->r_io[ATA_CYL_LSB].offset = ATA_AHCI_P_SIG + 2 + offset;
- ch->r_io[ATA_CYL_MSB].res = ctlr->r_res2;
- ch->r_io[ATA_CYL_MSB].offset = ATA_AHCI_P_SIG + 3 + offset;
- ch->r_io[ATA_STATUS].res = ctlr->r_res2;
- ch->r_io[ATA_STATUS].offset = ATA_AHCI_P_TFD + offset;
- ch->r_io[ATA_ALTSTAT].res = ctlr->r_res2;
- ch->r_io[ATA_ALTSTAT].offset = ATA_AHCI_P_TFD + offset;
-
/* set the SATA resources */
ch->r_io[ATA_SSTATUS].res = ctlr->r_res2;
ch->r_io[ATA_SSTATUS].offset = ATA_AHCI_P_SSTS + offset;
@@ -667,8 +675,9 @@ ata_ahci_reset(device_t dev)
if (!(ATA_INL(ctlr->r_res2, ATA_AHCI_PI) & (1 << ch->unit))) {
device_printf(dev, "port not implemented\n");
- ch->devices = 0;
+ return;
}
+ ch->devices = 0;
/* kill off all activity on this channel */
cmd = ATA_INL(ctlr->r_res2, ATA_AHCI_P_CMD + offset);
@@ -704,12 +713,22 @@ ata_ahci_reset(device_t dev)
ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_CMD + offset, ATA_AHCI_P_CMD_SUD);
/* enable interface */
- ata_sata_phy_reset(dev);
-
- /* no ATAPI yet */
- if (ch->devices & ATA_ATAPI_MASTER) {
- device_printf(ch->dev, "AHCI SATA ATAPI devices not supported yet\n");
- ch->devices = 0;
+ if (ata_sata_phy_reset(dev)) {
+ switch (ATA_INL(ctlr->r_res2, ATA_AHCI_P_SIG + offset)) {
+ case 0xeb140101:
+ ch->devices = ATA_ATAPI_MASTER;
+ device_printf(ch->dev, "SATA ATAPI devices not supported yet\n");
+ ch->devices = 0;
+ break;
+ case 0x96690101:
+ ch->devices = ATA_PORTMULTIPLIER;
+ device_printf(ch->dev, "Portmultipliers not supported yet\n");
+ ch->devices = 0;
+ break;
+ case 0x00000101:
+ ch->devices = ATA_ATA_MASTER;
+ break;
+ }
}
/* clear any interrupts pending on this channel */
@@ -754,47 +773,12 @@ ata_ahci_dmainit(device_t dev)
static int
ata_ahci_setup_fis(struct ata_ahci_cmd_tab *ctp, struct ata_request *request)
{
- struct ata_device *atadev = device_get_softc(request->dev);
-
bzero(ctp->cfis, 64);
if (request->flags & ATA_R_ATAPI) {
- ctp->cfis[0] = 0x27; /* host to device */
- ctp->cfis[1] = 0x80; /* command FIS (note PM goes here) */
- ctp->cfis[2] = ATA_PACKET_CMD;
- if (request->flags & ATA_R_DMA)
- ctp->cfis[3] = ATA_F_DMA;
- else {
- ctp->cfis[5] = request->transfersize;
- ctp->cfis[6] = request->transfersize >> 8;
- }
- ctp->cfis[7] = ATA_D_LBA | atadev->unit;
- ctp->cfis[15] = ATA_A_4BIT;
bzero(ctp->acmd, 32);
bcopy(request->u.atapi.ccb, ctp->acmd, 12);
- return 20;
- }
- else {
- ata_modify_if_48bit(request);
- ctp->cfis[0] = 0x27; /* host to device */
- ctp->cfis[1] = 0x80; /* command FIS (note PM goes here) */
- ctp->cfis[2] = request->u.ata.command;
- ctp->cfis[3] = request->u.ata.feature;
- ctp->cfis[4] = request->u.ata.lba;
- ctp->cfis[5] = request->u.ata.lba >> 8;
- ctp->cfis[6] = request->u.ata.lba >> 16;
- ctp->cfis[7] = ATA_D_LBA | atadev->unit;
- if (!(atadev->flags & ATA_D_48BIT_ACTIVE))
- ctp->cfis[7] |= (request->u.ata.lba >> 24 & 0x0f);
- ctp->cfis[8] = request->u.ata.lba >> 24;
- ctp->cfis[9] = request->u.ata.lba >> 32;
- ctp->cfis[10] = request->u.ata.lba >> 40;
- ctp->cfis[11] = request->u.ata.feature >> 8;
- ctp->cfis[12] = request->u.ata.count;
- ctp->cfis[13] = request->u.ata.count >> 8;
- ctp->cfis[15] = ATA_A_4BIT;
- return 20;
}
- return 0;
+ return ata_request2fis_h2d(request, &ctp->cfis[0]);
}
@@ -1362,6 +1346,7 @@ ata_ati_setmode(device_t dev, int mode)
}
}
+
/*
* Cyrix chipset support functions
*/
@@ -1751,7 +1736,7 @@ ata_intel_chipinit(device_t dev)
return ENXIO;
ctlr->channels = 4;
ctlr->allocate = ata_intel_31244_allocate;
- ctlr->reset = ata_sata_phy_reset;
+ ctlr->reset = ata_intel_31244_reset;
}
ctlr->setmode = ata_sata_setmode;
}
@@ -2042,6 +2027,13 @@ ata_intel_31244_command(struct ata_request *request)
return 0;
}
+static void
+ata_intel_31244_reset(device_t dev)
+{
+ if (ata_sata_phy_reset(dev))
+ ata_generic_reset(dev);
+}
+
/*
* Integrated Technology Express Inc. (ITE) chipset support functions
@@ -2694,9 +2686,6 @@ ata_marvell_edma_end_transaction(struct ata_request *request)
u_int32_t rsp_in, rsp_out;
int slot;
- /* unload SG list */
- ch->dma->unload(ch->dev);
-
/* stop timeout */
callout_stop(&request->callout);
@@ -2720,6 +2709,10 @@ ata_marvell_edma_end_transaction(struct ata_request *request)
if (!(request->status & ATA_S_ERROR) &&
!(request->flags & ATA_R_TIMEOUT))
request->donecount = request->bytecount;
+
+ /* unload SG list */
+ ch->dma->unload(ch->dev);
+
res = ATA_OP_FINISHED;
}
@@ -2754,7 +2747,8 @@ ata_marvell_edma_reset(device_t dev)
ATA_OUTL(ctlr->r_res1, 0x0200c + ATA_MV_EDMA_BASE(ch), ~0x0);
/* enable channel and test for devices */
- ata_sata_phy_reset(dev);
+ if (ata_sata_phy_reset(dev))
+ ata_generic_reset(dev);
/* enable EDMA machinery */
ATA_OUTL(ctlr->r_res1, 0x02028 + ATA_MV_EDMA_BASE(ch), 0x00000001);
@@ -2773,8 +2767,8 @@ ata_marvell_edma_dmasetprd(void *xsc, bus_dma_segment_t *segs, int nsegs,
for (i = 0; i < nsegs; i++) {
prd[i].addrlo = htole32(segs[i].ds_addr);
- prd[i].addrhi = 0;
prd[i].count = htole32(segs[i].ds_len);
+ prd[i].addrhi = htole32((u_int64_t)segs[i].ds_addr >> 32);
}
prd[i - 1].count |= htole32(ATA_DMA_EOT);
}
@@ -2866,6 +2860,7 @@ ata_national_setmode(device_t dev, int mode)
}
}
+
/*
* NetCell chipset support functions
*/
@@ -2909,6 +2904,7 @@ ata_netcell_allocate(device_t dev)
return 0;
}
+
/*
* nVidia chipset support functions
*/
@@ -2971,7 +2967,7 @@ ata_nvidia_chipinit(device_t dev)
int offset = ctlr->chip->cfg2 & NV4 ? 0x0440 : 0x0010;
ctlr->allocate = ata_nvidia_allocate;
- ctlr->reset = ata_sata_phy_reset;
+ ctlr->reset = ata_nvidia_reset;
/* enable control access */
pci_write_config(dev, 0x50, pci_read_config(dev, 0x50, 1) | 0x04,1);
@@ -3086,6 +3082,13 @@ ata_nvidia_status(device_t dev)
return (status & (0x01 << shift));
}
+static void
+ata_nvidia_reset(device_t dev)
+{
+ if (ata_sata_phy_reset(dev))
+ ata_generic_reset(dev);
+}
+
/*
* Promise chipset support functions
@@ -3755,7 +3758,8 @@ ata_promise_mio_reset(device_t dev)
if ((ctlr->chip->cfg2 == PRSATA) ||
((ctlr->chip->cfg2 == PRCMBO) && (ch->unit < 2))) {
- ata_sata_phy_reset(dev);
+ if (ata_sata_phy_reset(dev))
+ ata_generic_reset(dev);
/* reset and enable plug/unplug intr */
ATA_OUTL(ctlr->r_res2, 0x06c, (0x00000011 << ch->unit));
@@ -3790,7 +3794,8 @@ ata_promise_mio_reset(device_t dev)
(ATA_INL(ctlr->r_res2, 0x414 + (ch->unit << 8)) &
~0x00000003) | 0x00000001);
- ata_sata_phy_reset(dev);
+ if (ata_sata_phy_reset(dev))
+ ata_generic_reset(dev);
/* reset and enable plug/unplug intr */
ATA_OUTL(ctlr->r_res2, 0x060, (0x00000011 << ch->unit));
@@ -4527,7 +4532,8 @@ ata_sii_reset(device_t dev)
ATA_OUTL(ctlr->r_res2, 0x48,
ATA_INL(ctlr->r_res2, 0x48) & ~(0xc0 >> ch->unit));
- ata_sata_phy_reset(dev);
+ if (ata_sata_phy_reset(dev))
+ ata_generic_reset(dev);
/* enable PHY state change interrupt */
ATA_OUTL(ctlr->r_res2, 0x148 + offset, (1 << 16));
@@ -4713,7 +4719,7 @@ ata_sis_chipinit(device_t dev)
if ((ctlr->r_res2 = bus_alloc_resource_any(dev, ctlr->r_type2,
&ctlr->r_rid2, RF_ACTIVE))) {
ctlr->allocate = ata_sis_allocate;
- ctlr->reset = ata_sata_phy_reset;
+ ctlr->reset = ata_sis_reset;
/* enable PCI interrupt */
pci_write_config(dev, PCIR_COMMAND,
@@ -4753,6 +4759,13 @@ ata_sis_allocate(device_t dev)
}
static void
+ata_sis_reset(device_t dev)
+{
+ if (ata_sata_phy_reset(dev))
+ ata_generic_reset(dev);
+}
+
+static void
ata_sis_setmode(device_t dev, int mode)
{
device_t gparent = GRANDPARENT(dev);
@@ -5008,9 +5021,10 @@ ata_via_reset(device_t dev)
struct ata_channel *ch = device_get_softc(dev);
if ((ctlr->chip->cfg2 & VIABAR) && (ch->unit > 1))
- ata_generic_reset(dev);
+ ata_generic_reset(dev);
else
- ata_sata_phy_reset(dev);
+ if (ata_sata_phy_reset(dev))
+ ata_generic_reset(dev);
}
static void
OpenPOWER on IntegriCloud