Commit | Line | Data |
---|---|---|
6f231dda DW |
1 | /* |
2 | * This file is provided under a dual BSD/GPLv2 license. When using or | |
3 | * redistributing this file, you may do so under either license. | |
4 | * | |
5 | * GPL LICENSE SUMMARY | |
6 | * | |
7 | * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. | |
8 | * | |
9 | * This program is free software; you can redistribute it and/or modify | |
10 | * it under the terms of version 2 of the GNU General Public License as | |
11 | * published by the Free Software Foundation. | |
12 | * | |
13 | * This program is distributed in the hope that it will be useful, but | |
14 | * WITHOUT ANY WARRANTY; without even the implied warranty of | |
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
16 | * General Public License for more details. | |
17 | * | |
18 | * You should have received a copy of the GNU General Public License | |
19 | * along with this program; if not, write to the Free Software | |
20 | * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. | |
21 | * The full GNU General Public License is included in this distribution | |
22 | * in the file called LICENSE.GPL. | |
23 | * | |
24 | * BSD LICENSE | |
25 | * | |
26 | * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. | |
27 | * All rights reserved. | |
28 | * | |
29 | * Redistribution and use in source and binary forms, with or without | |
30 | * modification, are permitted provided that the following conditions | |
31 | * are met: | |
32 | * | |
33 | * * Redistributions of source code must retain the above copyright | |
34 | * notice, this list of conditions and the following disclaimer. | |
35 | * * Redistributions in binary form must reproduce the above copyright | |
36 | * notice, this list of conditions and the following disclaimer in | |
37 | * the documentation and/or other materials provided with the | |
38 | * distribution. | |
39 | * * Neither the name of Intel Corporation nor the names of its | |
40 | * contributors may be used to endorse or promote products derived | |
41 | * from this software without specific prior written permission. | |
42 | * | |
43 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
44 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
45 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | |
46 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | |
47 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
48 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |
49 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |
50 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |
51 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
52 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |
53 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
54 | */ | |
55 | ||
56 | #include "isci.h" | |
ce2b3261 | 57 | #include "host.h" |
6f231dda | 58 | #include "phy.h" |
d35bc1bd | 59 | #include "scu_event_codes.h" |
e2f8db50 | 60 | #include "probe_roms.h" |
6f231dda | 61 | |
d7a0ccdd DW |
62 | #undef C |
63 | #define C(a) (#a) | |
64 | static const char *phy_state_name(enum sci_phy_states state) | |
65 | { | |
66 | static const char * const strings[] = PHY_STATES; | |
67 | ||
68 | return strings[state]; | |
69 | } | |
70 | #undef C | |
71 | ||
d35bc1bd DW |
72 | /* Maximum arbitration wait time in micro-seconds */ |
73 | #define SCIC_SDS_PHY_MAX_ARBITRATION_WAIT_TIME (700) | |
74 | ||
85280955 | 75 | enum sas_linkrate sci_phy_linkrate(struct isci_phy *iphy) |
d35bc1bd | 76 | { |
85280955 | 77 | return iphy->max_negotiated_speed; |
d35bc1bd DW |
78 | } |
79 | ||
e462116a | 80 | static struct isci_host *phy_to_host(struct isci_phy *iphy) |
c132f692 DW |
81 | { |
82 | struct isci_phy *table = iphy - iphy->phy_index; | |
83 | struct isci_host *ihost = container_of(table, typeof(*ihost), phys[0]); | |
84 | ||
e462116a DW |
85 | return ihost; |
86 | } | |
87 | ||
88 | static struct device *sciphy_to_dev(struct isci_phy *iphy) | |
89 | { | |
90 | return &phy_to_host(iphy)->pdev->dev; | |
c132f692 DW |
91 | } |
92 | ||
89a7301f DW |
93 | static enum sci_status |
94 | sci_phy_transport_layer_initialization(struct isci_phy *iphy, | |
95 | struct scu_transport_layer_registers __iomem *reg) | |
d35bc1bd DW |
96 | { |
97 | u32 tl_control; | |
98 | ||
89a7301f | 99 | iphy->transport_layer_registers = reg; |
d35bc1bd DW |
100 | |
101 | writel(SCIC_SDS_REMOTE_NODE_CONTEXT_INVALID_INDEX, | |
85280955 | 102 | &iphy->transport_layer_registers->stp_rni); |
d35bc1bd DW |
103 | |
104 | /* | |
105 | * Hardware team recommends that we enable the STP prefetch for all | |
106 | * transports | |
107 | */ | |
85280955 | 108 | tl_control = readl(&iphy->transport_layer_registers->control); |
d35bc1bd | 109 | tl_control |= SCU_TLCR_GEN_BIT(STP_WRITE_DATA_PREFETCH); |
85280955 | 110 | writel(tl_control, &iphy->transport_layer_registers->control); |
d35bc1bd DW |
111 | |
112 | return SCI_SUCCESS; | |
113 | } | |
114 | ||
d35bc1bd | 115 | static enum sci_status |
89a7301f | 116 | sci_phy_link_layer_initialization(struct isci_phy *iphy, |
2e5da889 | 117 | struct scu_link_layer_registers __iomem *llr) |
d35bc1bd | 118 | { |
89a7301f | 119 | struct isci_host *ihost = iphy->owning_port->owning_controller; |
2e5da889 DW |
120 | struct sci_phy_user_params *phy_user; |
121 | struct sci_phy_oem_params *phy_oem; | |
85280955 | 122 | int phy_idx = iphy->phy_index; |
89a7301f | 123 | struct sci_phy_cap phy_cap; |
2e5da889 | 124 | u32 phy_configuration; |
d35bc1bd DW |
125 | u32 parity_check = 0; |
126 | u32 parity_count = 0; | |
127 | u32 llctl, link_rate; | |
128 | u32 clksm_value = 0; | |
985af6f7 | 129 | u32 sp_timeouts = 0; |
d35bc1bd | 130 | |
2e5da889 DW |
131 | phy_user = &ihost->user_parameters.phys[phy_idx]; |
132 | phy_oem = &ihost->oem_parameters.phys[phy_idx]; | |
133 | iphy->link_layer_registers = llr; | |
d35bc1bd DW |
134 | |
135 | /* Set our IDENTIFY frame data */ | |
136 | #define SCI_END_DEVICE 0x01 | |
137 | ||
138 | writel(SCU_SAS_TIID_GEN_BIT(SMP_INITIATOR) | | |
139 | SCU_SAS_TIID_GEN_BIT(SSP_INITIATOR) | | |
140 | SCU_SAS_TIID_GEN_BIT(STP_INITIATOR) | | |
141 | SCU_SAS_TIID_GEN_BIT(DA_SATA_HOST) | | |
142 | SCU_SAS_TIID_GEN_VAL(DEVICE_TYPE, SCI_END_DEVICE), | |
2e5da889 | 143 | &llr->transmit_identification); |
d35bc1bd DW |
144 | |
145 | /* Write the device SAS Address */ | |
2e5da889 DW |
146 | writel(0xFEDCBA98, &llr->sas_device_name_high); |
147 | writel(phy_idx, &llr->sas_device_name_low); | |
d35bc1bd DW |
148 | |
149 | /* Write the source SAS Address */ | |
2e5da889 DW |
150 | writel(phy_oem->sas_address.high, &llr->source_sas_address_high); |
151 | writel(phy_oem->sas_address.low, &llr->source_sas_address_low); | |
d35bc1bd DW |
152 | |
153 | /* Clear and Set the PHY Identifier */ | |
2e5da889 DW |
154 | writel(0, &llr->identify_frame_phy_id); |
155 | writel(SCU_SAS_TIPID_GEN_VALUE(ID, phy_idx), &llr->identify_frame_phy_id); | |
d35bc1bd DW |
156 | |
157 | /* Change the initial state of the phy configuration register */ | |
2e5da889 | 158 | phy_configuration = readl(&llr->phy_configuration); |
d35bc1bd DW |
159 | |
160 | /* Hold OOB state machine in reset */ | |
161 | phy_configuration |= SCU_SAS_PCFG_GEN_BIT(OOB_RESET); | |
2e5da889 | 162 | writel(phy_configuration, &llr->phy_configuration); |
d35bc1bd DW |
163 | |
164 | /* Configure the SNW capabilities */ | |
165 | phy_cap.all = 0; | |
166 | phy_cap.start = 1; | |
167 | phy_cap.gen3_no_ssc = 1; | |
168 | phy_cap.gen2_no_ssc = 1; | |
169 | phy_cap.gen1_no_ssc = 1; | |
594e566a DJ |
170 | if (ihost->oem_parameters.controller.do_enable_ssc) { |
171 | struct scu_afe_registers __iomem *afe = &ihost->scu_registers->afe; | |
6734092e | 172 | struct scu_afe_transceiver __iomem *xcvr = &afe->scu_afe_xcvr[phy_idx]; |
594e566a DJ |
173 | struct isci_pci_info *pci_info = to_pci_info(ihost->pdev); |
174 | bool en_sas = false; | |
175 | bool en_sata = false; | |
176 | u32 sas_type = 0; | |
177 | u32 sata_spread = 0x2; | |
178 | u32 sas_spread = 0x2; | |
179 | ||
d35bc1bd DW |
180 | phy_cap.gen3_ssc = 1; |
181 | phy_cap.gen2_ssc = 1; | |
182 | phy_cap.gen1_ssc = 1; | |
594e566a DJ |
183 | |
184 | if (pci_info->orom->hdr.version < ISCI_ROM_VER_1_1) | |
185 | en_sas = en_sata = true; | |
186 | else { | |
187 | sata_spread = ihost->oem_parameters.controller.ssc_sata_tx_spread_level; | |
188 | sas_spread = ihost->oem_parameters.controller.ssc_sas_tx_spread_level; | |
189 | ||
190 | if (sata_spread) | |
191 | en_sata = true; | |
192 | ||
193 | if (sas_spread) { | |
194 | en_sas = true; | |
195 | sas_type = ihost->oem_parameters.controller.ssc_sas_tx_type; | |
196 | } | |
197 | ||
198 | } | |
199 | ||
200 | if (en_sas) { | |
201 | u32 reg; | |
202 | ||
203 | reg = readl(&xcvr->afe_xcvr_control0); | |
204 | reg |= (0x00100000 | (sas_type << 19)); | |
205 | writel(reg, &xcvr->afe_xcvr_control0); | |
206 | ||
207 | reg = readl(&xcvr->afe_tx_ssc_control); | |
208 | reg |= sas_spread << 8; | |
209 | writel(reg, &xcvr->afe_tx_ssc_control); | |
210 | } | |
211 | ||
212 | if (en_sata) { | |
213 | u32 reg; | |
214 | ||
215 | reg = readl(&xcvr->afe_tx_ssc_control); | |
216 | reg |= sata_spread; | |
217 | writel(reg, &xcvr->afe_tx_ssc_control); | |
218 | ||
219 | reg = readl(&llr->stp_control); | |
220 | reg |= 1 << 12; | |
221 | writel(reg, &llr->stp_control); | |
222 | } | |
d35bc1bd DW |
223 | } |
224 | ||
2e5da889 DW |
225 | /* The SAS specification indicates that the phy_capabilities that |
226 | * are transmitted shall have an even parity. Calculate the parity. | |
227 | */ | |
d35bc1bd DW |
228 | parity_check = phy_cap.all; |
229 | while (parity_check != 0) { | |
230 | if (parity_check & 0x1) | |
231 | parity_count++; | |
232 | parity_check >>= 1; | |
233 | } | |
234 | ||
2e5da889 DW |
235 | /* If parity indicates there are an odd number of bits set, then |
236 | * set the parity bit to 1 in the phy capabilities. | |
237 | */ | |
d35bc1bd DW |
238 | if ((parity_count % 2) != 0) |
239 | phy_cap.parity = 1; | |
240 | ||
2e5da889 | 241 | writel(phy_cap.all, &llr->phy_capabilities); |
d35bc1bd DW |
242 | |
243 | /* Set the enable spinup period but disable the ability to send | |
244 | * notify enable spinup | |
245 | */ | |
246 | writel(SCU_ENSPINUP_GEN_VAL(COUNT, | |
247 | phy_user->notify_enable_spin_up_insertion_frequency), | |
2e5da889 | 248 | &llr->notify_enable_spinup_control); |
d35bc1bd DW |
249 | |
250 | /* Write the ALIGN Insertion Ferequency for connected phy and | |
251 | * inpendent of connected state | |
252 | */ | |
253 | clksm_value = SCU_ALIGN_INSERTION_FREQUENCY_GEN_VAL(CONNECTED, | |
254 | phy_user->in_connection_align_insertion_frequency); | |
255 | ||
256 | clksm_value |= SCU_ALIGN_INSERTION_FREQUENCY_GEN_VAL(GENERAL, | |
257 | phy_user->align_insertion_frequency); | |
258 | ||
2e5da889 | 259 | writel(clksm_value, &llr->clock_skew_management); |
d35bc1bd | 260 | |
afd13a1f JS |
261 | if (is_c0(ihost->pdev) || is_c1(ihost->pdev)) { |
262 | writel(0x04210400, &llr->afe_lookup_table_control); | |
263 | writel(0x020A7C05, &llr->sas_primitive_timeout); | |
264 | } else | |
265 | writel(0x02108421, &llr->afe_lookup_table_control); | |
d35bc1bd DW |
266 | |
267 | llctl = SCU_SAS_LLCTL_GEN_VAL(NO_OUTBOUND_TASK_TIMEOUT, | |
89a7301f | 268 | (u8)ihost->user_parameters.no_outbound_task_timeout); |
d35bc1bd | 269 | |
a5ec7f86 | 270 | switch (phy_user->max_speed_generation) { |
d35bc1bd DW |
271 | case SCIC_SDS_PARM_GEN3_SPEED: |
272 | link_rate = SCU_SAS_LINK_LAYER_CONTROL_MAX_LINK_RATE_GEN3; | |
273 | break; | |
274 | case SCIC_SDS_PARM_GEN2_SPEED: | |
275 | link_rate = SCU_SAS_LINK_LAYER_CONTROL_MAX_LINK_RATE_GEN2; | |
276 | break; | |
277 | default: | |
278 | link_rate = SCU_SAS_LINK_LAYER_CONTROL_MAX_LINK_RATE_GEN1; | |
279 | break; | |
280 | } | |
281 | llctl |= SCU_SAS_LLCTL_GEN_VAL(MAX_LINK_RATE, link_rate); | |
2e5da889 | 282 | writel(llctl, &llr->link_layer_control); |
d35bc1bd | 283 | |
2e5da889 | 284 | sp_timeouts = readl(&llr->sas_phy_timeouts); |
985af6f7 MT |
285 | |
286 | /* Clear the default 0x36 (54us) RATE_CHANGE timeout value. */ | |
287 | sp_timeouts &= ~SCU_SAS_PHYTOV_GEN_VAL(RATE_CHANGE, 0xFF); | |
288 | ||
289 | /* Set RATE_CHANGE timeout value to 0x3B (59us). This ensures SCU can | |
290 | * lock with 3Gb drive when SCU max rate is set to 1.5Gb. | |
291 | */ | |
292 | sp_timeouts |= SCU_SAS_PHYTOV_GEN_VAL(RATE_CHANGE, 0x3B); | |
293 | ||
2e5da889 | 294 | writel(sp_timeouts, &llr->sas_phy_timeouts); |
985af6f7 | 295 | |
dc00c8b6 | 296 | if (is_a2(ihost->pdev)) { |
2e5da889 DW |
297 | /* Program the max ARB time for the PHY to 700us so we |
298 | * inter-operate with the PMC expander which shuts down | |
299 | * PHYs if the expander PHY generates too many breaks. | |
300 | * This time value will guarantee that the initiator PHY | |
301 | * will generate the break. | |
d35bc1bd DW |
302 | */ |
303 | writel(SCIC_SDS_PHY_MAX_ARBITRATION_WAIT_TIME, | |
2e5da889 | 304 | &llr->maximum_arbitration_wait_timer_timeout); |
d35bc1bd DW |
305 | } |
306 | ||
2e5da889 DW |
307 | /* Disable link layer hang detection, rely on the OS timeout for |
308 | * I/O timeouts. | |
309 | */ | |
310 | writel(0, &llr->link_layer_hang_detection_timeout); | |
d35bc1bd DW |
311 | |
312 | /* We can exit the initial state to the stopped state */ | |
85280955 | 313 | sci_change_state(&iphy->sm, SCI_PHY_STOPPED); |
d35bc1bd DW |
314 | |
315 | return SCI_SUCCESS; | |
316 | } | |
317 | ||
a628d478 | 318 | static void phy_sata_timeout(unsigned long data) |
d35bc1bd | 319 | { |
a628d478 | 320 | struct sci_timer *tmr = (struct sci_timer *)data; |
85280955 | 321 | struct isci_phy *iphy = container_of(tmr, typeof(*iphy), sata_timer); |
d9dcb4ba | 322 | struct isci_host *ihost = iphy->owning_port->owning_controller; |
a628d478 EN |
323 | unsigned long flags; |
324 | ||
325 | spin_lock_irqsave(&ihost->scic_lock, flags); | |
326 | ||
327 | if (tmr->cancel) | |
328 | goto done; | |
d35bc1bd | 329 | |
85280955 | 330 | dev_dbg(sciphy_to_dev(iphy), |
d35bc1bd DW |
331 | "%s: SCIC SDS Phy 0x%p did not receive signature fis before " |
332 | "timeout.\n", | |
333 | __func__, | |
85280955 | 334 | iphy); |
d35bc1bd | 335 | |
85280955 | 336 | sci_change_state(&iphy->sm, SCI_PHY_STARTING); |
a628d478 EN |
337 | done: |
338 | spin_unlock_irqrestore(&ihost->scic_lock, flags); | |
d35bc1bd DW |
339 | } |
340 | ||
341 | /** | |
342 | * This method returns the port currently containing this phy. If the phy is | |
343 | * currently contained by the dummy port, then the phy is considered to not | |
344 | * be part of a port. | |
345 | * @sci_phy: This parameter specifies the phy for which to retrieve the | |
346 | * containing port. | |
347 | * | |
348 | * This method returns a handle to a port that contains the supplied phy. | |
349 | * NULL This value is returned if the phy is not part of a real | |
350 | * port (i.e. it's contained in the dummy port). !NULL All other | |
351 | * values indicate a handle/pointer to the port containing the phy. | |
352 | */ | |
34a99158 | 353 | struct isci_port *phy_get_non_dummy_port(struct isci_phy *iphy) |
d35bc1bd | 354 | { |
34a99158 DW |
355 | struct isci_port *iport = iphy->owning_port; |
356 | ||
357 | if (iport->physical_port_index == SCIC_SDS_DUMMY_PORT) | |
d35bc1bd DW |
358 | return NULL; |
359 | ||
85280955 | 360 | return iphy->owning_port; |
d35bc1bd DW |
361 | } |
362 | ||
363 | /** | |
364 | * This method will assign a port to the phy object. | |
85280955 | 365 | * @out]: iphy This parameter specifies the phy for which to assign a port |
d35bc1bd DW |
366 | * object. |
367 | * | |
368 | * | |
369 | */ | |
89a7301f | 370 | void sci_phy_set_port( |
85280955 | 371 | struct isci_phy *iphy, |
ffe191c9 | 372 | struct isci_port *iport) |
d35bc1bd | 373 | { |
ffe191c9 | 374 | iphy->owning_port = iport; |
d35bc1bd | 375 | |
85280955 DW |
376 | if (iphy->bcn_received_while_port_unassigned) { |
377 | iphy->bcn_received_while_port_unassigned = false; | |
89a7301f | 378 | sci_port_broadcast_change_received(iphy->owning_port, iphy); |
d35bc1bd DW |
379 | } |
380 | } | |
381 | ||
89a7301f DW |
382 | enum sci_status sci_phy_initialize(struct isci_phy *iphy, |
383 | struct scu_transport_layer_registers __iomem *tl, | |
384 | struct scu_link_layer_registers __iomem *ll) | |
d35bc1bd | 385 | { |
d35bc1bd | 386 | /* Perfrom the initialization of the TL hardware */ |
89a7301f | 387 | sci_phy_transport_layer_initialization(iphy, tl); |
d35bc1bd DW |
388 | |
389 | /* Perofrm the initialization of the PE hardware */ | |
89a7301f | 390 | sci_phy_link_layer_initialization(iphy, ll); |
d35bc1bd | 391 | |
89a7301f DW |
392 | /* There is nothing that needs to be done in this state just |
393 | * transition to the stopped state | |
394 | */ | |
85280955 | 395 | sci_change_state(&iphy->sm, SCI_PHY_STOPPED); |
d35bc1bd DW |
396 | |
397 | return SCI_SUCCESS; | |
398 | } | |
399 | ||
400 | /** | |
401 | * This method assigns the direct attached device ID for this phy. | |
402 | * | |
85280955 | 403 | * @iphy The phy for which the direct attached device id is to |
d35bc1bd DW |
404 | * be assigned. |
405 | * @device_id The direct attached device ID to assign to the phy. | |
406 | * This will either be the RNi for the device or an invalid RNi if there | |
407 | * is no current device assigned to the phy. | |
408 | */ | |
89a7301f | 409 | void sci_phy_setup_transport(struct isci_phy *iphy, u32 device_id) |
d35bc1bd DW |
410 | { |
411 | u32 tl_control; | |
412 | ||
85280955 | 413 | writel(device_id, &iphy->transport_layer_registers->stp_rni); |
d35bc1bd DW |
414 | |
415 | /* | |
416 | * The read should guarantee that the first write gets posted | |
417 | * before the next write | |
418 | */ | |
85280955 | 419 | tl_control = readl(&iphy->transport_layer_registers->control); |
d35bc1bd | 420 | tl_control |= SCU_TLCR_GEN_BIT(CLEAR_TCI_NCQ_MAPPING_TABLE); |
85280955 | 421 | writel(tl_control, &iphy->transport_layer_registers->control); |
d35bc1bd DW |
422 | } |
423 | ||
89a7301f | 424 | static void sci_phy_suspend(struct isci_phy *iphy) |
d35bc1bd DW |
425 | { |
426 | u32 scu_sas_pcfg_value; | |
427 | ||
428 | scu_sas_pcfg_value = | |
85280955 | 429 | readl(&iphy->link_layer_registers->phy_configuration); |
d35bc1bd DW |
430 | scu_sas_pcfg_value |= SCU_SAS_PCFG_GEN_BIT(SUSPEND_PROTOCOL_ENGINE); |
431 | writel(scu_sas_pcfg_value, | |
85280955 | 432 | &iphy->link_layer_registers->phy_configuration); |
d35bc1bd | 433 | |
89a7301f | 434 | sci_phy_setup_transport(iphy, SCIC_SDS_REMOTE_NODE_CONTEXT_INVALID_INDEX); |
d35bc1bd DW |
435 | } |
436 | ||
89a7301f | 437 | void sci_phy_resume(struct isci_phy *iphy) |
d35bc1bd DW |
438 | { |
439 | u32 scu_sas_pcfg_value; | |
440 | ||
441 | scu_sas_pcfg_value = | |
85280955 | 442 | readl(&iphy->link_layer_registers->phy_configuration); |
d35bc1bd DW |
443 | scu_sas_pcfg_value &= ~SCU_SAS_PCFG_GEN_BIT(SUSPEND_PROTOCOL_ENGINE); |
444 | writel(scu_sas_pcfg_value, | |
85280955 | 445 | &iphy->link_layer_registers->phy_configuration); |
d35bc1bd DW |
446 | } |
447 | ||
89a7301f | 448 | void sci_phy_get_sas_address(struct isci_phy *iphy, struct sci_sas_address *sas) |
d35bc1bd | 449 | { |
89a7301f DW |
450 | sas->high = readl(&iphy->link_layer_registers->source_sas_address_high); |
451 | sas->low = readl(&iphy->link_layer_registers->source_sas_address_low); | |
d35bc1bd DW |
452 | } |
453 | ||
89a7301f | 454 | void sci_phy_get_attached_sas_address(struct isci_phy *iphy, struct sci_sas_address *sas) |
d35bc1bd DW |
455 | { |
456 | struct sas_identify_frame *iaf; | |
d35bc1bd DW |
457 | |
458 | iaf = &iphy->frame_rcvd.iaf; | |
89a7301f | 459 | memcpy(sas, iaf->sas_addr, SAS_ADDR_SIZE); |
d35bc1bd DW |
460 | } |
461 | ||
89a7301f | 462 | void sci_phy_get_protocols(struct isci_phy *iphy, struct sci_phy_proto *proto) |
d35bc1bd | 463 | { |
89a7301f | 464 | proto->all = readl(&iphy->link_layer_registers->transmit_identification); |
d35bc1bd DW |
465 | } |
466 | ||
89a7301f | 467 | enum sci_status sci_phy_start(struct isci_phy *iphy) |
d35bc1bd | 468 | { |
89a7301f | 469 | enum sci_phy_states state = iphy->sm.current_state_id; |
966699b5 | 470 | |
e301370a | 471 | if (state != SCI_PHY_STOPPED) { |
d7a0ccdd DW |
472 | dev_dbg(sciphy_to_dev(iphy), "%s: in wrong state: %s\n", |
473 | __func__, phy_state_name(state)); | |
966699b5 DW |
474 | return SCI_FAILURE_INVALID_STATE; |
475 | } | |
476 | ||
85280955 | 477 | sci_change_state(&iphy->sm, SCI_PHY_STARTING); |
966699b5 | 478 | return SCI_SUCCESS; |
d35bc1bd DW |
479 | } |
480 | ||
89a7301f | 481 | enum sci_status sci_phy_stop(struct isci_phy *iphy) |
d35bc1bd | 482 | { |
89a7301f | 483 | enum sci_phy_states state = iphy->sm.current_state_id; |
93153236 DW |
484 | |
485 | switch (state) { | |
e301370a EN |
486 | case SCI_PHY_SUB_INITIAL: |
487 | case SCI_PHY_SUB_AWAIT_OSSP_EN: | |
488 | case SCI_PHY_SUB_AWAIT_SAS_SPEED_EN: | |
489 | case SCI_PHY_SUB_AWAIT_SAS_POWER: | |
490 | case SCI_PHY_SUB_AWAIT_SATA_POWER: | |
491 | case SCI_PHY_SUB_AWAIT_SATA_PHY_EN: | |
492 | case SCI_PHY_SUB_AWAIT_SATA_SPEED_EN: | |
493 | case SCI_PHY_SUB_AWAIT_SIG_FIS_UF: | |
494 | case SCI_PHY_SUB_FINAL: | |
495 | case SCI_PHY_READY: | |
93153236 DW |
496 | break; |
497 | default: | |
d7a0ccdd DW |
498 | dev_dbg(sciphy_to_dev(iphy), "%s: in wrong state: %s\n", |
499 | __func__, phy_state_name(state)); | |
93153236 DW |
500 | return SCI_FAILURE_INVALID_STATE; |
501 | } | |
502 | ||
85280955 | 503 | sci_change_state(&iphy->sm, SCI_PHY_STOPPED); |
93153236 | 504 | return SCI_SUCCESS; |
d35bc1bd DW |
505 | } |
506 | ||
89a7301f | 507 | enum sci_status sci_phy_reset(struct isci_phy *iphy) |
d35bc1bd | 508 | { |
89a7301f | 509 | enum sci_phy_states state = iphy->sm.current_state_id; |
0cf36fa9 | 510 | |
e301370a | 511 | if (state != SCI_PHY_READY) { |
d7a0ccdd DW |
512 | dev_dbg(sciphy_to_dev(iphy), "%s: in wrong state: %s\n", |
513 | __func__, phy_state_name(state)); | |
0cf36fa9 DW |
514 | return SCI_FAILURE_INVALID_STATE; |
515 | } | |
516 | ||
85280955 | 517 | sci_change_state(&iphy->sm, SCI_PHY_RESETTING); |
0cf36fa9 | 518 | return SCI_SUCCESS; |
d35bc1bd DW |
519 | } |
520 | ||
89a7301f | 521 | enum sci_status sci_phy_consume_power_handler(struct isci_phy *iphy) |
d35bc1bd | 522 | { |
89a7301f | 523 | enum sci_phy_states state = iphy->sm.current_state_id; |
5b1d4af2 DW |
524 | |
525 | switch (state) { | |
e301370a | 526 | case SCI_PHY_SUB_AWAIT_SAS_POWER: { |
5b1d4af2 DW |
527 | u32 enable_spinup; |
528 | ||
85280955 | 529 | enable_spinup = readl(&iphy->link_layer_registers->notify_enable_spinup_control); |
5b1d4af2 | 530 | enable_spinup |= SCU_ENSPINUP_GEN_BIT(ENABLE); |
85280955 | 531 | writel(enable_spinup, &iphy->link_layer_registers->notify_enable_spinup_control); |
5b1d4af2 DW |
532 | |
533 | /* Change state to the final state this substate machine has run to completion */ | |
85280955 | 534 | sci_change_state(&iphy->sm, SCI_PHY_SUB_FINAL); |
5b1d4af2 DW |
535 | |
536 | return SCI_SUCCESS; | |
537 | } | |
e301370a | 538 | case SCI_PHY_SUB_AWAIT_SATA_POWER: { |
5b1d4af2 DW |
539 | u32 scu_sas_pcfg_value; |
540 | ||
541 | /* Release the spinup hold state and reset the OOB state machine */ | |
542 | scu_sas_pcfg_value = | |
85280955 | 543 | readl(&iphy->link_layer_registers->phy_configuration); |
5b1d4af2 DW |
544 | scu_sas_pcfg_value &= |
545 | ~(SCU_SAS_PCFG_GEN_BIT(SATA_SPINUP_HOLD) | SCU_SAS_PCFG_GEN_BIT(OOB_ENABLE)); | |
546 | scu_sas_pcfg_value |= SCU_SAS_PCFG_GEN_BIT(OOB_RESET); | |
547 | writel(scu_sas_pcfg_value, | |
85280955 | 548 | &iphy->link_layer_registers->phy_configuration); |
5b1d4af2 DW |
549 | |
550 | /* Now restart the OOB operation */ | |
551 | scu_sas_pcfg_value &= ~SCU_SAS_PCFG_GEN_BIT(OOB_RESET); | |
552 | scu_sas_pcfg_value |= SCU_SAS_PCFG_GEN_BIT(OOB_ENABLE); | |
553 | writel(scu_sas_pcfg_value, | |
85280955 | 554 | &iphy->link_layer_registers->phy_configuration); |
5b1d4af2 DW |
555 | |
556 | /* Change state to the final state this substate machine has run to completion */ | |
85280955 | 557 | sci_change_state(&iphy->sm, SCI_PHY_SUB_AWAIT_SATA_PHY_EN); |
5b1d4af2 DW |
558 | |
559 | return SCI_SUCCESS; | |
560 | } | |
561 | default: | |
d7a0ccdd DW |
562 | dev_dbg(sciphy_to_dev(iphy), "%s: in wrong state: %s\n", |
563 | __func__, phy_state_name(state)); | |
5b1d4af2 DW |
564 | return SCI_FAILURE_INVALID_STATE; |
565 | } | |
d35bc1bd DW |
566 | } |
567 | ||
89a7301f | 568 | static void sci_phy_start_sas_link_training(struct isci_phy *iphy) |
d35bc1bd | 569 | { |
89a7301f DW |
570 | /* continue the link training for the phy as if it were a SAS PHY |
571 | * instead of a SATA PHY. This is done because the completion queue had a SAS | |
572 | * PHY DETECTED event when the state machine was expecting a SATA PHY event. | |
573 | */ | |
d35bc1bd DW |
574 | u32 phy_control; |
575 | ||
89a7301f | 576 | phy_control = readl(&iphy->link_layer_registers->phy_configuration); |
d35bc1bd DW |
577 | phy_control |= SCU_SAS_PCFG_GEN_BIT(SATA_SPINUP_HOLD); |
578 | writel(phy_control, | |
89a7301f | 579 | &iphy->link_layer_registers->phy_configuration); |
d35bc1bd | 580 | |
85280955 | 581 | sci_change_state(&iphy->sm, SCI_PHY_SUB_AWAIT_SAS_SPEED_EN); |
d35bc1bd | 582 | |
c79dd80d | 583 | iphy->protocol = SAS_PROTOCOL_SSP; |
d35bc1bd DW |
584 | } |
585 | ||
89a7301f | 586 | static void sci_phy_start_sata_link_training(struct isci_phy *iphy) |
d35bc1bd | 587 | { |
89a7301f DW |
588 | /* This method continues the link training for the phy as if it were a SATA PHY |
589 | * instead of a SAS PHY. This is done because the completion queue had a SATA | |
590 | * SPINUP HOLD event when the state machine was expecting a SAS PHY event. none | |
591 | */ | |
85280955 | 592 | sci_change_state(&iphy->sm, SCI_PHY_SUB_AWAIT_SATA_POWER); |
d35bc1bd | 593 | |
c79dd80d | 594 | iphy->protocol = SAS_PROTOCOL_SATA; |
d35bc1bd DW |
595 | } |
596 | ||
597 | /** | |
89a7301f | 598 | * sci_phy_complete_link_training - perform processing common to |
d35bc1bd DW |
599 | * all protocols upon completion of link training. |
600 | * @sci_phy: This parameter specifies the phy object for which link training | |
601 | * has completed. | |
602 | * @max_link_rate: This parameter specifies the maximum link rate to be | |
603 | * associated with this phy. | |
604 | * @next_state: This parameter specifies the next state for the phy's starting | |
605 | * sub-state machine. | |
606 | * | |
607 | */ | |
89a7301f DW |
608 | static void sci_phy_complete_link_training(struct isci_phy *iphy, |
609 | enum sas_linkrate max_link_rate, | |
610 | u32 next_state) | |
d35bc1bd | 611 | { |
85280955 | 612 | iphy->max_negotiated_speed = max_link_rate; |
d35bc1bd | 613 | |
85280955 | 614 | sci_change_state(&iphy->sm, next_state); |
d35bc1bd DW |
615 | } |
616 | ||
e462116a DW |
617 | static const char *phy_event_name(u32 event_code) |
618 | { | |
619 | switch (scu_get_event_code(event_code)) { | |
620 | case SCU_EVENT_PORT_SELECTOR_DETECTED: | |
621 | return "port selector"; | |
622 | case SCU_EVENT_SENT_PORT_SELECTION: | |
623 | return "port selection"; | |
624 | case SCU_EVENT_HARD_RESET_TRANSMITTED: | |
625 | return "tx hard reset"; | |
626 | case SCU_EVENT_HARD_RESET_RECEIVED: | |
627 | return "rx hard reset"; | |
628 | case SCU_EVENT_RECEIVED_IDENTIFY_TIMEOUT: | |
629 | return "identify timeout"; | |
630 | case SCU_EVENT_LINK_FAILURE: | |
631 | return "link fail"; | |
632 | case SCU_EVENT_SATA_SPINUP_HOLD: | |
633 | return "sata spinup hold"; | |
634 | case SCU_EVENT_SAS_15_SSC: | |
635 | case SCU_EVENT_SAS_15: | |
636 | return "sas 1.5"; | |
637 | case SCU_EVENT_SAS_30_SSC: | |
638 | case SCU_EVENT_SAS_30: | |
639 | return "sas 3.0"; | |
640 | case SCU_EVENT_SAS_60_SSC: | |
641 | case SCU_EVENT_SAS_60: | |
642 | return "sas 6.0"; | |
643 | case SCU_EVENT_SATA_15_SSC: | |
644 | case SCU_EVENT_SATA_15: | |
645 | return "sata 1.5"; | |
646 | case SCU_EVENT_SATA_30_SSC: | |
647 | case SCU_EVENT_SATA_30: | |
648 | return "sata 3.0"; | |
649 | case SCU_EVENT_SATA_60_SSC: | |
650 | case SCU_EVENT_SATA_60: | |
651 | return "sata 6.0"; | |
652 | case SCU_EVENT_SAS_PHY_DETECTED: | |
653 | return "sas detect"; | |
654 | case SCU_EVENT_SATA_PHY_DETECTED: | |
655 | return "sata detect"; | |
656 | default: | |
657 | return "unknown"; | |
658 | } | |
659 | } | |
660 | ||
661 | #define phy_event_dbg(iphy, state, code) \ | |
662 | dev_dbg(sciphy_to_dev(iphy), "phy-%d:%d: %s event: %s (%x)\n", \ | |
663 | phy_to_host(iphy)->id, iphy->phy_index, \ | |
664 | phy_state_name(state), phy_event_name(code), code) | |
665 | ||
666 | #define phy_event_warn(iphy, state, code) \ | |
667 | dev_warn(sciphy_to_dev(iphy), "phy-%d:%d: %s event: %s (%x)\n", \ | |
668 | phy_to_host(iphy)->id, iphy->phy_index, \ | |
669 | phy_state_name(state), phy_event_name(code), code) | |
670 | ||
6119908f AJ |
671 | |
672 | void scu_link_layer_set_txcomsas_timeout(struct isci_phy *iphy, u32 timeout) | |
673 | { | |
674 | u32 val; | |
675 | ||
676 | /* Extend timeout */ | |
677 | val = readl(&iphy->link_layer_registers->transmit_comsas_signal); | |
678 | val &= ~SCU_SAS_LLTXCOMSAS_GEN_VAL(NEGTIME, SCU_SAS_LINK_LAYER_TXCOMSAS_NEGTIME_MASK); | |
679 | val |= SCU_SAS_LLTXCOMSAS_GEN_VAL(NEGTIME, timeout); | |
680 | ||
681 | writel(val, &iphy->link_layer_registers->transmit_comsas_signal); | |
682 | } | |
683 | ||
89a7301f | 684 | enum sci_status sci_phy_event_handler(struct isci_phy *iphy, u32 event_code) |
4a33c525 | 685 | { |
89a7301f | 686 | enum sci_phy_states state = iphy->sm.current_state_id; |
4a33c525 | 687 | |
23506a69 | 688 | switch (state) { |
e301370a | 689 | case SCI_PHY_SUB_AWAIT_OSSP_EN: |
23506a69 DW |
690 | switch (scu_get_event_code(event_code)) { |
691 | case SCU_EVENT_SAS_PHY_DETECTED: | |
89a7301f | 692 | sci_phy_start_sas_link_training(iphy); |
85280955 | 693 | iphy->is_in_link_training = true; |
23506a69 DW |
694 | break; |
695 | case SCU_EVENT_SATA_SPINUP_HOLD: | |
89a7301f | 696 | sci_phy_start_sata_link_training(iphy); |
85280955 | 697 | iphy->is_in_link_training = true; |
23506a69 | 698 | break; |
6119908f AJ |
699 | case SCU_EVENT_RECEIVED_IDENTIFY_TIMEOUT: |
700 | /* Extend timeout value */ | |
701 | scu_link_layer_set_txcomsas_timeout(iphy, SCU_SAS_LINK_LAYER_TXCOMSAS_NEGTIME_EXTENDED); | |
702 | ||
703 | /* Start the oob/sn state machine over again */ | |
704 | sci_change_state(&iphy->sm, SCI_PHY_STARTING); | |
705 | break; | |
23506a69 | 706 | default: |
e462116a | 707 | phy_event_dbg(iphy, state, event_code); |
23506a69 DW |
708 | return SCI_FAILURE; |
709 | } | |
710 | return SCI_SUCCESS; | |
e301370a | 711 | case SCI_PHY_SUB_AWAIT_SAS_SPEED_EN: |
23506a69 DW |
712 | switch (scu_get_event_code(event_code)) { |
713 | case SCU_EVENT_SAS_PHY_DETECTED: | |
714 | /* | |
715 | * Why is this being reported again by the controller? | |
716 | * We would re-enter this state so just stay here */ | |
717 | break; | |
718 | case SCU_EVENT_SAS_15: | |
719 | case SCU_EVENT_SAS_15_SSC: | |
89a7301f DW |
720 | sci_phy_complete_link_training(iphy, SAS_LINK_RATE_1_5_GBPS, |
721 | SCI_PHY_SUB_AWAIT_IAF_UF); | |
23506a69 DW |
722 | break; |
723 | case SCU_EVENT_SAS_30: | |
724 | case SCU_EVENT_SAS_30_SSC: | |
89a7301f DW |
725 | sci_phy_complete_link_training(iphy, SAS_LINK_RATE_3_0_GBPS, |
726 | SCI_PHY_SUB_AWAIT_IAF_UF); | |
23506a69 DW |
727 | break; |
728 | case SCU_EVENT_SAS_60: | |
729 | case SCU_EVENT_SAS_60_SSC: | |
89a7301f DW |
730 | sci_phy_complete_link_training(iphy, SAS_LINK_RATE_6_0_GBPS, |
731 | SCI_PHY_SUB_AWAIT_IAF_UF); | |
23506a69 DW |
732 | break; |
733 | case SCU_EVENT_SATA_SPINUP_HOLD: | |
734 | /* | |
735 | * We were doing SAS PHY link training and received a SATA PHY event | |
736 | * continue OOB/SN as if this were a SATA PHY */ | |
89a7301f | 737 | sci_phy_start_sata_link_training(iphy); |
23506a69 DW |
738 | break; |
739 | case SCU_EVENT_LINK_FAILURE: | |
6119908f AJ |
740 | /* Change the timeout value to default */ |
741 | scu_link_layer_set_txcomsas_timeout(iphy, SCU_SAS_LINK_LAYER_TXCOMSAS_NEGTIME_DEFAULT); | |
742 | ||
23506a69 | 743 | /* Link failure change state back to the starting state */ |
85280955 | 744 | sci_change_state(&iphy->sm, SCI_PHY_STARTING); |
23506a69 | 745 | break; |
6119908f AJ |
746 | case SCU_EVENT_RECEIVED_IDENTIFY_TIMEOUT: |
747 | /* Extend the timeout value */ | |
748 | scu_link_layer_set_txcomsas_timeout(iphy, SCU_SAS_LINK_LAYER_TXCOMSAS_NEGTIME_EXTENDED); | |
749 | ||
750 | /* Start the oob/sn state machine over again */ | |
751 | sci_change_state(&iphy->sm, SCI_PHY_STARTING); | |
752 | break; | |
23506a69 | 753 | default: |
e462116a | 754 | phy_event_warn(iphy, state, event_code); |
23506a69 DW |
755 | return SCI_FAILURE; |
756 | break; | |
757 | } | |
758 | return SCI_SUCCESS; | |
e301370a | 759 | case SCI_PHY_SUB_AWAIT_IAF_UF: |
23506a69 DW |
760 | switch (scu_get_event_code(event_code)) { |
761 | case SCU_EVENT_SAS_PHY_DETECTED: | |
762 | /* Backup the state machine */ | |
89a7301f | 763 | sci_phy_start_sas_link_training(iphy); |
23506a69 DW |
764 | break; |
765 | case SCU_EVENT_SATA_SPINUP_HOLD: | |
766 | /* We were doing SAS PHY link training and received a | |
767 | * SATA PHY event continue OOB/SN as if this were a | |
768 | * SATA PHY | |
769 | */ | |
89a7301f | 770 | sci_phy_start_sata_link_training(iphy); |
23506a69 DW |
771 | break; |
772 | case SCU_EVENT_RECEIVED_IDENTIFY_TIMEOUT: | |
6119908f AJ |
773 | /* Extend the timeout value */ |
774 | scu_link_layer_set_txcomsas_timeout(iphy, SCU_SAS_LINK_LAYER_TXCOMSAS_NEGTIME_EXTENDED); | |
775 | ||
776 | /* Start the oob/sn state machine over again */ | |
777 | sci_change_state(&iphy->sm, SCI_PHY_STARTING); | |
778 | break; | |
23506a69 | 779 | case SCU_EVENT_LINK_FAILURE: |
6119908f | 780 | scu_link_layer_set_txcomsas_timeout(iphy, SCU_SAS_LINK_LAYER_TXCOMSAS_NEGTIME_DEFAULT); |
23506a69 DW |
781 | case SCU_EVENT_HARD_RESET_RECEIVED: |
782 | /* Start the oob/sn state machine over again */ | |
85280955 | 783 | sci_change_state(&iphy->sm, SCI_PHY_STARTING); |
23506a69 DW |
784 | break; |
785 | default: | |
e462116a | 786 | phy_event_warn(iphy, state, event_code); |
23506a69 DW |
787 | return SCI_FAILURE; |
788 | } | |
789 | return SCI_SUCCESS; | |
e301370a | 790 | case SCI_PHY_SUB_AWAIT_SAS_POWER: |
23506a69 DW |
791 | switch (scu_get_event_code(event_code)) { |
792 | case SCU_EVENT_LINK_FAILURE: | |
6119908f AJ |
793 | /* Change the timeout value to default */ |
794 | scu_link_layer_set_txcomsas_timeout(iphy, SCU_SAS_LINK_LAYER_TXCOMSAS_NEGTIME_DEFAULT); | |
795 | ||
23506a69 | 796 | /* Link failure change state back to the starting state */ |
85280955 | 797 | sci_change_state(&iphy->sm, SCI_PHY_STARTING); |
23506a69 DW |
798 | break; |
799 | default: | |
e462116a | 800 | phy_event_warn(iphy, state, event_code); |
23506a69 DW |
801 | return SCI_FAILURE; |
802 | } | |
803 | return SCI_SUCCESS; | |
e301370a | 804 | case SCI_PHY_SUB_AWAIT_SATA_POWER: |
23506a69 DW |
805 | switch (scu_get_event_code(event_code)) { |
806 | case SCU_EVENT_LINK_FAILURE: | |
6119908f AJ |
807 | /* Change the timeout value to default */ |
808 | scu_link_layer_set_txcomsas_timeout(iphy, SCU_SAS_LINK_LAYER_TXCOMSAS_NEGTIME_DEFAULT); | |
809 | ||
23506a69 | 810 | /* Link failure change state back to the starting state */ |
85280955 | 811 | sci_change_state(&iphy->sm, SCI_PHY_STARTING); |
23506a69 DW |
812 | break; |
813 | case SCU_EVENT_SATA_SPINUP_HOLD: | |
814 | /* These events are received every 10ms and are | |
815 | * expected while in this state | |
816 | */ | |
817 | break; | |
818 | ||
819 | case SCU_EVENT_SAS_PHY_DETECTED: | |
820 | /* There has been a change in the phy type before OOB/SN for the | |
821 | * SATA finished start down the SAS link traning path. | |
822 | */ | |
89a7301f | 823 | sci_phy_start_sas_link_training(iphy); |
23506a69 DW |
824 | break; |
825 | ||
826 | default: | |
e462116a | 827 | phy_event_warn(iphy, state, event_code); |
23506a69 DW |
828 | return SCI_FAILURE; |
829 | } | |
830 | return SCI_SUCCESS; | |
e301370a | 831 | case SCI_PHY_SUB_AWAIT_SATA_PHY_EN: |
23506a69 DW |
832 | switch (scu_get_event_code(event_code)) { |
833 | case SCU_EVENT_LINK_FAILURE: | |
6119908f AJ |
834 | /* Change the timeout value to default */ |
835 | scu_link_layer_set_txcomsas_timeout(iphy, SCU_SAS_LINK_LAYER_TXCOMSAS_NEGTIME_DEFAULT); | |
836 | ||
23506a69 | 837 | /* Link failure change state back to the starting state */ |
85280955 | 838 | sci_change_state(&iphy->sm, SCI_PHY_STARTING); |
23506a69 DW |
839 | break; |
840 | case SCU_EVENT_SATA_SPINUP_HOLD: | |
841 | /* These events might be received since we dont know how many may be in | |
842 | * the completion queue while waiting for power | |
843 | */ | |
844 | break; | |
845 | case SCU_EVENT_SATA_PHY_DETECTED: | |
c79dd80d | 846 | iphy->protocol = SAS_PROTOCOL_SATA; |
23506a69 DW |
847 | |
848 | /* We have received the SATA PHY notification change state */ | |
85280955 | 849 | sci_change_state(&iphy->sm, SCI_PHY_SUB_AWAIT_SATA_SPEED_EN); |
23506a69 DW |
850 | break; |
851 | case SCU_EVENT_SAS_PHY_DETECTED: | |
852 | /* There has been a change in the phy type before OOB/SN for the | |
853 | * SATA finished start down the SAS link traning path. | |
854 | */ | |
89a7301f | 855 | sci_phy_start_sas_link_training(iphy); |
23506a69 DW |
856 | break; |
857 | default: | |
e462116a | 858 | phy_event_warn(iphy, state, event_code); |
69932487 | 859 | return SCI_FAILURE; |
23506a69 DW |
860 | } |
861 | return SCI_SUCCESS; | |
e301370a | 862 | case SCI_PHY_SUB_AWAIT_SATA_SPEED_EN: |
23506a69 DW |
863 | switch (scu_get_event_code(event_code)) { |
864 | case SCU_EVENT_SATA_PHY_DETECTED: | |
865 | /* | |
866 | * The hardware reports multiple SATA PHY detected events | |
867 | * ignore the extras */ | |
868 | break; | |
869 | case SCU_EVENT_SATA_15: | |
870 | case SCU_EVENT_SATA_15_SSC: | |
89a7301f DW |
871 | sci_phy_complete_link_training(iphy, SAS_LINK_RATE_1_5_GBPS, |
872 | SCI_PHY_SUB_AWAIT_SIG_FIS_UF); | |
23506a69 DW |
873 | break; |
874 | case SCU_EVENT_SATA_30: | |
875 | case SCU_EVENT_SATA_30_SSC: | |
89a7301f DW |
876 | sci_phy_complete_link_training(iphy, SAS_LINK_RATE_3_0_GBPS, |
877 | SCI_PHY_SUB_AWAIT_SIG_FIS_UF); | |
23506a69 DW |
878 | break; |
879 | case SCU_EVENT_SATA_60: | |
880 | case SCU_EVENT_SATA_60_SSC: | |
89a7301f DW |
881 | sci_phy_complete_link_training(iphy, SAS_LINK_RATE_6_0_GBPS, |
882 | SCI_PHY_SUB_AWAIT_SIG_FIS_UF); | |
23506a69 DW |
883 | break; |
884 | case SCU_EVENT_LINK_FAILURE: | |
6119908f AJ |
885 | /* Change the timeout value to default */ |
886 | scu_link_layer_set_txcomsas_timeout(iphy, SCU_SAS_LINK_LAYER_TXCOMSAS_NEGTIME_DEFAULT); | |
887 | ||
23506a69 | 888 | /* Link failure change state back to the starting state */ |
85280955 | 889 | sci_change_state(&iphy->sm, SCI_PHY_STARTING); |
23506a69 DW |
890 | break; |
891 | case SCU_EVENT_SAS_PHY_DETECTED: | |
892 | /* | |
893 | * There has been a change in the phy type before OOB/SN for the | |
894 | * SATA finished start down the SAS link traning path. */ | |
89a7301f | 895 | sci_phy_start_sas_link_training(iphy); |
23506a69 DW |
896 | break; |
897 | default: | |
e462116a | 898 | phy_event_warn(iphy, state, event_code); |
23506a69 DW |
899 | return SCI_FAILURE; |
900 | } | |
901 | ||
902 | return SCI_SUCCESS; | |
e301370a | 903 | case SCI_PHY_SUB_AWAIT_SIG_FIS_UF: |
23506a69 DW |
904 | switch (scu_get_event_code(event_code)) { |
905 | case SCU_EVENT_SATA_PHY_DETECTED: | |
906 | /* Backup the state machine */ | |
85280955 | 907 | sci_change_state(&iphy->sm, SCI_PHY_SUB_AWAIT_SATA_SPEED_EN); |
23506a69 | 908 | break; |
4a33c525 | 909 | |
23506a69 | 910 | case SCU_EVENT_LINK_FAILURE: |
6119908f AJ |
911 | /* Change the timeout value to default */ |
912 | scu_link_layer_set_txcomsas_timeout(iphy, SCU_SAS_LINK_LAYER_TXCOMSAS_NEGTIME_DEFAULT); | |
913 | ||
23506a69 | 914 | /* Link failure change state back to the starting state */ |
85280955 | 915 | sci_change_state(&iphy->sm, SCI_PHY_STARTING); |
23506a69 DW |
916 | break; |
917 | ||
918 | default: | |
e462116a | 919 | phy_event_warn(iphy, state, event_code); |
23506a69 DW |
920 | return SCI_FAILURE; |
921 | } | |
922 | return SCI_SUCCESS; | |
e301370a | 923 | case SCI_PHY_READY: |
23506a69 DW |
924 | switch (scu_get_event_code(event_code)) { |
925 | case SCU_EVENT_LINK_FAILURE: | |
6119908f AJ |
926 | /* Set default timeout */ |
927 | scu_link_layer_set_txcomsas_timeout(iphy, SCU_SAS_LINK_LAYER_TXCOMSAS_NEGTIME_DEFAULT); | |
928 | ||
23506a69 | 929 | /* Link failure change state back to the starting state */ |
85280955 | 930 | sci_change_state(&iphy->sm, SCI_PHY_STARTING); |
23506a69 DW |
931 | break; |
932 | case SCU_EVENT_BROADCAST_CHANGE: | |
944b787d TJ |
933 | case SCU_EVENT_BROADCAST_SES: |
934 | case SCU_EVENT_BROADCAST_RESERVED0: | |
935 | case SCU_EVENT_BROADCAST_RESERVED1: | |
936 | case SCU_EVENT_BROADCAST_EXPANDER: | |
937 | case SCU_EVENT_BROADCAST_AEN: | |
23506a69 | 938 | /* Broadcast change received. Notify the port. */ |
85280955 | 939 | if (phy_get_non_dummy_port(iphy) != NULL) |
89a7301f | 940 | sci_port_broadcast_change_received(iphy->owning_port, iphy); |
23506a69 | 941 | else |
85280955 | 942 | iphy->bcn_received_while_port_unassigned = true; |
23506a69 | 943 | break; |
944b787d TJ |
944 | case SCU_EVENT_BROADCAST_RESERVED3: |
945 | case SCU_EVENT_BROADCAST_RESERVED4: | |
23506a69 | 946 | default: |
e462116a | 947 | phy_event_warn(iphy, state, event_code); |
23506a69 DW |
948 | return SCI_FAILURE_INVALID_STATE; |
949 | } | |
950 | return SCI_SUCCESS; | |
e301370a | 951 | case SCI_PHY_RESETTING: |
23506a69 DW |
952 | switch (scu_get_event_code(event_code)) { |
953 | case SCU_EVENT_HARD_RESET_TRANSMITTED: | |
954 | /* Link failure change state back to the starting state */ | |
85280955 | 955 | sci_change_state(&iphy->sm, SCI_PHY_STARTING); |
23506a69 DW |
956 | break; |
957 | default: | |
e462116a | 958 | phy_event_warn(iphy, state, event_code); |
23506a69 DW |
959 | return SCI_FAILURE_INVALID_STATE; |
960 | break; | |
961 | } | |
962 | return SCI_SUCCESS; | |
963 | default: | |
d7a0ccdd DW |
964 | dev_dbg(sciphy_to_dev(iphy), "%s: in wrong state: %s\n", |
965 | __func__, phy_state_name(state)); | |
23506a69 DW |
966 | return SCI_FAILURE_INVALID_STATE; |
967 | } | |
4a33c525 AG |
968 | } |
969 | ||
89a7301f | 970 | enum sci_status sci_phy_frame_handler(struct isci_phy *iphy, u32 frame_index) |
4a33c525 | 971 | { |
89a7301f | 972 | enum sci_phy_states state = iphy->sm.current_state_id; |
d9dcb4ba | 973 | struct isci_host *ihost = iphy->owning_port->owning_controller; |
23506a69 | 974 | enum sci_status result; |
4cffe13e | 975 | unsigned long flags; |
4a33c525 | 976 | |
23506a69 | 977 | switch (state) { |
e301370a | 978 | case SCI_PHY_SUB_AWAIT_IAF_UF: { |
23506a69 DW |
979 | u32 *frame_words; |
980 | struct sas_identify_frame iaf; | |
4a33c525 | 981 | |
89a7301f DW |
982 | result = sci_unsolicited_frame_control_get_header(&ihost->uf_control, |
983 | frame_index, | |
984 | (void **)&frame_words); | |
4a33c525 | 985 | |
23506a69 DW |
986 | if (result != SCI_SUCCESS) |
987 | return result; | |
988 | ||
989 | sci_swab32_cpy(&iaf, frame_words, sizeof(iaf) / sizeof(u32)); | |
990 | if (iaf.frame_type == 0) { | |
991 | u32 state; | |
992 | ||
4cffe13e | 993 | spin_lock_irqsave(&iphy->sas_phy.frame_rcvd_lock, flags); |
23506a69 | 994 | memcpy(&iphy->frame_rcvd.iaf, &iaf, sizeof(iaf)); |
4cffe13e | 995 | spin_unlock_irqrestore(&iphy->sas_phy.frame_rcvd_lock, flags); |
23506a69 DW |
996 | if (iaf.smp_tport) { |
997 | /* We got the IAF for an expander PHY go to the final | |
998 | * state since there are no power requirements for | |
999 | * expander phys. | |
1000 | */ | |
e301370a | 1001 | state = SCI_PHY_SUB_FINAL; |
23506a69 DW |
1002 | } else { |
1003 | /* We got the IAF we can now go to the await spinup | |
1004 | * semaphore state | |
1005 | */ | |
e301370a | 1006 | state = SCI_PHY_SUB_AWAIT_SAS_POWER; |
23506a69 | 1007 | } |
85280955 | 1008 | sci_change_state(&iphy->sm, state); |
23506a69 DW |
1009 | result = SCI_SUCCESS; |
1010 | } else | |
85280955 | 1011 | dev_warn(sciphy_to_dev(iphy), |
23506a69 DW |
1012 | "%s: PHY starting substate machine received " |
1013 | "unexpected frame id %x\n", | |
1014 | __func__, frame_index); | |
1015 | ||
89a7301f | 1016 | sci_controller_release_frame(ihost, frame_index); |
23506a69 | 1017 | return result; |
4a33c525 | 1018 | } |
e301370a | 1019 | case SCI_PHY_SUB_AWAIT_SIG_FIS_UF: { |
23506a69 DW |
1020 | struct dev_to_host_fis *frame_header; |
1021 | u32 *fis_frame_data; | |
23506a69 | 1022 | |
34a99158 DW |
1023 | result = sci_unsolicited_frame_control_get_header(&ihost->uf_control, |
1024 | frame_index, | |
1025 | (void **)&frame_header); | |
23506a69 DW |
1026 | |
1027 | if (result != SCI_SUCCESS) | |
1028 | return result; | |
4a33c525 | 1029 | |
23506a69 DW |
1030 | if ((frame_header->fis_type == FIS_REGD2H) && |
1031 | !(frame_header->status & ATA_BUSY)) { | |
89a7301f DW |
1032 | sci_unsolicited_frame_control_get_buffer(&ihost->uf_control, |
1033 | frame_index, | |
1034 | (void **)&fis_frame_data); | |
23506a69 | 1035 | |
4cffe13e | 1036 | spin_lock_irqsave(&iphy->sas_phy.frame_rcvd_lock, flags); |
89a7301f DW |
1037 | sci_controller_copy_sata_response(&iphy->frame_rcvd.fis, |
1038 | frame_header, | |
1039 | fis_frame_data); | |
4cffe13e | 1040 | spin_unlock_irqrestore(&iphy->sas_phy.frame_rcvd_lock, flags); |
23506a69 DW |
1041 | |
1042 | /* got IAF we can now go to the await spinup semaphore state */ | |
85280955 | 1043 | sci_change_state(&iphy->sm, SCI_PHY_SUB_FINAL); |
23506a69 DW |
1044 | |
1045 | result = SCI_SUCCESS; | |
1046 | } else | |
85280955 | 1047 | dev_warn(sciphy_to_dev(iphy), |
23506a69 DW |
1048 | "%s: PHY starting substate machine received " |
1049 | "unexpected frame id %x\n", | |
1050 | __func__, frame_index); | |
1051 | ||
1052 | /* Regardless of the result we are done with this frame with it */ | |
89a7301f | 1053 | sci_controller_release_frame(ihost, frame_index); |
23506a69 DW |
1054 | |
1055 | return result; | |
1056 | } | |
1057 | default: | |
d7a0ccdd DW |
1058 | dev_dbg(sciphy_to_dev(iphy), "%s: in wrong state: %s\n", |
1059 | __func__, phy_state_name(state)); | |
23506a69 DW |
1060 | return SCI_FAILURE_INVALID_STATE; |
1061 | } | |
5076a1a9 | 1062 | |
4a33c525 AG |
1063 | } |
1064 | ||
89a7301f | 1065 | static void sci_phy_starting_initial_substate_enter(struct sci_base_state_machine *sm) |
d35bc1bd | 1066 | { |
85280955 | 1067 | struct isci_phy *iphy = container_of(sm, typeof(*iphy), sm); |
d35bc1bd | 1068 | |
d35bc1bd | 1069 | /* This is just an temporary state go off to the starting state */ |
85280955 | 1070 | sci_change_state(&iphy->sm, SCI_PHY_SUB_AWAIT_OSSP_EN); |
d35bc1bd DW |
1071 | } |
1072 | ||
89a7301f | 1073 | static void sci_phy_starting_await_sas_power_substate_enter(struct sci_base_state_machine *sm) |
d35bc1bd | 1074 | { |
85280955 | 1075 | struct isci_phy *iphy = container_of(sm, typeof(*iphy), sm); |
d9dcb4ba | 1076 | struct isci_host *ihost = iphy->owning_port->owning_controller; |
d35bc1bd | 1077 | |
89a7301f | 1078 | sci_controller_power_control_queue_insert(ihost, iphy); |
d35bc1bd DW |
1079 | } |
1080 | ||
89a7301f | 1081 | static void sci_phy_starting_await_sas_power_substate_exit(struct sci_base_state_machine *sm) |
d35bc1bd | 1082 | { |
85280955 | 1083 | struct isci_phy *iphy = container_of(sm, typeof(*iphy), sm); |
d9dcb4ba | 1084 | struct isci_host *ihost = iphy->owning_port->owning_controller; |
d35bc1bd | 1085 | |
89a7301f | 1086 | sci_controller_power_control_queue_remove(ihost, iphy); |
d35bc1bd DW |
1087 | } |
1088 | ||
89a7301f | 1089 | static void sci_phy_starting_await_sata_power_substate_enter(struct sci_base_state_machine *sm) |
d35bc1bd | 1090 | { |
85280955 | 1091 | struct isci_phy *iphy = container_of(sm, typeof(*iphy), sm); |
d9dcb4ba | 1092 | struct isci_host *ihost = iphy->owning_port->owning_controller; |
d35bc1bd | 1093 | |
89a7301f | 1094 | sci_controller_power_control_queue_insert(ihost, iphy); |
d35bc1bd DW |
1095 | } |
1096 | ||
89a7301f | 1097 | static void sci_phy_starting_await_sata_power_substate_exit(struct sci_base_state_machine *sm) |
d35bc1bd | 1098 | { |
85280955 | 1099 | struct isci_phy *iphy = container_of(sm, typeof(*iphy), sm); |
d9dcb4ba | 1100 | struct isci_host *ihost = iphy->owning_port->owning_controller; |
d35bc1bd | 1101 | |
89a7301f | 1102 | sci_controller_power_control_queue_remove(ihost, iphy); |
d35bc1bd DW |
1103 | } |
1104 | ||
89a7301f | 1105 | static void sci_phy_starting_await_sata_phy_substate_enter(struct sci_base_state_machine *sm) |
d35bc1bd | 1106 | { |
85280955 | 1107 | struct isci_phy *iphy = container_of(sm, typeof(*iphy), sm); |
d35bc1bd | 1108 | |
85280955 | 1109 | sci_mod_timer(&iphy->sata_timer, SCIC_SDS_SATA_LINK_TRAINING_TIMEOUT); |
d35bc1bd DW |
1110 | } |
1111 | ||
89a7301f | 1112 | static void sci_phy_starting_await_sata_phy_substate_exit(struct sci_base_state_machine *sm) |
d35bc1bd | 1113 | { |
85280955 | 1114 | struct isci_phy *iphy = container_of(sm, typeof(*iphy), sm); |
d35bc1bd | 1115 | |
85280955 | 1116 | sci_del_timer(&iphy->sata_timer); |
d35bc1bd DW |
1117 | } |
1118 | ||
89a7301f | 1119 | static void sci_phy_starting_await_sata_speed_substate_enter(struct sci_base_state_machine *sm) |
d35bc1bd | 1120 | { |
85280955 | 1121 | struct isci_phy *iphy = container_of(sm, typeof(*iphy), sm); |
d35bc1bd | 1122 | |
85280955 | 1123 | sci_mod_timer(&iphy->sata_timer, SCIC_SDS_SATA_LINK_TRAINING_TIMEOUT); |
d35bc1bd DW |
1124 | } |
1125 | ||
89a7301f | 1126 | static void sci_phy_starting_await_sata_speed_substate_exit(struct sci_base_state_machine *sm) |
d35bc1bd | 1127 | { |
85280955 | 1128 | struct isci_phy *iphy = container_of(sm, typeof(*iphy), sm); |
d35bc1bd | 1129 | |
85280955 | 1130 | sci_del_timer(&iphy->sata_timer); |
d35bc1bd DW |
1131 | } |
1132 | ||
89a7301f | 1133 | static void sci_phy_starting_await_sig_fis_uf_substate_enter(struct sci_base_state_machine *sm) |
d35bc1bd | 1134 | { |
85280955 | 1135 | struct isci_phy *iphy = container_of(sm, typeof(*iphy), sm); |
d35bc1bd | 1136 | |
89a7301f | 1137 | if (sci_port_link_detected(iphy->owning_port, iphy)) { |
d35bc1bd | 1138 | |
d35bc1bd DW |
1139 | /* |
1140 | * Clear the PE suspend condition so we can actually | |
1141 | * receive SIG FIS | |
1142 | * The hardware will not respond to the XRDY until the PE | |
1143 | * suspend condition is cleared. | |
1144 | */ | |
89a7301f | 1145 | sci_phy_resume(iphy); |
d35bc1bd | 1146 | |
85280955 | 1147 | sci_mod_timer(&iphy->sata_timer, |
a628d478 | 1148 | SCIC_SDS_SIGNATURE_FIS_TIMEOUT); |
d35bc1bd | 1149 | } else |
85280955 | 1150 | iphy->is_in_link_training = false; |
d35bc1bd DW |
1151 | } |
1152 | ||
89a7301f | 1153 | static void sci_phy_starting_await_sig_fis_uf_substate_exit(struct sci_base_state_machine *sm) |
d35bc1bd | 1154 | { |
85280955 | 1155 | struct isci_phy *iphy = container_of(sm, typeof(*iphy), sm); |
d35bc1bd | 1156 | |
85280955 | 1157 | sci_del_timer(&iphy->sata_timer); |
d35bc1bd DW |
1158 | } |
1159 | ||
89a7301f | 1160 | static void sci_phy_starting_final_substate_enter(struct sci_base_state_machine *sm) |
d35bc1bd | 1161 | { |
85280955 | 1162 | struct isci_phy *iphy = container_of(sm, typeof(*iphy), sm); |
d35bc1bd | 1163 | |
d35bc1bd DW |
1164 | /* State machine has run to completion so exit out and change |
1165 | * the base state machine to the ready state | |
1166 | */ | |
85280955 | 1167 | sci_change_state(&iphy->sm, SCI_PHY_READY); |
d35bc1bd DW |
1168 | } |
1169 | ||
d35bc1bd DW |
1170 | /** |
1171 | * | |
85280955 | 1172 | * @sci_phy: This is the struct isci_phy object to stop. |
d35bc1bd | 1173 | * |
85280955 | 1174 | * This method will stop the struct isci_phy object. This does not reset the |
d35bc1bd DW |
1175 | * protocol engine it just suspends it and places it in a state where it will |
1176 | * not cause the end device to power up. none | |
1177 | */ | |
1178 | static void scu_link_layer_stop_protocol_engine( | |
85280955 | 1179 | struct isci_phy *iphy) |
d35bc1bd DW |
1180 | { |
1181 | u32 scu_sas_pcfg_value; | |
1182 | u32 enable_spinup_value; | |
1183 | ||
1184 | /* Suspend the protocol engine and place it in a sata spinup hold state */ | |
1185 | scu_sas_pcfg_value = | |
85280955 | 1186 | readl(&iphy->link_layer_registers->phy_configuration); |
d35bc1bd DW |
1187 | scu_sas_pcfg_value |= |
1188 | (SCU_SAS_PCFG_GEN_BIT(OOB_RESET) | | |
1189 | SCU_SAS_PCFG_GEN_BIT(SUSPEND_PROTOCOL_ENGINE) | | |
1190 | SCU_SAS_PCFG_GEN_BIT(SATA_SPINUP_HOLD)); | |
1191 | writel(scu_sas_pcfg_value, | |
85280955 | 1192 | &iphy->link_layer_registers->phy_configuration); |
d35bc1bd DW |
1193 | |
1194 | /* Disable the notify enable spinup primitives */ | |
85280955 | 1195 | enable_spinup_value = readl(&iphy->link_layer_registers->notify_enable_spinup_control); |
d35bc1bd | 1196 | enable_spinup_value &= ~SCU_ENSPINUP_GEN_BIT(ENABLE); |
85280955 | 1197 | writel(enable_spinup_value, &iphy->link_layer_registers->notify_enable_spinup_control); |
d35bc1bd DW |
1198 | } |
1199 | ||
0953dbea | 1200 | static void scu_link_layer_start_oob(struct isci_phy *iphy) |
d35bc1bd | 1201 | { |
0953dbea MT |
1202 | struct scu_link_layer_registers __iomem *ll = iphy->link_layer_registers; |
1203 | u32 val; | |
1204 | ||
1205 | /** Reset OOB sequence - start */ | |
1206 | val = readl(&ll->phy_configuration); | |
1207 | val &= ~(SCU_SAS_PCFG_GEN_BIT(OOB_RESET) | | |
a9003756 | 1208 | SCU_SAS_PCFG_GEN_BIT(OOB_ENABLE) | |
0953dbea MT |
1209 | SCU_SAS_PCFG_GEN_BIT(HARD_RESET)); |
1210 | writel(val, &ll->phy_configuration); | |
1211 | readl(&ll->phy_configuration); /* flush */ | |
1212 | /** Reset OOB sequence - end */ | |
1213 | ||
1214 | /** Start OOB sequence - start */ | |
1215 | val = readl(&ll->phy_configuration); | |
1216 | val |= SCU_SAS_PCFG_GEN_BIT(OOB_ENABLE); | |
1217 | writel(val, &ll->phy_configuration); | |
1218 | readl(&ll->phy_configuration); /* flush */ | |
1219 | /** Start OOB sequence - end */ | |
d35bc1bd DW |
1220 | } |
1221 | ||
1222 | /** | |
1223 | * | |
1224 | * | |
1225 | * This method will transmit a hard reset request on the specified phy. The SCU | |
1226 | * hardware requires that we reset the OOB state machine and set the hard reset | |
1227 | * bit in the phy configuration register. We then must start OOB over with the | |
1228 | * hard reset bit set. | |
1229 | */ | |
1230 | static void scu_link_layer_tx_hard_reset( | |
85280955 | 1231 | struct isci_phy *iphy) |
d35bc1bd DW |
1232 | { |
1233 | u32 phy_configuration_value; | |
1234 | ||
1235 | /* | |
1236 | * SAS Phys must wait for the HARD_RESET_TX event notification to transition | |
1237 | * to the starting state. */ | |
1238 | phy_configuration_value = | |
85280955 | 1239 | readl(&iphy->link_layer_registers->phy_configuration); |
a9003756 | 1240 | phy_configuration_value &= ~(SCU_SAS_PCFG_GEN_BIT(OOB_ENABLE)); |
d35bc1bd DW |
1241 | phy_configuration_value |= |
1242 | (SCU_SAS_PCFG_GEN_BIT(HARD_RESET) | | |
1243 | SCU_SAS_PCFG_GEN_BIT(OOB_RESET)); | |
1244 | writel(phy_configuration_value, | |
85280955 | 1245 | &iphy->link_layer_registers->phy_configuration); |
d35bc1bd DW |
1246 | |
1247 | /* Now take the OOB state machine out of reset */ | |
1248 | phy_configuration_value |= SCU_SAS_PCFG_GEN_BIT(OOB_ENABLE); | |
1249 | phy_configuration_value &= ~SCU_SAS_PCFG_GEN_BIT(OOB_RESET); | |
1250 | writel(phy_configuration_value, | |
85280955 | 1251 | &iphy->link_layer_registers->phy_configuration); |
d35bc1bd DW |
1252 | } |
1253 | ||
89a7301f | 1254 | static void sci_phy_stopped_state_enter(struct sci_base_state_machine *sm) |
d35bc1bd | 1255 | { |
85280955 | 1256 | struct isci_phy *iphy = container_of(sm, typeof(*iphy), sm); |
34a99158 DW |
1257 | struct isci_port *iport = iphy->owning_port; |
1258 | struct isci_host *ihost = iport->owning_controller; | |
d35bc1bd DW |
1259 | |
1260 | /* | |
1261 | * @todo We need to get to the controller to place this PE in a | |
1262 | * reset state | |
1263 | */ | |
85280955 | 1264 | sci_del_timer(&iphy->sata_timer); |
d35bc1bd | 1265 | |
85280955 | 1266 | scu_link_layer_stop_protocol_engine(iphy); |
d35bc1bd | 1267 | |
85280955 | 1268 | if (iphy->sm.previous_state_id != SCI_PHY_INITIAL) |
34a99158 | 1269 | sci_controller_link_down(ihost, phy_get_non_dummy_port(iphy), iphy); |
d35bc1bd DW |
1270 | } |
1271 | ||
89a7301f | 1272 | static void sci_phy_starting_state_enter(struct sci_base_state_machine *sm) |
d35bc1bd | 1273 | { |
85280955 | 1274 | struct isci_phy *iphy = container_of(sm, typeof(*iphy), sm); |
34a99158 DW |
1275 | struct isci_port *iport = iphy->owning_port; |
1276 | struct isci_host *ihost = iport->owning_controller; | |
d35bc1bd | 1277 | |
85280955 DW |
1278 | scu_link_layer_stop_protocol_engine(iphy); |
1279 | scu_link_layer_start_oob(iphy); | |
d35bc1bd DW |
1280 | |
1281 | /* We don't know what kind of phy we are going to be just yet */ | |
c79dd80d | 1282 | iphy->protocol = SAS_PROTOCOL_NONE; |
85280955 | 1283 | iphy->bcn_received_while_port_unassigned = false; |
d35bc1bd | 1284 | |
85280955 | 1285 | if (iphy->sm.previous_state_id == SCI_PHY_READY) |
34a99158 | 1286 | sci_controller_link_down(ihost, phy_get_non_dummy_port(iphy), iphy); |
4a33c525 | 1287 | |
85280955 | 1288 | sci_change_state(&iphy->sm, SCI_PHY_SUB_INITIAL); |
d35bc1bd DW |
1289 | } |
1290 | ||
89a7301f | 1291 | static void sci_phy_ready_state_enter(struct sci_base_state_machine *sm) |
d35bc1bd | 1292 | { |
85280955 | 1293 | struct isci_phy *iphy = container_of(sm, typeof(*iphy), sm); |
34a99158 DW |
1294 | struct isci_port *iport = iphy->owning_port; |
1295 | struct isci_host *ihost = iport->owning_controller; | |
d35bc1bd | 1296 | |
34a99158 | 1297 | sci_controller_link_up(ihost, phy_get_non_dummy_port(iphy), iphy); |
d35bc1bd DW |
1298 | } |
1299 | ||
89a7301f | 1300 | static void sci_phy_ready_state_exit(struct sci_base_state_machine *sm) |
d35bc1bd | 1301 | { |
85280955 | 1302 | struct isci_phy *iphy = container_of(sm, typeof(*iphy), sm); |
d35bc1bd | 1303 | |
89a7301f | 1304 | sci_phy_suspend(iphy); |
d35bc1bd DW |
1305 | } |
1306 | ||
89a7301f | 1307 | static void sci_phy_resetting_state_enter(struct sci_base_state_machine *sm) |
d35bc1bd | 1308 | { |
85280955 | 1309 | struct isci_phy *iphy = container_of(sm, typeof(*iphy), sm); |
d35bc1bd | 1310 | |
5b1d4af2 DW |
1311 | /* The phy is being reset, therefore deactivate it from the port. In |
1312 | * the resetting state we don't notify the user regarding link up and | |
1313 | * link down notifications | |
1314 | */ | |
89a7301f | 1315 | sci_port_deactivate_phy(iphy->owning_port, iphy, false); |
d35bc1bd | 1316 | |
c79dd80d | 1317 | if (iphy->protocol == SAS_PROTOCOL_SSP) { |
85280955 | 1318 | scu_link_layer_tx_hard_reset(iphy); |
d35bc1bd | 1319 | } else { |
5b1d4af2 | 1320 | /* The SCU does not need to have a discrete reset state so |
d35bc1bd DW |
1321 | * just go back to the starting state. |
1322 | */ | |
85280955 | 1323 | sci_change_state(&iphy->sm, SCI_PHY_STARTING); |
d35bc1bd DW |
1324 | } |
1325 | } | |
1326 | ||
89a7301f | 1327 | static const struct sci_base_state sci_phy_state_table[] = { |
e301370a EN |
1328 | [SCI_PHY_INITIAL] = { }, |
1329 | [SCI_PHY_STOPPED] = { | |
89a7301f | 1330 | .enter_state = sci_phy_stopped_state_enter, |
d35bc1bd | 1331 | }, |
e301370a | 1332 | [SCI_PHY_STARTING] = { |
89a7301f | 1333 | .enter_state = sci_phy_starting_state_enter, |
d35bc1bd | 1334 | }, |
e301370a | 1335 | [SCI_PHY_SUB_INITIAL] = { |
89a7301f | 1336 | .enter_state = sci_phy_starting_initial_substate_enter, |
4a33c525 | 1337 | }, |
e301370a EN |
1338 | [SCI_PHY_SUB_AWAIT_OSSP_EN] = { }, |
1339 | [SCI_PHY_SUB_AWAIT_SAS_SPEED_EN] = { }, | |
1340 | [SCI_PHY_SUB_AWAIT_IAF_UF] = { }, | |
1341 | [SCI_PHY_SUB_AWAIT_SAS_POWER] = { | |
89a7301f DW |
1342 | .enter_state = sci_phy_starting_await_sas_power_substate_enter, |
1343 | .exit_state = sci_phy_starting_await_sas_power_substate_exit, | |
4a33c525 | 1344 | }, |
e301370a | 1345 | [SCI_PHY_SUB_AWAIT_SATA_POWER] = { |
89a7301f DW |
1346 | .enter_state = sci_phy_starting_await_sata_power_substate_enter, |
1347 | .exit_state = sci_phy_starting_await_sata_power_substate_exit | |
4a33c525 | 1348 | }, |
e301370a | 1349 | [SCI_PHY_SUB_AWAIT_SATA_PHY_EN] = { |
89a7301f DW |
1350 | .enter_state = sci_phy_starting_await_sata_phy_substate_enter, |
1351 | .exit_state = sci_phy_starting_await_sata_phy_substate_exit | |
4a33c525 | 1352 | }, |
e301370a | 1353 | [SCI_PHY_SUB_AWAIT_SATA_SPEED_EN] = { |
89a7301f DW |
1354 | .enter_state = sci_phy_starting_await_sata_speed_substate_enter, |
1355 | .exit_state = sci_phy_starting_await_sata_speed_substate_exit | |
4a33c525 | 1356 | }, |
e301370a | 1357 | [SCI_PHY_SUB_AWAIT_SIG_FIS_UF] = { |
89a7301f DW |
1358 | .enter_state = sci_phy_starting_await_sig_fis_uf_substate_enter, |
1359 | .exit_state = sci_phy_starting_await_sig_fis_uf_substate_exit | |
4a33c525 | 1360 | }, |
e301370a | 1361 | [SCI_PHY_SUB_FINAL] = { |
89a7301f | 1362 | .enter_state = sci_phy_starting_final_substate_enter, |
4a33c525 | 1363 | }, |
e301370a | 1364 | [SCI_PHY_READY] = { |
89a7301f DW |
1365 | .enter_state = sci_phy_ready_state_enter, |
1366 | .exit_state = sci_phy_ready_state_exit, | |
d35bc1bd | 1367 | }, |
e301370a | 1368 | [SCI_PHY_RESETTING] = { |
89a7301f | 1369 | .enter_state = sci_phy_resetting_state_enter, |
d35bc1bd | 1370 | }, |
e301370a | 1371 | [SCI_PHY_FINAL] = { }, |
d35bc1bd DW |
1372 | }; |
1373 | ||
89a7301f | 1374 | void sci_phy_construct(struct isci_phy *iphy, |
ffe191c9 | 1375 | struct isci_port *iport, u8 phy_index) |
d35bc1bd | 1376 | { |
89a7301f | 1377 | sci_init_sm(&iphy->sm, sci_phy_state_table, SCI_PHY_INITIAL); |
d35bc1bd DW |
1378 | |
1379 | /* Copy the rest of the input data to our locals */ | |
ffe191c9 | 1380 | iphy->owning_port = iport; |
85280955 DW |
1381 | iphy->phy_index = phy_index; |
1382 | iphy->bcn_received_while_port_unassigned = false; | |
c79dd80d | 1383 | iphy->protocol = SAS_PROTOCOL_NONE; |
85280955 DW |
1384 | iphy->link_layer_registers = NULL; |
1385 | iphy->max_negotiated_speed = SAS_LINK_RATE_UNKNOWN; | |
a628d478 EN |
1386 | |
1387 | /* Create the SIGNATURE FIS Timeout timer for this phy */ | |
85280955 | 1388 | sci_init_timer(&iphy->sata_timer, phy_sata_timeout); |
d35bc1bd | 1389 | } |
6f231dda | 1390 | |
4b33981a | 1391 | void isci_phy_init(struct isci_phy *iphy, struct isci_host *ihost, int index) |
6f231dda | 1392 | { |
89a7301f | 1393 | struct sci_oem_params *oem = &ihost->oem_parameters; |
4b33981a DW |
1394 | u64 sci_sas_addr; |
1395 | __be64 sas_addr; | |
1396 | ||
89a7301f | 1397 | sci_sas_addr = oem->phys[index].sas_address.high; |
4b33981a | 1398 | sci_sas_addr <<= 32; |
89a7301f | 1399 | sci_sas_addr |= oem->phys[index].sas_address.low; |
4b33981a DW |
1400 | sas_addr = cpu_to_be64(sci_sas_addr); |
1401 | memcpy(iphy->sas_addr, &sas_addr, sizeof(sas_addr)); | |
1402 | ||
4b33981a DW |
1403 | iphy->sas_phy.enabled = 0; |
1404 | iphy->sas_phy.id = index; | |
1405 | iphy->sas_phy.sas_addr = &iphy->sas_addr[0]; | |
1406 | iphy->sas_phy.frame_rcvd = (u8 *)&iphy->frame_rcvd; | |
1407 | iphy->sas_phy.ha = &ihost->sas_ha; | |
1408 | iphy->sas_phy.lldd_phy = iphy; | |
1409 | iphy->sas_phy.enabled = 1; | |
1410 | iphy->sas_phy.class = SAS; | |
1411 | iphy->sas_phy.iproto = SAS_PROTOCOL_ALL; | |
1412 | iphy->sas_phy.tproto = 0; | |
1413 | iphy->sas_phy.type = PHY_TYPE_PHYSICAL; | |
1414 | iphy->sas_phy.role = PHY_ROLE_INITIATOR; | |
1415 | iphy->sas_phy.oob_mode = OOB_NOT_CONNECTED; | |
1416 | iphy->sas_phy.linkrate = SAS_LINK_RATE_UNKNOWN; | |
1417 | memset(&iphy->frame_rcvd, 0, sizeof(iphy->frame_rcvd)); | |
6f231dda DW |
1418 | } |
1419 | ||
1420 | ||
1421 | /** | |
1422 | * isci_phy_control() - This function is one of the SAS Domain Template | |
1423 | * functions. This is a phy management function. | |
1424 | * @phy: This parameter specifies the sphy being controlled. | |
1425 | * @func: This parameter specifies the phy control function being invoked. | |
1426 | * @buf: This parameter is specific to the phy function being invoked. | |
1427 | * | |
1428 | * status, zero indicates success. | |
1429 | */ | |
4d07f7f3 DJ |
1430 | int isci_phy_control(struct asd_sas_phy *sas_phy, |
1431 | enum phy_func func, | |
1432 | void *buf) | |
6f231dda | 1433 | { |
4d07f7f3 DJ |
1434 | int ret = 0; |
1435 | struct isci_phy *iphy = sas_phy->lldd_phy; | |
c132f692 | 1436 | struct asd_sas_port *port = sas_phy->port; |
4d07f7f3 DJ |
1437 | struct isci_host *ihost = sas_phy->ha->lldd_ha; |
1438 | unsigned long flags; | |
6f231dda | 1439 | |
4d07f7f3 DJ |
1440 | dev_dbg(&ihost->pdev->dev, |
1441 | "%s: phy %p; func %d; buf %p; isci phy %p, port %p\n", | |
c132f692 | 1442 | __func__, sas_phy, func, buf, iphy, port); |
6f231dda DW |
1443 | |
1444 | switch (func) { | |
4d07f7f3 DJ |
1445 | case PHY_FUNC_DISABLE: |
1446 | spin_lock_irqsave(&ihost->scic_lock, flags); | |
c5457a82 | 1447 | scu_link_layer_start_oob(iphy); |
89a7301f | 1448 | sci_phy_stop(iphy); |
4d07f7f3 DJ |
1449 | spin_unlock_irqrestore(&ihost->scic_lock, flags); |
1450 | break; | |
1451 | ||
6f231dda | 1452 | case PHY_FUNC_LINK_RESET: |
4d07f7f3 | 1453 | spin_lock_irqsave(&ihost->scic_lock, flags); |
c5457a82 | 1454 | scu_link_layer_start_oob(iphy); |
89a7301f DW |
1455 | sci_phy_stop(iphy); |
1456 | sci_phy_start(iphy); | |
4d07f7f3 DJ |
1457 | spin_unlock_irqrestore(&ihost->scic_lock, flags); |
1458 | break; | |
1459 | ||
1460 | case PHY_FUNC_HARD_RESET: | |
c132f692 | 1461 | if (!port) |
4d07f7f3 | 1462 | return -ENODEV; |
6f231dda | 1463 | |
c132f692 | 1464 | ret = isci_port_perform_hard_reset(ihost, port->lldd_port, iphy); |
6f231dda DW |
1465 | |
1466 | break; | |
ac013ed1 DW |
1467 | case PHY_FUNC_GET_EVENTS: { |
1468 | struct scu_link_layer_registers __iomem *r; | |
1469 | struct sas_phy *phy = sas_phy->phy; | |
1470 | ||
1471 | r = iphy->link_layer_registers; | |
1472 | phy->running_disparity_error_count = readl(&r->running_disparity_error_count); | |
1473 | phy->loss_of_dword_sync_count = readl(&r->loss_of_sync_error_count); | |
1474 | phy->phy_reset_problem_count = readl(&r->phy_reset_problem_count); | |
1475 | phy->invalid_dword_count = readl(&r->invalid_dword_counter); | |
1476 | break; | |
1477 | } | |
6f231dda | 1478 | |
6f231dda | 1479 | default: |
4d07f7f3 DJ |
1480 | dev_dbg(&ihost->pdev->dev, |
1481 | "%s: phy %p; func %d NOT IMPLEMENTED!\n", | |
1482 | __func__, sas_phy, func); | |
1483 | ret = -ENOSYS; | |
6f231dda DW |
1484 | break; |
1485 | } | |
1486 | return ret; | |
1487 | } |