1/* $NetBSD: satapmp_subr.c,v 1.12 2013/05/03 20:02:08 jakllsch Exp $ */
2
3/*
4 * Copyright (c) 2012 Manuel Bouyer. All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
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__KERNEL_RCSID(0, "$NetBSD: satapmp_subr.c,v 1.12 2013/05/03 20:02:08 jakllsch Exp $");
29
30#include <sys/param.h>
31#include <sys/systm.h>
32#include <sys/kernel.h>
33#include <sys/device.h>
34#include <sys/conf.h>
35#include <sys/fcntl.h>
36#include <sys/proc.h>
37#include <sys/errno.h>
38#include <sys/kmem.h>
39#include <sys/intr.h>
40
41#include <dev/ata/ataconf.h>
42#include <dev/ata/atareg.h>
43#include <dev/ata/atavar.h>
44
45#include <dev/ata/satapmpvar.h>
46#include <dev/ata/satapmpreg.h>
47#include <dev/ata/satavar.h>
48#include <dev/ata/satareg.h>
49
50static int
51satapmp_read_8(struct ata_channel *chp, int port, int reg, uint64_t *value)
52{
53 struct ata_command ata_c;
54 struct atac_softc *atac = chp->ch_atac;
55 struct ata_drive_datas *drvp;
56
57 KASSERT(port < PMP_MAX_DRIVES);
58 KASSERT(reg < PMP_GSCR_NREGS);
59 KASSERT(chp->ch_ndrives >= PMP_MAX_DRIVES);
60 drvp = &chp->ch_drive[PMP_PORT_CTL];
61 KASSERT(drvp->drive == PMP_PORT_CTL);
62
63 memset(&ata_c, 0, sizeof(struct ata_command));
64
65 ata_c.r_command = PMPC_READ_PORT;
66 ata_c.r_features = reg;
67 ata_c.r_device = port;
68 ata_c.timeout = 3000; /* 3s */
69 ata_c.r_st_bmask = 0;
70 ata_c.r_st_pmask = WDCS_DRDY;
71 ata_c.flags = AT_LBA48 | AT_READREG | AT_WAIT;
72
73 if ((*atac->atac_bustype_ata->ata_exec_command)(drvp,
74 &ata_c) != ATACMD_COMPLETE) {
75 aprint_error_dev(chp->atabus,
76 "PMP port %d register %d read failed\n", port, reg);
77 return EIO;
78 }
79 if (ata_c.flags & (AT_TIMEOU | AT_DF)) {
80 aprint_error_dev(chp->atabus,
81 "PMP port %d register %d read failed, flags 0x%x\n",
82 port, reg, ata_c.flags);
83 return EIO;
84 }
85 if (ata_c.flags & AT_ERROR) {
86 aprint_verbose_dev(chp->atabus,
87 "PMP port %d register %d read failed, error 0x%x\n",
88 port, reg, ata_c.r_error);
89 return EIO;
90 }
91
92 *value = ((uint64_t)((ata_c.r_lba >> 24) & 0xffffff) << 40) |
93 ((uint64_t)((ata_c.r_count >> 8) & 0xff) << 32) |
94 ((uint64_t)((ata_c.r_lba >> 0) & 0xffffff) << 8) |
95 ((uint64_t)((ata_c.r_count >> 0) & 0xff) << 0);
96
97 return 0;
98}
99
100static inline int
101satapmp_read(struct ata_channel *chp, int port, int reg, uint32_t *value)
102{
103 uint64_t value64;
104 int ret;
105
106 ret = satapmp_read_8(chp, port, reg, &value64);
107 if (ret)
108 return ret;
109
110 *value = value64 & 0xffffffff;
111 return ret;
112}
113
114static int
115satapmp_write_8(struct ata_channel *chp, int port, int reg, uint64_t value)
116{
117 struct ata_command ata_c;
118 struct atac_softc *atac = chp->ch_atac;
119 struct ata_drive_datas *drvp;
120
121 KASSERT(port < PMP_MAX_DRIVES);
122 KASSERT(reg < PMP_GSCR_NREGS);
123 KASSERT(chp->ch_ndrives >= PMP_MAX_DRIVES);
124 drvp = &chp->ch_drive[PMP_PORT_CTL];
125 KASSERT(drvp->drive == PMP_PORT_CTL);
126
127 memset(&ata_c, 0, sizeof(struct ata_command));
128
129 ata_c.r_command = PMPC_WRITE_PORT;
130 ata_c.r_features = reg;
131 ata_c.r_device = port;
132 ata_c.r_lba = (((value >> 40) & 0xffffff) << 24) |
133 (((value >> 8) & 0xffffff) << 0);
134 ata_c.r_count = (((value >> 32) & 0xff) << 8) |
135 (((value >> 0) & 0xff) << 0);
136 ata_c.timeout = 3000; /* 3s */
137 ata_c.r_st_bmask = 0;
138 ata_c.r_st_pmask = WDCS_DRDY;
139 ata_c.flags = AT_LBA48 | AT_WAIT;
140
141 if ((*atac->atac_bustype_ata->ata_exec_command)(drvp,
142 &ata_c) != ATACMD_COMPLETE) {
143 aprint_error_dev(chp->atabus,
144 "PMP port %d register %d write failed\n", port, reg);
145 return EIO;
146 }
147 if (ata_c.flags & (AT_TIMEOU | AT_DF)) {
148 aprint_error_dev(chp->atabus,
149 "PMP port %d register %d write failed, flags 0x%x\n",
150 port, reg, ata_c.flags);
151 return EIO;
152 }
153 if (ata_c.flags & AT_ERROR) {
154 aprint_verbose_dev(chp->atabus,
155 "PMP port %d register %d write failed, error 0x%x\n",
156 port, reg, ata_c.r_error);
157 return EIO;
158 }
159 return 0;
160}
161
162static inline int
163satapmp_write(struct ata_channel *chp, int port, int reg, uint32_t value)
164{
165 return satapmp_write_8(chp, port, reg, value);
166}
167
168/*
169 * Reset one port's PHY and bring it online
170 * XXX duplicate of sata_reset_interface()
171 */
172static uint32_t
173satapmp_reset_device_port(struct ata_channel *chp, int port)
174{
175 uint32_t scontrol, sstatus;
176 int i;
177
178 /* bring the PHY online */
179 scontrol = SControl_IPM_NONE | SControl_SPD_ANY | SControl_DET_INIT;
180 if (satapmp_write(chp, port, PMP_PSCR_SControl, scontrol) != 0)
181 return 0;
182
183 tsleep(chp, PRIBIO, "sataup", mstohz(50));
184 scontrol &= ~SControl_DET_INIT;
185 if (satapmp_write(chp, port, PMP_PSCR_SControl, scontrol) != 0)
186 return 0;
187 tsleep(chp, PRIBIO, "sataup", mstohz(50));
188
189 /* wait up to 1s for device to come up */
190 for (i = 0; i < 100; i++) {
191
192 if (satapmp_read(chp, port, PMP_PSCR_SStatus, &sstatus) != 0)
193 return 0;
194 if ((sstatus & SStatus_DET_mask) == SStatus_DET_DEV)
195 break;
196 tsleep(chp, PRIBIO, "sataup", mstohz(10));
197 }
198
199 switch (sstatus & SStatus_DET_mask) {
200 case SStatus_DET_NODEV:
201 /* No Device; be silent. */
202 break;
203 case SStatus_DET_DEV_NE:
204 aprint_error("%s PMP port %d: device connected, but "
205 "communication not established\n",
206 device_xname(chp->atabus), port);
207 break;
208 case SStatus_DET_OFFLINE:
209 aprint_error("%s PMP port %d: PHY offline\n",
210 device_xname(chp->atabus), port);
211 break;
212 case SStatus_DET_DEV:
213 aprint_normal("%s PMP port %d: device present, speed: %s\n",
214 device_xname(chp->atabus), port, sata_speed(sstatus));
215 break;
216 default:
217 aprint_error("%s PMP port %d: unknown SStatus: 0x%08x\n",
218 device_xname(chp->atabus), port, sstatus);
219 }
220 return(sstatus & SStatus_DET_mask);
221}
222
223void
224satapmp_rescan(struct ata_channel *chp) {
225 int i;
226 uint32_t sig;
227
228 KASSERT(chp->ch_satapmp_nports <= PMP_PORT_CTL);
229 KASSERT(chp->ch_satapmp_nports <= chp->ch_ndrives);
230
231 for (i = 0; i < chp->ch_satapmp_nports; i++) {
232 if (chp->ch_drive[i].drive_type != ATA_DRIVET_NONE ||
233 satapmp_reset_device_port(chp, i) != SStatus_DET_DEV) {
234 continue;
235 }
236 if (satapmp_write(chp, i, PMP_PSCR_SError, 0xffffffff) != 0) {
237 aprint_error("%s PMP port %d: can't write SError\n",
238 device_xname(chp->atabus), i);
239 continue;
240 }
241 chp->ch_atac->atac_bustype_ata->ata_reset_drive(
242 &chp->ch_drive[i], AT_WAIT, &sig);
243
244 sata_interpret_sig(chp, i, sig);
245 }
246}
247
248void
249satapmp_attach(struct ata_channel *chp)
250{
251 uint32_t id, rev, inf;
252
253 if (satapmp_read(chp, PMP_PORT_CTL, PMP_GSCR_ID, &id) != 0 ||
254 satapmp_read(chp, PMP_PORT_CTL, PMP_GSCR_REV, &rev) != 0 ||
255 satapmp_read(chp, PMP_PORT_CTL, PMP_GSCR_INF, &inf) != 0) {
256 aprint_normal_dev(chp->atabus, "can't read PMP registers\n");
257 return;
258 }
259
260 aprint_normal_dev(chp->atabus,
261 "SATA port multiplier, %d ports\n", PMP_INF_NPORTS(inf));
262 aprint_verbose_dev(chp->atabus,
263 "vendor 0x%04x, product 0x%04x",
264 PMP_ID_VEND(id), PMP_ID_DEV(id));
265 if (rev & PMP_REV_SPEC_11) {
266 aprint_verbose(", revision 1.1");
267 } else if (rev & PMP_REV_SPEC_10) {
268 aprint_verbose(", revision 1.0");
269 } else {
270 aprint_verbose(", unknown revision 0x%x", rev & 0x0f);
271 }
272 aprint_verbose(", level %d\n", PMP_REV_LEVEL(rev));
273
274 chp->ch_satapmp_nports = PMP_INF_NPORTS(inf);
275
276 /* reset and bring up PHYs */
277 satapmp_rescan(chp);
278}
279