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