| Commit | Line | Data |
|---|---|---|
| 1980eff3 MD |
1 | /* |
| 2 | * Copyright (c) 2009 The DragonFly Project. All rights reserved. | |
| 3 | * | |
| 4 | * This code is derived from software contributed to The DragonFly Project | |
| 5 | * by Matthew Dillon <dillon@backplane.com> | |
| 6 | * | |
| 7 | * Redistribution and use in source and binary forms, with or without | |
| 8 | * modification, are permitted provided that the following conditions | |
| 9 | * are met: | |
| 10 | * | |
| 11 | * 1. Redistributions of source code must retain the above copyright | |
| 12 | * notice, this list of conditions and the following disclaimer. | |
| 13 | * 2. Redistributions in binary form must reproduce the above copyright | |
| 14 | * notice, this list of conditions and the following disclaimer in | |
| 15 | * the documentation and/or other materials provided with the | |
| 16 | * distribution. | |
| 17 | * 3. Neither the name of The DragonFly Project nor the names of its | |
| 18 | * contributors may be used to endorse or promote products derived | |
| 19 | * from this software without specific, prior written permission. | |
| 20 | * | |
| 21 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
| 22 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
| 23 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | |
| 24 | * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE | |
| 25 | * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, | |
| 26 | * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, | |
| 27 | * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | |
| 28 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED | |
| 29 | * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | |
| 30 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT | |
| 31 | * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
| 32 | * SUCH DAMAGE. | |
| 33 | */ | |
| 34 | ||
| 35 | #include "ahci.h" | |
| 36 | ||
| 37 | static void ahci_pm_dummy_done(struct ata_xfer *xa); | |
| 38 | static void ahci_pm_empty_done(struct ahci_ccb *ccb); | |
| 39 | ||
| 40 | /* | |
| 41 | * Identify the port multiplier | |
| 42 | */ | |
| 43 | int | |
| 44 | ahci_pm_identify(struct ahci_port *ap) | |
| 45 | { | |
| 46 | u_int32_t chipid; | |
| 47 | u_int32_t rev; | |
| 48 | u_int32_t nports; | |
| 3209f581 MD |
49 | u_int32_t data1; |
| 50 | u_int32_t data2; | |
| 1980eff3 MD |
51 | |
| 52 | ap->ap_pmcount = 0; | |
| 53 | ap->ap_probe = ATA_PROBE_FAILED; | |
| 54 | if (ahci_pm_read(ap, 15, 0, &chipid)) | |
| 3209f581 | 55 | goto err; |
| 1980eff3 | 56 | if (ahci_pm_read(ap, 15, 1, &rev)) |
| 3209f581 | 57 | goto err; |
| 1980eff3 | 58 | if (ahci_pm_read(ap, 15, 2, &nports)) |
| 3209f581 MD |
59 | goto err; |
| 60 | nports &= 0x0000000F; /* only the low 4 bits */ | |
| 1980eff3 | 61 | ap->ap_probe = ATA_PROBE_GOOD; |
| 3209f581 MD |
62 | kprintf("%s: Port multiplier: chip=%08x rev=0x%b nports=%d\n", |
| 63 | PORTNAME(ap), | |
| 64 | chipid, | |
| 65 | rev, AHCI_PFMT_PM_REV, | |
| 66 | nports); | |
| 1980eff3 | 67 | ap->ap_pmcount = nports; |
| 3209f581 MD |
68 | |
| 69 | if (ahci_pm_read(ap, 15, AHCI_PMREG_FEA, &data1)) { | |
| 70 | kprintf("%s: Port multiplier: Warning, " | |
| 71 | "cannot read feature register\n", PORTNAME(ap)); | |
| 72 | } else { | |
| 73 | kprintf("%s: Port multiplier features: 0x%b\n", | |
| 74 | PORTNAME(ap), | |
| 75 | data1, | |
| 76 | AHCI_PFMT_PM_FEA); | |
| 77 | } | |
| 78 | if (ahci_pm_read(ap, 15, AHCI_PMREG_FEAEN, &data2) == 0) { | |
| 79 | kprintf("%s: Port multiplier defaults: 0x%b\n", | |
| 80 | PORTNAME(ap), | |
| 81 | data2, | |
| 82 | AHCI_PFMT_PM_FEA); | |
| 83 | } | |
| 84 | ||
| 85 | /* | |
| 86 | * Turn on async notification if we support and the PM supports it. | |
| 87 | * This allows the PM to forward async notification events to us and | |
| 88 | * it will also generate an event for target 15 for hot-plug events | |
| 89 | * (or is supposed to anyway). | |
| 90 | */ | |
| 91 | if ((ap->ap_sc->sc_cap & AHCI_REG_CAP_SSNTF) && | |
| 92 | (data1 & AHCI_PMFEA_ASYNCNOTIFY)) { | |
| 93 | u_int32_t serr_bits = AHCI_PREG_SERR_DIAG_N | | |
| 94 | AHCI_PREG_SERR_DIAG_X; | |
| 95 | data2 |= AHCI_PMFEA_ASYNCNOTIFY; | |
| 96 | if (ahci_pm_write(ap, 15, AHCI_PMREG_FEAEN, data2)) { | |
| 97 | kprintf("%s: Port multiplier: AsyncNotify cannot be " | |
| 98 | "enabled\n", PORTNAME(ap)); | |
| 99 | } else if (ahci_pm_write(ap, 15, AHCI_PMREG_EEENA, serr_bits)) { | |
| 100 | kprintf("%s: Port mulltiplier: AsyncNotify unable " | |
| 101 | "to enable error info bits\n", PORTNAME(ap)); | |
| 102 | } else { | |
| 103 | kprintf("%s: Port multiplier: AsyncNotify enabled\n", | |
| 104 | PORTNAME(ap)); | |
| 105 | } | |
| 106 | } | |
| 107 | ||
| 1980eff3 | 108 | return (0); |
| 3209f581 MD |
109 | err: |
| 110 | kprintf("%s: Port multiplier cannot be identified\n", PORTNAME(ap)); | |
| 111 | return (EIO); | |
| 1980eff3 MD |
112 | } |
| 113 | ||
| 114 | /* | |
| 115 | * Do a COMRESET sequence on the target behind a port multiplier. | |
| 116 | * | |
| 117 | * If hard is 2 we also cycle the phy on the target. | |
| 118 | * | |
| 119 | * This must be done prior to any softreset or probe attempts on | |
| 120 | * targets behind the port multiplier. | |
| 121 | * | |
| 122 | * Returns 0 on success or an error. | |
| 123 | */ | |
| 124 | int | |
| 125 | ahci_pm_hardreset(struct ahci_port *ap, int target, int hard) | |
| 126 | { | |
| 127 | struct ata_port *at; | |
| 128 | u_int32_t data; | |
| 129 | int loop; | |
| 3209f581 | 130 | int error = EIO; |
| 1980eff3 | 131 | |
| 1980eff3 MD |
132 | at = &ap->ap_ata[target]; |
| 133 | ||
| 134 | /* | |
| 135 | * Turn off power management and kill the phy on the target | |
| 136 | * if requested. Hold state for 10ms. | |
| 137 | */ | |
| 138 | data = AHCI_PREG_SCTL_IPM_DISABLED; | |
| 139 | if (hard == 2) | |
| 140 | data |= AHCI_PREG_SCTL_DET_DISABLE; | |
| 3209f581 MD |
141 | if (ahci_pm_write(ap, target, AHCI_PMREG_SERR, -1)) |
| 142 | goto err; | |
| 1980eff3 | 143 | if (ahci_pm_write(ap, target, AHCI_PMREG_SCTL, data)) |
| 3209f581 MD |
144 | goto err; |
| 145 | ahci_os_sleep(10); | |
| 1980eff3 MD |
146 | |
| 147 | /* | |
| 148 | * Start transmitting COMRESET. COMRESET must be sent for at | |
| 149 | * least 1ms. | |
| 150 | */ | |
| 151 | at->at_probe = ATA_PROBE_FAILED; | |
| 152 | at->at_type = ATA_PORT_T_NONE; | |
| 153 | data = AHCI_PREG_SCTL_IPM_DISABLED | AHCI_PREG_SCTL_DET_INIT; | |
| 154 | if (AhciForceGen1 & (1 << ap->ap_num)) { | |
| 155 | kprintf("%s.%d: Force 1.5GBits\n", PORTNAME(ap), target); | |
| 156 | data |= AHCI_PREG_SCTL_SPD_GEN1; | |
| 157 | } else { | |
| 158 | data |= AHCI_PREG_SCTL_SPD_ANY; | |
| 159 | } | |
| 160 | if (ahci_pm_write(ap, target, AHCI_PMREG_SCTL, data)) | |
| 3209f581 | 161 | goto err; |
| 3209f581 | 162 | |
| 831bc9e3 MD |
163 | /* |
| 164 | * It takes about 100ms for the DET logic to settle down, | |
| 165 | * from trial and error testing. If this is too short | |
| 166 | * the softreset code will fail. | |
| 167 | */ | |
| 168 | ahci_os_sleep(100); | |
| 169 | ||
| 3209f581 | 170 | if (ahci_pm_phy_status(ap, target, &data)) { |
| 831bc9e3 | 171 | kprintf("%s: (A)Cannot clear phy status\n", |
| 3209f581 MD |
172 | ATANAME(ap ,at)); |
| 173 | } | |
| 1980eff3 MD |
174 | |
| 175 | /* | |
| 176 | * Flush any status, then clear DET to initiate negotiation. | |
| 177 | */ | |
| 178 | ahci_pm_write(ap, target, AHCI_PMREG_SERR, -1); | |
| 179 | data = AHCI_PREG_SCTL_IPM_DISABLED | AHCI_PREG_SCTL_DET_NONE; | |
| 180 | if (ahci_pm_write(ap, target, AHCI_PMREG_SCTL, data)) | |
| 3209f581 | 181 | goto err; |
| 1980eff3 MD |
182 | |
| 183 | /* | |
| 184 | * Try to determine if there is a device on the port. | |
| 185 | * | |
| 186 | * Give the device 3/10 second to at least be detected. | |
| 187 | * If we fail clear any pending status since we may have | |
| 188 | * cycled the phy and probably caused another PRCS interrupt. | |
| 189 | */ | |
| 3209f581 | 190 | for (loop = 3; loop; --loop) { |
| 1980eff3 | 191 | if (ahci_pm_read(ap, target, AHCI_PMREG_SSTS, &data)) |
| 3209f581 | 192 | goto err; |
| 1980eff3 MD |
193 | if (data & AHCI_PREG_SSTS_DET) |
| 194 | break; | |
| 3209f581 | 195 | ahci_os_sleep(100); |
| 1980eff3 MD |
196 | } |
| 197 | if (loop == 0) { | |
| 198 | kprintf("%s.%d: Port appears to be unplugged\n", | |
| 199 | PORTNAME(ap), target); | |
| 3209f581 MD |
200 | error = ENODEV; |
| 201 | goto err; | |
| 1980eff3 MD |
202 | } |
| 203 | ||
| 204 | /* | |
| 205 | * There is something on the port. Give the device 3 seconds | |
| 206 | * to fully negotiate. | |
| 207 | */ | |
| 3209f581 | 208 | for (loop = 30; loop; --loop) { |
| 1980eff3 | 209 | if (ahci_pm_read(ap, target, AHCI_PMREG_SSTS, &data)) |
| 3209f581 | 210 | goto err; |
| 1980eff3 MD |
211 | if ((data & AHCI_PREG_SSTS_DET) == AHCI_PREG_SSTS_DET_DEV) |
| 212 | break; | |
| 3209f581 | 213 | ahci_os_sleep(100); |
| 1980eff3 | 214 | } |
| 3209f581 MD |
215 | |
| 216 | /* | |
| 3209f581 MD |
217 | * Device not detected |
| 218 | */ | |
| 1980eff3 MD |
219 | if (loop == 0) { |
| 220 | kprintf("%s: Device may be powered down\n", | |
| 221 | PORTNAME(ap)); | |
| 3209f581 MD |
222 | error = ENODEV; |
| 223 | goto err; | |
| 1980eff3 MD |
224 | } |
| 225 | ||
| 226 | /* | |
| 3209f581 | 227 | * Device detected |
| 1980eff3 | 228 | */ |
| 1980eff3 MD |
229 | kprintf("%s.%d: Device detected data=%08x\n", |
| 230 | PORTNAME(ap), target, data); | |
| 831bc9e3 MD |
231 | /* |
| 232 | * Clear SERR on the target so we get a new NOTIFY event if a hot-plug | |
| 233 | * or hot-unplug occurs. | |
| 234 | */ | |
| 3209f581 | 235 | ahci_os_sleep(100); |
| 831bc9e3 | 236 | |
| 3209f581 MD |
237 | error = 0; |
| 238 | err: | |
| 239 | at->at_probe = error ? ATA_PROBE_FAILED : ATA_PROBE_NEED_SOFT_RESET; | |
| 831bc9e3 | 240 | return (error); |
| 1980eff3 MD |
241 | } |
| 242 | ||
| 243 | /* | |
| 244 | * AHCI soft reset through port multiplier. | |
| 245 | * | |
| 246 | * This function keeps port communications intact and attempts to generate | |
| 247 | * a reset to the connected device using device commands. Unlike | |
| 248 | * hard-port operations we can't do fancy stop/starts or stuff like | |
| 249 | * that without messing up other commands that might be running or | |
| 250 | * queued. | |
| 251 | */ | |
| 252 | int | |
| 253 | ahci_pm_softreset(struct ahci_port *ap, int target) | |
| 254 | { | |
| 255 | struct ata_port *at; | |
| 256 | struct ahci_ccb *ccb = NULL; | |
| 257 | struct ahci_cmd_hdr *cmd_slot; | |
| 258 | u_int8_t *fis; | |
| 3209f581 MD |
259 | int count; |
| 260 | int error; | |
| 1980eff3 | 261 | u_int32_t data; |
| 3209f581 | 262 | int tried_longer; |
| 1980eff3 | 263 | |
| 3209f581 | 264 | error = EIO; |
| 1980eff3 MD |
265 | at = &ap->ap_ata[target]; |
| 266 | ||
| 267 | DPRINTF(AHCI_D_VERBOSE, "%s: soft reset\n", PORTNAME(ap)); | |
| 268 | ||
| 1980eff3 | 269 | count = 2; |
| 3209f581 | 270 | tried_longer = 0; |
| 1980eff3 MD |
271 | retry: |
| 272 | /* | |
| 273 | * Try to clear the phy so we get a good signature, otherwise | |
| 274 | * the PM may not latch a new signature. | |
| 275 | * | |
| 276 | * NOTE: This cannot be safely done between the first and second | |
| 277 | * softreset FISs. It's now or never. | |
| 278 | */ | |
| 1980eff3 | 279 | if (ahci_pm_phy_status(ap, target, &data)) { |
| 831bc9e3 | 280 | kprintf("%s: (B)Cannot clear phy status\n", |
| 1980eff3 MD |
281 | ATANAME(ap ,at)); |
| 282 | } | |
| 831bc9e3 | 283 | ahci_pm_write(ap, target, AHCI_PMREG_SERR, -1); |
| 1980eff3 MD |
284 | |
| 285 | /* | |
| 286 | * Prep first D2H command with SRST feature & clear busy/reset flags | |
| 287 | * | |
| 288 | * It is unclear which other fields in the FIS are used. Just zero | |
| 289 | * everything. | |
| 290 | * | |
| 291 | * When soft-resetting a port behind a multiplier at will be | |
| 292 | * non-NULL, assigning it to the ccb prevents the port interrupt | |
| 293 | * from hard-resetting the port if a problem crops up. | |
| 294 | */ | |
| 295 | ccb = ahci_get_ccb(ap); | |
| 296 | ccb->ccb_done = ahci_pm_empty_done; | |
| 297 | ccb->ccb_xa.flags = ATA_F_READ | ATA_F_POLL; | |
| 298 | ccb->ccb_xa.complete = ahci_pm_dummy_done; | |
| 299 | ccb->ccb_xa.at = at; | |
| 300 | ||
| 301 | fis = ccb->ccb_cmd_table->cfis; | |
| 302 | bzero(fis, sizeof(ccb->ccb_cmd_table->cfis)); | |
| 303 | fis[0] = ATA_FIS_TYPE_H2D; | |
| 304 | fis[1] = at->at_target; | |
| 305 | fis[15] = ATA_FIS_CONTROL_SRST|ATA_FIS_CONTROL_4BIT; | |
| 306 | ||
| 307 | cmd_slot = ccb->ccb_cmd_hdr; | |
| 308 | cmd_slot->prdtl = 0; | |
| 309 | cmd_slot->flags = htole16(5); /* FIS length: 5 DWORDS */ | |
| 310 | cmd_slot->flags |= htole16(AHCI_CMD_LIST_FLAG_C); /* Clear busy on OK */ | |
| 311 | cmd_slot->flags |= htole16(AHCI_CMD_LIST_FLAG_R); /* Reset */ | |
| 312 | cmd_slot->flags |= htole16(at->at_target << | |
| 313 | AHCI_CMD_LIST_FLAG_PMP_SHIFT); | |
| 314 | ||
| 315 | ccb->ccb_xa.state = ATA_S_PENDING; | |
| 316 | ccb->ccb_xa.flags = 0; | |
| 317 | ||
| 3209f581 MD |
318 | /* |
| 319 | * XXX hack to ignore IFS errors which can occur during the target | |
| 320 | * device's reset. | |
| 321 | * | |
| 322 | * If an IFS error occurs the target is probably powering up, | |
| 323 | * so we try for a longer period of time. | |
| 324 | */ | |
| 325 | ap->ap_flags |= AP_F_IGNORE_IFS; | |
| 326 | ap->ap_flags &= ~(AP_F_IFS_IGNORED | AP_F_IFS_OCCURED); | |
| 327 | ||
| 831bc9e3 MD |
328 | if (ahci_poll(ccb, 1000, ahci_ata_cmd_timeout) != ATA_S_COMPLETE) { |
| 329 | kprintf("%s: (PM) First FIS failed\n", ATANAME(ap, at)); | |
| 330 | if (ap->ap_flags & AP_F_IFS_OCCURED) { | |
| 331 | if (tried_longer == 0) | |
| 332 | count += 4; | |
| 333 | ++tried_longer; | |
| 3209f581 | 334 | } |
| 1980eff3 | 335 | if (--count) { |
| 1980eff3 MD |
336 | ahci_put_ccb(ccb); |
| 337 | goto retry; | |
| 338 | } | |
| 339 | goto err; | |
| 340 | } | |
| 341 | ||
| 342 | /* | |
| 831bc9e3 MD |
343 | * WARNING! SENSITIVE TIME PERIOD! WARNING! |
| 344 | * | |
| 345 | * The first and second FISes are supposed to be back-to-back, | |
| 346 | * I think the idea is to get the second sent and then after | |
| 347 | * the device resets it will send a signature. Do not delay | |
| 348 | * here and most definitely do not issue any commands to other | |
| 349 | * targets! | |
| 1980eff3 | 350 | */ |
| 1980eff3 MD |
351 | |
| 352 | /* | |
| 353 | * Prep second D2H command to read status and complete reset sequence | |
| 354 | * AHCI 10.4.1 and "Serial ATA Revision 2.6". I can't find the ATA | |
| 355 | * Rev 2.6 and it is unclear how the second FIS should be set up | |
| 356 | * from the AHCI document. | |
| 357 | * | |
| 358 | * Give the device 3ms before sending the second FIS. | |
| 359 | * | |
| 360 | * It is unclear which other fields in the FIS are used. Just zero | |
| 361 | * everything. | |
| 362 | */ | |
| 363 | bzero(fis, sizeof(ccb->ccb_cmd_table->cfis)); | |
| 364 | fis[0] = ATA_FIS_TYPE_H2D; | |
| 365 | fis[1] = at->at_target; | |
| 366 | fis[15] = ATA_FIS_CONTROL_4BIT; | |
| 367 | ||
| 368 | cmd_slot->prdtl = 0; | |
| 369 | cmd_slot->flags = htole16(5); /* FIS length: 5 DWORDS */ | |
| 370 | cmd_slot->flags |= htole16(at->at_target << | |
| 371 | AHCI_CMD_LIST_FLAG_PMP_SHIFT); | |
| 372 | ||
| 373 | ccb->ccb_xa.state = ATA_S_PENDING; | |
| 374 | ccb->ccb_xa.flags = 0; | |
| 375 | ||
| 831bc9e3 MD |
376 | if (ahci_poll(ccb, 1000, ahci_ata_cmd_timeout) != ATA_S_COMPLETE) { |
| 377 | kprintf("%s: (PM) Second FIS failed\n", ATANAME(ap, at)); | |
| 1980eff3 | 378 | if (--count) { |
| 1980eff3 MD |
379 | ahci_put_ccb(ccb); |
| 380 | goto retry; | |
| 381 | } | |
| 382 | goto err; | |
| 383 | } | |
| 384 | ||
| 831bc9e3 MD |
385 | ahci_os_sleep(100); |
| 386 | ahci_pm_write(ap, target, AHCI_PMREG_SERR, -1); | |
| 387 | if (ahci_pm_phy_status(ap, target, &data)) { | |
| 388 | kprintf("%s: (C)Cannot clear phy status\n", | |
| 389 | ATANAME(ap ,at)); | |
| 390 | } | |
| 391 | ahci_pm_write(ap, target, AHCI_PMREG_SERR, -1); | |
| 1980eff3 MD |
392 | |
| 393 | /* | |
| 394 | * Do it again, even if we think we got a good result | |
| 395 | */ | |
| 396 | if (--count) { | |
| 397 | fis[15] = 0; | |
| 398 | ahci_put_ccb(ccb); | |
| 399 | goto retry; | |
| 400 | } | |
| 401 | ||
| 402 | /* | |
| 403 | * If the softreset is trying to clear a BSY condition after a | |
| 404 | * normal portreset we assign the port type. | |
| 405 | * | |
| 406 | * If the softreset is being run first as part of the ccb error | |
| 407 | * processing code then report if the device signature changed | |
| 408 | * unexpectedly. | |
| 409 | */ | |
| 410 | if (at->at_type == ATA_PORT_T_NONE) { | |
| 411 | at->at_type = ahci_port_signature_detect(ap, at); | |
| 412 | } else { | |
| 413 | if (ahci_port_signature_detect(ap, at) != at->at_type) { | |
| 414 | kprintf("%s: device signature unexpectedly " | |
| 415 | "changed\n", ATANAME(ap, at)); | |
| 3209f581 | 416 | error = EBUSY; /* XXX */ |
| 1980eff3 MD |
417 | } |
| 418 | } | |
| 3209f581 | 419 | error = 0; |
| 1980eff3 | 420 | |
| 831bc9e3 MD |
421 | /* |
| 422 | * Who knows what kind of mess occured. We have exclusive access | |
| 423 | * to the port so try to clean up potential problems. | |
| 424 | */ | |
| 3209f581 | 425 | ahci_os_sleep(100); |
| 1980eff3 MD |
426 | err: |
| 427 | /* | |
| 428 | * Clean up the CCB. If the command failed it already went through | |
| 429 | * the standard timeout handling and should no longer be active. | |
| 430 | */ | |
| 431 | if (ccb) { | |
| 432 | KKASSERT((ap->ap_active & (1 << ccb->ccb_slot)) == 0); | |
| 1980eff3 MD |
433 | ahci_put_ccb(ccb); |
| 434 | } | |
| 435 | ||
| 436 | /* | |
| 831bc9e3 | 437 | * Clear error status so we can detect removal. |
| 3209f581 MD |
438 | */ |
| 439 | if (ahci_pm_write(ap, target, AHCI_PMREG_SERR, -1)) { | |
| 440 | kprintf("%s: ahci_pm_softreset unable to clear SERR\n", | |
| 441 | ATANAME(ap, at)); | |
| 831bc9e3 | 442 | ap->ap_flags &= ~AP_F_IGNORE_IFS; |
| 3209f581 | 443 | } |
| 831bc9e3 | 444 | ahci_pwrite(ap, AHCI_PREG_SERR, -1); |
| 3209f581 | 445 | |
| 1980eff3 | 446 | |
| 3209f581 MD |
447 | at->at_probe = error ? ATA_PROBE_FAILED : ATA_PROBE_NEED_IDENT; |
| 448 | return (error); | |
| 1980eff3 MD |
449 | } |
| 450 | ||
| 451 | ||
| 452 | /* | |
| 453 | * Return the phy status for a target behind a port multiplier and | |
| 454 | * reset AHCI_PMREG_SERR. | |
| 455 | * | |
| 456 | * Returned bits follow AHCI_PREG_SSTS bits. The AHCI_PREG_SSTS_SPD | |
| 457 | * bits can be used to determine the link speed and will be 0 if there | |
| 458 | * is no link. | |
| 459 | * | |
| 460 | * 0 is returned if any communications error occurs. | |
| 461 | */ | |
| 462 | int | |
| 463 | ahci_pm_phy_status(struct ahci_port *ap, int target, u_int32_t *datap) | |
| 464 | { | |
| 465 | int error; | |
| 466 | ||
| 467 | error = ahci_pm_read(ap, target, AHCI_PMREG_SSTS, datap); | |
| 468 | if (error == 0) | |
| 469 | error = ahci_pm_write(ap, target, AHCI_PMREG_SERR, -1); | |
| 470 | if (error) | |
| 471 | *datap = 0; | |
| 472 | return(error); | |
| 473 | } | |
| 474 | ||
| 3209f581 MD |
475 | int |
| 476 | ahci_pm_set_feature(struct ahci_port *ap, int feature, int enable) | |
| 477 | { | |
| 478 | struct ata_xfer *xa; | |
| 3209f581 MD |
479 | int error; |
| 480 | ||
| 481 | xa = ahci_ata_get_xfer(ap, &ap->ap_ata[15]); | |
| 482 | ||
| 483 | bzero(xa->fis, sizeof(*xa->fis)); | |
| 484 | xa->fis->type = ATA_FIS_TYPE_H2D; | |
| 485 | xa->fis->flags = ATA_H2D_FLAGS_CMD | 15; | |
| 486 | xa->fis->command = enable ? ATA_C_SATA_FEATURE_ENA : | |
| 487 | ATA_C_SATA_FEATURE_DIS; | |
| 488 | xa->fis->sector_count = feature; | |
| 489 | xa->fis->control = ATA_FIS_CONTROL_4BIT; | |
| 490 | ||
| 491 | xa->complete = ahci_pm_dummy_done; | |
| 492 | xa->datalen = 0; | |
| 493 | xa->flags = ATA_F_READ | ATA_F_POLL; | |
| 494 | xa->timeout = 1000; | |
| 495 | ||
| 831bc9e3 MD |
496 | if (ahci_ata_cmd(xa) == ATA_S_COMPLETE) |
| 497 | error = 0; | |
| 498 | else | |
| 499 | error = EIO; | |
| 3209f581 MD |
500 | ahci_ata_put_xfer(xa); |
| 501 | return(error); | |
| 502 | } | |
| 503 | ||
| 504 | /* | |
| 505 | * Check that a target is still good. | |
| 506 | */ | |
| 507 | void | |
| 508 | ahci_pm_check_good(struct ahci_port *ap, int target) | |
| 509 | { | |
| 510 | struct ata_port *at; | |
| 511 | u_int32_t data; | |
| 512 | ||
| 513 | /* | |
| 514 | * It looks like we might have to read the EINFO register | |
| 515 | * to allow the PM to generate a new event. | |
| 516 | */ | |
| 517 | if (ahci_pm_read(ap, 15, AHCI_PMREG_EINFO, &data)) { | |
| 518 | kprintf("%s: Port multiplier EINFO could not be read\n", | |
| 519 | PORTNAME(ap)); | |
| 520 | } | |
| 521 | if (ahci_pm_write(ap, target, AHCI_PMREG_SERR, -1)) { | |
| 522 | kprintf("%s: Port multiplier: SERR could not be cleared\n", | |
| 523 | PORTNAME(ap)); | |
| 524 | } | |
| 525 | ||
| 526 | if (target == CAM_TARGET_WILDCARD) | |
| 527 | return; | |
| 528 | ||
| 529 | at = &ap->ap_ata[target]; | |
| 530 | if (ahci_pm_read(ap, target, AHCI_PMREG_SSTS, &data)) { | |
| 531 | kprintf("%s: Unable to access PM SSTS register target %d\n", | |
| 532 | PORTNAME(ap), target); | |
| 533 | return; | |
| 534 | } | |
| 535 | if ((data & AHCI_PREG_SSTS_DET) != AHCI_PREG_SSTS_DET_DEV) { | |
| 536 | if (at->at_probe != ATA_PROBE_FAILED) { | |
| 537 | at->at_probe = ATA_PROBE_FAILED; | |
| 538 | at->at_type = ATA_PORT_T_NONE; | |
| 539 | at->at_features |= ATA_PORT_F_RESCAN; | |
| 831bc9e3 | 540 | kprintf("%s: HOTPLUG (PM) - Device removed\n", |
| 3209f581 MD |
541 | ATANAME(ap, at)); |
| 542 | } | |
| 543 | } else { | |
| 544 | if (at->at_probe == ATA_PROBE_FAILED) { | |
| 545 | at->at_probe = ATA_PROBE_NEED_HARD_RESET; | |
| 546 | at->at_features |= ATA_PORT_F_RESCAN; | |
| 831bc9e3 | 547 | kprintf("%s: HOTPLUG (PM) - Device inserted\n", |
| 3209f581 MD |
548 | ATANAME(ap, at)); |
| 549 | } | |
| 550 | } | |
| 551 | } | |
| 552 | ||
| 1980eff3 MD |
553 | /* |
| 554 | * Read a PM register | |
| 555 | */ | |
| 556 | int | |
| 557 | ahci_pm_read(struct ahci_port *ap, int target, int which, u_int32_t *datap) | |
| 558 | { | |
| 559 | struct ata_xfer *xa; | |
| 1980eff3 MD |
560 | int error; |
| 561 | ||
| 562 | xa = ahci_ata_get_xfer(ap, &ap->ap_ata[15]); | |
| 563 | ||
| 564 | bzero(xa->fis, sizeof(*xa->fis)); | |
| 565 | xa->fis->type = ATA_FIS_TYPE_H2D; | |
| 566 | xa->fis->flags = ATA_H2D_FLAGS_CMD | 15; | |
| 567 | xa->fis->command = ATA_C_READ_PM; | |
| 568 | xa->fis->features = which; | |
| 569 | xa->fis->device = target | ATA_H2D_DEVICE_LBA; | |
| 570 | xa->fis->control = ATA_FIS_CONTROL_4BIT; | |
| 571 | ||
| 572 | xa->complete = ahci_pm_dummy_done; | |
| 573 | xa->datalen = 0; | |
| 574 | xa->flags = ATA_F_READ | ATA_F_POLL; | |
| 3209f581 | 575 | xa->timeout = 1000; |
| 1980eff3 | 576 | |
| 831bc9e3 | 577 | if (ahci_ata_cmd(xa) == ATA_S_COMPLETE) { |
| 1980eff3 MD |
578 | *datap = xa->rfis.sector_count | (xa->rfis.lba_low << 8) | |
| 579 | (xa->rfis.lba_mid << 16) | (xa->rfis.lba_high << 24); | |
| 580 | error = 0; | |
| 581 | } else { | |
| 831bc9e3 MD |
582 | kprintf("%s.%d pm_read SCA[%d] failed\n", |
| 583 | PORTNAME(ap), target, which); | |
| 1980eff3 MD |
584 | *datap = 0; |
| 585 | error = EIO; | |
| 586 | } | |
| 587 | ahci_ata_put_xfer(xa); | |
| 588 | return (error); | |
| 589 | } | |
| 590 | ||
| 591 | /* | |
| 592 | * Write a PM register | |
| 593 | */ | |
| 594 | int | |
| 595 | ahci_pm_write(struct ahci_port *ap, int target, int which, u_int32_t data) | |
| 596 | { | |
| 597 | struct ata_xfer *xa; | |
| 1980eff3 MD |
598 | int error; |
| 599 | ||
| 600 | xa = ahci_ata_get_xfer(ap, &ap->ap_ata[15]); | |
| 601 | ||
| 602 | bzero(xa->fis, sizeof(*xa->fis)); | |
| 603 | xa->fis->type = ATA_FIS_TYPE_H2D; | |
| 604 | xa->fis->flags = ATA_H2D_FLAGS_CMD | 15; | |
| 605 | xa->fis->command = ATA_C_WRITE_PM; | |
| 606 | xa->fis->features = which; | |
| 607 | xa->fis->device = target | ATA_H2D_DEVICE_LBA; | |
| 608 | xa->fis->sector_count = (u_int8_t)data; | |
| 609 | xa->fis->lba_low = (u_int8_t)(data >> 8); | |
| 610 | xa->fis->lba_mid = (u_int8_t)(data >> 16); | |
| 611 | xa->fis->lba_high = (u_int8_t)(data >> 24); | |
| 612 | xa->fis->control = ATA_FIS_CONTROL_4BIT; | |
| 613 | ||
| 614 | xa->complete = ahci_pm_dummy_done; | |
| 615 | xa->datalen = 0; | |
| 616 | xa->flags = ATA_F_READ | ATA_F_POLL; | |
| 3209f581 | 617 | xa->timeout = 1000; |
| 1980eff3 | 618 | |
| 831bc9e3 MD |
619 | if (ahci_ata_cmd(xa) == ATA_S_COMPLETE) |
| 620 | error = 0; | |
| 621 | else | |
| 622 | error = EIO; | |
| 1980eff3 MD |
623 | ahci_ata_put_xfer(xa); |
| 624 | return(error); | |
| 625 | } | |
| 626 | ||
| 627 | /* | |
| 628 | * Dummy done callback for xa. | |
| 629 | */ | |
| 630 | static void | |
| 631 | ahci_pm_dummy_done(struct ata_xfer *xa) | |
| 632 | { | |
| 633 | } | |
| 634 | ||
| 635 | static void | |
| 636 | ahci_pm_empty_done(struct ahci_ccb *ccb) | |
| 637 | { | |
| 831bc9e3 MD |
638 | if (ccb->ccb_xa.state == ATA_S_ONCHIP) |
| 639 | ccb->ccb_xa.state = ATA_S_COMPLETE; | |
| 1980eff3 | 640 | } |