summaryrefslogtreecommitdiffstats
path: root/sys/dev/ata/ata-chipset.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/dev/ata/ata-chipset.c')
-rw-r--r--sys/dev/ata/ata-chipset.c1063
1 files changed, 797 insertions, 266 deletions
diff --git a/sys/dev/ata/ata-chipset.c b/sys/dev/ata/ata-chipset.c
index 29a6117..d6ff0ac 100644
--- a/sys/dev/ata/ata-chipset.c
+++ b/sys/dev/ata/ata-chipset.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 1998 - 2007 Søren Schmidt <sos@FreeBSD.org>
+ * Copyright (c) 1998 - 2008 Søren Schmidt <sos@FreeBSD.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -66,6 +66,9 @@ static int ata_ahci_allocate(device_t dev);
static int ata_ahci_status(device_t dev);
static int ata_ahci_begin_transaction(struct ata_request *request);
static int ata_ahci_end_transaction(struct ata_request *request);
+static int ata_ahci_pm_read(device_t dev, int port, int reg, u_int32_t *result);
+static int ata_ahci_pm_write(device_t dev, int port, int reg, u_int32_t result);
+static u_int32_t ata_ahci_softreset(device_t dev, int port);
static void ata_ahci_reset(device_t dev);
static void ata_ahci_dmasetprd(void *xsc, bus_dma_segment_t *segs, int nsegs, int error);
static void ata_ahci_dmainit(device_t dev);
@@ -130,8 +133,8 @@ 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);
-static int ata_promise_dmastart(device_t dev);
-static int ata_promise_dmastop(device_t dev);
+static int ata_promise_dmastart(struct ata_request *request);
+static int ata_promise_dmastop(struct ata_request *request);
static void ata_promise_dmareset(device_t dev);
static void ata_promise_dmainit(device_t dev);
static void ata_promise_setmode(device_t dev, int mode);
@@ -142,6 +145,9 @@ static void ata_promise_mio_intr(void *data);
static int ata_promise_mio_status(device_t dev);
static int ata_promise_mio_command(struct ata_request *request);
static void ata_promise_mio_reset(device_t dev);
+static int ata_promise_mio_pm_read(device_t dev, int port, int reg, u_int32_t *result);
+static int ata_promise_mio_pm_write(device_t dev, int port, int reg, u_int32_t result);
+static u_int32_t ata_promise_mio_softreset(device_t dev, int port);
static void ata_promise_mio_dmainit(device_t dev);
static void ata_promise_mio_setprd(void *xsc, bus_dma_segment_t *segs, int nsegs, int error);
static void ata_promise_mio_setmode(device_t dev, int mode);
@@ -167,6 +173,9 @@ static int ata_siiprb_allocate(device_t dev);
static int ata_siiprb_status(device_t dev);
static int ata_siiprb_begin_transaction(struct ata_request *request);
static int ata_siiprb_end_transaction(struct ata_request *request);
+static int ata_siiprb_pm_read(device_t dev, int port, int reg, u_int32_t *result);
+static int ata_siiprb_pm_write(device_t dev, int port, int reg, u_int32_t result);
+static u_int32_t ata_siiprb_softreset(device_t dev, int port);
static void ata_siiprb_reset(device_t dev);
static void ata_siiprb_dmasetprd(void *xsc, bus_dma_segment_t *segs, int nsegs, int error);
static void ata_siiprb_dmainit(device_t dev);
@@ -268,15 +277,15 @@ ata_sata_phy_check_events(device_t dev)
if (((status & ATA_SS_CONWELL_MASK) == ATA_SS_CONWELL_GEN1) ||
((status & ATA_SS_CONWELL_MASK) == ATA_SS_CONWELL_GEN2)) {
if (bootverbose)
- device_printf(ch->dev, "CONNECT requested\n");
+ device_printf(dev, "CONNECT requested\n");
tp->action = ATA_C_ATTACH;
}
else {
if (bootverbose)
- device_printf(ch->dev, "DISCONNECT requested\n");
+ device_printf(dev, "DISCONNECT requested\n");
tp->action = ATA_C_DETACH;
}
- tp->dev = ch->dev;
+ tp->dev = dev;
TASK_INIT(&tp->task, 0, ata_sata_phy_event, tp);
taskqueue_enqueue(taskqueue_thread, &tp->task);
}
@@ -407,14 +416,109 @@ ata_sata_setmode(device_t dev, int mode)
}
}
+static void
+ata_pm_identify(device_t dev)
+{
+ struct ata_channel *ch = device_get_softc(dev);
+ u_int32_t pm_chipid, pm_revision, pm_ports;
+ int port;
+
+ /* get PM vendor & product data */
+ if (ch->hw.pm_read(dev, ATA_PM, 0, &pm_chipid)) {
+ device_printf(dev, "error getting PM vendor data\n");
+ return;
+ }
+
+ /* get PM revision data */
+ if (ch->hw.pm_read(dev, ATA_PM, 1, &pm_revision)) {
+ device_printf(dev, "error getting PM revison data\n");
+ return;
+ }
+
+ /* get number of HW ports on the PM */
+ if (ch->hw.pm_read(dev, ATA_PM, 2, &pm_ports)) {
+ device_printf(dev, "error getting PM port info\n");
+ return;
+ }
+ pm_ports &= 0x0000000f;
+
+ /* chip specific quirks */
+ switch (pm_chipid) {
+ case 0x37261095:
+ /* Some of these bogusly reports 6 ports */
+ pm_ports = 5;
+ device_printf(dev, "SiI-3726-R%x Portmultiplier with %d ports\n",
+ pm_revision, pm_ports);
+ break;
+
+ default:
+ device_printf(dev, "Portmultiplier (id=%08x rev=%x) with %d ports\n",
+ pm_chipid, pm_revision, pm_ports);
+ }
+
+ /* reset all ports and register if anything connected */
+ for (port=0; port < pm_ports; port++) {
+ u_int32_t signature, status;
+ int timeout;
+
+ if (ch->hw.pm_write(dev, port, 2, ATA_SC_DET_RESET)) {
+ device_printf(dev, "p%d: writing ATA_SC_DET_RESET failed\n", port);
+ continue;
+ }
+
+ ata_udelay(5000);
+
+ if (ch->hw.pm_write(dev, port, 2, ATA_SC_DET_IDLE)) {
+ device_printf(dev, "p%d: writing ATA_SC_DET_idle failed\n", port);
+ continue;
+ }
+
+ ata_udelay(5000);
+
+ /* wait up to 1 second for "connect well" */
+ for (timeout = 0; timeout < 100 ; timeout++) {
+ ch->hw.pm_read(dev, port, 0, &status);
+ if ((status & ATA_SS_CONWELL_MASK) == ATA_SS_CONWELL_GEN1 ||
+ (status & ATA_SS_CONWELL_MASK) == ATA_SS_CONWELL_GEN2)
+ break;
+ ata_udelay(10000);
+ }
+ if (timeout >= 100) {
+ if (bootverbose)
+ device_printf(dev, "p%d: connect status=%08x\n", port, status);
+ continue;
+ }
+ if (bootverbose)
+ device_printf(dev, "p%d: connect time %dms\n", port, timeout * 10);
+
+ /* clear SERROR register */
+ ch->hw.pm_write(dev, port, 1, 0xffffffff);
+
+ signature = ch->hw.softreset(dev, port);
+
+ if (bootverbose)
+ device_printf(dev, "p%d: SIGNATURE=%08x\n", port, signature);
+
+ /* figure out whats there */
+ switch (signature) {
+ case 0x00000101:
+ ch->devices |= (ATA_ATA_MASTER << port);
+ continue;
+ case 0xeb140101:
+ ch->devices |= (ATA_ATAPI_MASTER << port);
+ continue;
+ }
+ }
+}
+
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[0] = 0x27; /* host to device */
+ fis[1] = 0x80 | (atadev->unit & 0x0f);
fis[2] = ATA_PACKET_CMD;
if (request->flags & (ATA_R_READ | ATA_R_WRITE))
fis[3] = ATA_F_DMA;
@@ -422,22 +526,22 @@ ata_request2fis_h2d(struct ata_request *request, u_int8_t *fis)
fis[5] = request->transfersize;
fis[6] = request->transfersize >> 8;
}
- fis[7] = ATA_D_LBA | atadev->unit;
+ fis[7] = ATA_D_LBA;
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[0] = 0x27; /* host to device */
+ fis[1] = 0x80 | (atadev->unit & 0x0f);
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;
+ fis[7] = ATA_D_LBA;
if (!(atadev->flags & ATA_D_48BIT_ACTIVE))
- fis[7] |= (request->u.ata.lba >> 24 & 0x0f);
+ fis[7] |= (ATA_D_IBM | (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;
@@ -534,10 +638,12 @@ ata_ahci_chipinit(device_t dev)
/* announce we support the HW */
version = ATA_INL(ctlr->r_res2, ATA_AHCI_VS);
device_printf(dev,
- "AHCI Version %x%x.%x%x controller with %d ports detected\n",
+ "AHCI Version %x%x.%x%x controller with %d ports PM %s\n",
(version >> 24) & 0xff, (version >> 16) & 0xff,
(version >> 8) & 0xff, version & 0xff,
- (ATA_INL(ctlr->r_res2, ATA_AHCI_CAP) & ATA_AHCI_NPMASK) + 1);
+ (ATA_INL(ctlr->r_res2, ATA_AHCI_CAP) & ATA_AHCI_NPMASK) + 1,
+ (ATA_INL(ctlr->r_res2, ATA_AHCI_CAP) & ATA_AHCI_CAP_SPM) ?
+ "supported" : "not supported");
return 0;
}
@@ -563,13 +669,16 @@ ata_ahci_allocate(device_t dev)
ch->hw.begin_transaction = ata_ahci_begin_transaction;
ch->hw.end_transaction = ata_ahci_end_transaction;
ch->hw.command = NULL; /* not used here */
+ ch->hw.softreset = ata_ahci_softreset;
+ ch->hw.pm_read = ata_ahci_pm_read;
+ ch->hw.pm_write = ata_ahci_pm_write;
/* setup work areas */
- work = ch->dma->work_bus + ATA_AHCI_CL_OFFSET;
+ work = ch->dma.work_bus + ATA_AHCI_CL_OFFSET;
ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_CLB + offset, work & 0xffffffff);
ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_CLBU + offset, work >> 32);
- work = ch->dma->work_bus + ATA_AHCI_FB_OFFSET;
+ work = ch->dma.work_bus + ATA_AHCI_FB_OFFSET;
ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_FB + offset, work & 0xffffffff);
ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_FBU + offset, work >> 32);
@@ -581,6 +690,9 @@ ata_ahci_allocate(device_t dev)
ATA_AHCI_P_IX_UF | ATA_AHCI_P_IX_SDB | ATA_AHCI_P_IX_DS |
ATA_AHCI_P_IX_PS | ATA_AHCI_P_IX_DHR));
+ /* enable FIS based switching */
+ ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_FBS + offset, 0x00000003);
+
/* start operations on this channel */
ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_CMD + offset,
(ATA_AHCI_P_CMD_ACTIVE | ATA_AHCI_P_CMD_FRE |
@@ -595,7 +707,6 @@ ata_ahci_status(device_t dev)
struct ata_channel *ch = device_get_softc(dev);
u_int32_t action = ATA_INL(ctlr->r_res2, ATA_AHCI_IS);
int offset = ch->unit << 7;
- int tag = 0;
if (action & (1 << ch->unit)) {
u_int32_t istatus = ATA_INL(ctlr->r_res2, ATA_AHCI_P_IS + offset);
@@ -610,7 +721,8 @@ ata_ahci_status(device_t dev)
ata_sata_phy_check_events(dev);
/* do we have a potentially hanging engine to take care of? */
- if ((istatus & 0x78400050) && (cstatus & (1 << tag))) {
+ /* XXX SOS what todo on NCQ */
+ if ((istatus & 0x78400050) && (cstatus & 1)) {
u_int32_t cmd = ATA_INL(ctlr->r_res2, ATA_AHCI_P_CMD + offset);
int timeout = 0;
@@ -622,7 +734,7 @@ ata_ahci_status(device_t dev)
/* XXX SOS this is not entirely wrong */
do {
DELAY(1000);
- if (timeout++ > 500) {
+ if (timeout++ > 1000) {
device_printf(dev, "stopping AHCI engine failed\n");
break;
}
@@ -636,7 +748,8 @@ ata_ahci_status(device_t dev)
return 1;
}
else
- return (!(cstatus & (1 << tag)));
+ /* XXX SOS what todo on NCQ */
+ return (!(cstatus & 1));
}
return 0;
}
@@ -646,16 +759,18 @@ static int
ata_ahci_begin_transaction(struct ata_request *request)
{
struct ata_pci_controller *ctlr=device_get_softc(GRANDPARENT(request->dev));
- struct ata_channel *ch = device_get_softc(device_get_parent(request->dev));
+ struct ata_channel *ch = device_get_softc(request->parent);
+ struct ata_device *atadev = device_get_softc(request->dev);
struct ata_ahci_cmd_tab *ctp;
struct ata_ahci_cmd_list *clp;
int offset = ch->unit << 7;
- int tag = 0, entries = 0;
+ int port = atadev->unit & 0x0f;
+ int entries = 0;
int fis_size;
/* get a piece of the workspace for this request */
ctp = (struct ata_ahci_cmd_tab *)
- (ch->dma->work + ATA_AHCI_CT_OFFSET + (ATA_AHCI_CT_SIZE * tag));
+ (ch->dma.work + ATA_AHCI_CT_OFFSET + (ATA_AHCI_CT_SIZE*request->tag));
/* setup the FIS for this request */
if (!(fis_size = ata_ahci_setup_fis(ctp, request))) {
@@ -666,9 +781,7 @@ ata_ahci_begin_transaction(struct ata_request *request)
/* if request moves data setup and load SG list */
if (request->flags & (ATA_R_READ | ATA_R_WRITE)) {
- if (ch->dma->load(ch->dev, request->data, request->bytecount,
- request->flags & ATA_R_READ,
- ctp->prd_tab, &entries)) {
+ if (ch->dma.load(request, ctp->prd_tab, &entries)) {
device_printf(request->dev, "setting up DMA failed\n");
request->result = EIO;
return ATA_OP_FINISHED;
@@ -677,18 +790,21 @@ ata_ahci_begin_transaction(struct ata_request *request)
/* setup the command list entry */
clp = (struct ata_ahci_cmd_list *)
- (ch->dma->work + ATA_AHCI_CL_OFFSET + (ATA_AHCI_CL_SIZE * tag));
+ (ch->dma.work + ATA_AHCI_CL_OFFSET + (ATA_AHCI_CL_SIZE*request->tag));
clp->prd_length = entries;
- clp->cmd_flags = (request->flags & ATA_R_WRITE ? (1<<6) : 0) |
- (request->flags & ATA_R_ATAPI ? ((1<<5) | (1<<7)) : 0) |
- (fis_size / sizeof(u_int32_t));
+ clp->cmd_flags = (request->flags & ATA_R_WRITE ? ATA_AHCI_CMD_WRITE : 0) |
+ (request->flags & ATA_R_ATAPI ?
+ (ATA_AHCI_CMD_ATAPI | ATA_AHCI_CMD_PREFETCH) : 0) |
+ (fis_size / sizeof(u_int32_t)) |
+ (port << 12);
clp->bytecount = 0;
- clp->cmd_table_phys = htole64(ch->dma->work_bus + ATA_AHCI_CT_OFFSET +
- (ATA_AHCI_CT_SIZE * tag));
+ clp->cmd_table_phys = htole64(ch->dma.work_bus + ATA_AHCI_CT_OFFSET +
+ (ATA_AHCI_CT_SIZE * request->tag));
/* clear eventual ACTIVE bit */
- ATA_IDX_OUTL(ch, ATA_SACTIVE, ATA_IDX_INL(ch, ATA_SACTIVE) & (1 << tag));
+ ATA_IDX_OUTL(ch, ATA_SACTIVE,
+ ATA_IDX_INL(ch, ATA_SACTIVE) & (1 << request->tag));
/* set command type bit */
if (request->flags & ATA_R_ATAPI)
@@ -700,8 +816,11 @@ ata_ahci_begin_transaction(struct ata_request *request)
ATA_INL(ctlr->r_res2, ATA_AHCI_P_CMD + offset) &
~ATA_AHCI_P_CMD_ATAPI);
+ /* set PM port to address */
+ ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_FBS + offset, (port << 8) | 0x00000001);
+
/* issue command to controller */
- ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_CI + offset, (1 << tag));
+ ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_CI + offset, (1 << request->tag));
if (!(request->flags & ATA_R_ATAPI)) {
/* device reset doesn't interrupt */
@@ -734,11 +853,10 @@ static int
ata_ahci_end_transaction(struct ata_request *request)
{
struct ata_pci_controller *ctlr=device_get_softc(GRANDPARENT(request->dev));
- struct ata_channel *ch = device_get_softc(device_get_parent(request->dev));
+ struct ata_channel *ch = device_get_softc(request->parent);
struct ata_ahci_cmd_list *clp;
u_int32_t tf_data;
int offset = ch->unit << 7;
- int tag = 0;
/* kill the timeout */
callout_stop(&request->callout);
@@ -751,31 +869,140 @@ ata_ahci_end_transaction(struct ata_request *request)
if (request->status & ATA_S_ERROR)
request->error = tf_data >> 8;
+ /* on control commands read back registers to the request struct */
+ if (request->flags & ATA_R_CONTROL) {
+ struct ata_device *atadev = device_get_softc(request->dev);
+ u_int8_t *fis = ch->dma.work + ATA_AHCI_FB_OFFSET + 0x40;
+
+ request->u.ata.count = fis[12] | ((u_int16_t)fis[13] << 8);
+ request->u.ata.lba = fis[4] | ((u_int64_t)fis[5] << 8) |
+ ((u_int64_t)fis[6] << 16);
+ if (atadev->flags & ATA_D_48BIT_ACTIVE)
+ request->u.ata.lba |= ((u_int64_t)fis[8] << 24) |
+ ((u_int64_t)fis[9] << 32) |
+ ((u_int64_t)fis[10] << 40);
+ else
+ request->u.ata.lba |= ((u_int64_t)(fis[7] & 0x0f) << 24);
+ }
+
/* record how much data we actually moved */
clp = (struct ata_ahci_cmd_list *)
- (ch->dma->work + ATA_AHCI_CL_OFFSET + (ATA_AHCI_CL_SIZE * tag));
+ (ch->dma.work + ATA_AHCI_CL_OFFSET + (ATA_AHCI_CL_SIZE*request->tag));
request->donecount = clp->bytecount;
/* release SG list etc */
- ch->dma->unload(ch->dev);
+ ch->dma.unload(request);
return ATA_OP_FINISHED;
}
-static void
-ata_ahci_reset(device_t dev)
+static int
+ata_ahci_issue_cmd(device_t dev, u_int16_t flags, int timeout)
{
struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev));
struct ata_channel *ch = device_get_softc(dev);
- u_int32_t cmd, signature;
+ struct ata_ahci_cmd_list *clp =
+ (struct ata_ahci_cmd_list *)(ch->dma.work + ATA_AHCI_CL_OFFSET);
+ struct ata_ahci_cmd_tab *ctp =
+ (struct ata_ahci_cmd_tab *)(ch->dma.work + ATA_AHCI_CT_OFFSET);
+ u_int32_t status = 0;
int offset = ch->unit << 7;
- int timeout;
+ int port = (ctp->cfis[1] & 0x0f);
+ int count;
- if (!(ATA_INL(ctlr->r_res2, ATA_AHCI_PI) & (1 << ch->unit))) {
- device_printf(dev, "port not implemented\n");
- return;
+ clp->prd_length = 0;
+ clp->cmd_flags = (20 / sizeof(u_int32_t)) | flags | (port << 12);
+ clp->bytecount = 0;
+ clp->cmd_table_phys = htole64(ch->dma.work_bus + ATA_AHCI_CT_OFFSET);
+
+ /* set PM port */
+ ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_FBS + offset, (port << 8) | 0x00000001);
+
+ /* issue command to controller */
+ ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_CI + offset, 1);
+
+ /* poll for command finished */
+ for (count = 0; count < timeout; count++) {
+ DELAY(1000);
+ if (!((status = ATA_INL(ctlr->r_res2, ATA_AHCI_P_CI + offset)) & 1))
+ break;
+ }
+
+ /* clear interrupts */
+ ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_IS + offset,
+ ATA_INL(ctlr->r_res2, ATA_AHCI_P_IS + offset));
+
+ if (bootverbose)
+ device_printf(dev, "ahci_issue_cmd time=%dms cnt=%dms status=%08x\n",
+ timeout, count, status);
+ if (timeout && (count >= timeout))
+ return EIO;
+
+ return 0;
+}
+
+static int
+ata_ahci_pm_read(device_t dev, int port, int reg, u_int32_t *result)
+{
+ struct ata_channel *ch = device_get_softc(dev);
+ struct ata_ahci_cmd_tab *ctp =
+ (struct ata_ahci_cmd_tab *)(ch->dma.work + ATA_AHCI_CT_OFFSET);
+ u_int8_t *fis = ch->dma.work + ATA_AHCI_FB_OFFSET + 0x40;
+
+ bzero(ctp->cfis, 64);
+ ctp->cfis[0] = 0x27; /* host to device */
+ ctp->cfis[1] = 0x8f; /* command FIS to PM port */
+ ctp->cfis[2] = ATA_READ_PM;
+ ctp->cfis[3] = reg;
+ ctp->cfis[7] = port | ATA_D_LBA;
+ ctp->cfis[15] = ATA_A_4BIT;
+
+ if (ata_ahci_issue_cmd(dev, 0, 10)) {
+ device_printf(dev, "error reading PM port\n");
+ return EIO;
+ }
+
+ *result = fis[12] | (fis[4] << 8) | (fis[5] << 16) | (fis[6] << 24);
+ return 0;
+}
+
+static int
+ata_ahci_pm_write(device_t dev, int port, int reg, u_int32_t value)
+{
+ struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev));
+ struct ata_channel *ch = device_get_softc(dev);
+ struct ata_ahci_cmd_tab *ctp =
+ (struct ata_ahci_cmd_tab *)(ch->dma.work + ATA_AHCI_CT_OFFSET);
+ int offset = ch->unit << 7;
+
+ bzero(ctp->cfis, 64);
+ ctp->cfis[0] = 0x27; /* host to device */
+ ctp->cfis[1] = 0x8f; /* command FIS to PM port */
+ ctp->cfis[2] = ATA_WRITE_PM;
+ ctp->cfis[3] = reg;
+ ctp->cfis[7] = port | ATA_D_LBA;
+ ctp->cfis[12] = value & 0xff;
+ ctp->cfis[4] = (value >> 8) & 0xff;;
+ ctp->cfis[5] = (value >> 16) & 0xff;;
+ ctp->cfis[6] = (value >> 24) & 0xff;;
+ ctp->cfis[15] = ATA_A_4BIT;
+
+ if (ata_ahci_issue_cmd(dev, 0, 100)) {
+ device_printf(dev, "error writing PM port\n");
+ return ATA_E_ABORT;
}
- ch->devices = 0;
+
+ return (ATA_INL(ctlr->r_res2, ATA_AHCI_P_TFD + offset) >> 8) & 0xff;
+}
+
+static void
+ata_ahci_restart(device_t dev)
+{
+ struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev));
+ struct ata_channel *ch = device_get_softc(dev);
+ u_int32_t cmd;
+ int offset = ch->unit << 7;
+ int timeout;
/* kill off all activity on this channel */
cmd = ATA_INL(ctlr->r_res2, ATA_AHCI_P_CMD + offset);
@@ -786,7 +1013,7 @@ ata_ahci_reset(device_t dev)
timeout = 0;
do {
DELAY(1000);
- if (timeout++ > 500) {
+ if (timeout++ > 1000) {
device_printf(dev, "stopping AHCI engine failed\n");
break;
}
@@ -801,7 +1028,7 @@ ata_ahci_reset(device_t dev)
timeout = 0;
do {
DELAY(1000);
- if (timeout++ > 500) {
+ if (timeout++ > 1000) {
device_printf(dev, "executing CLO failed\n");
break;
}
@@ -809,45 +1036,119 @@ ata_ahci_reset(device_t dev)
while (ATA_INL(ctlr->r_res2, ATA_AHCI_P_CMD+offset)&ATA_AHCI_P_CMD_CLO);
}
- /* reset PHY and decide what is present */
- if (ata_sata_phy_reset(dev)) {
+ /* clear SATA error register */
+ ATA_IDX_OUTL(ch, ATA_SERROR, ATA_IDX_INL(ch, ATA_SERROR));
+
+ /* clear any interrupts pending on this channel */
+ ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_IS + offset,
+ ATA_INL(ctlr->r_res2, ATA_AHCI_P_IS + offset));
+
+ /* start operations on this channel */
+ ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_CMD + offset,
+ (ATA_AHCI_P_CMD_ACTIVE | ATA_AHCI_P_CMD_FRE |
+ ATA_AHCI_P_CMD_POD | ATA_AHCI_P_CMD_SUD | ATA_AHCI_P_CMD_ST)
+ | (ch->devices & ATA_PORTMULTIPLIER ? ATA_AHCI_P_CMD_PMA : 0));
+}
+
+static u_int32_t
+ata_ahci_softreset(device_t dev, int port)
+{
+ struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev));
+ struct ata_channel *ch = device_get_softc(dev);
+ struct ata_ahci_cmd_tab *ctp =
+ (struct ata_ahci_cmd_tab *)(ch->dma.work + ATA_AHCI_CT_OFFSET);
+ int offset = ch->unit << 7;
+ int timeout = 0;
- /* clear any interrupts pending on this channel */
- ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_IS + offset,
- ATA_INL(ctlr->r_res2, ATA_AHCI_P_IS + offset));
+ /* kick controller into sane state if needed */
+ ata_ahci_restart(dev);
- /* clear SATA error register */
- ATA_IDX_OUTL(ch, ATA_SERROR, ATA_IDX_INL(ch, ATA_SERROR));
+ /* pull reset active */
+ bzero(ctp->cfis, 64);
+ ctp->cfis[0] = 0x27;
+ ctp->cfis[1] = port & 0x0f;
+ //ctp->cfis[7] = ATA_D_LBA | ATA_D_IBM;
+ ctp->cfis[15] = (ATA_A_4BIT | ATA_A_RESET);
- /* start operations on this channel */
- ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_CMD + offset,
- (ATA_AHCI_P_CMD_ACTIVE | ATA_AHCI_P_CMD_FRE |
- ATA_AHCI_P_CMD_POD | ATA_AHCI_P_CMD_SUD | ATA_AHCI_P_CMD_ST));
+ if (ata_ahci_issue_cmd(dev, ATA_AHCI_CMD_RESET | ATA_AHCI_CMD_CLR_BUSY,100))
+ device_printf(dev, "setting SRST failed ??\n");
+ //return -1;
+
+ ata_udelay(5000);
+
+ /* pull reset inactive -> device softreset */
+ bzero(ctp->cfis, 64);
+ ctp->cfis[0] = 0x27;
+ ctp->cfis[1] = port & 0x0f;
+ //ctp->cfis[7] = ATA_D_LBA | ATA_D_IBM;
+ ctp->cfis[15] = ATA_A_4BIT;
+ if (ata_ahci_issue_cmd(dev, 0, 0))
+ return -1;
+
+ ata_udelay(150000);
+
+ timeout = 0;
+ do {
+ DELAY(1000);
+ if (timeout++ > 1000) {
+ device_printf(dev, "still BUSY after softreset\n");
+ break;
+ }
+ } while (ATA_INL(ctlr->r_res2, ATA_AHCI_P_TFD + offset) & ATA_S_BUSY);
+ if (bootverbose)
+ device_printf(dev, "BUSY wait time=%dms\n", timeout);
+
+ return ATA_INL(ctlr->r_res2, ATA_AHCI_P_SIG + offset);
+}
+
+static void
+ata_ahci_reset(device_t dev)
+{
+ struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev));
+ struct ata_channel *ch = device_get_softc(dev);
+ u_int32_t signature;
+
+ if (!(ATA_INL(ctlr->r_res2, ATA_AHCI_PI) & (1 << ch->unit))) {
+ device_printf(dev, "port not implemented\n");
+ return;
+ }
+
+ ata_ahci_restart(dev);
- signature = ATA_INL(ctlr->r_res2, ATA_AHCI_P_SIG + offset);
+ if (!ata_sata_phy_reset(dev)) {
if (bootverbose)
- device_printf(dev, "SIGNATURE: %08x\n", signature);
- switch (signature) {
- case 0x00000101:
- ch->devices = ATA_ATA_MASTER;
- break;
- case 0x96690101:
- ch->devices = ATA_PORTMULTIPLIER;
- device_printf(ch->dev, "Portmultipliers not supported yet\n");
- ch->devices = 0;
- break;
- case 0xeb140101:
- ch->devices = ATA_ATAPI_MASTER;
- break;
- default: /* SOS XXX */
- if (bootverbose)
- device_printf(ch->dev, "No signature, asuming disk device\n");
- ch->devices = ATA_ATA_MASTER;
- }
+ device_printf(dev, "phy reset found no device\n");
+ ch->devices = 0;
+ return;
+ }
+
+ /* only probe for PortMultiplier if HW has support */
+ if (ATA_INL(ctlr->r_res2, ATA_AHCI_CAP) & ATA_AHCI_CAP_SPM)
+ signature = ata_ahci_softreset(dev, ATA_PM);
+ else {
+ signature = ata_ahci_softreset(dev, 0);
+ }
+ if (bootverbose)
+ device_printf(dev, "SIGNATURE: %08x\n", signature);
+
+ switch (signature) {
+ case 0x00000101:
+ ch->devices = ATA_ATA_MASTER;
+ break;
+ case 0x96690101:
+ ch->devices = ATA_PORTMULTIPLIER;
+ ata_pm_identify(dev);
+ break;
+ case 0xeb140101:
+ ch->devices = ATA_ATAPI_MASTER;
+ break;
+ default: /* SOS XXX */
+ if (bootverbose)
+ device_printf(dev, "No signature, asuming disk device\n");
+ ch->devices = ATA_ATA_MASTER;
}
if (bootverbose)
- device_printf(dev, "ahci_reset devices=0x%b\n", ch->devices,
- "\20\4ATAPI_SLAVE\3ATAPI_MASTER\2ATA_SLAVE\1ATA_MASTER");
+ device_printf(dev, "ahci_reset devices=%08x\n", ch->devices);
}
static void
@@ -863,7 +1164,9 @@ ata_ahci_dmasetprd(void *xsc, bus_dma_segment_t *segs, int nsegs, int error)
prd[i].dbc = htole32((segs[i].ds_len - 1) & ATA_AHCI_PRD_MASK);
}
}
- KASSERT(nsegs <= ATA_DMA_ENTRIES, ("too many DMA segment entries\n"));
+
+ /* we only have space for 16 entries in a slot */
+ KASSERT(nsegs <= 16, ("too many DMA segment entries\n"));
args->nsegs = nsegs;
}
@@ -874,13 +1177,11 @@ ata_ahci_dmainit(device_t dev)
struct ata_channel *ch = device_get_softc(dev);
ata_dmainit(dev);
- if (ch->dma) {
- /* note start and stop are not used here */
- ch->dma->setprd = ata_ahci_dmasetprd;
- ch->dma->max_iosize = 8192 * DEV_BSIZE;
- if (ATA_INL(ctlr->r_res2, ATA_AHCI_CAP) & ATA_AHCI_CAP_64BIT)
- ch->dma->max_address = BUS_SPACE_MAXADDR;
- }
+ /* note start and stop are not used here */
+ ch->dma.setprd = ata_ahci_dmasetprd;
+ ch->dma.max_iosize = 8192 * DEV_BSIZE;
+ if (ATA_INL(ctlr->r_res2, ATA_AHCI_CAP) & ATA_AHCI_CAP_64BIT)
+ ch->dma.max_address = BUS_SPACE_MAXADDR;
}
static int
@@ -956,9 +1257,9 @@ ata_acard_status(device_t dev)
struct ata_channel *ch = device_get_softc(dev);
if (ctlr->chip->cfg1 == ATPOLD &&
- ATA_LOCKING(ch->dev, ATA_LF_WHICH) != ch->unit)
+ ATA_LOCKING(dev, ATA_LF_WHICH) != ch->unit)
return 0;
- if (ch->dma && (ch->dma->flags & ATA_DMA_ACTIVE)) {
+ if (ch->dma.flags & ATA_DMA_ACTIVE) {
int bmstat = ATA_IDX_INB(ch, ATA_BMSTAT_PORT) & ATA_BMSTAT_MASK;
if ((bmstat & (ATA_BMSTAT_ACTIVE | ATA_BMSTAT_INTERRUPT)) !=
@@ -985,7 +1286,7 @@ ata_acard_850_setmode(device_t dev, int mode)
struct ata_pci_controller *ctlr = device_get_softc(gparent);
struct ata_channel *ch = device_get_softc(device_get_parent(dev));
struct ata_device *atadev = device_get_softc(dev);
- int devno = (ch->unit << 1) + ATA_DEV(atadev->unit);
+ int devno = (ch->unit << 1) + atadev->unit;
int error;
mode = ata_limit_mode(dev, mode,
@@ -1021,7 +1322,7 @@ ata_acard_86X_setmode(device_t dev, int mode)
struct ata_pci_controller *ctlr = device_get_softc(gparent);
struct ata_channel *ch = device_get_softc(device_get_parent(dev));
struct ata_device *atadev = device_get_softc(dev);
- int devno = (ch->unit << 1) + ATA_DEV(atadev->unit);
+ int devno = (ch->unit << 1) + atadev->unit;
int error;
@@ -1234,7 +1535,7 @@ ata_ali_setmode(device_t dev, int mode)
struct ata_pci_controller *ctlr = device_get_softc(gparent);
struct ata_channel *ch = device_get_softc(device_get_parent(dev));
struct ata_device *atadev = device_get_softc(dev);
- int devno = (ch->unit << 1) + ATA_DEV(atadev->unit);
+ int devno = (ch->unit << 1) + atadev->unit;
int error;
mode = ata_limit_mode(dev, mode, ctlr->chip->max_dma);
@@ -1398,7 +1699,7 @@ ata_ati_setmode(device_t dev, int mode)
struct ata_pci_controller *ctlr = device_get_softc(gparent);
struct ata_channel *ch = device_get_softc(device_get_parent(dev));
struct ata_device *atadev = device_get_softc(dev);
- int devno = (ch->unit << 1) + ATA_DEV(atadev->unit);
+ int devno = (ch->unit << 1) + atadev->unit;
int offset = (devno ^ 0x01) << 3;
int error;
u_int8_t piotimings[] = { 0x5d, 0x47, 0x34, 0x22, 0x20, 0x34, 0x22, 0x20,
@@ -1492,15 +1793,15 @@ ata_cyrix_setmode(device_t dev, int mode)
{
struct ata_channel *ch = device_get_softc(device_get_parent(dev));
struct ata_device *atadev = device_get_softc(dev);
- int devno = (ch->unit << 1) + ATA_DEV(atadev->unit);
+ int devno = (ch->unit << 1) + atadev->unit;
u_int32_t piotiming[] =
{ 0x00009172, 0x00012171, 0x00020080, 0x00032010, 0x00040010 };
u_int32_t dmatiming[] = { 0x00077771, 0x00012121, 0x00002020 };
u_int32_t udmatiming[] = { 0x00921250, 0x00911140, 0x00911030 };
int error;
- ch->dma->alignment = 16;
- ch->dma->max_iosize = 126 * DEV_BSIZE;
+ ch->dma.alignment = 16;
+ ch->dma.max_iosize = 126 * DEV_BSIZE;
mode = ata_limit_mode(dev, mode, ATA_UDMA2);
@@ -1681,7 +1982,7 @@ ata_highpoint_setmode(device_t dev, int mode)
struct ata_pci_controller *ctlr = device_get_softc(gparent);
struct ata_channel *ch = device_get_softc(device_get_parent(dev));
struct ata_device *atadev = device_get_softc(dev);
- int devno = (ch->unit << 1) + ATA_DEV(atadev->unit);
+ int devno = (ch->unit << 1) + atadev->unit;
int error;
u_int32_t timings33[][4] = {
/* HPT366 HPT370 HPT372 HPT374 mode */
@@ -1960,7 +2261,7 @@ ata_intel_new_setmode(device_t dev, int mode)
struct ata_pci_controller *ctlr = device_get_softc(gparent);
struct ata_channel *ch = device_get_softc(device_get_parent(dev));
struct ata_device *atadev = device_get_softc(dev);
- int devno = (ch->unit << 1) + ATA_DEV(atadev->unit);
+ int devno = (ch->unit << 1) + atadev->unit;
u_int32_t reg40 = pci_read_config(gparent, 0x40, 4);
u_int8_t reg44 = pci_read_config(gparent, 0x44, 1);
u_int8_t reg48 = pci_read_config(gparent, 0x48, 1);
@@ -2042,7 +2343,7 @@ ata_intel_sata_setmode(device_t dev, int mode)
atadev->param.satacapabilities != 0xffff) {
struct ata_channel *ch = device_get_softc(device_get_parent(dev));
- int devno = (ch->unit << 1) + ATA_DEV(atadev->unit);
+ int devno = (ch->unit << 1) + atadev->unit;
/* on some drives we need to set the transfer mode */
ata_controlcmd(dev, ATA_SETFEATURES, ATA_SF_SETXFER, 0,
@@ -2116,11 +2417,13 @@ ata_intel_31244_allocate(device_t dev)
static int
ata_intel_31244_status(device_t dev)
{
+ struct ata_channel *ch = device_get_softc(dev);
+
/* do we have any PHY events ? */
ata_sata_phy_check_events(dev);
/* any drive action to take care of ? */
- return ata_pci_status(dev);
+ return ch->hw.status(dev);
}
static void
@@ -2138,7 +2441,7 @@ ata_intel_31244_tf_write(struct ata_request *request)
((request->u.ata.lba >> 8) & 0x00ff));
ATA_IDX_OUTW(ch, ATA_CYL_MSB, ((request->u.ata.lba >> 32) & 0xff00) |
((request->u.ata.lba >> 16) & 0x00ff));
- ATA_IDX_OUTW(ch, ATA_DRIVE, ATA_D_LBA | atadev->unit);
+ ATA_IDX_OUTW(ch, ATA_DRIVE, ATA_D_LBA | ATA_DEV(atadev->unit));
}
else {
ATA_IDX_OUTB(ch, ATA_FEATURE, request->u.ata.feature);
@@ -2159,7 +2462,7 @@ ata_intel_31244_tf_write(struct ata_request *request)
(request->u.ata.lba / (sectors * heads)));
ATA_IDX_OUTB(ch, ATA_CYL_MSB,
(request->u.ata.lba / (sectors * heads)) >> 8);
- ATA_IDX_OUTB(ch, ATA_DRIVE, ATA_D_IBM | atadev->unit |
+ ATA_IDX_OUTB(ch, ATA_DRIVE, ATA_D_IBM | ATA_DEV(atadev->unit) |
(((request->u.ata.lba% (sectors * heads)) /
sectors) & 0xf));
}
@@ -2168,7 +2471,7 @@ ata_intel_31244_tf_write(struct ata_request *request)
ATA_IDX_OUTB(ch, ATA_CYL_LSB, request->u.ata.lba >> 8);
ATA_IDX_OUTB(ch, ATA_CYL_MSB, request->u.ata.lba >> 16);
ATA_IDX_OUTB(ch, ATA_DRIVE,
- ATA_D_IBM | ATA_D_LBA | atadev->unit |
+ ATA_D_IBM | ATA_D_LBA | ATA_DEV(atadev->unit) |
((request->u.ata.lba >> 24) & 0x0f));
}
}
@@ -2227,7 +2530,7 @@ ata_ite_setmode(device_t dev, int mode)
device_t gparent = GRANDPARENT(dev);
struct ata_channel *ch = device_get_softc(device_get_parent(dev));
struct ata_device *atadev = device_get_softc(dev);
- int devno = (ch->unit << 1) + ATA_DEV(atadev->unit);
+ int devno = (ch->unit << 1) + atadev->unit;
int error;
/* correct the mode for what the HW supports */
@@ -2260,7 +2563,7 @@ ata_ite_setmode(device_t dev, int mode)
/* set UDMA timing */
pci_write_config(gparent,
- 0x56 + (ch->unit << 2) + ATA_DEV(atadev->unit),
+ 0x56 + (ch->unit << 2) + atadev->unit,
udmatiming[mode & ATA_MODE_MASK], 1);
}
else {
@@ -2570,11 +2873,11 @@ ata_marvell_edma_allocate(device_t dev)
{
struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev));
struct ata_channel *ch = device_get_softc(dev);
- u_int64_t work = ch->dma->work_bus;
+ u_int64_t work = ch->dma.work_bus;
int i;
/* clear work area */
- bzero(ch->dma->work, 1024+256);
+ bzero(ch->dma.work, 1024+256);
/* set legacy ATA resources */
for (i = ATA_DATA; i <= ATA_COMMAND; i++) {
@@ -2681,13 +2984,13 @@ static int
ata_marvell_edma_begin_transaction(struct ata_request *request)
{
struct ata_pci_controller *ctlr=device_get_softc(GRANDPARENT(request->dev));
- struct ata_channel *ch = device_get_softc(device_get_parent(request->dev));
+ struct ata_channel *ch = device_get_softc(request->parent);
u_int32_t req_in;
u_int8_t *bytep;
u_int16_t *wordp;
u_int32_t *quadp;
- int i, tag = 0x07;
- int dummy, error, slot;
+ int i;
+ int error, slot;
/* only DMA R/W goes through the EMDA machine */
if (request->u.ata.command != ATA_READ_DMA &&
@@ -2703,9 +3006,7 @@ ata_marvell_edma_begin_transaction(struct ata_request *request)
ata_modify_if_48bit(request);
/* check sanity, setup SG list and DMA engine */
- if ((error = ch->dma->load(ch->dev, request->data, request->bytecount,
- request->flags & ATA_R_READ, ch->dma->sg,
- &dummy))) {
+ if ((error = ch->dma.load(request, NULL, NULL))) {
device_printf(request->dev, "setting up DMA failed\n");
request->result = error;
return ATA_OP_FINISHED;
@@ -2714,15 +3015,15 @@ ata_marvell_edma_begin_transaction(struct ata_request *request)
/* get next free request queue slot */
req_in = ATA_INL(ctlr->r_res1, 0x02014 + ATA_MV_EDMA_BASE(ch));
slot = (((req_in & ~0xfffffc00) >> 5) + 0) & 0x1f;
- bytep = (u_int8_t *)(ch->dma->work);
+ bytep = (u_int8_t *)(ch->dma.work);
bytep += (slot << 5);
wordp = (u_int16_t *)bytep;
quadp = (u_int32_t *)bytep;
/* fill in this request */
- quadp[0] = (long)ch->dma->sg_bus & 0xffffffff;
- quadp[1] = (u_int64_t)ch->dma->sg_bus >> 32;
- wordp[4] = (request->flags & ATA_R_READ ? 0x01 : 0x00) | (tag<<1);
+ quadp[0] = (long)request->dma.sg_bus & 0xffffffff;
+ quadp[1] = (u_int64_t)request->dma.sg_bus >> 32;
+ wordp[4] = (request->flags & ATA_R_READ ? 0x01 : 0x00) | (request->tag<<1);
i = 10;
bytep[i++] = (request->u.ata.count >> 8) & 0xff;
@@ -2773,7 +3074,7 @@ static int
ata_marvell_edma_end_transaction(struct ata_request *request)
{
struct ata_pci_controller *ctlr=device_get_softc(GRANDPARENT(request->dev));
- struct ata_channel *ch = device_get_softc(device_get_parent(request->dev));
+ struct ata_channel *ch = device_get_softc(request->parent);
int offset = (ch->unit > 3 ? 0x30014 : 0x20014);
u_int32_t icr = ATA_INL(ctlr->r_res1, offset);
int res;
@@ -2794,7 +3095,7 @@ ata_marvell_edma_end_transaction(struct ata_request *request)
rsp_out &= 0xffffff00;
rsp_out += (slot << 3);
response = (struct ata_marvell_response *)
- (ch->dma->work + 1024 + (slot << 3));
+ (ch->dma.work + 1024 + (slot << 3));
/* record status for this request */
request->status = response->dev_status;
@@ -2809,7 +3110,7 @@ ata_marvell_edma_end_transaction(struct ata_request *request)
request->donecount = request->bytecount;
/* unload SG list */
- ch->dma->unload(ch->dev);
+ ch->dma.unload(request);
res = ATA_OP_FINISHED;
}
@@ -2880,17 +3181,15 @@ ata_marvell_edma_dmainit(device_t dev)
struct ata_channel *ch = device_get_softc(dev);
ata_dmainit(dev);
- if (ch->dma) {
- /* note start and stop are not used here */
- ch->dma->setprd = ata_marvell_edma_dmasetprd;
+ /* note start and stop are not used here */
+ ch->dma.setprd = ata_marvell_edma_dmasetprd;
- /* if 64bit support present adjust max address used */
- if (ATA_INL(ctlr->r_res1, 0x00d00) & 0x00000004)
- ch->dma->max_address = BUS_SPACE_MAXADDR;
+ /* if 64bit support present adjust max address used */
+ if (ATA_INL(ctlr->r_res1, 0x00d00) & 0x00000004)
+ ch->dma.max_address = BUS_SPACE_MAXADDR;
- /* chip does not reliably do 64K DMA transfers */
- ch->dma->max_iosize = 126 * DEV_BSIZE;
- }
+ /* chip does not reliably do 64K DMA transfers */
+ ch->dma.max_iosize = 126 * DEV_BSIZE;
}
@@ -2929,7 +3228,7 @@ ata_national_setmode(device_t dev, int mode)
device_t gparent = GRANDPARENT(dev);
struct ata_channel *ch = device_get_softc(device_get_parent(dev));
struct ata_device *atadev = device_get_softc(dev);
- int devno = (ch->unit << 1) + ATA_DEV(atadev->unit);
+ int devno = (ch->unit << 1) + atadev->unit;
u_int32_t piotiming[] =
{ 0x9172d132, 0x21717121, 0x00803020, 0x20102010, 0x00100010,
0x00803020, 0x20102010, 0x00100010,
@@ -2938,8 +3237,8 @@ ata_national_setmode(device_t dev, int mode)
u_int32_t udmatiming[] = { 0x80921250, 0x80911140, 0x80911030 };
int error;
- ch->dma->alignment = 16;
- ch->dma->max_iosize = 126 * DEV_BSIZE;
+ ch->dma.alignment = 16;
+ ch->dma.max_iosize = 126 * DEV_BSIZE;
mode = ata_limit_mode(dev, mode, ATA_UDMA2);
@@ -3405,7 +3704,7 @@ sataii:
/* clear SATA status and unmask interrupts */
ATA_OUTL(ctlr->r_res2, stat_reg, 0x000000ff);
- /* enable "long burst lenght" on gen2 chips */
+ /* enable "long burst length" on gen2 chips */
if ((ctlr->chip->cfg2 == PRSATA2) || (ctlr->chip->cfg2 == PRCMBO2))
ATA_OUTL(ctlr->r_res2, 0x44, ATA_INL(ctlr->r_res2, 0x44) | 0x2000);
@@ -3444,41 +3743,41 @@ ata_promise_status(device_t dev)
struct ata_channel *ch = device_get_softc(dev);
if (ATA_INL(ctlr->r_res1, 0x1c) & (ch->unit ? 0x00004000 : 0x00000400)) {
- return ata_pci_status(dev);
+ return ch->hw.status(dev);
}
return 0;
}
static int
-ata_promise_dmastart(device_t dev)
+ata_promise_dmastart(struct ata_request *request)
{
- struct ata_pci_controller *ctlr = device_get_softc(GRANDPARENT(dev));
- struct ata_channel *ch = device_get_softc(device_get_parent(dev));
- struct ata_device *atadev = device_get_softc(dev);
+ struct ata_pci_controller *ctlr=device_get_softc(GRANDPARENT(request->dev));
+ struct ata_channel *ch = device_get_softc(request->parent);
+ struct ata_device *atadev = device_get_softc(request->dev);
if (atadev->flags & ATA_D_48BIT_ACTIVE) {
ATA_OUTB(ctlr->r_res1, 0x11,
ATA_INB(ctlr->r_res1, 0x11) | (ch->unit ? 0x08 : 0x02));
ATA_OUTL(ctlr->r_res1, ch->unit ? 0x24 : 0x20,
- ((ch->dma->flags & ATA_DMA_READ) ? 0x05000000 : 0x06000000) |
- (ch->dma->cur_iosize >> 1));
+ ((request->flags & ATA_R_READ) ? 0x05000000 : 0x06000000) |
+ (request->dma.cur_iosize >> 1));
}
ATA_IDX_OUTB(ch, ATA_BMSTAT_PORT, (ATA_IDX_INB(ch, ATA_BMSTAT_PORT) |
(ATA_BMSTAT_INTERRUPT | ATA_BMSTAT_ERROR)));
- ATA_IDX_OUTL(ch, ATA_BMDTP_PORT, ch->dma->sg_bus);
+ ATA_IDX_OUTL(ch, ATA_BMDTP_PORT, request->dma.sg_bus);
ATA_IDX_OUTB(ch, ATA_BMCMD_PORT,
- ((ch->dma->flags & ATA_DMA_READ) ? ATA_BMCMD_WRITE_READ : 0) |
+ ((request->flags & ATA_R_READ) ? ATA_BMCMD_WRITE_READ : 0) |
ATA_BMCMD_START_STOP);
- ch->flags |= ATA_DMA_ACTIVE;
+ ch->dma.flags |= ATA_DMA_ACTIVE;
return 0;
}
static int
-ata_promise_dmastop(device_t dev)
+ata_promise_dmastop(struct ata_request *request)
{
- struct ata_pci_controller *ctlr = device_get_softc(GRANDPARENT(dev));
- struct ata_channel *ch = device_get_softc(device_get_parent(dev));
- struct ata_device *atadev = device_get_softc(dev);
+ struct ata_pci_controller *ctlr=device_get_softc(GRANDPARENT(request->dev));
+ struct ata_channel *ch = device_get_softc(request->parent);
+ struct ata_device *atadev = device_get_softc(request->dev);
int error;
if (atadev->flags & ATA_D_48BIT_ACTIVE) {
@@ -3490,7 +3789,7 @@ ata_promise_dmastop(device_t dev)
ATA_IDX_OUTB(ch, ATA_BMCMD_PORT,
ATA_IDX_INB(ch, ATA_BMCMD_PORT) & ~ATA_BMCMD_START_STOP);
ATA_IDX_OUTB(ch, ATA_BMSTAT_PORT, ATA_BMSTAT_INTERRUPT | ATA_BMSTAT_ERROR);
- ch->flags &= ~ATA_DMA_ACTIVE;
+ ch->dma.flags &= ~ATA_DMA_ACTIVE;
return error;
}
@@ -3511,11 +3810,9 @@ ata_promise_dmainit(device_t dev)
struct ata_channel *ch = device_get_softc(dev);
ata_dmainit(dev);
- if (ch->dma) {
- ch->dma->start = ata_promise_dmastart;
- ch->dma->stop = ata_promise_dmastop;
- ch->dma->reset = ata_promise_dmareset;
- }
+ ch->dma.start = ata_promise_dmastart;
+ ch->dma.stop = ata_promise_dmastop;
+ ch->dma.reset = ata_promise_dmareset;
}
static void
@@ -3525,7 +3822,7 @@ ata_promise_setmode(device_t dev, int mode)
struct ata_pci_controller *ctlr = device_get_softc(gparent);
struct ata_channel *ch = device_get_softc(device_get_parent(dev));
struct ata_device *atadev = device_get_softc(dev);
- int devno = (ch->unit << 1) + ATA_DEV(atadev->unit);
+ int devno = (ch->unit << 1) + atadev->unit;
int error;
u_int32_t timings[][2] = {
/* PROLD PRNEW mode */
@@ -3613,7 +3910,7 @@ ata_promise_tx2_status(device_t dev)
ATA_IDX_OUTB(ch, ATA_BMDEVSPEC_0, 0x0b);
if (ATA_IDX_INB(ch, ATA_BMDEVSPEC_1) & 0x20) {
- return ata_pci_status(dev);
+ return ch->hw.status(dev);
}
return 0;
}
@@ -3653,6 +3950,9 @@ ata_promise_mio_allocate(device_t dev)
else {
ch->hw.command = ata_promise_mio_command;
ch->hw.status = ata_promise_mio_status;
+ ch->hw.softreset = ata_promise_mio_softreset;
+ ch->hw.pm_read = ata_promise_mio_pm_read;
+ ch->hw.pm_write = ata_promise_mio_pm_write;
}
return 0;
}
@@ -3734,9 +4034,9 @@ ata_promise_mio_status(device_t dev)
M_ATA, M_NOWAIT | M_ZERO))) {
if (bootverbose)
- device_printf(ch->dev, "DISCONNECT requested\n");
+ device_printf(dev, "DISCONNECT requested\n");
tp->action = ATA_C_DETACH;
- tp->dev = ch->dev;
+ tp->dev = dev;
TASK_INIT(&tp->task, 0, ata_sata_phy_event, tp);
taskqueue_enqueue(taskqueue_thread, &tp->task);
}
@@ -3748,9 +4048,9 @@ ata_promise_mio_status(device_t dev)
M_ATA, M_NOWAIT | M_ZERO))) {
if (bootverbose)
- device_printf(ch->dev, "CONNECT requested\n");
+ device_printf(dev, "CONNECT requested\n");
tp->action = ATA_C_ATTACH;
- tp->dev = ch->dev;
+ tp->dev = dev;
TASK_INIT(&tp->task, 0, ata_sata_phy_event, tp);
taskqueue_enqueue(taskqueue_thread, &tp->task);
}
@@ -3763,11 +4063,16 @@ static int
ata_promise_mio_command(struct ata_request *request)
{
struct ata_pci_controller *ctlr=device_get_softc(GRANDPARENT(request->dev));
- struct ata_channel *ch = device_get_softc(device_get_parent(request->dev));
- u_int32_t *wordp = (u_int32_t *)ch->dma->work;
+ struct ata_channel *ch = device_get_softc(request->parent);
+ struct ata_device *atadev = device_get_softc(request->dev);
+
+ u_int32_t *wordp = (u_int32_t *)ch->dma.work;
ATA_OUTL(ctlr->r_res2, (ch->unit + 1) << 2, 0x00000001);
+ /* set portmultiplier port */
+ ATA_OUTB(ctlr->r_res2, 0x4e8 + (ch->unit << 8), atadev->unit & 0x0f);
+
/* XXX SOS add ATAPI commands support later */
switch (request->u.ata.command) {
default:
@@ -3783,11 +4088,11 @@ ata_promise_mio_command(struct ata_request *request)
wordp[0] = htole32(0x00 | ((ch->unit + 1) << 16) | (0x00 << 24));
break;
}
- wordp[1] = htole32(ch->dma->sg_bus);
+ wordp[1] = htole32(request->dma.sg_bus);
wordp[2] = 0;
ata_promise_apkt((u_int8_t*)wordp, request);
- ATA_OUTL(ctlr->r_res2, 0x0240 + (ch->unit << 7), ch->dma->work_bus);
+ ATA_OUTL(ctlr->r_res2, 0x0240 + (ch->unit << 7), ch->dma.work_bus);
return 0;
}
@@ -3856,7 +4161,7 @@ ata_promise_mio_reset(device_t dev)
if ((ctlr->chip->cfg2 == PRSATA2) ||
((ctlr->chip->cfg2 == PRCMBO2) && (ch->unit < 2))) {
/* set portmultiplier port */
- ATA_OUTL(ctlr->r_res2, 0x4e8 + (ch->unit << 8), 0x0f);
+ //ATA_OUTL(ctlr->r_res2, 0x4e8 + (ch->unit << 8), 0x0f);
/* mask plug/unplug intr */
ATA_OUTL(ctlr->r_res2, 0x060, (0x00110000 << ch->unit));
@@ -3877,13 +4182,39 @@ ata_promise_mio_reset(device_t dev)
(ATA_INL(ctlr->r_res2, 0x414 + (ch->unit << 8)) &
~0x00000003) | 0x00000001);
- if (ata_sata_phy_reset(dev))
- ata_generic_reset(dev);
+ if (ata_sata_phy_reset(dev)) {
+ u_int32_t signature = ch->hw.softreset(dev, ATA_PM);
+
+ if (1 | bootverbose)
+ device_printf(dev, "SIGNATURE: %08x\n", signature);
+
+ switch (signature) {
+ case 0x00000101:
+ ch->devices = ATA_ATA_MASTER;
+ break;
+ case 0x96690101:
+ ch->devices = ATA_PORTMULTIPLIER;
+ ata_pm_identify(dev);
+ break;
+ case 0xeb140101:
+ ch->devices = ATA_ATAPI_MASTER;
+ break;
+ default: /* SOS XXX */
+ if (bootverbose)
+ device_printf(dev,
+ "No signature, asuming disk device\n");
+ ch->devices = ATA_ATA_MASTER;
+ }
+ if (bootverbose)
+ device_printf(dev, "promise_mio_reset devices=%08x\n",
+ ch->devices);
+
+ }
/* reset and enable plug/unplug intr */
ATA_OUTL(ctlr->r_res2, 0x060, (0x00000011 << ch->unit));
- /* set portmultiplier port */
+ ///* set portmultiplier port */
ATA_OUTL(ctlr->r_res2, 0x4e8 + (ch->unit << 8), 0x00);
}
else
@@ -3893,15 +4224,127 @@ ata_promise_mio_reset(device_t dev)
}
}
+static int
+ata_promise_mio_pm_read(device_t dev, int port, int reg, u_int32_t *result)
+{
+ struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev));
+ struct ata_channel *ch = device_get_softc(dev);
+ int timeout = 0;
+
+ /* set portmultiplier port */
+ ATA_OUTB(ctlr->r_res2, 0x4e8 + (ch->unit << 8), 0x0f);
+
+ ATA_IDX_OUTB(ch, ATA_FEATURE, reg);
+ ATA_IDX_OUTB(ch, ATA_DRIVE, port);
+
+ ATA_IDX_OUTB(ch, ATA_COMMAND, ATA_READ_PM);
+
+ while (timeout < 1000000) {
+ u_int8_t status = ATA_IDX_INB(ch, ATA_STATUS);
+ if (!(status & ATA_S_BUSY))
+ break;
+ timeout += 1000;
+ DELAY(1000);
+ }
+ if (timeout >= 1000000)
+ return ATA_E_ABORT;
+
+ *result = ATA_IDX_INB(ch, ATA_COUNT) |
+ (ATA_IDX_INB(ch, ATA_SECTOR) << 8) |
+ (ATA_IDX_INB(ch, ATA_CYL_LSB) << 16) |
+ (ATA_IDX_INB(ch, ATA_CYL_MSB) << 24);
+ return 0;
+}
+
+static int
+ata_promise_mio_pm_write(device_t dev, int port, int reg, u_int32_t value)
+{
+ struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev));
+ struct ata_channel *ch = device_get_softc(dev);
+ int timeout = 0;
+
+ /* set portmultiplier port */
+ ATA_OUTB(ctlr->r_res2, 0x4e8 + (ch->unit << 8), 0x0f);
+
+ ATA_IDX_OUTB(ch, ATA_FEATURE, reg);
+ ATA_IDX_OUTB(ch, ATA_DRIVE, port);
+ ATA_IDX_OUTB(ch, ATA_COUNT, value & 0xff);
+ ATA_IDX_OUTB(ch, ATA_SECTOR, (value >> 8) & 0xff);
+ ATA_IDX_OUTB(ch, ATA_CYL_LSB, (value >> 16) & 0xff);
+ ATA_IDX_OUTB(ch, ATA_CYL_MSB, (value >> 24) & 0xff);
+
+ ATA_IDX_OUTB(ch, ATA_COMMAND, ATA_WRITE_PM);
+
+ while (timeout < 1000000) {
+ u_int8_t status = ATA_IDX_INB(ch, ATA_STATUS);
+ if (!(status & ATA_S_BUSY))
+ break;
+ timeout += 1000;
+ DELAY(1000);
+ }
+ if (timeout >= 1000000)
+ return ATA_E_ABORT;
+
+ return ATA_IDX_INB(ch, ATA_ERROR);
+}
+
+/* must be called with ATA channel locked and state_mtx held */
+static u_int32_t
+ata_promise_mio_softreset(device_t dev, int port)
+{
+ struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev));
+ struct ata_channel *ch = device_get_softc(dev);
+ int timeout;
+
+ /* set portmultiplier port */
+ ATA_OUTB(ctlr->r_res2, 0x4e8 + (ch->unit << 8), port & 0x0f);
+
+ /* softreset device on this channel */
+ ATA_IDX_OUTB(ch, ATA_DRIVE, ATA_D_IBM | ATA_D_LBA | ATA_MASTER);
+ DELAY(10);
+ ATA_IDX_OUTB(ch, ATA_CONTROL, ATA_A_IDS | ATA_A_RESET);
+ ata_udelay(10000);
+ ATA_IDX_OUTB(ch, ATA_CONTROL, ATA_A_IDS);
+ ata_udelay(150000);
+ ATA_IDX_INB(ch, ATA_ERROR);
+
+ /* wait for BUSY to go inactive */
+ for (timeout = 0; timeout < 100; timeout++) {
+ u_int8_t err, stat;
+
+ err = ATA_IDX_INB(ch, ATA_ERROR);
+ stat = ATA_IDX_INB(ch, ATA_STATUS);
+
+ //if (stat == err && timeout > (stat & ATA_S_BUSY ? 100 : 10))
+ //break;
+
+ if (!(stat & ATA_S_BUSY)) {
+ //if ((err & 0x7f) == ATA_E_ILI) {
+ return ATA_IDX_INB(ch, ATA_COUNT) |
+ (ATA_IDX_INB(ch, ATA_SECTOR) << 8) |
+ (ATA_IDX_INB(ch, ATA_CYL_LSB) << 16) |
+ (ATA_IDX_INB(ch, ATA_CYL_MSB) << 24);
+ //}
+ //else if (stat & 0x0f) {
+ //stat |= ATA_S_BUSY;
+ //}
+ }
+
+ if (!(stat & ATA_S_BUSY) || (stat == 0xff && timeout > 10))
+ break;
+ ata_udelay(100000);
+ }
+ return -1;
+}
+
static void
ata_promise_mio_dmainit(device_t dev)
{
struct ata_channel *ch = device_get_softc(dev);
- /* note start and stop are not used here */
ata_dmainit(dev);
- if (ch->dma)
- ch->dma->setprd = ata_promise_mio_setprd;
+ /* note start and stop are not used here */
+ ch->dma.setprd = ata_promise_mio_setprd;
}
@@ -3987,8 +4430,8 @@ ata_promise_sx4_command(struct ata_request *request)
{
device_t gparent = GRANDPARENT(request->dev);
struct ata_pci_controller *ctlr = device_get_softc(gparent);
- struct ata_channel *ch = device_get_softc(device_get_parent(request->dev));
- struct ata_dma_prdentry *prd = ch->dma->sg;
+ struct ata_channel *ch = device_get_softc(request->parent);
+ struct ata_dma_prdentry *prd = request->dma.sg;
caddr_t window = rman_get_virtual(ctlr->r_res1);
u_int32_t *wordp;
int i, idx, length = 0;
@@ -4095,7 +4538,7 @@ ata_promise_apkt(u_int8_t *bytep, struct ata_request *request)
int i = 12;
bytep[i++] = ATA_PDC_1B | ATA_PDC_WRITE_REG | ATA_PDC_WAIT_NBUSY|ATA_DRIVE;
- bytep[i++] = ATA_D_IBM | ATA_D_LBA | atadev->unit;
+ bytep[i++] = ATA_D_IBM | ATA_D_LBA | ATA_DEV(atadev->unit);
bytep[i++] = ATA_PDC_1B | ATA_PDC_WRITE_CTL;
bytep[i++] = ATA_A_4BIT;
@@ -4116,7 +4559,7 @@ ata_promise_apkt(u_int8_t *bytep, struct ata_request *request)
bytep[i++] = request->u.ata.lba >> 40;
bytep[i++] = request->u.ata.lba >> 16;
bytep[i++] = ATA_PDC_1B | ATA_PDC_WRITE_REG | ATA_DRIVE;
- bytep[i++] = ATA_D_LBA | atadev->unit;
+ bytep[i++] = ATA_D_LBA | ATA_DEV(atadev->unit);
}
else {
bytep[i++] = ATA_PDC_1B | ATA_PDC_WRITE_REG | ATA_FEATURE;
@@ -4131,7 +4574,8 @@ ata_promise_apkt(u_int8_t *bytep, struct ata_request *request)
bytep[i++] = request->u.ata.lba >> 16;
bytep[i++] = ATA_PDC_1B | ATA_PDC_WRITE_REG | ATA_DRIVE;
bytep[i++] = (atadev->flags & ATA_D_USE_CHS ? 0 : ATA_D_LBA) |
- ATA_D_IBM | atadev->unit | ((request->u.ata.lba >> 24)&0xf);
+ ATA_D_IBM | ATA_DEV(atadev->unit) |
+ ((request->u.ata.lba >> 24)&0xf);
}
bytep[i++] = ATA_PDC_1B | ATA_PDC_WRITE_END | ATA_COMMAND;
bytep[i++] = request->u.ata.command;
@@ -4291,8 +4735,7 @@ ata_serverworks_allocate(device_t dev)
ch->hw.tf_write = ata_serverworks_tf_write;
/* chip does not reliably do 64K DMA transfers */
- if (ch->dma)
- ch->dma->max_iosize = 126 * DEV_BSIZE;
+ ch->dma.max_iosize = 126 * DEV_BSIZE;
return 0;
}
@@ -4300,7 +4743,7 @@ ata_serverworks_allocate(device_t dev)
static void
ata_serverworks_tf_read(struct ata_request *request)
{
- struct ata_channel *ch = device_get_softc(device_get_parent(request->dev));
+ struct ata_channel *ch = device_get_softc(request->parent);
struct ata_device *atadev = device_get_softc(request->dev);
if (atadev->flags & ATA_D_48BIT_ACTIVE) {
@@ -4329,7 +4772,7 @@ ata_serverworks_tf_read(struct ata_request *request)
static void
ata_serverworks_tf_write(struct ata_request *request)
{
- struct ata_channel *ch = device_get_softc(device_get_parent(request->dev));
+ struct ata_channel *ch = device_get_softc(request->parent);
struct ata_device *atadev = device_get_softc(request->dev);
if (atadev->flags & ATA_D_48BIT_ACTIVE) {
@@ -4341,7 +4784,7 @@ ata_serverworks_tf_write(struct ata_request *request)
((request->u.ata.lba >> 8) & 0x00ff));
ATA_IDX_OUTW(ch, ATA_CYL_MSB, ((request->u.ata.lba >> 32) & 0xff00) |
((request->u.ata.lba >> 16) & 0x00ff));
- ATA_IDX_OUTW(ch, ATA_DRIVE, ATA_D_LBA | atadev->unit);
+ ATA_IDX_OUTW(ch, ATA_DRIVE, ATA_D_LBA | ATA_DEV(atadev->unit));
}
else {
ATA_IDX_OUTW(ch, ATA_FEATURE, request->u.ata.feature);
@@ -4362,7 +4805,7 @@ ata_serverworks_tf_write(struct ata_request *request)
(request->u.ata.lba / (sectors * heads)));
ATA_IDX_OUTW(ch, ATA_CYL_MSB,
(request->u.ata.lba / (sectors * heads)) >> 8);
- ATA_IDX_OUTW(ch, ATA_DRIVE, ATA_D_IBM | atadev->unit |
+ ATA_IDX_OUTW(ch, ATA_DRIVE, ATA_D_IBM | ATA_DEV(atadev->unit) |
(((request->u.ata.lba% (sectors * heads)) /
sectors) & 0xf));
}
@@ -4371,7 +4814,7 @@ ata_serverworks_tf_write(struct ata_request *request)
ATA_IDX_OUTW(ch, ATA_CYL_LSB, request->u.ata.lba >> 8);
ATA_IDX_OUTW(ch, ATA_CYL_MSB, request->u.ata.lba >> 16);
ATA_IDX_OUTW(ch, ATA_DRIVE,
- ATA_D_IBM | ATA_D_LBA | atadev->unit |
+ ATA_D_IBM | ATA_D_LBA | ATA_DEV(atadev->unit) |
((request->u.ata.lba >> 24) & 0x0f));
}
}
@@ -4384,7 +4827,7 @@ ata_serverworks_setmode(device_t dev, int mode)
struct ata_pci_controller *ctlr = device_get_softc(gparent);
struct ata_channel *ch = device_get_softc(device_get_parent(dev));
struct ata_device *atadev = device_get_softc(dev);
- int devno = (ch->unit << 1) + ATA_DEV(atadev->unit);
+ int devno = (ch->unit << 1) + atadev->unit;
int offset = (devno ^ 0x01) << 3;
int error;
u_int8_t piotimings[] = { 0x5d, 0x47, 0x34, 0x22, 0x20, 0x34, 0x22, 0x20,
@@ -4585,11 +5028,11 @@ ata_cmd_status(device_t dev)
struct ata_channel *ch = device_get_softc(dev);
u_int8_t reg71;
- if (((reg71 = pci_read_config(device_get_parent(ch->dev), 0x71, 1)) &
+ if (((reg71 = pci_read_config(device_get_parent(dev), 0x71, 1)) &
(ch->unit ? 0x08 : 0x04))) {
- pci_write_config(device_get_parent(ch->dev), 0x71,
+ pci_write_config(device_get_parent(dev), 0x71,
reg71 & ~(ch->unit ? 0x04 : 0x08), 1);
- return ata_pci_status(dev);
+ return ch->hw.status(dev);
}
return 0;
}
@@ -4601,7 +5044,7 @@ ata_cmd_setmode(device_t dev, int mode)
struct ata_pci_controller *ctlr = device_get_softc(gparent);
struct ata_channel *ch = device_get_softc(device_get_parent(dev));
struct ata_device *atadev = device_get_softc(dev);
- int devno = (ch->unit << 1) + ATA_DEV(atadev->unit);
+ int devno = (ch->unit << 1) + atadev->unit;
int error;
mode = ata_limit_mode(dev, mode, ctlr->chip->max_dma);
@@ -4626,7 +5069,7 @@ ata_cmd_setmode(device_t dev, int mode)
u_int8_t umode = pci_read_config(gparent, ureg, 1);
umode &= ~(atadev->unit == ATA_MASTER ? 0x35 : 0xca);
- umode |= udmatimings[mode & ATA_MODE_MASK][ATA_DEV(atadev->unit)];
+ umode |= udmatimings[mode & ATA_MODE_MASK][atadev->unit];
pci_write_config(gparent, ureg, umode, 1);
}
else if (mode >= ATA_WDMA0) {
@@ -4686,10 +5129,10 @@ ata_sii_allocate(device_t dev)
ATA_OUTL(ctlr->r_res2, 0x148 + (unit01 << 7) + (unit10 << 8),(1 << 16));
}
- if ((ctlr->chip->cfg2 & SIIBUG) && ch->dma) {
+ if (ctlr->chip->cfg2 & SIIBUG) {
/* work around errata in early chips */
- ch->dma->boundary = 8192;
- ch->dma->segsize = 15 * DEV_BSIZE;
+ ch->dma.boundary = 8192;
+ ch->dma.segsize = 15 * DEV_BSIZE;
}
ata_pci_hw(dev);
@@ -4711,7 +5154,7 @@ ata_sii_status(device_t dev)
ata_sata_phy_check_events(dev);
if (ATA_INL(ctlr->r_res2, 0xa0 + offset1) & 0x00000800)
- return ata_pci_status(dev);
+ return ch->hw.status(dev);
else
return 0;
}
@@ -4730,9 +5173,9 @@ ata_sii_setmode(device_t dev, int mode)
struct ata_pci_controller *ctlr = device_get_softc(gparent);
struct ata_channel *ch = device_get_softc(device_get_parent(dev));
struct ata_device *atadev = device_get_softc(dev);
- int rego = (ch->unit << 4) + (ATA_DEV(atadev->unit) << 1);
+ int rego = (ch->unit << 4) + (atadev->unit << 1);
int mreg = ch->unit ? 0x84 : 0x80;
- int mask = 0x03 << (ATA_DEV(atadev->unit) << 2);
+ int mask = 0x03 << (atadev->unit << 2);
int mval = pci_read_config(gparent, mreg, 1) & ~mask;
int error;
@@ -4762,7 +5205,7 @@ ata_sii_setmode(device_t dev, int mode)
u_int8_t ureg = 0xac + rego;
pci_write_config(gparent, mreg,
- mval | (0x03 << (ATA_DEV(atadev->unit) << 2)), 1);
+ mval | (0x03 << (atadev->unit << 2)), 1);
pci_write_config(gparent, ureg,
(pci_read_config(gparent, ureg, 1) & ~0x3f) |
udmatimings[mode & ATA_MODE_MASK], 1);
@@ -4773,7 +5216,7 @@ ata_sii_setmode(device_t dev, int mode)
u_int16_t dmatimings[] = { 0x2208, 0x10c2, 0x10c1 };
pci_write_config(gparent, mreg,
- mval | (0x02 << (ATA_DEV(atadev->unit) << 2)), 1);
+ mval | (0x02 << (atadev->unit << 2)), 1);
pci_write_config(gparent, dreg, dmatimings[mode & ATA_MODE_MASK], 2);
}
@@ -4782,7 +5225,7 @@ ata_sii_setmode(device_t dev, int mode)
u_int16_t piotimings[] = { 0x328a, 0x2283, 0x1104, 0x10c3, 0x10c1 };
pci_write_config(gparent, mreg,
- mval | (0x01 << (ATA_DEV(atadev->unit) << 2)), 1);
+ mval | (0x01 << (atadev->unit << 2)), 1);
pci_write_config(gparent, preg, piotimings[mode & ATA_MODE_MASK], 2);
}
atadev->mode = mode;
@@ -4832,10 +5275,14 @@ ata_siiprb_allocate(device_t dev)
ch->r_io[ATA_SACTIVE].res = ctlr->r_res2;
ch->r_io[ATA_SACTIVE].offset = 0x1f0c + offset;
+ ch->hw.status = ata_siiprb_status;
ch->hw.begin_transaction = ata_siiprb_begin_transaction;
ch->hw.end_transaction = ata_siiprb_end_transaction;
- ch->hw.status = ata_siiprb_status;
ch->hw.command = NULL; /* not used here */
+ ch->hw.softreset = ata_siiprb_softreset;
+ ch->hw.pm_read = ata_siiprb_pm_read;
+ ch->hw.pm_write = ata_siiprb_pm_write;
+
return 0;
}
@@ -4866,12 +5313,11 @@ static int
ata_siiprb_begin_transaction(struct ata_request *request)
{
struct ata_pci_controller *ctlr=device_get_softc(GRANDPARENT(request->dev));
- struct ata_channel *ch = device_get_softc(device_get_parent(request->dev));
+ struct ata_channel *ch = device_get_softc(request->parent);
struct ata_siiprb_command *prb;
struct ata_siiprb_dma_prdentry *prd;
int offset = ch->unit * 0x2000;
u_int64_t prb_bus;
- int tag = 0, dummy;
/* SOS XXX */
if (request->u.ata.command == ATA_DEVICE_RESET) {
@@ -4879,12 +5325,9 @@ ata_siiprb_begin_transaction(struct ata_request *request)
return ATA_OP_FINISHED;
}
- /* check for 48 bit access and convert if needed */
- ata_modify_if_48bit(request);
-
/* get a piece of the workspace for this request */
prb = (struct ata_siiprb_command *)
- (ch->dma->work + (sizeof(struct ata_siiprb_command) * tag));
+ (ch->dma.work + (sizeof(struct ata_siiprb_command) * request->tag));
/* set basic prd options ata/atapi etc etc */
bzero(prb, sizeof(struct ata_siiprb_command));
@@ -4916,8 +5359,7 @@ ata_siiprb_begin_transaction(struct ata_request *request)
/* if request moves data setup and load SG list */
if (request->flags & (ATA_R_READ | ATA_R_WRITE)) {
- if (ch->dma->load(ch->dev, request->data, request->bytecount,
- request->flags & ATA_R_READ, prd, &dummy)) {
+ if (ch->dma.load(request, prd, NULL)) {
device_printf(request->dev, "setting up DMA failed\n");
request->result = EIO;
return ATA_OP_FINISHED;
@@ -4925,11 +5367,12 @@ ata_siiprb_begin_transaction(struct ata_request *request)
}
/* activate the prb */
- prb_bus = ch->dma->work_bus + (sizeof(struct ata_siiprb_command) * tag);
+ prb_bus = ch->dma.work_bus +
+ (sizeof(struct ata_siiprb_command) * request->tag);
ATA_OUTL(ctlr->r_res2,
- 0x1c00 + offset + (tag * sizeof(u_int64_t)), prb_bus);
+ 0x1c00 + offset + (request->tag * sizeof(u_int64_t)), prb_bus);
ATA_OUTL(ctlr->r_res2,
- 0x1c04 + offset + (tag * sizeof(u_int64_t)), prb_bus>>32);
+ 0x1c04 + offset + (request->tag * sizeof(u_int64_t)), prb_bus>>32);
/* start the timeout */
callout_reset(&request->callout, request->timeout * hz,
@@ -4941,16 +5384,16 @@ static int
ata_siiprb_end_transaction(struct ata_request *request)
{
struct ata_pci_controller *ctlr=device_get_softc(GRANDPARENT(request->dev));
- struct ata_channel *ch = device_get_softc(device_get_parent(request->dev));
+ struct ata_channel *ch = device_get_softc(request->parent);
struct ata_siiprb_command *prb;
int offset = ch->unit * 0x2000;
- int error, timeout, tag = 0;
+ int error, timeout;
/* kill the timeout */
callout_stop(&request->callout);
prb = (struct ata_siiprb_command *)
- ((u_int8_t *)rman_get_virtual(ctlr->r_res2) + (tag << 7) + offset);
+ ((u_int8_t *)rman_get_virtual(ctlr->r_res2)+(request->tag << 7)+offset);
/* any controller errors flagged ? */
if ((error = ATA_INL(ctlr->r_res2, 0x1024 + offset))) {
@@ -4984,6 +5427,21 @@ ata_siiprb_end_transaction(struct ata_request *request)
}
}
+ /* on control commands read back registers to the request struct */
+ if (request->flags & ATA_R_CONTROL) {
+ struct ata_device *atadev = device_get_softc(request->dev);
+
+ request->u.ata.count = prb->fis[12] | ((u_int16_t)prb->fis[13] << 8);
+ request->u.ata.lba = prb->fis[4] | ((u_int64_t)prb->fis[5] << 8) |
+ ((u_int64_t)prb->fis[6] << 16);
+ if (atadev->flags & ATA_D_48BIT_ACTIVE)
+ request->u.ata.lba |= ((u_int64_t)prb->fis[8] << 24) |
+ ((u_int64_t)prb->fis[9] << 32) |
+ ((u_int64_t)prb->fis[10] << 40);
+ else
+ request->u.ata.lba |= ((u_int64_t)(prb->fis[7] & 0x0f) << 24);
+ }
+
/* update progress */
if (!(request->status & ATA_S_ERROR) && !(request->flags & ATA_R_TIMEOUT)) {
if (request->flags & ATA_R_READ)
@@ -4993,21 +5451,126 @@ ata_siiprb_end_transaction(struct ata_request *request)
}
/* release SG list etc */
- ch->dma->unload(ch->dev);
+ ch->dma.unload(request);
return ATA_OP_FINISHED;
}
+static int
+ata_siiprb_issue_cmd(device_t dev)
+{
+ struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev));
+ struct ata_channel *ch = device_get_softc(dev);
+ u_int64_t prb_bus = ch->dma.work_bus;
+ u_int32_t status;
+ int offset = ch->unit * 0x2000;
+ int timeout;
+
+ /* issue command to chip */
+ ATA_OUTL(ctlr->r_res2, 0x1c00 + offset, prb_bus);
+ ATA_OUTL(ctlr->r_res2, 0x1c04 + offset, prb_bus >> 32);
+
+ /* poll for command finished */
+ for (timeout = 0; timeout < 10000; timeout++) {
+ DELAY(1000);
+ if ((status = ATA_INL(ctlr->r_res2, 0x1008 + offset)) & 0x00010000)
+ break;
+ }
+ ATA_OUTL(ctlr->r_res2, 0x1008 + offset, 0x00010000);
+
+ if (timeout >= 1000)
+ return EIO;
+
+ if (bootverbose)
+ device_printf(dev, "siiprb_issue_cmd time=%dms status=%08x\n",
+ timeout, status);
+ return 0;
+}
+
+static int
+ata_siiprb_pm_read(device_t dev, int port, int reg, u_int32_t *result)
+{
+ struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev));
+ struct ata_channel *ch = device_get_softc(dev);
+ struct ata_siiprb_command *prb = (struct ata_siiprb_command *)ch->dma.work;
+ int offset = ch->unit * 0x2000;
+
+ bzero(prb, sizeof(struct ata_siiprb_command));
+ prb->fis[0] = 0x27; /* host to device */
+ prb->fis[1] = 0x8f; /* command FIS to PM port */
+ prb->fis[2] = ATA_READ_PM;
+ prb->fis[3] = reg;
+ prb->fis[7] = port;
+ if (ata_siiprb_issue_cmd(dev)) {
+ device_printf(dev, "error reading PM port\n");
+ return EIO;
+ }
+ prb = (struct ata_siiprb_command *)
+ ((u_int8_t *)rman_get_virtual(ctlr->r_res2) + offset);
+ *result = prb->fis[12]|(prb->fis[4]<<8)|(prb->fis[5]<<16)|(prb->fis[6]<<24);
+ return 0;
+}
+
+static int
+ata_siiprb_pm_write(device_t dev, int port, int reg, u_int32_t value)
+{
+ struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev));
+ struct ata_channel *ch = device_get_softc(dev);
+ struct ata_siiprb_command *prb = (struct ata_siiprb_command *)ch->dma.work;
+ int offset = ch->unit * 0x2000;
+
+ bzero(prb, sizeof(struct ata_siiprb_command));
+ prb->fis[0] = 0x27; /* host to device */
+ prb->fis[1] = 0x8f; /* command FIS to PM port */
+ prb->fis[2] = ATA_WRITE_PM;
+ prb->fis[3] = reg;
+ prb->fis[7] = port;
+ prb->fis[12] = value & 0xff;
+ prb->fis[4] = (value >> 8) & 0xff;;
+ prb->fis[5] = (value >> 16) & 0xff;;
+ prb->fis[6] = (value >> 24) & 0xff;;
+ if (ata_siiprb_issue_cmd(dev)) {
+ device_printf(dev, "error writing PM port\n");
+ return ATA_E_ABORT;
+ }
+ prb = (struct ata_siiprb_command *)
+ ((u_int8_t *)rman_get_virtual(ctlr->r_res2) + offset);
+ return prb->fis[3];
+}
+
+static u_int32_t
+ata_siiprb_softreset(device_t dev, int port)
+{
+ struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev));
+ struct ata_channel *ch = device_get_softc(dev);
+ struct ata_siiprb_command *prb = (struct ata_siiprb_command *)ch->dma.work;
+ int offset = ch->unit * 0x2000;
+
+ /* setup the workspace for a soft reset command */
+ bzero(prb, sizeof(struct ata_siiprb_command));
+ prb->control = htole16(0x0080);
+ prb->fis[1] = port & 0x0f;
+
+ /* issue soft reset */
+ if (ata_siiprb_issue_cmd(dev))
+ return -1;
+
+ ata_udelay(150000);
+
+ /* return possible signature */
+ prb = (struct ata_siiprb_command *)
+ ((u_int8_t *)rman_get_virtual(ctlr->r_res2) + offset);
+ return prb->fis[12]|(prb->fis[4]<<8)|(prb->fis[5]<<16)|(prb->fis[6]<<24);
+}
+
static void
ata_siiprb_reset(device_t dev)
{
struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev));
struct ata_channel *ch = device_get_softc(dev);
int offset = ch->unit * 0x2000;
- struct ata_siiprb_command *prb;
- u_int64_t prb_bus;
u_int32_t status, signature;
- int timeout, tag = 0;
+ int timeout;
/* reset channel HW */
ATA_OUTL(ctlr->r_res2, 0x1000 + offset, 0x00000001);
@@ -5024,62 +5587,33 @@ ata_siiprb_reset(device_t dev)
if (bootverbose) {
if (timeout >= 1000)
- device_printf(ch->dev, "channel HW reset timeout\n");
+ device_printf(dev, "channel HW reset timeout\n");
else
- device_printf(ch->dev, "channel HW reset time=%dms\n", timeout);
+ device_printf(dev, "channel HW reset time=%dms\n", timeout);
}
/* reset phy */
if (!ata_sata_phy_reset(dev)) {
if (bootverbose)
- device_printf(ch->dev, "phy reset found no device\n");
+ device_printf(dev, "phy reset found no device\n");
ch->devices = 0;
goto finish;
}
- /* get a piece of the workspace for a soft reset request */
- prb = (struct ata_siiprb_command *)
- (ch->dma->work + (sizeof(struct ata_siiprb_command) * tag));
- bzero(prb, sizeof(struct ata_siiprb_command));
- prb->control = htole16(0x0080);
-
- /* activate the soft reset prb */
- prb_bus = ch->dma->work_bus + (sizeof(struct ata_siiprb_command) * tag);
- ATA_OUTL(ctlr->r_res2,
- 0x1c00 + offset + (tag * sizeof(u_int64_t)), prb_bus);
- ATA_OUTL(ctlr->r_res2,
- 0x1c04 + offset + (tag * sizeof(u_int64_t)), prb_bus>>32);
-
- /* poll for command finished */
- for (timeout = 0; timeout < 10000; timeout++) {
- DELAY(1000);
- if ((status = ATA_INL(ctlr->r_res2, 0x1008 + offset)) & 0x00010000)
- break;
- }
- if (timeout >= 1000) {
- device_printf(ch->dev, "reset timeout - no device found\n");
- ch->devices = 0;
- goto finish;
- }
+ /* issue soft reset */
+ signature = ata_siiprb_softreset(dev, ATA_PM);
if (bootverbose)
- device_printf(ch->dev, "soft reset exec time=%dms status=%08x\n",
- timeout, status);
+ device_printf(dev, "SIGNATURE=%08x\n", signature);
- /* find out whats there */
- prb = (struct ata_siiprb_command *)
- ((u_int8_t *)rman_get_virtual(ctlr->r_res2) + (tag << 7) + offset);
- signature =
- prb->fis[12]|(prb->fis[4]<<8)|(prb->fis[5]<<16)|(prb->fis[6]<<24);
- if (bootverbose)
- device_printf(ch->dev, "SIGNATURE=%08x\n", signature);
+ /* figure out whats there */
switch (signature) {
case 0x00000101:
ch->devices = ATA_ATA_MASTER;
break;
case 0x96690101:
ch->devices = ATA_PORTMULTIPLIER;
- device_printf(ch->dev, "Portmultipliers not supported yet\n");
- ch->devices = 0;
+ ATA_OUTL(ctlr->r_res2, 0x1000 + offset, 0x2000); /* enable PM support */
+ ata_pm_identify(dev);
break;
case 0xeb140101:
ch->devices = ATA_ATAPI_MASTER;
@@ -5088,8 +5622,7 @@ ata_siiprb_reset(device_t dev)
ch->devices = 0;
}
if (bootverbose)
- device_printf(dev, "siiprb_reset devices=0x%b\n", ch->devices,
- "\20\4ATAPI_SLAVE\3ATAPI_MASTER\2ATA_SLAVE\1ATA_MASTER");
+ device_printf(dev, "siiprb_reset devices=%08x\n", ch->devices);
finish:
/* clear interrupt(s) */
@@ -5130,11 +5663,9 @@ ata_siiprb_dmainit(device_t dev)
struct ata_channel *ch = device_get_softc(dev);
ata_dmainit(dev);
- if (ch->dma) {
- /* note start and stop are not used here */
- ch->dma->setprd = ata_siiprb_dmasetprd;
- ch->dma->max_address = BUS_SPACE_MAXADDR;
- }
+ /* note start and stop are not used here */
+ ch->dma.setprd = ata_siiprb_dmasetprd;
+ ch->dma.max_address = BUS_SPACE_MAXADDR;
}
@@ -5305,7 +5836,7 @@ ata_sis_setmode(device_t dev, int mode)
struct ata_pci_controller *ctlr = device_get_softc(gparent);
struct ata_channel *ch = device_get_softc(device_get_parent(dev));
struct ata_device *atadev = device_get_softc(dev);
- int devno = (ch->unit << 1) + ATA_DEV(atadev->unit);
+ int devno = (ch->unit << 1) + atadev->unit;
int error;
mode = ata_limit_mode(dev, mode, ctlr->chip->max_dma);
@@ -5630,7 +6161,7 @@ ata_via_family_setmode(device_t dev, int mode)
{ 0xf7, 0xf6, 0xf4, 0xf2, 0xf1, 0xf0, 0x00 }, /* VIA ATA100 */
{ 0xf7, 0xf7, 0xf6, 0xf4, 0xf2, 0xf1, 0xf0 }, /* VIA ATA133 */
{ 0xc2, 0xc1, 0xc0, 0xc4, 0xc5, 0xc6, 0xc7 }}; /* AMD/nVIDIA */
- int devno = (ch->unit << 1) + ATA_DEV(atadev->unit);
+ int devno = (ch->unit << 1) + atadev->unit;
int reg = 0x53 - devno;
int error;
@@ -5784,7 +6315,7 @@ ata_serialize(device_t dev, int flags)
if ((ch = ctlr->interrupt[serial->restart_ch].argument)) {
serial->restart_ch = -1;
mtx_unlock(&serial->locked_mtx);
- ata_start(ch->dev);
+ ata_start(dev);
return -1;
}
}
OpenPOWER on IntegriCloud