| Commit | Line | Data |
|---|---|---|
| 1980eff3 | 1 | /* |
| fb00c6ed MD |
2 | * (MPSAFE) |
| 3 | * | |
| 1980eff3 MD |
4 | * Copyright (c) 2009 The DragonFly Project. All rights reserved. |
| 5 | * | |
| 6 | * This code is derived from software contributed to The DragonFly Project | |
| 7 | * by Matthew Dillon <dillon@backplane.com> | |
| 8 | * | |
| 9 | * Redistribution and use in source and binary forms, with or without | |
| 10 | * modification, are permitted provided that the following conditions | |
| 11 | * are met: | |
| 12 | * | |
| 13 | * 1. Redistributions of source code must retain the above copyright | |
| 14 | * notice, this list of conditions and the following disclaimer. | |
| 15 | * 2. Redistributions in binary form must reproduce the above copyright | |
| 16 | * notice, this list of conditions and the following disclaimer in | |
| 17 | * the documentation and/or other materials provided with the | |
| 18 | * distribution. | |
| 19 | * 3. Neither the name of The DragonFly Project nor the names of its | |
| 20 | * contributors may be used to endorse or promote products derived | |
| 21 | * from this software without specific, prior written permission. | |
| 22 | * | |
| 23 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
| 24 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
| 25 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | |
| 26 | * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE | |
| 27 | * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, | |
| 28 | * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, | |
| 29 | * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | |
| 30 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED | |
| 31 | * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | |
| 32 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT | |
| 33 | * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
| 34 | * SUCH DAMAGE. | |
| 35 | */ | |
| 36 | ||
| 37 | #include "ahci.h" | |
| 38 | ||
| 39 | static void ahci_pm_dummy_done(struct ata_xfer *xa); | |
| 12feb904 MD |
40 | |
| 41 | int | |
| 42 | ahci_pm_port_init(struct ahci_port *ap, struct ata_port *at) | |
| 43 | { | |
| 44 | at->at_probe = ATA_PROBE_NEED_HARD_RESET; | |
| 45 | return (0); | |
| 46 | } | |
| 47 | ||
| 48 | /* | |
| 49 | * AHCI port multiplier probe. This routine is run by the hardreset code | |
| 50 | * if it gets past the device detect, whether or not BSY is found to be | |
| 51 | * stuck. | |
| 52 | * | |
| 53 | * We MUST use CLO to properly probe whether the port multiplier exists | |
| 54 | * or not. | |
| 55 | * | |
| 56 | * Return 0 on success, non-zero on failure. | |
| 57 | */ | |
| 58 | int | |
| 59 | ahci_pm_port_probe(struct ahci_port *ap, int orig_error) | |
| 60 | { | |
| 61 | struct ahci_cmd_hdr *cmd_slot; | |
| 62 | struct ata_port *at; | |
| 63 | struct ahci_ccb *ccb = NULL; | |
| 64 | u_int8_t *fis = NULL; | |
| 65 | int error; | |
| 66 | u_int32_t cmd; | |
| 67 | int count; | |
| 68 | int i; | |
| 69 | ||
| 70 | count = 2; | |
| 71 | retry: | |
| 72 | /* | |
| 73 | * This code is only called from hardreset, which does not | |
| 74 | * high level command processing. The port should be stopped. | |
| 75 | * | |
| 76 | * Set PMA mode while the port is stopped. | |
| 77 | * | |
| 78 | * NOTE: On retry the port might be running, stopped, or failed. | |
| 79 | */ | |
| 80 | ahci_port_stop(ap, 0); | |
| 81 | ap->ap_state = AP_S_NORMAL; | |
| 82 | cmd = ahci_pread(ap, AHCI_PREG_CMD) & ~AHCI_PREG_CMD_ICC; | |
| 83 | if ((cmd & AHCI_PREG_CMD_PMA) == 0) { | |
| 84 | cmd |= AHCI_PREG_CMD_PMA; | |
| 85 | ahci_pwrite(ap, AHCI_PREG_CMD, cmd); | |
| 86 | } | |
| 87 | ||
| 88 | /* | |
| 89 | * Flush any errors and request CLO unconditionally, then start | |
| 90 | * the port. | |
| 91 | */ | |
| 92 | ahci_flush_tfd(ap); | |
| 93 | ahci_port_clo(ap); | |
| 94 | if (ahci_port_start(ap)) { | |
| 95 | kprintf("%s: PMPROBE failed to start port, cannot softreset\n", | |
| 96 | PORTNAME(ap)); | |
| 97 | error = EIO; | |
| 98 | goto err; | |
| 99 | } | |
| 100 | ||
| 101 | /* | |
| 102 | * Check whether CLO worked | |
| 103 | */ | |
| 104 | if (ahci_pwait_clr(ap, AHCI_PREG_TFD, | |
| 105 | AHCI_PREG_TFD_STS_BSY | AHCI_PREG_TFD_STS_DRQ)) { | |
| 106 | kprintf("%s: PMPROBE CLO %s, need port reset\n", | |
| 107 | PORTNAME(ap), | |
| 108 | (ahci_read(ap->ap_sc, AHCI_REG_CAP) & AHCI_REG_CAP_SCLO) | |
| 109 | ? "failed" : "unsupported"); | |
| 110 | error = EBUSY; | |
| 111 | goto err; | |
| 112 | } | |
| 113 | ||
| 114 | /* | |
| 115 | * Use the error CCB for all commands | |
| 116 | * | |
| 117 | * NOTE! This CCB is used for both the first and second commands. | |
| 118 | * The second command must use CCB slot 1 to properly load | |
| 119 | * the signature. | |
| 120 | */ | |
| 121 | ccb = ahci_get_err_ccb(ap); | |
| 492bffaf | 122 | ccb->ccb_xa.flags = ATA_F_POLL | ATA_F_SILENT; |
| 12feb904 | 123 | ccb->ccb_xa.complete = ahci_pm_dummy_done; |
| b012a2ca | 124 | ccb->ccb_xa.at = ap->ap_ata[15]; |
| 12feb904 MD |
125 | cmd_slot = ccb->ccb_cmd_hdr; |
| 126 | KKASSERT(ccb->ccb_slot == 1); | |
| 127 | ||
| 128 | /* | |
| 129 | * Prep the first H2D command with SRST feature & clear busy/reset | |
| 130 | * flags. | |
| 131 | */ | |
| 132 | fis = ccb->ccb_cmd_table->cfis; | |
| 133 | bzero(fis, sizeof(ccb->ccb_cmd_table->cfis)); | |
| 134 | fis[0] = ATA_FIS_TYPE_H2D; | |
| 135 | fis[1] = 0x0F; /* Target 15 */ | |
| 136 | fis[15] = ATA_FIS_CONTROL_SRST | ATA_FIS_CONTROL_4BIT; | |
| 137 | ||
| 138 | cmd_slot->prdtl = 0; | |
| 139 | cmd_slot->flags = htole16(5); /* FIS length: 5 DWORDS */ | |
| 140 | cmd_slot->flags |= htole16(AHCI_CMD_LIST_FLAG_C); /* Clear busy on OK */ | |
| 141 | cmd_slot->flags |= htole16(AHCI_CMD_LIST_FLAG_R); /* Reset */ | |
| 142 | cmd_slot->flags |= htole16(AHCI_CMD_LIST_FLAG_PMP); /* port 0xF */ | |
| 143 | ||
| 144 | ccb->ccb_xa.state = ATA_S_PENDING; | |
| 145 | ||
| cae23e97 MD |
146 | /* |
| 147 | * The only way one can determine if a port multiplier is on the | |
| 148 | * port is to probe target 15, and of course this will fail if | |
| 149 | * there is no port multiplier. | |
| 150 | * | |
| 151 | * The probing has to be done whether or not a device is probed on | |
| 152 | * target 0, because when a PM is attached target 0 represents | |
| 153 | * slot #0 behind the PM. | |
| 492bffaf MD |
154 | * |
| 155 | * Port multipliers are expected to answer more quickly than normal | |
| 156 | * devices, use a shorter timeout than normal. | |
| 157 | * | |
| 158 | * If there is no PM here this command can still succeed due to | |
| 159 | * the _C_ | |
| cae23e97 | 160 | */ |
| 492bffaf MD |
161 | if (ahci_poll(ccb, 500, ahci_quick_timeout) != ATA_S_COMPLETE) { |
| 162 | kprintf("%s: PMPROBE(1) No Port Multiplier was found.\n", | |
| cae23e97 | 163 | PORTNAME(ap)); |
| 12feb904 MD |
164 | if (--count) { |
| 165 | ahci_put_err_ccb(ccb); | |
| 166 | goto retry; | |
| 167 | } | |
| 168 | error = EBUSY; | |
| 169 | goto err; | |
| 170 | } | |
| 492bffaf | 171 | |
| 12feb904 MD |
172 | if (ahci_pwait_clr(ap, AHCI_PREG_TFD, |
| 173 | AHCI_PREG_TFD_STS_BSY | AHCI_PREG_TFD_STS_DRQ)) { | |
| 174 | kprintf("%s: PMPROBE Busy after first FIS\n", PORTNAME(ap)); | |
| 175 | } | |
| 176 | ||
| 177 | /* | |
| 178 | * The device may have muffed up the PHY when it reset. | |
| 179 | */ | |
| 12feb904 MD |
180 | ahci_flush_tfd(ap); |
| 181 | ahci_pwrite(ap, AHCI_PREG_SERR, -1); | |
| 182 | /* ahci_pm_phy_status(ap, 15, &cmd); */ | |
| 183 | ||
| 184 | /* | |
| 185 | * Prep second D2H command to read status and complete reset sequence | |
| 186 | * AHCI 10.4.1 and "Serial ATA Revision 2.6". I can't find the ATA | |
| 187 | * Rev 2.6 and it is unclear how the second FIS should be set up | |
| 188 | * from the AHCI document. | |
| 189 | * | |
| 190 | * Give the device 3ms before sending the second FIS. | |
| 191 | * | |
| 192 | * It is unclear which other fields in the FIS are used. Just zero | |
| 193 | * everything. | |
| 194 | */ | |
| 492bffaf | 195 | ccb->ccb_xa.flags = ATA_F_POLL | ATA_F_SILENT; |
| 12feb904 MD |
196 | |
| 197 | bzero(fis, sizeof(ccb->ccb_cmd_table->cfis)); | |
| 198 | fis[0] = ATA_FIS_TYPE_H2D; | |
| 199 | fis[1] = 0x0F; | |
| 200 | fis[15] = ATA_FIS_CONTROL_4BIT; | |
| 201 | ||
| 202 | cmd_slot->prdtl = 0; | |
| 203 | cmd_slot->flags = htole16(5); /* FIS length: 5 DWORDS */ | |
| 204 | cmd_slot->flags |= htole16(AHCI_CMD_LIST_FLAG_PMP); /* port 0xF */ | |
| 205 | ||
| 206 | ccb->ccb_xa.state = ATA_S_PENDING; | |
| 207 | ||
| cae23e97 MD |
208 | /* |
| 209 | * The only way one can determine if a port multiplier is on the | |
| 210 | * port is to probe target 15, and of course this will fail if | |
| 211 | * there is no port multiplier. | |
| 212 | * | |
| 213 | * The probing has to be done whether or not a device is probed on | |
| 214 | * target 0, because when a PM is attached target 0 represents | |
| 215 | * slot #0 behind the PM. | |
| 216 | */ | |
| 12feb904 | 217 | if (ahci_poll(ccb, 5000, ahci_quick_timeout) != ATA_S_COMPLETE) { |
| 492bffaf | 218 | kprintf("%s: PMPROBE(2) No Port Multiplier was found.\n", |
| cae23e97 | 219 | PORTNAME(ap)); |
| 12feb904 MD |
220 | if (--count) { |
| 221 | ahci_put_err_ccb(ccb); | |
| 222 | goto retry; | |
| 223 | } | |
| 224 | error = EBUSY; | |
| 225 | goto err; | |
| 226 | } | |
| 227 | ||
| 228 | /* | |
| 229 | * What? We succeeded? Yup, but for some reason the signature | |
| 230 | * is still latched from the original detect (that saw target 0 | |
| 231 | * behind the PM), and I don't know how to clear the condition | |
| 232 | * other then by retrying the whole reset sequence. | |
| 233 | */ | |
| 234 | if (--count) { | |
| 235 | fis[15] = 0; | |
| 236 | ahci_put_err_ccb(ccb); | |
| 237 | goto retry; | |
| 238 | } | |
| 239 | ||
| 240 | /* | |
| 241 | * Get the signature. The caller sets the ap fields. | |
| 242 | */ | |
| 243 | if (ahci_port_signature_detect(ap, NULL) == ATA_PORT_T_PM) { | |
| b012a2ca | 244 | ap->ap_ata[15]->at_probe = ATA_PROBE_GOOD; |
| 12feb904 MD |
245 | error = 0; |
| 246 | } else { | |
| 247 | error = EBUSY; | |
| 248 | } | |
| 249 | ||
| 250 | /* | |
| 251 | * Fall through / clean up the CCB and perform error processing. | |
| 252 | */ | |
| 253 | err: | |
| 254 | if (ccb != NULL) | |
| 255 | ahci_put_err_ccb(ccb); | |
| 256 | ||
| 257 | if (error == 0 && ahci_pm_identify(ap)) { | |
| 258 | kprintf("%s: PM - cannot identify port multiplier\n", | |
| 259 | PORTNAME(ap)); | |
| 260 | error = EBUSY; | |
| 261 | } | |
| 262 | ||
| 263 | /* | |
| 264 | * If we probed the PM reset the state for the targets behind | |
| 265 | * it so they get probed by the state machine. | |
| 266 | */ | |
| 267 | if (error == 0) { | |
| 268 | for (i = 0; i < AHCI_MAX_PMPORTS; ++i) { | |
| b012a2ca | 269 | at = ap->ap_ata[i]; |
| 12feb904 MD |
270 | at->at_probe = ATA_PROBE_NEED_INIT; |
| 271 | at->at_features |= ATA_PORT_F_RESCAN; | |
| 272 | } | |
| 273 | ap->ap_type = ATA_PORT_T_PM; | |
| 274 | return (0); | |
| 275 | } | |
| 276 | ||
| 277 | /* | |
| 278 | * If we failed turn off PMA, otherwise identify the port multiplier. | |
| 279 | * CAM will iterate the devices. | |
| 280 | */ | |
| 281 | ahci_port_stop(ap, 0); | |
| 282 | ahci_port_clo(ap); | |
| 283 | cmd = ahci_pread(ap, AHCI_PREG_CMD) & ~AHCI_PREG_CMD_ICC; | |
| 284 | cmd &= ~AHCI_PREG_CMD_PMA; | |
| 285 | ahci_pwrite(ap, AHCI_PREG_CMD, cmd); | |
| 286 | ahci_port_init(ap); | |
| 287 | if (orig_error == 0) { | |
| 288 | if (ahci_pwait_clr(ap, AHCI_PREG_TFD, | |
| 289 | AHCI_PREG_TFD_STS_BSY | AHCI_PREG_TFD_STS_DRQ)) { | |
| 290 | kprintf("%s: PM probe: port will not come ready\n", | |
| 291 | PORTNAME(ap)); | |
| 292 | orig_error = EBUSY; | |
| 293 | } | |
| 294 | } | |
| 295 | return(orig_error); | |
| 296 | } | |
| 1980eff3 MD |
297 | |
| 298 | /* | |
| 299 | * Identify the port multiplier | |
| 300 | */ | |
| 301 | int | |
| 302 | ahci_pm_identify(struct ahci_port *ap) | |
| 303 | { | |
| 304 | u_int32_t chipid; | |
| 305 | u_int32_t rev; | |
| 306 | u_int32_t nports; | |
| 3209f581 MD |
307 | u_int32_t data1; |
| 308 | u_int32_t data2; | |
| 19b34835 | 309 | int has_dummy_port; |
| 1980eff3 | 310 | |
| 1980eff3 MD |
311 | ap->ap_probe = ATA_PROBE_FAILED; |
| 312 | if (ahci_pm_read(ap, 15, 0, &chipid)) | |
| 3209f581 | 313 | goto err; |
| 1980eff3 | 314 | if (ahci_pm_read(ap, 15, 1, &rev)) |
| 3209f581 | 315 | goto err; |
| 1980eff3 | 316 | if (ahci_pm_read(ap, 15, 2, &nports)) |
| 3209f581 MD |
317 | goto err; |
| 318 | nports &= 0x0000000F; /* only the low 4 bits */ | |
| 1980eff3 | 319 | ap->ap_probe = ATA_PROBE_GOOD; |
| 19b34835 MD |
320 | |
| 321 | /* | |
| 322 | * Ignore fake port on PMs which have it. We can probe it but the | |
| 323 | * softreset will probably fail. | |
| 324 | */ | |
| 325 | switch(chipid) { | |
| 326 | case 0x37261095: | |
| 327 | has_dummy_port = 1; | |
| 328 | break; | |
| 329 | default: | |
| 330 | has_dummy_port = 0; | |
| 331 | break; | |
| 332 | } | |
| 333 | if (has_dummy_port) { | |
| 334 | if (nports > 1) | |
| 335 | --nports; | |
| 336 | } | |
| 337 | ||
| 3209f581 MD |
338 | kprintf("%s: Port multiplier: chip=%08x rev=0x%b nports=%d\n", |
| 339 | PORTNAME(ap), | |
| 340 | chipid, | |
| 2cc2e845 | 341 | rev, SATA_PFMT_PM_REV, |
| 3209f581 | 342 | nports); |
| 19b34835 MD |
343 | if (has_dummy_port) { |
| 344 | kprintf("%s: Port multiplier: Ignoring dummy port #%d\n", | |
| 345 | PORTNAME(ap), nports); | |
| 346 | } | |
| 1980eff3 | 347 | ap->ap_pmcount = nports; |
| 3209f581 | 348 | |
| 2cc2e845 | 349 | if (ahci_pm_read(ap, 15, SATA_PMREG_FEA, &data1)) { |
| 3209f581 MD |
350 | kprintf("%s: Port multiplier: Warning, " |
| 351 | "cannot read feature register\n", PORTNAME(ap)); | |
| 352 | } else { | |
| 353 | kprintf("%s: Port multiplier features: 0x%b\n", | |
| 354 | PORTNAME(ap), | |
| 355 | data1, | |
| 2cc2e845 | 356 | SATA_PFMT_PM_FEA); |
| 3209f581 | 357 | } |
| 2cc2e845 | 358 | if (ahci_pm_read(ap, 15, SATA_PMREG_FEAEN, &data2) == 0) { |
| 3209f581 MD |
359 | kprintf("%s: Port multiplier defaults: 0x%b\n", |
| 360 | PORTNAME(ap), | |
| 361 | data2, | |
| 2cc2e845 | 362 | SATA_PFMT_PM_FEA); |
| 3209f581 MD |
363 | } |
| 364 | ||
| 365 | /* | |
| 366 | * Turn on async notification if we support and the PM supports it. | |
| 367 | * This allows the PM to forward async notification events to us and | |
| 368 | * it will also generate an event for target 15 for hot-plug events | |
| 369 | * (or is supposed to anyway). | |
| 370 | */ | |
| 371 | if ((ap->ap_sc->sc_cap & AHCI_REG_CAP_SSNTF) && | |
| 2cc2e845 | 372 | (data1 & SATA_PMFEA_ASYNCNOTIFY)) { |
| 3209f581 MD |
373 | u_int32_t serr_bits = AHCI_PREG_SERR_DIAG_N | |
| 374 | AHCI_PREG_SERR_DIAG_X; | |
| 2cc2e845 MD |
375 | data2 |= SATA_PMFEA_ASYNCNOTIFY; |
| 376 | if (ahci_pm_write(ap, 15, SATA_PMREG_FEAEN, data2)) { | |
| 3209f581 MD |
377 | kprintf("%s: Port multiplier: AsyncNotify cannot be " |
| 378 | "enabled\n", PORTNAME(ap)); | |
| 2cc2e845 | 379 | } else if (ahci_pm_write(ap, 15, SATA_PMREG_EEENA, serr_bits)) { |
| 3209f581 MD |
380 | kprintf("%s: Port mulltiplier: AsyncNotify unable " |
| 381 | "to enable error info bits\n", PORTNAME(ap)); | |
| 382 | } else { | |
| 383 | kprintf("%s: Port multiplier: AsyncNotify enabled\n", | |
| 384 | PORTNAME(ap)); | |
| 385 | } | |
| 386 | } | |
| 387 | ||
| 1980eff3 | 388 | return (0); |
| 3209f581 MD |
389 | err: |
| 390 | kprintf("%s: Port multiplier cannot be identified\n", PORTNAME(ap)); | |
| 391 | return (EIO); | |
| 1980eff3 MD |
392 | } |
| 393 | ||
| 394 | /* | |
| 395 | * Do a COMRESET sequence on the target behind a port multiplier. | |
| 396 | * | |
| 397 | * If hard is 2 we also cycle the phy on the target. | |
| 398 | * | |
| 399 | * This must be done prior to any softreset or probe attempts on | |
| 400 | * targets behind the port multiplier. | |
| 401 | * | |
| 402 | * Returns 0 on success or an error. | |
| 403 | */ | |
| 404 | int | |
| 405 | ahci_pm_hardreset(struct ahci_port *ap, int target, int hard) | |
| 406 | { | |
| 407 | struct ata_port *at; | |
| 408 | u_int32_t data; | |
| 409 | int loop; | |
| 3209f581 | 410 | int error = EIO; |
| 1980eff3 | 411 | |
| b012a2ca | 412 | at = ap->ap_ata[target]; |
| 1980eff3 MD |
413 | |
| 414 | /* | |
| 415 | * Turn off power management and kill the phy on the target | |
| 416 | * if requested. Hold state for 10ms. | |
| 417 | */ | |
| 418 | data = AHCI_PREG_SCTL_IPM_DISABLED; | |
| 419 | if (hard == 2) | |
| 420 | data |= AHCI_PREG_SCTL_DET_DISABLE; | |
| 2cc2e845 | 421 | if (ahci_pm_write(ap, target, SATA_PMREG_SERR, -1)) |
| 3209f581 | 422 | goto err; |
| 2cc2e845 | 423 | if (ahci_pm_write(ap, target, SATA_PMREG_SCTL, data)) |
| 3209f581 MD |
424 | goto err; |
| 425 | ahci_os_sleep(10); | |
| 1980eff3 MD |
426 | |
| 427 | /* | |
| 428 | * Start transmitting COMRESET. COMRESET must be sent for at | |
| 429 | * least 1ms. | |
| 430 | */ | |
| 431 | at->at_probe = ATA_PROBE_FAILED; | |
| 432 | at->at_type = ATA_PORT_T_NONE; | |
| 433 | data = AHCI_PREG_SCTL_IPM_DISABLED | AHCI_PREG_SCTL_DET_INIT; | |
| 434 | if (AhciForceGen1 & (1 << ap->ap_num)) { | |
| 435 | kprintf("%s.%d: Force 1.5GBits\n", PORTNAME(ap), target); | |
| 436 | data |= AHCI_PREG_SCTL_SPD_GEN1; | |
| 437 | } else { | |
| 438 | data |= AHCI_PREG_SCTL_SPD_ANY; | |
| 439 | } | |
| 2cc2e845 | 440 | if (ahci_pm_write(ap, target, SATA_PMREG_SCTL, data)) |
| 3209f581 | 441 | goto err; |
| 3209f581 | 442 | |
| 831bc9e3 MD |
443 | /* |
| 444 | * It takes about 100ms for the DET logic to settle down, | |
| 445 | * from trial and error testing. If this is too short | |
| 446 | * the softreset code will fail. | |
| 447 | */ | |
| 448 | ahci_os_sleep(100); | |
| 449 | ||
| 3209f581 | 450 | if (ahci_pm_phy_status(ap, target, &data)) { |
| 831bc9e3 | 451 | kprintf("%s: (A)Cannot clear phy status\n", |
| 3209f581 MD |
452 | ATANAME(ap ,at)); |
| 453 | } | |
| 1980eff3 MD |
454 | |
| 455 | /* | |
| 456 | * Flush any status, then clear DET to initiate negotiation. | |
| 457 | */ | |
| 2cc2e845 | 458 | ahci_pm_write(ap, target, SATA_PMREG_SERR, -1); |
| 1980eff3 | 459 | data = AHCI_PREG_SCTL_IPM_DISABLED | AHCI_PREG_SCTL_DET_NONE; |
| 2cc2e845 | 460 | if (ahci_pm_write(ap, target, SATA_PMREG_SCTL, data)) |
| 3209f581 | 461 | goto err; |
| 1980eff3 MD |
462 | |
| 463 | /* | |
| 464 | * Try to determine if there is a device on the port. | |
| 465 | * | |
| 466 | * Give the device 3/10 second to at least be detected. | |
| 467 | * If we fail clear any pending status since we may have | |
| 468 | * cycled the phy and probably caused another PRCS interrupt. | |
| 469 | */ | |
| 3209f581 | 470 | for (loop = 3; loop; --loop) { |
| 2cc2e845 | 471 | if (ahci_pm_read(ap, target, SATA_PMREG_SSTS, &data)) |
| 3209f581 | 472 | goto err; |
| 1980eff3 MD |
473 | if (data & AHCI_PREG_SSTS_DET) |
| 474 | break; | |
| 3209f581 | 475 | ahci_os_sleep(100); |
| 1980eff3 MD |
476 | } |
| 477 | if (loop == 0) { | |
| 478 | kprintf("%s.%d: Port appears to be unplugged\n", | |
| 479 | PORTNAME(ap), target); | |
| 3209f581 MD |
480 | error = ENODEV; |
| 481 | goto err; | |
| 1980eff3 MD |
482 | } |
| 483 | ||
| 484 | /* | |
| 485 | * There is something on the port. Give the device 3 seconds | |
| 486 | * to fully negotiate. | |
| 487 | */ | |
| 3209f581 | 488 | for (loop = 30; loop; --loop) { |
| 2cc2e845 | 489 | if (ahci_pm_read(ap, target, SATA_PMREG_SSTS, &data)) |
| 3209f581 | 490 | goto err; |
| 1980eff3 MD |
491 | if ((data & AHCI_PREG_SSTS_DET) == AHCI_PREG_SSTS_DET_DEV) |
| 492 | break; | |
| 3209f581 | 493 | ahci_os_sleep(100); |
| 1980eff3 | 494 | } |
| 3209f581 MD |
495 | |
| 496 | /* | |
| 3209f581 MD |
497 | * Device not detected |
| 498 | */ | |
| 1980eff3 MD |
499 | if (loop == 0) { |
| 500 | kprintf("%s: Device may be powered down\n", | |
| 501 | PORTNAME(ap)); | |
| 3209f581 MD |
502 | error = ENODEV; |
| 503 | goto err; | |
| 1980eff3 MD |
504 | } |
| 505 | ||
| 506 | /* | |
| 3209f581 | 507 | * Device detected |
| 1980eff3 | 508 | */ |
| 1980eff3 MD |
509 | kprintf("%s.%d: Device detected data=%08x\n", |
| 510 | PORTNAME(ap), target, data); | |
| 831bc9e3 MD |
511 | /* |
| 512 | * Clear SERR on the target so we get a new NOTIFY event if a hot-plug | |
| 492bffaf MD |
513 | * or hot-unplug occurs. Clear any spurious IFS that may have |
| 514 | * occured during the probe. | |
| 515 | * | |
| 516 | * WARNING! 100ms seems to work in most cases but | |
| 831bc9e3 | 517 | */ |
| 3209f581 | 518 | ahci_os_sleep(100); |
| 492bffaf MD |
519 | ahci_pm_write(ap, target, SATA_PMREG_SERR, -1); |
| 520 | ahci_pwrite(ap, AHCI_PREG_SERR, -1); | |
| 521 | ahci_pwrite(ap, AHCI_PREG_IS, AHCI_PREG_IS_IFS); | |
| 831bc9e3 | 522 | |
| 3209f581 MD |
523 | error = 0; |
| 524 | err: | |
| 525 | at->at_probe = error ? ATA_PROBE_FAILED : ATA_PROBE_NEED_SOFT_RESET; | |
| 831bc9e3 | 526 | return (error); |
| 1980eff3 MD |
527 | } |
| 528 | ||
| 529 | /* | |
| 530 | * AHCI soft reset through port multiplier. | |
| 531 | * | |
| 532 | * This function keeps port communications intact and attempts to generate | |
| 533 | * a reset to the connected device using device commands. Unlike | |
| 534 | * hard-port operations we can't do fancy stop/starts or stuff like | |
| 535 | * that without messing up other commands that might be running or | |
| 536 | * queued. | |
| 537 | */ | |
| 538 | int | |
| 539 | ahci_pm_softreset(struct ahci_port *ap, int target) | |
| 540 | { | |
| 541 | struct ata_port *at; | |
| baef7501 | 542 | struct ahci_ccb *ccb; |
| 1980eff3 MD |
543 | struct ahci_cmd_hdr *cmd_slot; |
| 544 | u_int8_t *fis; | |
| 3209f581 MD |
545 | int count; |
| 546 | int error; | |
| 1980eff3 | 547 | u_int32_t data; |
| 3209f581 | 548 | int tried_longer; |
| 1980eff3 | 549 | |
| 3209f581 | 550 | error = EIO; |
| b012a2ca | 551 | at = ap->ap_ata[target]; |
| 1980eff3 MD |
552 | |
| 553 | DPRINTF(AHCI_D_VERBOSE, "%s: soft reset\n", PORTNAME(ap)); | |
| 554 | ||
| 1980eff3 | 555 | count = 2; |
| 3209f581 | 556 | tried_longer = 0; |
| 1980eff3 MD |
557 | retry: |
| 558 | /* | |
| 559 | * Try to clear the phy so we get a good signature, otherwise | |
| 560 | * the PM may not latch a new signature. | |
| 561 | * | |
| 562 | * NOTE: This cannot be safely done between the first and second | |
| 563 | * softreset FISs. It's now or never. | |
| 564 | */ | |
| 1980eff3 | 565 | if (ahci_pm_phy_status(ap, target, &data)) { |
| 831bc9e3 | 566 | kprintf("%s: (B)Cannot clear phy status\n", |
| 1980eff3 MD |
567 | ATANAME(ap ,at)); |
| 568 | } | |
| 2cc2e845 | 569 | ahci_pm_write(ap, target, SATA_PMREG_SERR, -1); |
| 1980eff3 MD |
570 | |
| 571 | /* | |
| 572 | * Prep first D2H command with SRST feature & clear busy/reset flags | |
| 573 | * | |
| 574 | * It is unclear which other fields in the FIS are used. Just zero | |
| 575 | * everything. | |
| 576 | * | |
| 577 | * When soft-resetting a port behind a multiplier at will be | |
| 578 | * non-NULL, assigning it to the ccb prevents the port interrupt | |
| 579 | * from hard-resetting the port if a problem crops up. | |
| 580 | */ | |
| baef7501 | 581 | ccb = ahci_get_err_ccb(ap); |
| 12feb904 | 582 | ccb->ccb_xa.flags = ATA_F_POLL | ATA_F_EXCLUSIVE | ATA_F_AUTOSENSE; |
| 1980eff3 MD |
583 | ccb->ccb_xa.complete = ahci_pm_dummy_done; |
| 584 | ccb->ccb_xa.at = at; | |
| 585 | ||
| 586 | fis = ccb->ccb_cmd_table->cfis; | |
| 587 | bzero(fis, sizeof(ccb->ccb_cmd_table->cfis)); | |
| 588 | fis[0] = ATA_FIS_TYPE_H2D; | |
| 589 | fis[1] = at->at_target; | |
| 590 | fis[15] = ATA_FIS_CONTROL_SRST|ATA_FIS_CONTROL_4BIT; | |
| 591 | ||
| 592 | cmd_slot = ccb->ccb_cmd_hdr; | |
| 593 | cmd_slot->prdtl = 0; | |
| 594 | cmd_slot->flags = htole16(5); /* FIS length: 5 DWORDS */ | |
| 595 | cmd_slot->flags |= htole16(AHCI_CMD_LIST_FLAG_C); /* Clear busy on OK */ | |
| 596 | cmd_slot->flags |= htole16(AHCI_CMD_LIST_FLAG_R); /* Reset */ | |
| 597 | cmd_slot->flags |= htole16(at->at_target << | |
| 598 | AHCI_CMD_LIST_FLAG_PMP_SHIFT); | |
| 599 | ||
| 600 | ccb->ccb_xa.state = ATA_S_PENDING; | |
| 1980eff3 | 601 | |
| 3209f581 | 602 | /* |
| 492bffaf MD |
603 | * This soft reset of the AP target can cause a stream of IFS |
| 604 | * errors to occur. Setting AP_F_IGNORE_IFS prevents the port | |
| 605 | * from being hard reset (because its the target behind the | |
| 606 | * port that isn't happy). | |
| 3209f581 | 607 | * |
| 492bffaf MD |
608 | * The act of sending the soft reset can cause the target to |
| 609 | * blow the port up and generate IFS errors. | |
| 3209f581 MD |
610 | */ |
| 611 | ap->ap_flags |= AP_F_IGNORE_IFS; | |
| 492bffaf | 612 | ap->ap_flags &= ~AP_F_IFS_IGNORED; |
| 3209f581 | 613 | |
| 831bc9e3 | 614 | if (ahci_poll(ccb, 1000, ahci_ata_cmd_timeout) != ATA_S_COMPLETE) { |
| 492bffaf MD |
615 | kprintf("%s: Soft-reset through PM failed, %s\n", |
| 616 | ATANAME(ap, at), | |
| 617 | (count > 1 ? "retrying" : "giving up")); | |
| baef7501 | 618 | ahci_put_err_ccb(ccb); |
| 492bffaf MD |
619 | if (--count) { |
| 620 | if (ap->ap_flags & AP_F_IFS_IGNORED) | |
| 621 | ahci_os_sleep(5000); | |
| 622 | else | |
| 623 | ahci_os_sleep(1000); | |
| 624 | ahci_pwrite(ap, AHCI_PREG_SERR, -1); | |
| 625 | ahci_pwrite(ap, AHCI_PREG_IS, AHCI_PREG_IS_IFS); | |
| 1980eff3 | 626 | goto retry; |
| 492bffaf | 627 | } |
| 1980eff3 MD |
628 | goto err; |
| 629 | } | |
| 630 | ||
| 631 | /* | |
| 831bc9e3 MD |
632 | * WARNING! SENSITIVE TIME PERIOD! WARNING! |
| 633 | * | |
| 634 | * The first and second FISes are supposed to be back-to-back, | |
| 635 | * I think the idea is to get the second sent and then after | |
| 636 | * the device resets it will send a signature. Do not delay | |
| 637 | * here and most definitely do not issue any commands to other | |
| 638 | * targets! | |
| 1980eff3 | 639 | */ |
| 1980eff3 MD |
640 | |
| 641 | /* | |
| 642 | * Prep second D2H command to read status and complete reset sequence | |
| 643 | * AHCI 10.4.1 and "Serial ATA Revision 2.6". I can't find the ATA | |
| 644 | * Rev 2.6 and it is unclear how the second FIS should be set up | |
| 645 | * from the AHCI document. | |
| 646 | * | |
| 647 | * Give the device 3ms before sending the second FIS. | |
| 648 | * | |
| 649 | * It is unclear which other fields in the FIS are used. Just zero | |
| 650 | * everything. | |
| 651 | */ | |
| 652 | bzero(fis, sizeof(ccb->ccb_cmd_table->cfis)); | |
| 653 | fis[0] = ATA_FIS_TYPE_H2D; | |
| 654 | fis[1] = at->at_target; | |
| 655 | fis[15] = ATA_FIS_CONTROL_4BIT; | |
| 656 | ||
| 657 | cmd_slot->prdtl = 0; | |
| 658 | cmd_slot->flags = htole16(5); /* FIS length: 5 DWORDS */ | |
| 659 | cmd_slot->flags |= htole16(at->at_target << | |
| 660 | AHCI_CMD_LIST_FLAG_PMP_SHIFT); | |
| 661 | ||
| 662 | ccb->ccb_xa.state = ATA_S_PENDING; | |
| 12feb904 | 663 | ccb->ccb_xa.flags = ATA_F_POLL | ATA_F_EXCLUSIVE | ATA_F_AUTOSENSE; |
| 1980eff3 | 664 | |
| 492bffaf MD |
665 | ap->ap_flags &= ~AP_F_IFS_IGNORED; |
| 666 | ||
| 831bc9e3 | 667 | if (ahci_poll(ccb, 1000, ahci_ata_cmd_timeout) != ATA_S_COMPLETE) { |
| 492bffaf MD |
668 | kprintf("%s: Soft-reset(2) through PM failed, %s\n", |
| 669 | ATANAME(ap, at), | |
| 670 | (count > 1 ? "retrying" : "giving up")); | |
| 671 | if (--count) { | |
| 672 | ahci_os_sleep(1000); | |
| 673 | ahci_put_err_ccb(ccb); | |
| 674 | ahci_pwrite(ap, AHCI_PREG_SERR, -1); | |
| 675 | ahci_pwrite(ap, AHCI_PREG_IS, AHCI_PREG_IS_IFS); | |
| 1980eff3 | 676 | goto retry; |
| 492bffaf | 677 | } |
| 1980eff3 MD |
678 | goto err; |
| 679 | } | |
| 680 | ||
| baef7501 | 681 | ahci_put_err_ccb(ccb); |
| 831bc9e3 | 682 | ahci_os_sleep(100); |
| 492bffaf MD |
683 | ahci_pwrite(ap, AHCI_PREG_SERR, -1); |
| 684 | ahci_pwrite(ap, AHCI_PREG_IS, AHCI_PREG_IS_IFS); | |
| 685 | ||
| 2cc2e845 | 686 | ahci_pm_write(ap, target, SATA_PMREG_SERR, -1); |
| 831bc9e3 MD |
687 | if (ahci_pm_phy_status(ap, target, &data)) { |
| 688 | kprintf("%s: (C)Cannot clear phy status\n", | |
| 689 | ATANAME(ap ,at)); | |
| 690 | } | |
| 2cc2e845 | 691 | ahci_pm_write(ap, target, SATA_PMREG_SERR, -1); |
| 1980eff3 MD |
692 | |
| 693 | /* | |
| 694 | * Do it again, even if we think we got a good result | |
| 695 | */ | |
| 696 | if (--count) { | |
| 697 | fis[15] = 0; | |
| 1980eff3 MD |
698 | goto retry; |
| 699 | } | |
| 700 | ||
| 701 | /* | |
| 702 | * If the softreset is trying to clear a BSY condition after a | |
| 703 | * normal portreset we assign the port type. | |
| 704 | * | |
| 705 | * If the softreset is being run first as part of the ccb error | |
| 706 | * processing code then report if the device signature changed | |
| 707 | * unexpectedly. | |
| 708 | */ | |
| 709 | if (at->at_type == ATA_PORT_T_NONE) { | |
| 710 | at->at_type = ahci_port_signature_detect(ap, at); | |
| 711 | } else { | |
| 712 | if (ahci_port_signature_detect(ap, at) != at->at_type) { | |
| 713 | kprintf("%s: device signature unexpectedly " | |
| 714 | "changed\n", ATANAME(ap, at)); | |
| 3209f581 | 715 | error = EBUSY; /* XXX */ |
| 1980eff3 MD |
716 | } |
| 717 | } | |
| 3209f581 | 718 | error = 0; |
| 1980eff3 | 719 | |
| 831bc9e3 MD |
720 | /* |
| 721 | * Who knows what kind of mess occured. We have exclusive access | |
| 722 | * to the port so try to clean up potential problems. | |
| 723 | */ | |
| 1980eff3 | 724 | err: |
| 492bffaf MD |
725 | ahci_os_sleep(100); |
| 726 | ||
| 1980eff3 | 727 | /* |
| 831bc9e3 | 728 | * Clear error status so we can detect removal. |
| 3209f581 | 729 | */ |
| 2cc2e845 | 730 | if (ahci_pm_write(ap, target, SATA_PMREG_SERR, -1)) { |
| 3209f581 MD |
731 | kprintf("%s: ahci_pm_softreset unable to clear SERR\n", |
| 732 | ATANAME(ap, at)); | |
| 733 | } | |
| 492bffaf MD |
734 | ahci_pwrite(ap, AHCI_PREG_SERR, -1); |
| 735 | ahci_pwrite(ap, AHCI_PREG_IS, AHCI_PREG_IS_IFS); | |
| 736 | ap->ap_flags &= ~(AP_F_IGNORE_IFS | AP_F_IFS_IGNORED); | |
| 3209f581 | 737 | |
| 3209f581 MD |
738 | at->at_probe = error ? ATA_PROBE_FAILED : ATA_PROBE_NEED_IDENT; |
| 739 | return (error); | |
| 1980eff3 MD |
740 | } |
| 741 | ||
| 742 | ||
| 743 | /* | |
| 744 | * Return the phy status for a target behind a port multiplier and | |
| 2cc2e845 | 745 | * reset SATA_PMREG_SERR. |
| 1980eff3 MD |
746 | * |
| 747 | * Returned bits follow AHCI_PREG_SSTS bits. The AHCI_PREG_SSTS_SPD | |
| 748 | * bits can be used to determine the link speed and will be 0 if there | |
| 749 | * is no link. | |
| 750 | * | |
| 751 | * 0 is returned if any communications error occurs. | |
| 752 | */ | |
| 753 | int | |
| 754 | ahci_pm_phy_status(struct ahci_port *ap, int target, u_int32_t *datap) | |
| 755 | { | |
| 756 | int error; | |
| 757 | ||
| 2cc2e845 | 758 | error = ahci_pm_read(ap, target, SATA_PMREG_SSTS, datap); |
| 1980eff3 | 759 | if (error == 0) |
| 2cc2e845 | 760 | error = ahci_pm_write(ap, target, SATA_PMREG_SERR, -1); |
| 1980eff3 MD |
761 | if (error) |
| 762 | *datap = 0; | |
| 763 | return(error); | |
| 764 | } | |
| 765 | ||
| 3209f581 MD |
766 | /* |
| 767 | * Check that a target is still good. | |
| 768 | */ | |
| 769 | void | |
| 770 | ahci_pm_check_good(struct ahci_port *ap, int target) | |
| 771 | { | |
| 772 | struct ata_port *at; | |
| 773 | u_int32_t data; | |
| 774 | ||
| 775 | /* | |
| 776 | * It looks like we might have to read the EINFO register | |
| 777 | * to allow the PM to generate a new event. | |
| 778 | */ | |
| 2cc2e845 | 779 | if (ahci_pm_read(ap, 15, SATA_PMREG_EINFO, &data)) { |
| 3209f581 MD |
780 | kprintf("%s: Port multiplier EINFO could not be read\n", |
| 781 | PORTNAME(ap)); | |
| 782 | } | |
| e61560bd | 783 | |
| 2cc2e845 | 784 | if (ahci_pm_write(ap, target, SATA_PMREG_SERR, -1)) { |
| 3209f581 MD |
785 | kprintf("%s: Port multiplier: SERR could not be cleared\n", |
| 786 | PORTNAME(ap)); | |
| 787 | } | |
| 788 | ||
| e61560bd | 789 | if (target == CAM_TARGET_WILDCARD || target >= ap->ap_pmcount) |
| 3209f581 | 790 | return; |
| b012a2ca | 791 | at = ap->ap_ata[target]; |
| 1067474a MD |
792 | |
| 793 | /* | |
| 794 | * If the device needs an init or hard reset also make sure the | |
| 795 | * PHY is turned on. | |
| 796 | */ | |
| 797 | if (at->at_probe <= ATA_PROBE_NEED_HARD_RESET) { | |
| 798 | /*kprintf("%s DOHARD\n", ATANAME(ap, at));*/ | |
| 799 | ahci_pm_hardreset(ap, target, 1); | |
| 800 | } | |
| 801 | ||
| 802 | /* | |
| 803 | * Read the detect status | |
| 804 | */ | |
| 2cc2e845 | 805 | if (ahci_pm_read(ap, target, SATA_PMREG_SSTS, &data)) { |
| 3209f581 MD |
806 | kprintf("%s: Unable to access PM SSTS register target %d\n", |
| 807 | PORTNAME(ap), target); | |
| 808 | return; | |
| 809 | } | |
| 810 | if ((data & AHCI_PREG_SSTS_DET) != AHCI_PREG_SSTS_DET_DEV) { | |
| 1067474a | 811 | /*kprintf("%s: DETECT %08x\n", ATANAME(ap, at), data);*/ |
| 3209f581 MD |
812 | if (at->at_probe != ATA_PROBE_FAILED) { |
| 813 | at->at_probe = ATA_PROBE_FAILED; | |
| 814 | at->at_type = ATA_PORT_T_NONE; | |
| 815 | at->at_features |= ATA_PORT_F_RESCAN; | |
| 831bc9e3 | 816 | kprintf("%s: HOTPLUG (PM) - Device removed\n", |
| 3209f581 MD |
817 | ATANAME(ap, at)); |
| 818 | } | |
| 819 | } else { | |
| 820 | if (at->at_probe == ATA_PROBE_FAILED) { | |
| 821 | at->at_probe = ATA_PROBE_NEED_HARD_RESET; | |
| 822 | at->at_features |= ATA_PORT_F_RESCAN; | |
| 831bc9e3 | 823 | kprintf("%s: HOTPLUG (PM) - Device inserted\n", |
| 3209f581 MD |
824 | ATANAME(ap, at)); |
| 825 | } | |
| 826 | } | |
| 827 | } | |
| 828 | ||
| 1980eff3 MD |
829 | /* |
| 830 | * Read a PM register | |
| 831 | */ | |
| 832 | int | |
| 833 | ahci_pm_read(struct ahci_port *ap, int target, int which, u_int32_t *datap) | |
| 834 | { | |
| 835 | struct ata_xfer *xa; | |
| 1980eff3 MD |
836 | int error; |
| 837 | ||
| b012a2ca | 838 | xa = ahci_ata_get_xfer(ap, ap->ap_ata[15]); |
| 1980eff3 | 839 | |
| 1980eff3 MD |
840 | xa->fis->type = ATA_FIS_TYPE_H2D; |
| 841 | xa->fis->flags = ATA_H2D_FLAGS_CMD | 15; | |
| 842 | xa->fis->command = ATA_C_READ_PM; | |
| 843 | xa->fis->features = which; | |
| 844 | xa->fis->device = target | ATA_H2D_DEVICE_LBA; | |
| 845 | xa->fis->control = ATA_FIS_CONTROL_4BIT; | |
| 846 | ||
| 847 | xa->complete = ahci_pm_dummy_done; | |
| 848 | xa->datalen = 0; | |
| 12feb904 | 849 | xa->flags = ATA_F_POLL | ATA_F_AUTOSENSE; |
| 3209f581 | 850 | xa->timeout = 1000; |
| 1980eff3 | 851 | |
| 831bc9e3 | 852 | if (ahci_ata_cmd(xa) == ATA_S_COMPLETE) { |
| 1980eff3 MD |
853 | *datap = xa->rfis.sector_count | (xa->rfis.lba_low << 8) | |
| 854 | (xa->rfis.lba_mid << 16) | (xa->rfis.lba_high << 24); | |
| 855 | error = 0; | |
| 856 | } else { | |
| 831bc9e3 MD |
857 | kprintf("%s.%d pm_read SCA[%d] failed\n", |
| 858 | PORTNAME(ap), target, which); | |
| 1980eff3 MD |
859 | *datap = 0; |
| 860 | error = EIO; | |
| 861 | } | |
| 862 | ahci_ata_put_xfer(xa); | |
| 863 | return (error); | |
| 864 | } | |
| 865 | ||
| 866 | /* | |
| 867 | * Write a PM register | |
| 868 | */ | |
| 869 | int | |
| 870 | ahci_pm_write(struct ahci_port *ap, int target, int which, u_int32_t data) | |
| 871 | { | |
| 872 | struct ata_xfer *xa; | |
| 1980eff3 MD |
873 | int error; |
| 874 | ||
| b012a2ca | 875 | xa = ahci_ata_get_xfer(ap, ap->ap_ata[15]); |
| 1980eff3 | 876 | |
| 1980eff3 MD |
877 | xa->fis->type = ATA_FIS_TYPE_H2D; |
| 878 | xa->fis->flags = ATA_H2D_FLAGS_CMD | 15; | |
| 879 | xa->fis->command = ATA_C_WRITE_PM; | |
| 880 | xa->fis->features = which; | |
| 881 | xa->fis->device = target | ATA_H2D_DEVICE_LBA; | |
| 882 | xa->fis->sector_count = (u_int8_t)data; | |
| 883 | xa->fis->lba_low = (u_int8_t)(data >> 8); | |
| 884 | xa->fis->lba_mid = (u_int8_t)(data >> 16); | |
| 885 | xa->fis->lba_high = (u_int8_t)(data >> 24); | |
| 886 | xa->fis->control = ATA_FIS_CONTROL_4BIT; | |
| 887 | ||
| 888 | xa->complete = ahci_pm_dummy_done; | |
| 889 | xa->datalen = 0; | |
| 12feb904 | 890 | xa->flags = ATA_F_POLL; |
| 3209f581 | 891 | xa->timeout = 1000; |
| 1980eff3 | 892 | |
| 831bc9e3 MD |
893 | if (ahci_ata_cmd(xa) == ATA_S_COMPLETE) |
| 894 | error = 0; | |
| 895 | else | |
| 896 | error = EIO; | |
| 1980eff3 MD |
897 | ahci_ata_put_xfer(xa); |
| 898 | return(error); | |
| 899 | } | |
| 900 | ||
| 901 | /* | |
| 902 | * Dummy done callback for xa. | |
| 903 | */ | |
| 904 | static void | |
| 905 | ahci_pm_dummy_done(struct ata_xfer *xa) | |
| 906 | { | |
| 907 | } | |
| 908 |