summaryrefslogtreecommitdiffstats
path: root/sys/dev/ata/ata-all.c
diff options
context:
space:
mode:
authormav <mav@FreeBSD.org>2010-10-18 11:30:13 +0000
committermav <mav@FreeBSD.org>2010-10-18 11:30:13 +0000
commitd5157b74694d4a37a03c0245b1681f20321cd062 (patch)
treefd926a601552c1bcf585c33dddb137654dc80a3f /sys/dev/ata/ata-all.c
parentc2ef20d77bba663f8ce180c864d82fee39cb3482 (diff)
downloadFreeBSD-src-d5157b74694d4a37a03c0245b1681f20321cd062.zip
FreeBSD-src-d5157b74694d4a37a03c0245b1681f20321cd062.tar.gz
Set of legacy mode SATA enchancements:
- Implement proper combined mode decoding for Intel controllers to properly identify SATA and PATA channels and associate ATA channels with SATA ports. This fixes wrong reporting and in some cases hard resets to wrong SATA ports. - Improve SATA registers support to handle hot-plug events and potentially interface errors. For ICH5/6300ESB chipsets these registers accessible via PCI config space. For later ones they may be accessible via PCI BAR(5). - For controllers not generating interrupts on hot-plug events, implement periodic status polling. Use it to detect hot-plug on Intel and VIA controllers. Same probably could also be used for Serverworks and SIS.
Diffstat (limited to 'sys/dev/ata/ata-all.c')
-rw-r--r--sys/dev/ata/ata-all.c21
1 files changed, 21 insertions, 0 deletions
diff --git a/sys/dev/ata/ata-all.c b/sys/dev/ata/ata-all.c
index 8c0ea9d..f40dcc2 100644
--- a/sys/dev/ata/ata-all.c
+++ b/sys/dev/ata/ata-all.c
@@ -83,6 +83,7 @@ static void bswap(int8_t *, int);
static void btrim(int8_t *, int);
static void bpack(int8_t *, int8_t *, int);
static void ata_interrupt_locked(void *data);
+static void ata_periodic_poll(void *data);
/* global vars */
MALLOC_DEFINE(M_ATA, "ata_generic", "ATA driver generic layer");
@@ -173,6 +174,7 @@ ata_attach(device_t dev)
ch->curr[i] = ch->user[i];
}
#endif
+ callout_init(&ch->poll_callout, 1);
/* reset the controller HW, the channel and device(s) */
while (ATA_LOCKING(dev, ATA_LF_LOCK) != ch->unit)
@@ -200,6 +202,8 @@ ata_attach(device_t dev)
device_printf(dev, "unable to setup interrupt\n");
return error;
}
+ if (ch->flags & ATA_PERIODIC_POLL)
+ callout_reset(&ch->poll_callout, hz, ata_periodic_poll, ch);
#ifndef ATA_CAM
/* probe and attach devices on this channel unless we are in early boot */
@@ -246,6 +250,8 @@ err2:
err1:
bus_release_resource(dev, SYS_RES_IRQ, rid, ch->r_irq);
mtx_unlock(&ch->state_mtx);
+ if (ch->flags & ATA_PERIODIC_POLL)
+ callout_drain(&ch->poll_callout);
return (error);
#endif
}
@@ -267,6 +273,8 @@ ata_detach(device_t dev)
mtx_lock(&ch->state_mtx);
ch->state |= ATA_STALL_QUEUE;
mtx_unlock(&ch->state_mtx);
+ if (ch->flags & ATA_PERIODIC_POLL)
+ callout_drain(&ch->poll_callout);
#ifndef ATA_CAM
/* detach & delete all children */
@@ -454,6 +462,8 @@ ata_suspend(device_t dev)
if (!dev || !(ch = device_get_softc(dev)))
return ENXIO;
+ if (ch->flags & ATA_PERIODIC_POLL)
+ callout_drain(&ch->poll_callout);
#ifdef ATA_CAM
mtx_lock(&ch->state_mtx);
xpt_freeze_simq(ch->sim, 1);
@@ -498,6 +508,8 @@ ata_resume(device_t dev)
/* kick off requests on the queue */
ata_start(dev);
#endif
+ if (ch->flags & ATA_PERIODIC_POLL)
+ callout_reset(&ch->poll_callout, hz, ata_periodic_poll, ch);
return error;
}
@@ -564,6 +576,15 @@ ata_interrupt_locked(void *data)
#endif
}
+static void
+ata_periodic_poll(void *data)
+{
+ struct ata_channel *ch = (struct ata_channel *)data;
+
+ callout_reset(&ch->poll_callout, hz, ata_periodic_poll, ch);
+ ata_interrupt(ch);
+}
+
void
ata_print_cable(device_t dev, u_int8_t *who)
{
OpenPOWER on IntegriCloud