|
Lines 1-1068
Link Here
|
| 1 |
/*- |
|
|
| 2 |
* Copyright (c) 1998 - 2008 Søren Schmidt <sos@FreeBSD.org> |
| 3 |
* All rights reserved. |
| 4 |
* |
| 5 |
* Redistribution and use in source and binary forms, with or without |
| 6 |
* modification, are permitted provided that the following conditions |
| 7 |
* are met: |
| 8 |
* 1. Redistributions of source code must retain the above copyright |
| 9 |
* notice, this list of conditions and the following disclaimer, |
| 10 |
* without modification, immediately at the beginning of the file. |
| 11 |
* 2. Redistributions in binary form must reproduce the above copyright |
| 12 |
* notice, this list of conditions and the following disclaimer in the |
| 13 |
* documentation and/or other materials provided with the distribution. |
| 14 |
* |
| 15 |
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR |
| 16 |
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
| 17 |
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. |
| 18 |
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, |
| 19 |
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
| 20 |
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| 21 |
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| 22 |
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| 23 |
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
| 24 |
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| 25 |
*/ |
| 26 |
|
| 27 |
#include <sys/cdefs.h> |
| 28 |
__FBSDID("$FreeBSD$"); |
| 29 |
|
| 30 |
#include <sys/param.h> |
| 31 |
#include <sys/module.h> |
| 32 |
#include <sys/systm.h> |
| 33 |
#include <sys/kernel.h> |
| 34 |
#include <sys/ata.h> |
| 35 |
#include <sys/bus.h> |
| 36 |
#include <sys/endian.h> |
| 37 |
#include <sys/malloc.h> |
| 38 |
#include <sys/lock.h> |
| 39 |
#include <sys/mutex.h> |
| 40 |
#include <sys/sema.h> |
| 41 |
#include <sys/taskqueue.h> |
| 42 |
#include <vm/uma.h> |
| 43 |
#include <machine/stdarg.h> |
| 44 |
#include <machine/resource.h> |
| 45 |
#include <machine/bus.h> |
| 46 |
#include <sys/rman.h> |
| 47 |
#include <dev/pci/pcivar.h> |
| 48 |
#include <dev/pci/pcireg.h> |
| 49 |
#include <dev/ata/ata-all.h> |
| 50 |
#include <dev/ata/ata-pci.h> |
| 51 |
#include <ata_if.h> |
| 52 |
|
| 53 |
/* local prototypes */ |
| 54 |
static int ata_ahci_ch_attach(device_t dev); |
| 55 |
static int ata_ahci_ch_detach(device_t dev); |
| 56 |
static int ata_ahci_ch_suspend(device_t dev); |
| 57 |
static int ata_ahci_ch_resume(device_t dev); |
| 58 |
static int ata_ahci_ctlr_reset(device_t dev); |
| 59 |
static void ata_ahci_reset(device_t dev); |
| 60 |
static int ata_ahci_suspend(device_t dev); |
| 61 |
static int ata_ahci_status(device_t dev); |
| 62 |
static int ata_ahci_begin_transaction(struct ata_request *request); |
| 63 |
static int ata_ahci_end_transaction(struct ata_request *request); |
| 64 |
static int ata_ahci_pm_read(device_t dev, int port, int reg, u_int32_t *result); |
| 65 |
static int ata_ahci_pm_write(device_t dev, int port, int reg, u_int32_t result); |
| 66 |
static int ata_ahci_hardreset(device_t dev, int port, uint32_t *signature); |
| 67 |
static u_int32_t ata_ahci_softreset(device_t dev, int port); |
| 68 |
static void ata_ahci_dmasetprd(void *xsc, bus_dma_segment_t *segs, int nsegs, int error); |
| 69 |
static int ata_ahci_setup_fis(struct ata_ahci_cmd_tab *ctp, struct ata_request *equest); |
| 70 |
static void ata_ahci_dmainit(device_t dev); |
| 71 |
static void ata_ahci_start(device_t dev); |
| 72 |
static void ata_ahci_stop(device_t dev); |
| 73 |
static void ata_ahci_clo(device_t dev); |
| 74 |
static void ata_ahci_start_fr(device_t dev); |
| 75 |
static void ata_ahci_stop_fr(device_t dev); |
| 76 |
|
| 77 |
/* |
| 78 |
* AHCI v1.x compliant SATA chipset support functions |
| 79 |
*/ |
| 80 |
static int |
| 81 |
ata_ahci_probe(device_t dev) |
| 82 |
{ |
| 83 |
struct ata_pci_controller *ctlr = device_get_softc(dev); |
| 84 |
char buffer[64]; |
| 85 |
|
| 86 |
/* is this a possible AHCI candidate ? */ |
| 87 |
if (pci_get_class(dev) != PCIC_STORAGE || |
| 88 |
pci_get_subclass(dev) != PCIS_STORAGE_SATA) |
| 89 |
return (ENXIO); |
| 90 |
|
| 91 |
/* is this PCI device flagged as an AHCI compliant chip ? */ |
| 92 |
if (pci_get_progif(dev) != PCIP_STORAGE_SATA_AHCI_1_0) |
| 93 |
return (ENXIO); |
| 94 |
|
| 95 |
if (bootverbose) |
| 96 |
sprintf(buffer, "%s (ID=%08x) AHCI controller", |
| 97 |
ata_pcivendor2str(dev), pci_get_devid(dev)); |
| 98 |
else |
| 99 |
sprintf(buffer, "%s AHCI controller", ata_pcivendor2str(dev)); |
| 100 |
device_set_desc_copy(dev, buffer); |
| 101 |
ctlr->chipinit = ata_ahci_chipinit; |
| 102 |
return (BUS_PROBE_GENERIC); |
| 103 |
} |
| 104 |
|
| 105 |
static int |
| 106 |
ata_ahci_ata_probe(device_t dev) |
| 107 |
{ |
| 108 |
struct ata_pci_controller *ctlr = device_get_softc(dev); |
| 109 |
|
| 110 |
if ((intptr_t)device_get_ivars(dev) >= 0) |
| 111 |
return (ENXIO); |
| 112 |
device_set_desc_copy(dev, "AHCI SATA controller"); |
| 113 |
ctlr->chipinit = ata_ahci_chipinit; |
| 114 |
return (BUS_PROBE_GENERIC); |
| 115 |
} |
| 116 |
|
| 117 |
static int |
| 118 |
ata_ahci_ata_attach(device_t dev) |
| 119 |
{ |
| 120 |
struct ata_pci_controller *ctlr = device_get_softc(dev); |
| 121 |
device_t child; |
| 122 |
int unit; |
| 123 |
|
| 124 |
/* do chipset specific setups only needed once */ |
| 125 |
ctlr->legacy = 0; |
| 126 |
ctlr->ichannels = -1; |
| 127 |
ctlr->ch_attach = ata_pci_ch_attach; |
| 128 |
ctlr->ch_detach = ata_pci_ch_detach; |
| 129 |
ctlr->dev = dev; |
| 130 |
if (ctlr->chipinit(dev)) |
| 131 |
return ENXIO; |
| 132 |
/* attach all channels on this controller */ |
| 133 |
for (unit = 0; unit < ctlr->channels; unit++) { |
| 134 |
if ((ctlr->ichannels & (1 << unit)) == 0) |
| 135 |
continue; |
| 136 |
child = device_add_child(dev, "ata", |
| 137 |
((unit == 0 || unit == 1) && ctlr->legacy) ? |
| 138 |
unit : devclass_find_free_unit(ata_devclass, 2)); |
| 139 |
if (child == NULL) |
| 140 |
device_printf(dev, "failed to add ata child device\n"); |
| 141 |
else |
| 142 |
device_set_ivars(child, (void *)(intptr_t)unit); |
| 143 |
} |
| 144 |
bus_generic_attach(dev); |
| 145 |
return 0; |
| 146 |
} |
| 147 |
|
| 148 |
int |
| 149 |
ata_ahci_chipinit(device_t dev) |
| 150 |
{ |
| 151 |
struct ata_pci_controller *ctlr = device_get_softc(dev); |
| 152 |
int error, speed; |
| 153 |
u_int32_t caps, version; |
| 154 |
|
| 155 |
/* if we have a memory BAR(5) we are likely on an AHCI part */ |
| 156 |
ctlr->r_type2 = SYS_RES_MEMORY; |
| 157 |
ctlr->r_rid2 = PCIR_BAR(5); |
| 158 |
if (!(ctlr->r_res2 = bus_alloc_resource_any(dev, ctlr->r_type2, |
| 159 |
&ctlr->r_rid2, RF_ACTIVE))) |
| 160 |
return ENXIO; |
| 161 |
|
| 162 |
/* setup interrupt delivery if not done allready by a vendor driver */ |
| 163 |
if (!ctlr->r_irq) { |
| 164 |
if (ata_setup_interrupt(dev, ata_generic_intr)) { |
| 165 |
bus_release_resource(dev, ctlr->r_type2, ctlr->r_rid2, ctlr->r_res2); |
| 166 |
return ENXIO; |
| 167 |
} |
| 168 |
} |
| 169 |
else |
| 170 |
device_printf(dev, "AHCI called from vendor specific driver\n"); |
| 171 |
|
| 172 |
/* reset controller */ |
| 173 |
if ((error = ata_ahci_ctlr_reset(dev)) != 0) { |
| 174 |
bus_release_resource(dev, ctlr->r_type2, ctlr->r_rid2, ctlr->r_res2); |
| 175 |
return (error); |
| 176 |
}; |
| 177 |
|
| 178 |
/* get the number of HW channels */ |
| 179 |
ctlr->ichannels = ATA_INL(ctlr->r_res2, ATA_AHCI_PI); |
| 180 |
ctlr->channels = MAX(flsl(ctlr->ichannels), |
| 181 |
(ATA_INL(ctlr->r_res2, ATA_AHCI_CAP) & ATA_AHCI_CAP_NPMASK) + 1); |
| 182 |
if (pci_get_devid(dev) == ATA_M88SE6111) |
| 183 |
ctlr->channels = 1; |
| 184 |
else if (pci_get_devid(dev) == ATA_M88SE6121) |
| 185 |
ctlr->channels = 2; |
| 186 |
else if (pci_get_devid(dev) == ATA_M88SE6141 || |
| 187 |
pci_get_devid(dev) == ATA_M88SE6145) |
| 188 |
ctlr->channels = 4; |
| 189 |
|
| 190 |
ctlr->reset = ata_ahci_reset; |
| 191 |
ctlr->ch_attach = ata_ahci_ch_attach; |
| 192 |
ctlr->ch_detach = ata_ahci_ch_detach; |
| 193 |
ctlr->ch_suspend = ata_ahci_ch_suspend; |
| 194 |
ctlr->ch_resume = ata_ahci_ch_resume; |
| 195 |
ctlr->setmode = ata_sata_setmode; |
| 196 |
ctlr->getrev = ata_sata_getrev; |
| 197 |
ctlr->suspend = ata_ahci_suspend; |
| 198 |
ctlr->resume = ata_ahci_ctlr_reset; |
| 199 |
|
| 200 |
/* announce we support the HW */ |
| 201 |
version = ATA_INL(ctlr->r_res2, ATA_AHCI_VS); |
| 202 |
caps = ATA_INL(ctlr->r_res2, ATA_AHCI_CAP); |
| 203 |
speed = (caps & ATA_AHCI_CAP_ISS) >> ATA_AHCI_CAP_ISS_SHIFT; |
| 204 |
device_printf(dev, |
| 205 |
"AHCI v%x.%02x controller with %d %sGbps ports, PM %s\n", |
| 206 |
((version >> 20) & 0xf0) + ((version >> 16) & 0x0f), |
| 207 |
((version >> 4) & 0xf0) + (version & 0x0f), |
| 208 |
(caps & ATA_AHCI_CAP_NPMASK) + 1, |
| 209 |
((speed == 1) ? "1.5":((speed == 2) ? "3": |
| 210 |
((speed == 3) ? "6":"?"))), |
| 211 |
(caps & ATA_AHCI_CAP_SPM) ? |
| 212 |
"supported" : "not supported"); |
| 213 |
if (bootverbose) { |
| 214 |
device_printf(dev, "Caps:%s%s%s%s%s%s%s%s %sGbps", |
| 215 |
(caps & ATA_AHCI_CAP_64BIT) ? " 64bit":"", |
| 216 |
(caps & ATA_AHCI_CAP_SNCQ) ? " NCQ":"", |
| 217 |
(caps & ATA_AHCI_CAP_SSNTF) ? " SNTF":"", |
| 218 |
(caps & ATA_AHCI_CAP_SMPS) ? " MPS":"", |
| 219 |
(caps & ATA_AHCI_CAP_SSS) ? " SS":"", |
| 220 |
(caps & ATA_AHCI_CAP_SALP) ? " ALP":"", |
| 221 |
(caps & ATA_AHCI_CAP_SAL) ? " AL":"", |
| 222 |
(caps & ATA_AHCI_CAP_SCLO) ? " CLO":"", |
| 223 |
((speed == 1) ? "1.5":((speed == 2) ? "3": |
| 224 |
((speed == 3) ? "6":"?")))); |
| 225 |
printf("%s%s%s%s%s%s %dcmd%s%s%s %dports\n", |
| 226 |
(caps & ATA_AHCI_CAP_SAM) ? " AM":"", |
| 227 |
(caps & ATA_AHCI_CAP_SPM) ? " PM":"", |
| 228 |
(caps & ATA_AHCI_CAP_FBSS) ? " FBS":"", |
| 229 |
(caps & ATA_AHCI_CAP_PMD) ? " PMD":"", |
| 230 |
(caps & ATA_AHCI_CAP_SSC) ? " SSC":"", |
| 231 |
(caps & ATA_AHCI_CAP_PSC) ? " PSC":"", |
| 232 |
((caps & ATA_AHCI_CAP_NCS) >> ATA_AHCI_CAP_NCS_SHIFT) + 1, |
| 233 |
(caps & ATA_AHCI_CAP_CCCS) ? " CCC":"", |
| 234 |
(caps & ATA_AHCI_CAP_EMS) ? " EM":"", |
| 235 |
(caps & ATA_AHCI_CAP_SXS) ? " eSATA":"", |
| 236 |
(caps & ATA_AHCI_CAP_NPMASK) + 1); |
| 237 |
} |
| 238 |
return 0; |
| 239 |
} |
| 240 |
|
| 241 |
static int |
| 242 |
ata_ahci_ctlr_reset(device_t dev) |
| 243 |
{ |
| 244 |
struct ata_pci_controller *ctlr = device_get_softc(dev); |
| 245 |
int timeout; |
| 246 |
|
| 247 |
/* enable AHCI mode */ |
| 248 |
ATA_OUTL(ctlr->r_res2, ATA_AHCI_GHC, ATA_AHCI_GHC_AE); |
| 249 |
|
| 250 |
/* reset AHCI controller */ |
| 251 |
ATA_OUTL(ctlr->r_res2, ATA_AHCI_GHC, ATA_AHCI_GHC_AE|ATA_AHCI_GHC_HR); |
| 252 |
for (timeout = 1000; timeout > 0; timeout--) { |
| 253 |
DELAY(1000); |
| 254 |
if ((ATA_INL(ctlr->r_res2, ATA_AHCI_GHC) & ATA_AHCI_GHC_HR) == 0) |
| 255 |
break; |
| 256 |
} |
| 257 |
if (timeout == 0) { |
| 258 |
device_printf(dev, "AHCI controller reset failure\n"); |
| 259 |
return ENXIO; |
| 260 |
} |
| 261 |
|
| 262 |
/* reenable AHCI mode */ |
| 263 |
ATA_OUTL(ctlr->r_res2, ATA_AHCI_GHC, ATA_AHCI_GHC_AE); |
| 264 |
|
| 265 |
/* clear interrupts */ |
| 266 |
ATA_OUTL(ctlr->r_res2, ATA_AHCI_IS, ATA_INL(ctlr->r_res2, ATA_AHCI_IS)); |
| 267 |
|
| 268 |
/* enable AHCI interrupts */ |
| 269 |
ATA_OUTL(ctlr->r_res2, ATA_AHCI_GHC, |
| 270 |
ATA_INL(ctlr->r_res2, ATA_AHCI_GHC) | ATA_AHCI_GHC_IE); |
| 271 |
|
| 272 |
return 0; |
| 273 |
} |
| 274 |
|
| 275 |
static int |
| 276 |
ata_ahci_suspend(device_t dev) |
| 277 |
{ |
| 278 |
struct ata_pci_controller *ctlr = device_get_softc(dev); |
| 279 |
|
| 280 |
/* disable interupts so the state change(s) doesn't trigger */ |
| 281 |
ATA_OUTL(ctlr->r_res2, ATA_AHCI_GHC, |
| 282 |
ATA_INL(ctlr->r_res2, ATA_AHCI_GHC) & (~ATA_AHCI_GHC_IE)); |
| 283 |
return 0; |
| 284 |
} |
| 285 |
|
| 286 |
static int |
| 287 |
ata_ahci_ch_attach(device_t dev) |
| 288 |
{ |
| 289 |
struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev)); |
| 290 |
struct ata_channel *ch = device_get_softc(dev); |
| 291 |
int offset = ch->unit << 7; |
| 292 |
|
| 293 |
ata_ahci_dmainit(dev); |
| 294 |
|
| 295 |
/* set the SATA resources */ |
| 296 |
ch->r_io[ATA_SSTATUS].res = ctlr->r_res2; |
| 297 |
ch->r_io[ATA_SSTATUS].offset = ATA_AHCI_P_SSTS + offset; |
| 298 |
ch->r_io[ATA_SERROR].res = ctlr->r_res2; |
| 299 |
ch->r_io[ATA_SERROR].offset = ATA_AHCI_P_SERR + offset; |
| 300 |
ch->r_io[ATA_SCONTROL].res = ctlr->r_res2; |
| 301 |
ch->r_io[ATA_SCONTROL].offset = ATA_AHCI_P_SCTL + offset; |
| 302 |
ch->r_io[ATA_SACTIVE].res = ctlr->r_res2; |
| 303 |
ch->r_io[ATA_SACTIVE].offset = ATA_AHCI_P_SACT + offset; |
| 304 |
|
| 305 |
ch->hw.status = ata_ahci_status; |
| 306 |
ch->hw.begin_transaction = ata_ahci_begin_transaction; |
| 307 |
ch->hw.end_transaction = ata_ahci_end_transaction; |
| 308 |
ch->hw.command = NULL; /* not used here */ |
| 309 |
ch->hw.softreset = ata_ahci_softreset; |
| 310 |
ch->hw.pm_read = ata_ahci_pm_read; |
| 311 |
ch->hw.pm_write = ata_ahci_pm_write; |
| 312 |
ch->flags |= ATA_NO_SLAVE; |
| 313 |
ch->flags |= ATA_SATA; |
| 314 |
|
| 315 |
ata_ahci_ch_resume(dev); |
| 316 |
return 0; |
| 317 |
} |
| 318 |
|
| 319 |
static int |
| 320 |
ata_ahci_ch_detach(device_t dev) |
| 321 |
{ |
| 322 |
struct ata_channel *ch = device_get_softc(dev); |
| 323 |
|
| 324 |
if (ch->dma.work_tag && ch->dma.work_map) |
| 325 |
bus_dmamap_sync(ch->dma.work_tag, ch->dma.work_map, |
| 326 |
BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); |
| 327 |
ata_ahci_ch_suspend(dev); |
| 328 |
ata_dmafini(dev); |
| 329 |
return (0); |
| 330 |
} |
| 331 |
|
| 332 |
static int |
| 333 |
ata_ahci_ch_suspend(device_t dev) |
| 334 |
{ |
| 335 |
struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev)); |
| 336 |
struct ata_channel *ch = device_get_softc(dev); |
| 337 |
int offset = ch->unit << 7; |
| 338 |
|
| 339 |
/* Disable port interrupts. */ |
| 340 |
ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_IE + offset, 0); |
| 341 |
/* Reset command register. */ |
| 342 |
ata_ahci_stop(dev); |
| 343 |
ata_ahci_stop_fr(dev); |
| 344 |
ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_CMD + offset, 0); |
| 345 |
|
| 346 |
/* Allow everything including partial and slumber modes. */ |
| 347 |
ATA_IDX_OUTL(ch, ATA_SCONTROL, 0); |
| 348 |
/* Request slumber mode transition and give some time to get there. */ |
| 349 |
ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_CMD + offset, ATA_AHCI_P_CMD_SLUMBER); |
| 350 |
DELAY(100); |
| 351 |
/* Disable PHY. */ |
| 352 |
ATA_IDX_OUTL(ch, ATA_SCONTROL, ATA_SC_DET_DISABLE); |
| 353 |
|
| 354 |
return (0); |
| 355 |
} |
| 356 |
|
| 357 |
static int |
| 358 |
ata_ahci_ch_resume(device_t dev) |
| 359 |
{ |
| 360 |
struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev)); |
| 361 |
struct ata_channel *ch = device_get_softc(dev); |
| 362 |
uint64_t work; |
| 363 |
int offset = ch->unit << 7; |
| 364 |
|
| 365 |
/* Disable port interrupts */ |
| 366 |
ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_IE + offset, 0); |
| 367 |
|
| 368 |
/* setup work areas */ |
| 369 |
work = ch->dma.work_bus + ATA_AHCI_CL_OFFSET; |
| 370 |
ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_CLB + offset, work & 0xffffffff); |
| 371 |
ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_CLBU + offset, work >> 32); |
| 372 |
|
| 373 |
work = ch->dma.work_bus + ATA_AHCI_FB_OFFSET; |
| 374 |
ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_FB + offset, work & 0xffffffff); |
| 375 |
ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_FBU + offset, work >> 32); |
| 376 |
|
| 377 |
/* activate the channel and power/spin up device */ |
| 378 |
ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_CMD + offset, |
| 379 |
(ATA_AHCI_P_CMD_ACTIVE | ATA_AHCI_P_CMD_POD | ATA_AHCI_P_CMD_SUD | |
| 380 |
((ch->pm_level > 1) ? ATA_AHCI_P_CMD_ALPE : 0) | |
| 381 |
((ch->pm_level > 2) ? ATA_AHCI_P_CMD_ASP : 0 ))); |
| 382 |
ata_ahci_start_fr(dev); |
| 383 |
ata_ahci_start(dev); |
| 384 |
|
| 385 |
return (0); |
| 386 |
} |
| 387 |
|
| 388 |
static int |
| 389 |
ata_ahci_status(device_t dev) |
| 390 |
{ |
| 391 |
struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev)); |
| 392 |
struct ata_channel *ch = device_get_softc(dev); |
| 393 |
u_int32_t action = ATA_INL(ctlr->r_res2, ATA_AHCI_IS); |
| 394 |
int offset = ch->unit << 7; |
| 395 |
|
| 396 |
#define ATA_AHCI_STATBITS \ |
| 397 |
(ATA_AHCI_P_IX_IF|ATA_AHCI_P_IX_HBD|ATA_AHCI_P_IX_HBF|ATA_AHCI_P_IX_TFE) |
| 398 |
|
| 399 |
if (action & (1 << ch->unit)) { |
| 400 |
u_int32_t istatus = ATA_INL(ctlr->r_res2, ATA_AHCI_P_IS + offset); |
| 401 |
u_int32_t cstatus = ATA_INL(ctlr->r_res2, ATA_AHCI_P_CI + offset); |
| 402 |
|
| 403 |
/* clear interrupt(s) */ |
| 404 |
ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_IS + offset, istatus); |
| 405 |
ATA_OUTL(ctlr->r_res2, ATA_AHCI_IS, 1 << ch->unit); |
| 406 |
|
| 407 |
/* do we have any PHY events ? */ |
| 408 |
if (istatus & (ATA_AHCI_P_IX_PRC | ATA_AHCI_P_IX_PC)) |
| 409 |
ata_sata_phy_check_events(dev, -1); |
| 410 |
|
| 411 |
/* do we have a potentially hanging engine to take care of? */ |
| 412 |
/* XXX SOS what todo on NCQ */ |
| 413 |
if ((istatus & ATA_AHCI_STATBITS) && (cstatus & 1)) { |
| 414 |
|
| 415 |
u_int32_t cmd = ATA_INL(ctlr->r_res2, ATA_AHCI_P_CMD + offset); |
| 416 |
int timeout = 0; |
| 417 |
|
| 418 |
/* kill off all activity on this channel */ |
| 419 |
ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_CMD + offset, |
| 420 |
cmd & ~(ATA_AHCI_P_CMD_FRE | ATA_AHCI_P_CMD_ST)); |
| 421 |
|
| 422 |
/* XXX SOS this is not entirely wrong */ |
| 423 |
do { |
| 424 |
DELAY(1000); |
| 425 |
if (timeout++ > 1000) { |
| 426 |
device_printf(dev, "stopping AHCI engine failed\n"); |
| 427 |
break; |
| 428 |
} |
| 429 |
} while (ATA_INL(ctlr->r_res2, |
| 430 |
ATA_AHCI_P_CMD + offset) & ATA_AHCI_P_CMD_CR); |
| 431 |
|
| 432 |
/* start operations on this channel */ |
| 433 |
ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_CMD + offset, |
| 434 |
cmd | (ATA_AHCI_P_CMD_FRE | ATA_AHCI_P_CMD_ST)); |
| 435 |
|
| 436 |
return 1; |
| 437 |
} |
| 438 |
else |
| 439 |
/* XXX SOS what todo on NCQ */ |
| 440 |
return (!(cstatus & 1)); |
| 441 |
} |
| 442 |
return 0; |
| 443 |
} |
| 444 |
|
| 445 |
/* must be called with ATA channel locked and state_mtx held */ |
| 446 |
static int |
| 447 |
ata_ahci_begin_transaction(struct ata_request *request) |
| 448 |
{ |
| 449 |
struct ata_pci_controller *ctlr=device_get_softc(device_get_parent(request->parent)); |
| 450 |
struct ata_channel *ch = device_get_softc(request->parent); |
| 451 |
struct ata_ahci_cmd_tab *ctp; |
| 452 |
struct ata_ahci_cmd_list *clp; |
| 453 |
int offset = ch->unit << 7; |
| 454 |
int port = request->unit & 0x0f; |
| 455 |
int entries = 0; |
| 456 |
int fis_size; |
| 457 |
|
| 458 |
/* get a piece of the workspace for this request */ |
| 459 |
ctp = (struct ata_ahci_cmd_tab *) |
| 460 |
(ch->dma.work + ATA_AHCI_CT_OFFSET); |
| 461 |
|
| 462 |
/* setup the FIS for this request */ |
| 463 |
if (!(fis_size = ata_ahci_setup_fis(ctp, request))) { |
| 464 |
device_printf(request->parent, "setting up SATA FIS failed\n"); |
| 465 |
request->result = EIO; |
| 466 |
return ATA_OP_FINISHED; |
| 467 |
} |
| 468 |
|
| 469 |
/* if request moves data setup and load SG list */ |
| 470 |
if (request->flags & (ATA_R_READ | ATA_R_WRITE)) { |
| 471 |
if (ch->dma.load(request, ctp->prd_tab, &entries)) { |
| 472 |
device_printf(request->parent, "setting up DMA failed\n"); |
| 473 |
request->result = EIO; |
| 474 |
return ATA_OP_FINISHED; |
| 475 |
} |
| 476 |
} |
| 477 |
|
| 478 |
/* setup the command list entry */ |
| 479 |
clp = (struct ata_ahci_cmd_list *) |
| 480 |
(ch->dma.work + ATA_AHCI_CL_OFFSET); |
| 481 |
|
| 482 |
clp->prd_length = entries; |
| 483 |
clp->cmd_flags = (request->flags & ATA_R_WRITE ? ATA_AHCI_CMD_WRITE : 0) | |
| 484 |
(request->flags & ATA_R_ATAPI ? |
| 485 |
(ATA_AHCI_CMD_ATAPI | ATA_AHCI_CMD_PREFETCH) : 0) | |
| 486 |
(fis_size / sizeof(u_int32_t)) | |
| 487 |
(port << 12); |
| 488 |
clp->bytecount = 0; |
| 489 |
clp->cmd_table_phys = htole64(ch->dma.work_bus + ATA_AHCI_CT_OFFSET); |
| 490 |
|
| 491 |
/* set command type bit */ |
| 492 |
if (request->flags & ATA_R_ATAPI) |
| 493 |
ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_CMD + offset, |
| 494 |
ATA_INL(ctlr->r_res2, ATA_AHCI_P_CMD + offset) | |
| 495 |
ATA_AHCI_P_CMD_ATAPI); |
| 496 |
else |
| 497 |
ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_CMD + offset, |
| 498 |
ATA_INL(ctlr->r_res2, ATA_AHCI_P_CMD + offset) & |
| 499 |
~ATA_AHCI_P_CMD_ATAPI); |
| 500 |
|
| 501 |
bus_dmamap_sync(ch->dma.work_tag, ch->dma.work_map, |
| 502 |
BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); |
| 503 |
|
| 504 |
/* issue command to controller */ |
| 505 |
ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_CI + offset, 1); |
| 506 |
|
| 507 |
if (!(request->flags & ATA_R_ATAPI)) { |
| 508 |
/* device reset doesn't interrupt */ |
| 509 |
if (request->u.ata.command == ATA_DEVICE_RESET) { |
| 510 |
u_int32_t tf_data; |
| 511 |
int timeout = 1000000; |
| 512 |
|
| 513 |
do { |
| 514 |
DELAY(10); |
| 515 |
tf_data = ATA_INL(ctlr->r_res2, ATA_AHCI_P_TFD + (ch->unit<<7)); |
| 516 |
} while ((tf_data & ATA_S_BUSY) && timeout--); |
| 517 |
if (bootverbose) |
| 518 |
device_printf(ch->dev, "device_reset timeout=%dus\n", |
| 519 |
(1000000-timeout)*10); |
| 520 |
request->status = tf_data; |
| 521 |
if (request->status & ATA_S_ERROR) |
| 522 |
request->error = tf_data >> 8; |
| 523 |
return ATA_OP_FINISHED; |
| 524 |
} |
| 525 |
} |
| 526 |
|
| 527 |
/* start the timeout */ |
| 528 |
callout_reset(&request->callout, request->timeout * hz, |
| 529 |
(timeout_t*)ata_timeout, request); |
| 530 |
return ATA_OP_CONTINUES; |
| 531 |
} |
| 532 |
|
| 533 |
/* must be called with ATA channel locked and state_mtx held */ |
| 534 |
static int |
| 535 |
ata_ahci_end_transaction(struct ata_request *request) |
| 536 |
{ |
| 537 |
struct ata_pci_controller *ctlr=device_get_softc(device_get_parent(request->parent)); |
| 538 |
struct ata_channel *ch = device_get_softc(request->parent); |
| 539 |
struct ata_ahci_cmd_list *clp; |
| 540 |
u_int32_t tf_data; |
| 541 |
int offset = ch->unit << 7; |
| 542 |
|
| 543 |
/* kill the timeout */ |
| 544 |
callout_stop(&request->callout); |
| 545 |
|
| 546 |
bus_dmamap_sync(ch->dma.work_tag, ch->dma.work_map, |
| 547 |
BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); |
| 548 |
|
| 549 |
/* get status */ |
| 550 |
tf_data = ATA_INL(ctlr->r_res2, ATA_AHCI_P_TFD + offset); |
| 551 |
request->status = tf_data; |
| 552 |
|
| 553 |
/* if error status get details */ |
| 554 |
if (request->status & ATA_S_ERROR) |
| 555 |
request->error = tf_data >> 8; |
| 556 |
|
| 557 |
/* Read back registers to the request struct. */ |
| 558 |
if ((request->flags & ATA_R_ATAPI) == 0 && |
| 559 |
((request->status & ATA_S_ERROR) || |
| 560 |
(request->flags & (ATA_R_CONTROL | ATA_R_NEEDRESULT)))) { |
| 561 |
u_int8_t *fis = ch->dma.work + ATA_AHCI_FB_OFFSET + 0x40; |
| 562 |
|
| 563 |
request->u.ata.count = fis[12] | ((u_int16_t)fis[13] << 8); |
| 564 |
request->u.ata.lba = fis[4] | ((u_int64_t)fis[5] << 8) | |
| 565 |
((u_int64_t)fis[6] << 16); |
| 566 |
if (request->flags & ATA_R_48BIT) |
| 567 |
request->u.ata.lba |= ((u_int64_t)fis[8] << 24) | |
| 568 |
((u_int64_t)fis[9] << 32) | |
| 569 |
((u_int64_t)fis[10] << 40); |
| 570 |
else |
| 571 |
request->u.ata.lba |= ((u_int64_t)(fis[7] & 0x0f) << 24); |
| 572 |
} |
| 573 |
|
| 574 |
/* record how much data we actually moved */ |
| 575 |
clp = (struct ata_ahci_cmd_list *) |
| 576 |
(ch->dma.work + ATA_AHCI_CL_OFFSET); |
| 577 |
request->donecount = le32toh(clp->bytecount); |
| 578 |
|
| 579 |
/* release SG list etc */ |
| 580 |
ch->dma.unload(request); |
| 581 |
|
| 582 |
return ATA_OP_FINISHED; |
| 583 |
} |
| 584 |
|
| 585 |
static int |
| 586 |
ata_ahci_issue_cmd(device_t dev, u_int16_t flags, int timeout) |
| 587 |
{ |
| 588 |
struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev)); |
| 589 |
struct ata_channel *ch = device_get_softc(dev); |
| 590 |
struct ata_ahci_cmd_list *clp = |
| 591 |
(struct ata_ahci_cmd_list *)(ch->dma.work + ATA_AHCI_CL_OFFSET); |
| 592 |
struct ata_ahci_cmd_tab *ctp = |
| 593 |
(struct ata_ahci_cmd_tab *)(ch->dma.work + ATA_AHCI_CT_OFFSET); |
| 594 |
u_int32_t status = 0; |
| 595 |
int offset = ch->unit << 7; |
| 596 |
int port = (ctp->cfis[1] & 0x0f); |
| 597 |
int count; |
| 598 |
|
| 599 |
clp->prd_length = 0; |
| 600 |
clp->cmd_flags = (20 / sizeof(u_int32_t)) | flags | (port << 12); |
| 601 |
clp->bytecount = 0; |
| 602 |
clp->cmd_table_phys = htole64(ch->dma.work_bus + ATA_AHCI_CT_OFFSET); |
| 603 |
|
| 604 |
bus_dmamap_sync(ch->dma.work_tag, ch->dma.work_map, |
| 605 |
BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); |
| 606 |
|
| 607 |
/* issue command to controller */ |
| 608 |
ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_CI + offset, 1); |
| 609 |
|
| 610 |
/* poll for command finished */ |
| 611 |
for (count = 0; count < timeout; count++) { |
| 612 |
DELAY(1000); |
| 613 |
if (!((status = ATA_INL(ctlr->r_res2, ATA_AHCI_P_CI + offset)) & 1)) |
| 614 |
break; |
| 615 |
} |
| 616 |
|
| 617 |
bus_dmamap_sync(ch->dma.work_tag, ch->dma.work_map, |
| 618 |
BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); |
| 619 |
|
| 620 |
/* clear interrupts */ |
| 621 |
ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_IS + offset, |
| 622 |
ATA_INL(ctlr->r_res2, ATA_AHCI_P_IS + offset)); |
| 623 |
|
| 624 |
if (timeout && (count >= timeout)) { |
| 625 |
if (bootverbose) { |
| 626 |
device_printf(dev, "ahci_issue_cmd timeout: %d of %dms, status=%08x\n", |
| 627 |
count, timeout, status); |
| 628 |
} |
| 629 |
return EIO; |
| 630 |
} |
| 631 |
|
| 632 |
return 0; |
| 633 |
} |
| 634 |
|
| 635 |
static int |
| 636 |
ata_ahci_pm_read(device_t dev, int port, int reg, u_int32_t *result) |
| 637 |
{ |
| 638 |
struct ata_channel *ch = device_get_softc(dev); |
| 639 |
struct ata_ahci_cmd_tab *ctp = |
| 640 |
(struct ata_ahci_cmd_tab *)(ch->dma.work + ATA_AHCI_CT_OFFSET); |
| 641 |
u_int8_t *fis = ch->dma.work + ATA_AHCI_FB_OFFSET + 0x40; |
| 642 |
|
| 643 |
if (port < 0) { |
| 644 |
*result = ATA_IDX_INL(ch, reg); |
| 645 |
return (0); |
| 646 |
} |
| 647 |
if (port < ATA_PM) { |
| 648 |
switch (reg) { |
| 649 |
case ATA_SSTATUS: |
| 650 |
reg = 0; |
| 651 |
break; |
| 652 |
case ATA_SERROR: |
| 653 |
reg = 1; |
| 654 |
break; |
| 655 |
case ATA_SCONTROL: |
| 656 |
reg = 2; |
| 657 |
break; |
| 658 |
default: |
| 659 |
return (EINVAL); |
| 660 |
} |
| 661 |
} |
| 662 |
bzero(ctp->cfis, 64); |
| 663 |
ctp->cfis[0] = 0x27; /* host to device */ |
| 664 |
ctp->cfis[1] = 0x8f; /* command FIS to PM port */ |
| 665 |
ctp->cfis[2] = ATA_READ_PM; |
| 666 |
ctp->cfis[3] = reg; |
| 667 |
ctp->cfis[7] = port | ATA_D_LBA; |
| 668 |
ctp->cfis[15] = ATA_A_4BIT; |
| 669 |
|
| 670 |
if (ata_ahci_issue_cmd(dev, 0, 10)) { |
| 671 |
device_printf(dev, "error reading PM port\n"); |
| 672 |
return EIO; |
| 673 |
} |
| 674 |
|
| 675 |
*result = fis[12] | (fis[4] << 8) | (fis[5] << 16) | (fis[6] << 24); |
| 676 |
return 0; |
| 677 |
} |
| 678 |
|
| 679 |
static int |
| 680 |
ata_ahci_pm_write(device_t dev, int port, int reg, u_int32_t value) |
| 681 |
{ |
| 682 |
struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev)); |
| 683 |
struct ata_channel *ch = device_get_softc(dev); |
| 684 |
struct ata_ahci_cmd_tab *ctp = |
| 685 |
(struct ata_ahci_cmd_tab *)(ch->dma.work + ATA_AHCI_CT_OFFSET); |
| 686 |
int offset = ch->unit << 7; |
| 687 |
|
| 688 |
if (port < 0) { |
| 689 |
ATA_IDX_OUTL(ch, reg, value); |
| 690 |
return (0); |
| 691 |
} |
| 692 |
if (port < ATA_PM) { |
| 693 |
switch (reg) { |
| 694 |
case ATA_SSTATUS: |
| 695 |
reg = 0; |
| 696 |
break; |
| 697 |
case ATA_SERROR: |
| 698 |
reg = 1; |
| 699 |
break; |
| 700 |
case ATA_SCONTROL: |
| 701 |
reg = 2; |
| 702 |
break; |
| 703 |
default: |
| 704 |
return (EINVAL); |
| 705 |
} |
| 706 |
} |
| 707 |
bzero(ctp->cfis, 64); |
| 708 |
ctp->cfis[0] = 0x27; /* host to device */ |
| 709 |
ctp->cfis[1] = 0x8f; /* command FIS to PM port */ |
| 710 |
ctp->cfis[2] = ATA_WRITE_PM; |
| 711 |
ctp->cfis[3] = reg; |
| 712 |
ctp->cfis[7] = port | ATA_D_LBA; |
| 713 |
ctp->cfis[12] = value & 0xff; |
| 714 |
ctp->cfis[4] = (value >> 8) & 0xff; |
| 715 |
ctp->cfis[5] = (value >> 16) & 0xff; |
| 716 |
ctp->cfis[6] = (value >> 24) & 0xff; |
| 717 |
ctp->cfis[15] = ATA_A_4BIT; |
| 718 |
|
| 719 |
if (ata_ahci_issue_cmd(dev, 0, 100)) { |
| 720 |
device_printf(dev, "error writing PM port\n"); |
| 721 |
return ATA_E_ABORT; |
| 722 |
} |
| 723 |
|
| 724 |
return (ATA_INL(ctlr->r_res2, ATA_AHCI_P_TFD + offset) >> 8) & 0xff; |
| 725 |
} |
| 726 |
|
| 727 |
static void |
| 728 |
ata_ahci_stop(device_t dev) |
| 729 |
{ |
| 730 |
struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev)); |
| 731 |
struct ata_channel *ch = device_get_softc(dev); |
| 732 |
u_int32_t cmd; |
| 733 |
int offset = ch->unit << 7; |
| 734 |
int timeout; |
| 735 |
|
| 736 |
/* kill off all activity on this channel */ |
| 737 |
cmd = ATA_INL(ctlr->r_res2, ATA_AHCI_P_CMD + offset); |
| 738 |
ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_CMD + offset, |
| 739 |
cmd & ~ATA_AHCI_P_CMD_ST); |
| 740 |
|
| 741 |
/* XXX SOS this is not entirely wrong */ |
| 742 |
timeout = 0; |
| 743 |
do { |
| 744 |
DELAY(1000); |
| 745 |
if (timeout++ > 1000) { |
| 746 |
device_printf(dev, "stopping AHCI engine failed\n"); |
| 747 |
break; |
| 748 |
} |
| 749 |
} |
| 750 |
while (ATA_INL(ctlr->r_res2, ATA_AHCI_P_CMD + offset) & ATA_AHCI_P_CMD_CR); |
| 751 |
} |
| 752 |
|
| 753 |
static void |
| 754 |
ata_ahci_clo(device_t dev) |
| 755 |
{ |
| 756 |
struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev)); |
| 757 |
struct ata_channel *ch = device_get_softc(dev); |
| 758 |
u_int32_t cmd; |
| 759 |
int offset = ch->unit << 7; |
| 760 |
int timeout; |
| 761 |
|
| 762 |
/* issue Command List Override if supported */ |
| 763 |
if (ATA_INL(ctlr->r_res2, ATA_AHCI_CAP) & ATA_AHCI_CAP_SCLO) { |
| 764 |
cmd = ATA_INL(ctlr->r_res2, ATA_AHCI_P_CMD + offset); |
| 765 |
cmd |= ATA_AHCI_P_CMD_CLO; |
| 766 |
ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_CMD + offset, cmd); |
| 767 |
timeout = 0; |
| 768 |
do { |
| 769 |
DELAY(1000); |
| 770 |
if (timeout++ > 1000) { |
| 771 |
device_printf(dev, "executing CLO failed\n"); |
| 772 |
break; |
| 773 |
} |
| 774 |
} |
| 775 |
while (ATA_INL(ctlr->r_res2, ATA_AHCI_P_CMD+offset)&ATA_AHCI_P_CMD_CLO); |
| 776 |
} |
| 777 |
} |
| 778 |
|
| 779 |
static void |
| 780 |
ata_ahci_start(device_t dev) |
| 781 |
{ |
| 782 |
struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev)); |
| 783 |
struct ata_channel *ch = device_get_softc(dev); |
| 784 |
u_int32_t cmd; |
| 785 |
int offset = ch->unit << 7; |
| 786 |
|
| 787 |
/* clear SATA error register */ |
| 788 |
ATA_IDX_OUTL(ch, ATA_SERROR, ATA_IDX_INL(ch, ATA_SERROR)); |
| 789 |
|
| 790 |
/* clear any interrupts pending on this channel */ |
| 791 |
ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_IS + offset, |
| 792 |
ATA_INL(ctlr->r_res2, ATA_AHCI_P_IS + offset)); |
| 793 |
|
| 794 |
/* start operations on this channel */ |
| 795 |
cmd = ATA_INL(ctlr->r_res2, ATA_AHCI_P_CMD + offset); |
| 796 |
ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_CMD + offset, |
| 797 |
cmd | ATA_AHCI_P_CMD_ST | |
| 798 |
(ch->devices & ATA_PORTMULTIPLIER ? ATA_AHCI_P_CMD_PMA : 0)); |
| 799 |
} |
| 800 |
|
| 801 |
static void |
| 802 |
ata_ahci_stop_fr(device_t dev) |
| 803 |
{ |
| 804 |
struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev)); |
| 805 |
struct ata_channel *ch = device_get_softc(dev); |
| 806 |
u_int32_t cmd; |
| 807 |
int offset = ch->unit << 7; |
| 808 |
int timeout; |
| 809 |
|
| 810 |
/* kill off all activity on this channel */ |
| 811 |
cmd = ATA_INL(ctlr->r_res2, ATA_AHCI_P_CMD + offset); |
| 812 |
ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_CMD + offset, cmd & ~ATA_AHCI_P_CMD_FRE); |
| 813 |
|
| 814 |
timeout = 0; |
| 815 |
do { |
| 816 |
DELAY(1000); |
| 817 |
if (timeout++ > 1000) { |
| 818 |
device_printf(dev, "stopping AHCI FR engine failed\n"); |
| 819 |
break; |
| 820 |
} |
| 821 |
} |
| 822 |
while (ATA_INL(ctlr->r_res2, ATA_AHCI_P_CMD + offset) & ATA_AHCI_P_CMD_FR); |
| 823 |
} |
| 824 |
|
| 825 |
static void |
| 826 |
ata_ahci_start_fr(device_t dev) |
| 827 |
{ |
| 828 |
struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev)); |
| 829 |
struct ata_channel *ch = device_get_softc(dev); |
| 830 |
u_int32_t cmd; |
| 831 |
int offset = ch->unit << 7; |
| 832 |
|
| 833 |
/* start FIS reception on this channel */ |
| 834 |
cmd = ATA_INL(ctlr->r_res2, ATA_AHCI_P_CMD + offset); |
| 835 |
ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_CMD + offset, cmd | ATA_AHCI_P_CMD_FRE); |
| 836 |
} |
| 837 |
|
| 838 |
static int |
| 839 |
ata_ahci_wait_ready(device_t dev, int t) |
| 840 |
{ |
| 841 |
struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev)); |
| 842 |
struct ata_channel *ch = device_get_softc(dev); |
| 843 |
int offset = ch->unit << 7; |
| 844 |
int timeout = 0; |
| 845 |
uint32_t val; |
| 846 |
|
| 847 |
while ((val = ATA_INL(ctlr->r_res2, ATA_AHCI_P_TFD + offset)) & |
| 848 |
(ATA_S_BUSY | ATA_S_DRQ)) { |
| 849 |
DELAY(1000); |
| 850 |
if (timeout++ > t) { |
| 851 |
device_printf(dev, "port is not ready (timeout %dms) tfd = %08x\n", t, val); |
| 852 |
return (EBUSY); |
| 853 |
} |
| 854 |
} |
| 855 |
if (bootverbose) |
| 856 |
device_printf(dev, "ready wait time=%dms\n", timeout); |
| 857 |
return (0); |
| 858 |
} |
| 859 |
|
| 860 |
static int |
| 861 |
ata_ahci_hardreset(device_t dev, int port, uint32_t *signature) |
| 862 |
{ |
| 863 |
struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev)); |
| 864 |
struct ata_channel *ch = device_get_softc(dev); |
| 865 |
int offset = ch->unit << 7; |
| 866 |
|
| 867 |
*signature = 0xffffffff; |
| 868 |
ata_ahci_stop(dev); |
| 869 |
/* Reset port */ |
| 870 |
if (!ata_sata_phy_reset(dev, port, 0)) |
| 871 |
return (ENOENT); |
| 872 |
/* Wait for clearing busy status. */ |
| 873 |
if (ata_ahci_wait_ready(dev, 15000)) { |
| 874 |
device_printf(dev, "hardware reset timeout\n"); |
| 875 |
return (EBUSY); |
| 876 |
} |
| 877 |
*signature = ATA_INL(ctlr->r_res2, ATA_AHCI_P_SIG + offset); |
| 878 |
ata_ahci_start(dev); |
| 879 |
return (0); |
| 880 |
} |
| 881 |
|
| 882 |
static u_int32_t |
| 883 |
ata_ahci_softreset(device_t dev, int port) |
| 884 |
{ |
| 885 |
struct ata_channel *ch = device_get_softc(dev); |
| 886 |
struct ata_ahci_cmd_tab *ctp = |
| 887 |
(struct ata_ahci_cmd_tab *)(ch->dma.work + ATA_AHCI_CT_OFFSET); |
| 888 |
u_int8_t *fis = ch->dma.work + ATA_AHCI_FB_OFFSET + 0x40; |
| 889 |
|
| 890 |
if (bootverbose) |
| 891 |
device_printf(dev, "software reset port %d...\n", port); |
| 892 |
|
| 893 |
/* kick controller into sane state */ |
| 894 |
ata_ahci_stop(dev); |
| 895 |
ata_ahci_clo(dev); |
| 896 |
ata_ahci_start(dev); |
| 897 |
|
| 898 |
/* pull reset active */ |
| 899 |
bzero(ctp->cfis, 64); |
| 900 |
ctp->cfis[0] = 0x27; |
| 901 |
ctp->cfis[1] = port & 0x0f; |
| 902 |
//ctp->cfis[7] = ATA_D_LBA | ATA_D_IBM; |
| 903 |
ctp->cfis[15] = (ATA_A_4BIT | ATA_A_RESET); |
| 904 |
|
| 905 |
if (ata_ahci_issue_cmd(dev, ATA_AHCI_CMD_RESET | ATA_AHCI_CMD_CLR_BUSY,100)) { |
| 906 |
device_printf(dev, "software reset set timeout\n"); |
| 907 |
return (-1); |
| 908 |
} |
| 909 |
|
| 910 |
ata_udelay(50); |
| 911 |
|
| 912 |
/* pull reset inactive -> device softreset */ |
| 913 |
bzero(ctp->cfis, 64); |
| 914 |
ctp->cfis[0] = 0x27; |
| 915 |
ctp->cfis[1] = port & 0x0f; |
| 916 |
//ctp->cfis[7] = ATA_D_LBA | ATA_D_IBM; |
| 917 |
ctp->cfis[15] = ATA_A_4BIT; |
| 918 |
ata_ahci_issue_cmd(dev, 0, 3000); |
| 919 |
|
| 920 |
if (ata_ahci_wait_ready(dev, 0)) { |
| 921 |
device_printf(dev, "software reset clear timeout\n"); |
| 922 |
return (-1); |
| 923 |
} |
| 924 |
|
| 925 |
return (((u_int32_t)fis[6] << 24) | |
| 926 |
((u_int32_t)fis[5] << 16) | |
| 927 |
((u_int32_t)fis[4] << 8) | |
| 928 |
(u_int32_t)fis[12]); |
| 929 |
} |
| 930 |
|
| 931 |
static void |
| 932 |
ata_ahci_reset(device_t dev) |
| 933 |
{ |
| 934 |
struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev)); |
| 935 |
struct ata_channel *ch = device_get_softc(dev); |
| 936 |
u_int32_t signature; |
| 937 |
int offset = ch->unit << 7; |
| 938 |
|
| 939 |
if (bootverbose) |
| 940 |
device_printf(dev, "AHCI reset...\n"); |
| 941 |
|
| 942 |
/* Disable port interrupts */ |
| 943 |
ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_IE + offset, 0); |
| 944 |
|
| 945 |
if (ata_ahci_hardreset(dev, -1, &signature)) { |
| 946 |
if (bootverbose) |
| 947 |
device_printf(dev, "AHCI reset done: phy reset found no device\n"); |
| 948 |
ch->devices = 0; |
| 949 |
|
| 950 |
/* enable wanted port interrupts */ |
| 951 |
ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_IE + offset, |
| 952 |
(ATA_AHCI_P_IX_CPD | ATA_AHCI_P_IX_PRC | ATA_AHCI_P_IX_PC)); |
| 953 |
return; |
| 954 |
} |
| 955 |
|
| 956 |
/* enable wanted port interrupts */ |
| 957 |
ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_IE + offset, |
| 958 |
(ATA_AHCI_P_IX_CPD | ATA_AHCI_P_IX_TFE | ATA_AHCI_P_IX_HBF | |
| 959 |
ATA_AHCI_P_IX_HBD | ATA_AHCI_P_IX_IF | ATA_AHCI_P_IX_OF | |
| 960 |
((ch->pm_level == 0) ? ATA_AHCI_P_IX_PRC | ATA_AHCI_P_IX_PC : 0) | |
| 961 |
ATA_AHCI_P_IX_DP | ATA_AHCI_P_IX_UF | ATA_AHCI_P_IX_SDB | |
| 962 |
ATA_AHCI_P_IX_DS | ATA_AHCI_P_IX_PS | ATA_AHCI_P_IX_DHR)); |
| 963 |
/* |
| 964 |
* Only probe for PortMultiplier if HW has support. |
| 965 |
* Ignore Marvell, which is not working, |
| 966 |
*/ |
| 967 |
if ((ATA_INL(ctlr->r_res2, ATA_AHCI_CAP) & ATA_AHCI_CAP_SPM) && |
| 968 |
pci_get_vendor(ctlr->dev) != 0x11ab) { |
| 969 |
signature = ata_ahci_softreset(dev, ATA_PM); |
| 970 |
/* Workaround for some ATI chips, failing to soft-reset |
| 971 |
* when port multiplicator supported, but absent. |
| 972 |
* XXX: We can also check PxIS.IPMS==1 here to be sure. */ |
| 973 |
if (signature == 0xffffffff) |
| 974 |
signature = ata_ahci_softreset(dev, 0); |
| 975 |
} else { |
| 976 |
signature = ata_ahci_softreset(dev, 0); |
| 977 |
} |
| 978 |
if (bootverbose) |
| 979 |
device_printf(dev, "SIGNATURE: %08x\n", signature); |
| 980 |
|
| 981 |
switch (signature >> 16) { |
| 982 |
case 0x0000: |
| 983 |
ch->devices = ATA_ATA_MASTER; |
| 984 |
break; |
| 985 |
case 0x9669: |
| 986 |
ch->devices = ATA_PORTMULTIPLIER; |
| 987 |
ata_pm_identify(dev); |
| 988 |
break; |
| 989 |
case 0xeb14: |
| 990 |
ch->devices = ATA_ATAPI_MASTER; |
| 991 |
break; |
| 992 |
default: /* SOS XXX */ |
| 993 |
if (bootverbose) |
| 994 |
device_printf(dev, "Unknown signature, assuming disk device\n"); |
| 995 |
ch->devices = ATA_ATA_MASTER; |
| 996 |
} |
| 997 |
if (bootverbose) |
| 998 |
device_printf(dev, "AHCI reset done: devices=%08x\n", ch->devices); |
| 999 |
} |
| 1000 |
|
| 1001 |
static void |
| 1002 |
ata_ahci_dmasetprd(void *xsc, bus_dma_segment_t *segs, int nsegs, int error) |
| 1003 |
{ |
| 1004 |
struct ata_dmasetprd_args *args = xsc; |
| 1005 |
struct ata_ahci_dma_prd *prd = args->dmatab; |
| 1006 |
int i; |
| 1007 |
|
| 1008 |
if (!(args->error = error)) { |
| 1009 |
for (i = 0; i < nsegs; i++) { |
| 1010 |
prd[i].dba = htole64(segs[i].ds_addr); |
| 1011 |
prd[i].dbc = htole32((segs[i].ds_len - 1) & ATA_AHCI_PRD_MASK); |
| 1012 |
} |
| 1013 |
} |
| 1014 |
|
| 1015 |
KASSERT(nsegs <= ATA_AHCI_DMA_ENTRIES, ("too many DMA segment entries\n")); |
| 1016 |
args->nsegs = nsegs; |
| 1017 |
} |
| 1018 |
|
| 1019 |
static void |
| 1020 |
ata_ahci_dmainit(device_t dev) |
| 1021 |
{ |
| 1022 |
struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev)); |
| 1023 |
struct ata_channel *ch = device_get_softc(dev); |
| 1024 |
|
| 1025 |
/* note start and stop are not used here */ |
| 1026 |
ch->dma.setprd = ata_ahci_dmasetprd; |
| 1027 |
ch->dma.max_iosize = (ATA_AHCI_DMA_ENTRIES - 1) * PAGE_SIZE; |
| 1028 |
if (ATA_INL(ctlr->r_res2, ATA_AHCI_CAP) & ATA_AHCI_CAP_64BIT) |
| 1029 |
ch->dma.max_address = BUS_SPACE_MAXADDR; |
| 1030 |
ata_dmainit(dev); |
| 1031 |
} |
| 1032 |
|
| 1033 |
static int |
| 1034 |
ata_ahci_setup_fis(struct ata_ahci_cmd_tab *ctp, struct ata_request *request) |
| 1035 |
{ |
| 1036 |
bzero(ctp->cfis, 64); |
| 1037 |
if (request->flags & ATA_R_ATAPI) { |
| 1038 |
bzero(ctp->acmd, 32); |
| 1039 |
bcopy(request->u.atapi.ccb, ctp->acmd, 16); |
| 1040 |
} |
| 1041 |
return ata_request2fis_h2d(request, &ctp->cfis[0]); |
| 1042 |
} |
| 1043 |
|
| 1044 |
ATA_DECLARE_DRIVER(ata_ahci); |
| 1045 |
static device_method_t ata_ahci_ata_methods[] = { |
| 1046 |
DEVMETHOD(device_probe, ata_ahci_ata_probe), |
| 1047 |
DEVMETHOD(device_attach, ata_ahci_ata_attach), |
| 1048 |
DEVMETHOD(device_detach, ata_pci_detach), |
| 1049 |
DEVMETHOD(device_suspend, ata_pci_suspend), |
| 1050 |
DEVMETHOD(device_resume, ata_pci_resume), |
| 1051 |
DEVMETHOD(device_shutdown, bus_generic_shutdown), |
| 1052 |
DEVMETHOD(bus_read_ivar, ata_pci_read_ivar), |
| 1053 |
DEVMETHOD(bus_write_ivar, ata_pci_write_ivar), |
| 1054 |
DEVMETHOD(bus_alloc_resource, ata_pci_alloc_resource), |
| 1055 |
DEVMETHOD(bus_release_resource, ata_pci_release_resource), |
| 1056 |
DEVMETHOD(bus_activate_resource, bus_generic_activate_resource), |
| 1057 |
DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), |
| 1058 |
DEVMETHOD(bus_setup_intr, ata_pci_setup_intr), |
| 1059 |
DEVMETHOD(bus_teardown_intr, ata_pci_teardown_intr), |
| 1060 |
DEVMETHOD_END |
| 1061 |
}; |
| 1062 |
static driver_t ata_ahci_ata_driver = { |
| 1063 |
"atapci", |
| 1064 |
ata_ahci_ata_methods, |
| 1065 |
sizeof(struct ata_pci_controller) |
| 1066 |
}; |
| 1067 |
DRIVER_MODULE(ata_ahci_ata, atapci, ata_ahci_ata_driver, ata_pci_devclass, |
| 1068 |
NULL, NULL); |