2 * Copyright (c) 2009 The DragonFly Project. All rights reserved.
4 * This code is derived from software contributed to The DragonFly Project
5 * by Matthew Dillon <dillon@backplane.com>
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
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
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.
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
37 static void sili_pm_dummy_done(struct ata_xfer
*xa
);
38 static void sili_pm_empty_done(struct sili_ccb
*ccb
);
41 * Identify the port multiplier
44 sili_pm_identify(struct sili_port
*ap
)
53 ap
->ap_probe
= ATA_PROBE_FAILED
;
54 if (sili_pm_read(ap
, 15, 0, &chipid
))
56 if (sili_pm_read(ap
, 15, 1, &rev
))
58 if (sili_pm_read(ap
, 15, 2, &nports
))
60 nports
&= 0x0000000F; /* only the low 4 bits */
62 ap
->ap_probe
= ATA_PROBE_GOOD
;
63 kprintf("%s: Port multiplier: chip=%08x rev=0x%b nports=%d\n",
66 rev
, SATA_PFMT_PM_REV
,
68 ap
->ap_pmcount
= nports
;
70 if (sili_pm_read(ap
, 15, SATA_PMREG_FEA
, &data1
)) {
71 kprintf("%s: Port multiplier: Warning, "
72 "cannot read feature register\n", PORTNAME(ap
));
74 kprintf("%s: Port multiplier features: 0x%b\n",
79 if (sili_pm_read(ap
, 15, SATA_PMREG_FEAEN
, &data2
) == 0) {
80 kprintf("%s: Port multiplier defaults: 0x%b\n",
87 * Turn on async notification if we support and the PM supports it.
88 * This allows the PM to forward async notification events to us and
89 * it will also generate an event for target 15 for hot-plug events
90 * (or is supposed to anyway).
92 if ((ap
->ap_sc
->sc_flags
& SILI_F_SSNTF
) &&
93 (data1
& SATA_PMFEA_ASYNCNOTIFY
)) {
94 u_int32_t serr_bits
= SATA_PM_SERR_DIAG_N
|
96 data2
|= SATA_PMFEA_ASYNCNOTIFY
;
97 if (sili_pm_write(ap
, 15, SATA_PMREG_FEAEN
, data2
)) {
98 kprintf("%s: Port multiplier: AsyncNotify cannot be "
99 "enabled\n", PORTNAME(ap
));
100 } else if (sili_pm_write(ap
, 15, SATA_PMREG_EEENA
, serr_bits
)) {
101 kprintf("%s: Port mulltiplier: AsyncNotify unable "
102 "to enable error info bits\n", PORTNAME(ap
));
104 kprintf("%s: Port multiplier: AsyncNotify enabled\n",
111 kprintf("%s: Port multiplier cannot be identified\n", PORTNAME(ap
));
116 * Do a COMRESET sequence on the target behind a port multiplier.
118 * If hard is 2 we also cycle the phy on the target.
120 * This must be done prior to any softreset or probe attempts on
121 * targets behind the port multiplier.
123 * Returns 0 on success or an error.
126 sili_pm_hardreset(struct sili_port
*ap
, int target
, int hard
)
133 at
= &ap
->ap_ata
[target
];
136 * Turn off power management and kill the phy on the target
137 * if requested. Hold state for 10ms.
139 data
= SATA_PM_SCTL_IPM_DISABLED
;
141 data
|= SATA_PM_SCTL_DET_DISABLE
;
142 if (sili_pm_write(ap
, target
, SATA_PMREG_SERR
, -1))
144 if (sili_pm_write(ap
, target
, SATA_PMREG_SCTL
, data
))
149 * Start transmitting COMRESET. COMRESET must be sent for at
152 at
->at_probe
= ATA_PROBE_FAILED
;
153 at
->at_type
= ATA_PORT_T_NONE
;
154 data
= SATA_PM_SCTL_IPM_DISABLED
| SATA_PM_SCTL_DET_INIT
;
155 if (SiliForceGen1
& (1 << ap
->ap_num
)) {
156 kprintf("%s.%d: Force 1.5GBits\n", PORTNAME(ap
), target
);
157 data
|= SATA_PM_SCTL_SPD_GEN1
;
159 data
|= SATA_PM_SCTL_SPD_ANY
;
161 if (sili_pm_write(ap
, target
, SATA_PMREG_SCTL
, data
))
165 * It takes about 100ms for the DET logic to settle down,
166 * from trial and error testing. If this is too short
167 * the softreset code will fail.
171 if (sili_pm_phy_status(ap
, target
, &data
)) {
172 kprintf("%s: (A)Cannot clear phy status\n",
177 * Flush any status, then clear DET to initiate negotiation.
179 sili_pm_write(ap
, target
, SATA_PMREG_SERR
, -1);
180 data
= SATA_PM_SCTL_IPM_DISABLED
| SATA_PM_SCTL_DET_NONE
;
181 if (sili_pm_write(ap
, target
, SATA_PMREG_SCTL
, data
))
185 * Try to determine if there is a device on the port.
187 * Give the device 3/10 second to at least be detected.
188 * If we fail clear any pending status since we may have
189 * cycled the phy and probably caused another PRCS interrupt.
191 for (loop
= 3; loop
; --loop
) {
192 if (sili_pm_read(ap
, target
, SATA_PMREG_SSTS
, &data
))
194 if (data
& SATA_PM_SSTS_DET
)
199 kprintf("%s.%d: Port appears to be unplugged\n",
200 PORTNAME(ap
), target
);
206 * There is something on the port. Give the device 3 seconds
207 * to fully negotiate.
209 for (loop
= 30; loop
; --loop
) {
210 if (sili_pm_read(ap
, target
, SATA_PMREG_SSTS
, &data
))
212 if ((data
& SATA_PM_SSTS_DET
) == SATA_PM_SSTS_DET_DEV
)
218 * Device not detected
221 kprintf("%s: Device may be powered down\n",
230 kprintf("%s.%d: Device detected data=%08x\n",
231 PORTNAME(ap
), target
, data
);
233 * Clear SERR on the target so we get a new NOTIFY event if a hot-plug
234 * or hot-unplug occurs.
240 at
->at_probe
= error
? ATA_PROBE_FAILED
: ATA_PROBE_NEED_SOFT_RESET
;
245 * SILI soft reset through port multiplier.
247 * This function keeps port communications intact and attempts to generate
248 * a reset to the connected device using device commands. Unlike
249 * hard-port operations we can't do fancy stop/starts or stuff like
250 * that without messing up other commands that might be running or
253 * The SII chip will do the whole mess for us.
256 sili_pm_softreset(struct sili_port
*ap
, int target
)
259 struct sili_ccb
*ccb
;
260 struct sili_prb
*prb
;
266 at
= &ap
->ap_ata
[target
];
268 DPRINTF(SILI_D_VERBOSE
, "%s: soft reset\n", PORTNAME(ap
));
271 * Prep the special soft-reset SII command.
273 ccb
= sili_get_err_ccb(ap
);
274 ccb
->ccb_done
= sili_pm_empty_done
;
275 ccb
->ccb_xa
.flags
= ATA_F_POLL
| ATA_F_EXCLUSIVE
| ATA_F_AUTOSENSE
;
276 ccb
->ccb_xa
.complete
= sili_pm_dummy_done
;
280 bzero(&prb
->prb_h2d
, sizeof(prb
->prb_h2d
));
281 prb
->prb_h2d
.flags
= at
->at_target
;
282 prb
->prb_control
= SILI_PRB_CTRL_SOFTRESET
;
283 prb
->prb_override
= 0;
284 prb
->prb_xfer_count
= 0;
286 ccb
->ccb_xa
.state
= ATA_S_PENDING
;
287 ccb
->ccb_xa
.flags
= 0;
289 if (sili_poll(ccb
, 8000, sili_ata_cmd_timeout
) != ATA_S_COMPLETE
) {
290 kprintf("%s: (PM) Softreset FIS failed\n", ATANAME(ap
, at
));
291 sili_put_err_ccb(ccb
);
295 sig
= (prb
->prb_d2h
.lba_high
<< 24) |
296 (prb
->prb_d2h
.lba_mid
<< 16) |
297 (prb
->prb_d2h
.lba_low
<< 8) |
298 (prb
->prb_d2h
.sector_count
);
299 kprintf("%s: PM SOFTRESET SIGNATURE %08x\n", ATANAME(ap
, at
), sig
);
301 sili_put_err_ccb(ccb
);
304 * Clear the phy status of the target so we can get a new event.
306 * Target 15 is the PM itself and these registers have
307 * different meanings.
310 if (sili_pm_phy_status(ap
, target
, &data
)) {
311 kprintf("%s: (C)Cannot clear phy status\n",
314 sili_pm_write(ap
, target
, SATA_PMREG_SERR
, -1);
318 * If the softreset is trying to clear a BSY condition after a
319 * normal portreset we assign the port type.
321 * If the softreset is being run first as part of the ccb error
322 * processing code then report if the device signature changed
325 if (at
->at_type
== ATA_PORT_T_NONE
) {
326 at
->at_type
= sili_port_signature(ap
, at
, sig
);
328 if (sili_port_signature(ap
, at
, sig
) != at
->at_type
) {
329 kprintf("%s: device signature unexpectedly "
330 "changed\n", ATANAME(ap
, at
));
331 error
= EBUSY
; /* XXX */
337 * Clear error status so we can detect removal.
339 * Target 15 is the PM itself and these registers have
340 * different meanings.
342 if (error
== 0 && target
!= 15) {
343 if (sili_pm_write(ap
, target
, SATA_PMREG_SERR
, -1)) {
344 kprintf("%s: sili_pm_softreset unable to clear SERR\n",
346 ap
->ap_flags
&= ~AP_F_IGNORE_IFS
;
350 at
->at_probe
= error
? ATA_PROBE_FAILED
: ATA_PROBE_NEED_IDENT
;
356 * Return the phy status for a target behind a port multiplier and
357 * reset SATA_PMREG_SERR.
359 * Returned bits follow SILI_PREG_SSTS bits. The SILI_PREG_SSTS_SPD
360 * bits can be used to determine the link speed and will be 0 if there
363 * 0 is returned if any communications error occurs.
366 sili_pm_phy_status(struct sili_port
*ap
, int target
, u_int32_t
*datap
)
370 error
= sili_pm_read(ap
, target
, SATA_PMREG_SSTS
, datap
);
372 error
= sili_pm_write(ap
, target
, SATA_PMREG_SERR
, -1);
379 sili_pm_set_feature(struct sili_port
*ap
, int feature
, int enable
)
384 xa
= sili_ata_get_xfer(ap
, &ap
->ap_ata
[15]);
386 xa
->fis
->type
= ATA_FIS_TYPE_H2D
;
387 xa
->fis
->flags
= ATA_H2D_FLAGS_CMD
| 15;
388 xa
->fis
->command
= enable
? ATA_C_SATA_FEATURE_ENA
:
389 ATA_C_SATA_FEATURE_DIS
;
390 xa
->fis
->sector_count
= feature
;
391 xa
->fis
->control
= ATA_FIS_CONTROL_4BIT
;
393 xa
->complete
= sili_pm_dummy_done
;
395 xa
->flags
= ATA_F_POLL
| ATA_F_EXCLUSIVE
;
398 if (sili_ata_cmd(xa
) == ATA_S_COMPLETE
)
402 sili_ata_put_xfer(xa
);
407 * Check that a target is still good.
410 sili_pm_check_good(struct sili_port
*ap
, int target
)
416 * It looks like we might have to read the EINFO register
417 * to allow the PM to generate a new event.
419 if (sili_pm_read(ap
, 15, SATA_PMREG_EINFO
, &data
)) {
420 kprintf("%s: Port multiplier EINFO could not be read\n",
424 if (sili_pm_write(ap
, target
, SATA_PMREG_SERR
, -1)) {
425 kprintf("%s: Port multiplier: SERR could not be cleared\n",
429 if (target
== CAM_TARGET_WILDCARD
|| target
>= ap
->ap_pmcount
)
431 at
= &ap
->ap_ata
[target
];
434 * If the device needs an init or hard reset also make sure the
437 if (at
->at_probe
<= ATA_PROBE_NEED_HARD_RESET
) {
438 /*kprintf("%s DOHARD\n", ATANAME(ap, at));*/
439 sili_pm_hardreset(ap
, target
, 1);
443 * Read the detect status
445 if (sili_pm_read(ap
, target
, SATA_PMREG_SSTS
, &data
)) {
446 kprintf("%s: Unable to access PM SSTS register target %d\n",
447 PORTNAME(ap
), target
);
450 if ((data
& SATA_PM_SSTS_DET
) != SATA_PM_SSTS_DET_DEV
) {
451 /*kprintf("%s: DETECT %08x\n", ATANAME(ap, at), data);*/
452 if (at
->at_probe
!= ATA_PROBE_FAILED
) {
453 at
->at_probe
= ATA_PROBE_FAILED
;
454 at
->at_type
= ATA_PORT_T_NONE
;
455 at
->at_features
|= ATA_PORT_F_RESCAN
;
456 kprintf("%s: HOTPLUG (PM) - Device removed\n",
460 if (at
->at_probe
== ATA_PROBE_FAILED
) {
461 at
->at_probe
= ATA_PROBE_NEED_HARD_RESET
;
462 at
->at_features
|= ATA_PORT_F_RESCAN
;
463 kprintf("%s: HOTPLUG (PM) - Device inserted\n",
473 sili_pm_read(struct sili_port
*ap
, int target
, int which
, u_int32_t
*datap
)
478 xa
= sili_ata_get_xfer(ap
, &ap
->ap_ata
[15]);
480 xa
->fis
->type
= ATA_FIS_TYPE_H2D
;
481 xa
->fis
->flags
= ATA_H2D_FLAGS_CMD
| 15;
482 xa
->fis
->command
= ATA_C_READ_PM
;
483 xa
->fis
->features
= which
;
484 xa
->fis
->device
= target
| ATA_H2D_DEVICE_LBA
;
485 xa
->fis
->control
= ATA_FIS_CONTROL_4BIT
;
487 xa
->complete
= sili_pm_dummy_done
;
489 xa
->flags
= ATA_F_POLL
| ATA_F_AUTOSENSE
;
492 if (sili_ata_cmd(xa
) == ATA_S_COMPLETE
) {
493 *datap
= xa
->rfis
->sector_count
| (xa
->rfis
->lba_low
<< 8) |
494 (xa
->rfis
->lba_mid
<< 16) | (xa
->rfis
->lba_high
<< 24);
497 kprintf("%s.%d pm_read SCA[%d] failed\n",
498 PORTNAME(ap
), target
, which
);
502 sili_ata_put_xfer(xa
);
507 * Write a PM register
510 sili_pm_write(struct sili_port
*ap
, int target
, int which
, u_int32_t data
)
515 xa
= sili_ata_get_xfer(ap
, &ap
->ap_ata
[15]);
517 xa
->fis
->type
= ATA_FIS_TYPE_H2D
;
518 xa
->fis
->flags
= ATA_H2D_FLAGS_CMD
| 15;
519 xa
->fis
->command
= ATA_C_WRITE_PM
;
520 xa
->fis
->features
= which
;
521 xa
->fis
->device
= target
| ATA_H2D_DEVICE_LBA
;
522 xa
->fis
->sector_count
= (u_int8_t
)data
;
523 xa
->fis
->lba_low
= (u_int8_t
)(data
>> 8);
524 xa
->fis
->lba_mid
= (u_int8_t
)(data
>> 16);
525 xa
->fis
->lba_high
= (u_int8_t
)(data
>> 24);
526 xa
->fis
->control
= ATA_FIS_CONTROL_4BIT
;
528 xa
->complete
= sili_pm_dummy_done
;
530 xa
->flags
= ATA_F_POLL
| ATA_F_EXCLUSIVE
;
533 if (sili_ata_cmd(xa
) == ATA_S_COMPLETE
)
537 sili_ata_put_xfer(xa
);
542 * Dummy done callback for xa.
545 sili_pm_dummy_done(struct ata_xfer
*xa
)
550 sili_pm_empty_done(struct sili_ccb
*ccb
)