summaryrefslogtreecommitdiffstats
path: root/sys/dev/ahci
diff options
context:
space:
mode:
authormav <mav@FreeBSD.org>2010-01-28 08:41:30 +0000
committermav <mav@FreeBSD.org>2010-01-28 08:41:30 +0000
commit72062fdcece91a123423691068781de9366fbfaa (patch)
treed7388e60da90bf39b478369ea46d12722c323f78 /sys/dev/ahci
parent973b5fa5f2d400701ce9699f4118bd6ccc5a418c (diff)
downloadFreeBSD-src-72062fdcece91a123423691068781de9366fbfaa.zip
FreeBSD-src-72062fdcece91a123423691068781de9366fbfaa.tar.gz
MFp4: Large set of CAM inprovements.
- Unify bus reset/probe sequence. Whenever bus attached at boot or later, CAM will automatically reset and scan it. It allows to remove duplicate code from many drivers. - Any bus, attached before CAM completed it's boot-time initialization, will equally join to the process, delaying boot if needed. - New kern.cam.boot_delay loader tunable should help controllers that are still unable to register their buses in time (such as slow USB/ PCCard/ CardBus devices), by adding one more event to wait on boot. - To allow synchronization between different CAM levels, concept of requests priorities was extended. Priorities now split between several "run levels". Device can be freezed at specified level, allowing higher priority requests to pass. For example, no payload requests allowed, until PMP driver enable port. ATA XPT negotiate transfer parameters, periph driver configure caching and so on. - Frozen requests are no more counted by request allocation scheduler. It fixes deadlocks, when frozen low priority payload requests occupying slots, required by higher levels to manage theit execution. - Two last changes were holding proper ATA reinitialization and error recovery implementation. Now it is done: SATA controllers and Port Multipliers now implement automatic hot-plug and should correctly recover from timeouts and bus resets. - Improve SCSI error recovery for devices on buses without automatic sense reporting, such as ATAPI or USB. For example, it allows CAM to wait, while CD drive loads disk, instead of immediately return error status. - Decapitalize diagnostic messages and make them more readable and sensible. - Teach PMP driver to limit maximum speed on fan-out ports. - Make boot wait for PMP scan completes, and make rescan more reliable. - Fix pass driver, to return CCB to user level in case of error. - Increase number of retries in cd driver, as device may return several UAs.
Diffstat (limited to 'sys/dev/ahci')
-rw-r--r--sys/dev/ahci/ahci.c55
-rw-r--r--sys/dev/ahci/ahci.h15
2 files changed, 54 insertions, 16 deletions
diff --git a/sys/dev/ahci/ahci.c b/sys/dev/ahci/ahci.c
index 789a8aa..ecff8a0 100644
--- a/sys/dev/ahci/ahci.c
+++ b/sys/dev/ahci/ahci.c
@@ -52,7 +52,6 @@ __FBSDID("$FreeBSD$");
#include <cam/cam_ccb.h>
#include <cam/cam_sim.h>
#include <cam/cam_xpt_sim.h>
-#include <cam/cam_xpt_periph.h>
#include <cam/cam_debug.h>
/* local prototypes */
@@ -86,7 +85,7 @@ static void ahci_start_fr(device_t dev);
static void ahci_stop_fr(device_t dev);
static int ahci_sata_connect(struct ahci_channel *ch);
-static int ahci_sata_phy_reset(device_t dev, int quick);
+static int ahci_sata_phy_reset(device_t dev);
static void ahci_issue_read_log(device_t dev);
static void ahci_process_read_log(device_t dev, union ccb *ccb);
@@ -348,6 +347,8 @@ ahci_attach(device_t dev)
ctlr->caps = ATA_INL(ctlr->r_mem, AHCI_CAP);
if (version >= 0x00010020)
ctlr->caps2 = ATA_INL(ctlr->r_mem, AHCI_CAP2);
+ if (ctlr->caps & AHCI_CAP_EMS)
+ ctlr->capsem = ATA_INL(ctlr->r_mem, AHCI_EM_CTL);
ctlr->ichannels = ATA_INL(ctlr->r_mem, AHCI_PI);
if (ctlr->quirks & AHCI_Q_1CH) {
ctlr->caps &= ~AHCI_CAP_NPMASK;
@@ -417,6 +418,17 @@ ahci_attach(device_t dev)
(ctlr->caps2 & AHCI_CAP2_NVMP) ? " NVMP":"",
(ctlr->caps2 & AHCI_CAP2_BOH) ? " BOH":"");
}
+ if (bootverbose && (ctlr->caps & AHCI_CAP_EMS)) {
+ device_printf(dev, "EM Caps: %s%s%s%s%s%s%s%s\n",
+ (ctlr->capsem & AHCI_EM_PM) ? " PM":"",
+ (ctlr->capsem & AHCI_EM_ALHD) ? " ALHD":"",
+ (ctlr->capsem & AHCI_EM_XMT) ? " XMT":"",
+ (ctlr->capsem & AHCI_EM_SMB) ? " SMB":"",
+ (ctlr->capsem & AHCI_EM_SGPIO) ? " SGPIO":"",
+ (ctlr->capsem & AHCI_EM_SES2) ? " SES-2":"",
+ (ctlr->capsem & AHCI_EM_SAFTE) ? " SAF-TE":"",
+ (ctlr->capsem & AHCI_EM_LED) ? " LED":"");
+ }
/* Attach all channels on this controller */
for (unit = 0; unit < ctlr->channels; unit++) {
if ((ctlr->ichannels & (1 << unit)) == 0)
@@ -1131,6 +1143,8 @@ ahci_phy_check_events(device_t dev, u_int32_t serr)
if ((serr & ATA_SE_PHY_CHANGED) && (ch->pm_level == 0)) {
u_int32_t status = ATA_INL(ch->r_mem, AHCI_P_SSTS);
+ union ccb *ccb;
+
if (((status & ATA_SS_DET_MASK) == ATA_SS_DET_PHY_ONLINE) &&
((status & ATA_SS_SPD_MASK) != ATA_SS_SPD_NO_SPEED) &&
((status & ATA_SS_IPM_MASK) == ATA_SS_IPM_ACTIVE)) {
@@ -1142,6 +1156,15 @@ ahci_phy_check_events(device_t dev, u_int32_t serr)
device_printf(dev, "DISCONNECT requested\n");
ch->devices = 0;
}
+ if ((ccb = xpt_alloc_ccb_nowait()) == NULL)
+ return;
+ if (xpt_create_path(&ccb->ccb_h.path, NULL,
+ cam_sim_path(ch->sim),
+ CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD) != CAM_REQ_CMP) {
+ xpt_free_ccb(ccb);
+ return;
+ }
+ xpt_rescan(ccb);
}
}
@@ -1511,6 +1534,13 @@ ahci_execute_transaction(struct ahci_slot *slot)
if (timeout && (count >= timeout)) {
device_printf(ch->dev,
"Poll timeout on slot %d\n", slot->slot);
+ device_printf(dev, "is %08x cs %08x ss %08x "
+ "rs %08x tfd %02x serr %08x\n",
+ ATA_INL(ch->r_mem, AHCI_P_IS),
+ ATA_INL(ch->r_mem, AHCI_P_CI),
+ ATA_INL(ch->r_mem, AHCI_P_SACT), ch->rslots,
+ ATA_INL(ch->r_mem, AHCI_P_TFD),
+ ATA_INL(ch->r_mem, AHCI_P_SERR));
et = AHCI_ERR_TIMEOUT;
}
if (et != AHCI_ERR_NONE) {
@@ -1935,7 +1965,7 @@ ahci_wait_ready(device_t dev, int t)
(ATA_S_BUSY | ATA_S_DRQ)) {
DELAY(1000);
if (timeout++ > t) {
- device_printf(dev, "port is not ready (timeout %dms) "
+ device_printf(dev, "device is not ready (timeout %dms) "
"tfd = %08x\n", t, val);
return (EBUSY);
}
@@ -1952,6 +1982,7 @@ ahci_reset(device_t dev)
struct ahci_controller *ctlr = device_get_softc(device_get_parent(dev));
int i;
+ xpt_freeze_simq(ch->sim, 1);
if (bootverbose)
device_printf(dev, "AHCI reset...\n");
/* Requeue freezed command. */
@@ -1986,7 +2017,7 @@ ahci_reset(device_t dev)
/* Disable port interrupts */
ATA_OUTL(ch->r_mem, AHCI_P_IE, 0);
/* Reset and reconnect PHY, */
- if (!ahci_sata_phy_reset(dev, 0)) {
+ if (!ahci_sata_phy_reset(dev)) {
if (bootverbose)
device_printf(dev,
"AHCI reset done: phy reset found no device\n");
@@ -1994,13 +2025,12 @@ ahci_reset(device_t dev)
/* Enable wanted port interrupts */
ATA_OUTL(ch->r_mem, AHCI_P_IE,
(AHCI_P_IX_CPD | AHCI_P_IX_PRC | AHCI_P_IX_PC));
+ xpt_release_simq(ch->sim, TRUE);
return;
}
/* Wait for clearing busy status. */
- if (ahci_wait_ready(dev, 10000)) {
- device_printf(dev, "device ready timeout\n");
+ if (ahci_wait_ready(dev, 15000))
ahci_clo(dev);
- }
ahci_start(dev);
ch->devices = 1;
/* Enable wanted port interrupts */
@@ -2012,6 +2042,7 @@ ahci_reset(device_t dev)
AHCI_P_IX_DS | AHCI_P_IX_PS | (ctlr->ccc ? 0 : AHCI_P_IX_DHR)));
if (bootverbose)
device_printf(dev, "AHCI reset done: device found\n");
+ xpt_release_simq(ch->sim, TRUE);
}
static int
@@ -2104,20 +2135,12 @@ ahci_sata_connect(struct ahci_channel *ch)
}
static int
-ahci_sata_phy_reset(device_t dev, int quick)
+ahci_sata_phy_reset(device_t dev)
{
struct ahci_channel *ch = device_get_softc(dev);
int sata_rev;
uint32_t val;
- if (quick) {
- val = ATA_INL(ch->r_mem, AHCI_P_SCTL);
- if ((val & ATA_SC_DET_MASK) == ATA_SC_DET_IDLE)
- return (ahci_sata_connect(ch));
- }
-
- if (bootverbose)
- device_printf(dev, "hardware reset ...\n");
sata_rev = ch->user[ch->pm_present ? 15 : 0].revision;
if (sata_rev == 1)
val = ATA_SC_SPD_SPEED_GEN1;
diff --git a/sys/dev/ahci/ahci.h b/sys/dev/ahci/ahci.h
index e11f84f..d136d82 100644
--- a/sys/dev/ahci/ahci.h
+++ b/sys/dev/ahci/ahci.h
@@ -186,6 +186,20 @@
#define AHCI_CCCC_EN 0x00000001
#define AHCI_CCCP 0x18
+#define AHCI_EM_LOC 0x1C
+#define AHCI_EM_CTL 0x20
+#define AHCI_EM_MR 0x00000001
+#define AHCI_EM_TM 0x00000100
+#define AHCI_EM_RST 0x00000200
+#define AHCI_EM_LED 0x00010000
+#define AHCI_EM_SAFTE 0x00020000
+#define AHCI_EM_SES2 0x00040000
+#define AHCI_EM_SGPIO 0x00080000
+#define AHCI_EM_SMB 0x01000000
+#define AHCI_EM_XMT 0x02000000
+#define AHCI_EM_ALHD 0x04000000
+#define AHCI_EM_PM 0x08000000
+
#define AHCI_CAP2 0x24
#define AHCI_CAP2_BOH 0x00000001
#define AHCI_CAP2_NVMP 0x00000002
@@ -402,6 +416,7 @@ struct ahci_controller {
} irqs[16];
uint32_t caps; /* Controller capabilities */
uint32_t caps2; /* Controller capabilities */
+ uint32_t capsem; /* Controller capabilities */
int quirks;
int numirqs;
int channels;
OpenPOWER on IntegriCloud