diff options
author | Dan Williams <dan.j.williams@intel.com> | 2011-05-10 05:28:46 -0400 |
---|---|---|
committer | Dan Williams <dan.j.williams@intel.com> | 2011-07-03 07:04:47 -0400 |
commit | e2f8db509fdd354bb7a68c86515e9d2d8909ccc9 (patch) | |
tree | e27f2d33290b0c6f7ca20e408ce7f8ff9309dc43 /drivers/scsi/isci | |
parent | d35bc1bd18ab9e986cfb67c5a281a70cfd717f05 (diff) |
isci: uplevel port infrastructure
* Move port configuration agent implementation
* Merge core/scic_sds_port.[ch] into port.[ch]
Reported-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
Diffstat (limited to 'drivers/scsi/isci')
-rw-r--r-- | drivers/scsi/isci/Makefile | 4 | ||||
-rw-r--r-- | drivers/scsi/isci/core/scic_config_parameters.h | 249 | ||||
-rw-r--r-- | drivers/scsi/isci/core/scic_port.h | 97 | ||||
-rw-r--r-- | drivers/scsi/isci/core/scic_sds_port.c | 2423 | ||||
-rw-r--r-- | drivers/scsi/isci/core/scic_sds_port.h | 435 | ||||
-rw-r--r-- | drivers/scsi/isci/core/scic_sds_port_configuration_agent.h | 107 | ||||
-rw-r--r-- | drivers/scsi/isci/host.c | 1 | ||||
-rw-r--r-- | drivers/scsi/isci/host.h | 29 | ||||
-rw-r--r-- | drivers/scsi/isci/phy.c | 3 | ||||
-rw-r--r-- | drivers/scsi/isci/phy.h | 1 | ||||
-rw-r--r-- | drivers/scsi/isci/port.c | 2451 | ||||
-rw-r--r-- | drivers/scsi/isci/port.h | 425 | ||||
-rw-r--r-- | drivers/scsi/isci/port_config.c (renamed from drivers/scsi/isci/core/scic_sds_port_configuration_agent.c) | 1 | ||||
-rw-r--r-- | drivers/scsi/isci/probe_roms.h | 124 | ||||
-rw-r--r-- | drivers/scsi/isci/remote_device.c | 2 | ||||
-rw-r--r-- | drivers/scsi/isci/remote_node_context.c | 1 | ||||
-rw-r--r-- | drivers/scsi/isci/request.c | 1 |
17 files changed, 2929 insertions, 3425 deletions
diff --git a/drivers/scsi/isci/Makefile b/drivers/scsi/isci/Makefile index 2830a97a822a..48218ca908fe 100644 --- a/drivers/scsi/isci/Makefile +++ b/drivers/scsi/isci/Makefile | |||
@@ -1,4 +1,3 @@ | |||
1 | EXTRA_CFLAGS += -Idrivers/scsi/isci/core/ -Idrivers/scsi/isci/ | ||
2 | obj-$(CONFIG_SCSI_ISCI) += isci.o | 1 | obj-$(CONFIG_SCSI_ISCI) += isci.o |
3 | isci-objs := init.o phy.o request.o sata.o \ | 2 | isci-objs := init.o phy.o request.o sata.o \ |
4 | remote_device.o port.o timers.o \ | 3 | remote_device.o port.o timers.o \ |
@@ -10,5 +9,4 @@ isci-objs := init.o phy.o request.o sata.o \ | |||
10 | stp_request.o \ | 9 | stp_request.o \ |
11 | ssp_request.o \ | 10 | ssp_request.o \ |
12 | smp_request.o \ | 11 | smp_request.o \ |
13 | core/scic_sds_port.o \ | 12 | port_config.o \ |
14 | core/scic_sds_port_configuration_agent.o \ | ||
diff --git a/drivers/scsi/isci/core/scic_config_parameters.h b/drivers/scsi/isci/core/scic_config_parameters.h deleted file mode 100644 index 15e7744dbdcf..000000000000 --- a/drivers/scsi/isci/core/scic_config_parameters.h +++ /dev/null | |||
@@ -1,249 +0,0 @@ | |||
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 | #ifndef _SCIC_SDS_USER_PARAMETERS_H_ | ||
57 | #define _SCIC_SDS_USER_PARAMETERS_H_ | ||
58 | |||
59 | #include "probe_roms.h" | ||
60 | |||
61 | struct scic_sds_controller; | ||
62 | |||
63 | /** | ||
64 | * | ||
65 | * | ||
66 | * SCIC_SDS_PARM_PHY_SPEED These constants define the speeds utilized for a | ||
67 | * phy/port. | ||
68 | */ | ||
69 | #define SCIC_SDS_PARM_NO_SPEED 0 | ||
70 | |||
71 | /** | ||
72 | * | ||
73 | * | ||
74 | * This value of 1 indicates generation 1 (i.e. 1.5 Gb/s). | ||
75 | */ | ||
76 | #define SCIC_SDS_PARM_GEN1_SPEED 1 | ||
77 | |||
78 | /** | ||
79 | * | ||
80 | * | ||
81 | * This value of 2 indicates generation 2 (i.e. 3.0 Gb/s). | ||
82 | */ | ||
83 | #define SCIC_SDS_PARM_GEN2_SPEED 2 | ||
84 | |||
85 | /** | ||
86 | * | ||
87 | * | ||
88 | * This value of 3 indicates generation 3 (i.e. 6.0 Gb/s). | ||
89 | */ | ||
90 | #define SCIC_SDS_PARM_GEN3_SPEED 3 | ||
91 | |||
92 | /** | ||
93 | * | ||
94 | * | ||
95 | * For range checks, the max speed generation | ||
96 | */ | ||
97 | #define SCIC_SDS_PARM_MAX_SPEED SCIC_SDS_PARM_GEN3_SPEED | ||
98 | |||
99 | /** | ||
100 | * struct scic_sds_user_parameters - This structure delineates the various user | ||
101 | * parameters that can be changed by the core user. | ||
102 | * | ||
103 | * | ||
104 | */ | ||
105 | struct scic_sds_user_parameters { | ||
106 | struct sci_phy_user_params { | ||
107 | /** | ||
108 | * This field specifies the NOTIFY (ENABLE SPIN UP) primitive | ||
109 | * insertion frequency for this phy index. | ||
110 | */ | ||
111 | u32 notify_enable_spin_up_insertion_frequency; | ||
112 | |||
113 | /** | ||
114 | * This method specifies the number of transmitted DWORDs within which | ||
115 | * to transmit a single ALIGN primitive. This value applies regardless | ||
116 | * of what type of device is attached or connection state. A value of | ||
117 | * 0 indicates that no ALIGN primitives will be inserted. | ||
118 | */ | ||
119 | u16 align_insertion_frequency; | ||
120 | |||
121 | /** | ||
122 | * This method specifies the number of transmitted DWORDs within which | ||
123 | * to transmit 2 ALIGN primitives. This applies for SAS connections | ||
124 | * only. A minimum value of 3 is required for this field. | ||
125 | */ | ||
126 | u16 in_connection_align_insertion_frequency; | ||
127 | |||
128 | /** | ||
129 | * This field indicates the maximum speed generation to be utilized | ||
130 | * by phys in the supplied port. | ||
131 | * - A value of 1 indicates generation 1 (i.e. 1.5 Gb/s). | ||
132 | * - A value of 2 indicates generation 2 (i.e. 3.0 Gb/s). | ||
133 | * - A value of 3 indicates generation 3 (i.e. 6.0 Gb/s). | ||
134 | */ | ||
135 | u8 max_speed_generation; | ||
136 | |||
137 | } phys[SCI_MAX_PHYS]; | ||
138 | |||
139 | /** | ||
140 | * This field specifies the maximum number of direct attached devices | ||
141 | * that can have power supplied to them simultaneously. | ||
142 | */ | ||
143 | u8 max_number_concurrent_device_spin_up; | ||
144 | |||
145 | /** | ||
146 | * This field specifies the number of seconds to allow a phy to consume | ||
147 | * power before yielding to another phy. | ||
148 | * | ||
149 | */ | ||
150 | u8 phy_spin_up_delay_interval; | ||
151 | |||
152 | /** | ||
153 | * These timer values specifies how long a link will remain open with no | ||
154 | * activity in increments of a microsecond, it can be in increments of | ||
155 | * 100 microseconds if the upper most bit is set. | ||
156 | * | ||
157 | */ | ||
158 | u16 stp_inactivity_timeout; | ||
159 | u16 ssp_inactivity_timeout; | ||
160 | |||
161 | /** | ||
162 | * These timer values specifies how long a link will remain open in increments | ||
163 | * of 100 microseconds. | ||
164 | * | ||
165 | */ | ||
166 | u16 stp_max_occupancy_timeout; | ||
167 | u16 ssp_max_occupancy_timeout; | ||
168 | |||
169 | /** | ||
170 | * This timer value specifies how long a link will remain open with no | ||
171 | * outbound traffic in increments of a microsecond. | ||
172 | * | ||
173 | */ | ||
174 | u8 no_outbound_task_timeout; | ||
175 | |||
176 | }; | ||
177 | |||
178 | /** | ||
179 | * This structure/union specifies the various different user parameter sets | ||
180 | * available. Each type is specific to a hardware controller version. | ||
181 | * | ||
182 | * union scic_user_parameters | ||
183 | */ | ||
184 | union scic_user_parameters { | ||
185 | /** | ||
186 | * This field specifies the user parameters specific to the | ||
187 | * Storage Controller Unit (SCU) Driver Standard (SDS) version | ||
188 | * 1. | ||
189 | */ | ||
190 | struct scic_sds_user_parameters sds1; | ||
191 | |||
192 | }; | ||
193 | |||
194 | |||
195 | /** | ||
196 | * | ||
197 | * | ||
198 | * SCIC_SDS_OEM_PHY_MASK These constants define the valid values for phy_mask | ||
199 | */ | ||
200 | |||
201 | /** | ||
202 | * | ||
203 | * | ||
204 | * This is the min value assignable to a port's phy mask | ||
205 | */ | ||
206 | #define SCIC_SDS_PARM_PHY_MASK_MIN 0x0 | ||
207 | |||
208 | /** | ||
209 | * | ||
210 | * | ||
211 | * This is the max value assignable to a port's phy mask | ||
212 | */ | ||
213 | #define SCIC_SDS_PARM_PHY_MASK_MAX 0xF | ||
214 | |||
215 | #define MAX_CONCURRENT_DEVICE_SPIN_UP_COUNT 4 | ||
216 | |||
217 | /** | ||
218 | * This structure/union specifies the various different OEM parameter sets | ||
219 | * available. Each type is specific to a hardware controller version. | ||
220 | * | ||
221 | * union scic_oem_parameters | ||
222 | */ | ||
223 | union scic_oem_parameters { | ||
224 | /** | ||
225 | * This field specifies the OEM parameters specific to the | ||
226 | * Storage Controller Unit (SCU) Driver Standard (SDS) version | ||
227 | * 1. | ||
228 | */ | ||
229 | struct scic_sds_oem_params sds1; | ||
230 | }; | ||
231 | |||
232 | int scic_oem_parameters_validate(struct scic_sds_oem_params *oem); | ||
233 | |||
234 | /** | ||
235 | * scic_oem_parameters_get() - This method allows the user to retreive the OEM | ||
236 | * parameters utilized by the controller. | ||
237 | * @controller: This parameter specifies the controller on which to set the | ||
238 | * user parameters. | ||
239 | * @oem_parameters: This parameter specifies the OEM parameters object in which | ||
240 | * to write the core's OEM parameters. | ||
241 | * | ||
242 | */ | ||
243 | void scic_oem_parameters_get( | ||
244 | struct scic_sds_controller *controller, | ||
245 | union scic_oem_parameters *oem_parameters); | ||
246 | |||
247 | |||
248 | #endif /* _SCIC_SDS_USER_PARAMETERS_H_ */ | ||
249 | |||
diff --git a/drivers/scsi/isci/core/scic_port.h b/drivers/scsi/isci/core/scic_port.h deleted file mode 100644 index 431dbd2093f3..000000000000 --- a/drivers/scsi/isci/core/scic_port.h +++ /dev/null | |||
@@ -1,97 +0,0 @@ | |||
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 | #ifndef _SCIC_PORT_H_ | ||
57 | #define _SCIC_PORT_H_ | ||
58 | |||
59 | #include "isci.h" | ||
60 | #include "sas.h" | ||
61 | #include "phy.h" | ||
62 | |||
63 | struct scic_sds_port; | ||
64 | |||
65 | enum scic_port_not_ready_reason_code { | ||
66 | SCIC_PORT_NOT_READY_NO_ACTIVE_PHYS, | ||
67 | SCIC_PORT_NOT_READY_HARD_RESET_REQUESTED, | ||
68 | SCIC_PORT_NOT_READY_INVALID_PORT_CONFIGURATION, | ||
69 | SCIC_PORT_NOT_READY_RECONFIGURING, | ||
70 | |||
71 | SCIC_PORT_NOT_READY_REASON_CODE_MAX | ||
72 | }; | ||
73 | |||
74 | struct scic_port_end_point_properties { | ||
75 | struct sci_sas_address sas_address; | ||
76 | struct scic_phy_proto protocols; | ||
77 | }; | ||
78 | |||
79 | struct scic_port_properties { | ||
80 | u32 index; | ||
81 | struct scic_port_end_point_properties local; | ||
82 | struct scic_port_end_point_properties remote; | ||
83 | u32 phy_mask; | ||
84 | }; | ||
85 | |||
86 | enum sci_status scic_port_get_properties( | ||
87 | struct scic_sds_port *port, | ||
88 | struct scic_port_properties *properties); | ||
89 | |||
90 | enum sci_status scic_port_hard_reset( | ||
91 | struct scic_sds_port *port, | ||
92 | u32 reset_timeout); | ||
93 | |||
94 | void scic_port_enable_broadcast_change_notification( | ||
95 | struct scic_sds_port *port); | ||
96 | |||
97 | #endif /* _SCIC_PORT_H_ */ | ||
diff --git a/drivers/scsi/isci/core/scic_sds_port.c b/drivers/scsi/isci/core/scic_sds_port.c deleted file mode 100644 index 11b516a9a130..000000000000 --- a/drivers/scsi/isci/core/scic_sds_port.c +++ /dev/null | |||
@@ -1,2423 +0,0 @@ | |||
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 "host.h" | ||
57 | #include "scic_port.h" | ||
58 | #include "scic_sds_port.h" | ||
59 | #include "remote_device.h" | ||
60 | #include "remote_node_context.h" | ||
61 | #include "registers.h" | ||
62 | #include "timers.h" | ||
63 | #include "scu_task_context.h" | ||
64 | |||
65 | #define SCIC_SDS_PORT_MIN_TIMER_COUNT (SCI_MAX_PORTS) | ||
66 | #define SCIC_SDS_PORT_MAX_TIMER_COUNT (SCI_MAX_PORTS) | ||
67 | |||
68 | #define SCIC_SDS_PORT_HARD_RESET_TIMEOUT (1000) | ||
69 | #define SCU_DUMMY_INDEX (0xFFFF) | ||
70 | |||
71 | |||
72 | /** | ||
73 | * | ||
74 | * @sci_port: This is the port object to which the phy is being assigned. | ||
75 | * @phy_index: This is the phy index that is being assigned to the port. | ||
76 | * | ||
77 | * This method will return a true value if the specified phy can be assigned to | ||
78 | * this port The following is a list of phys for each port that are allowed: - | ||
79 | * Port 0 - 3 2 1 0 - Port 1 - 1 - Port 2 - 3 2 - Port 3 - 3 This method | ||
80 | * doesn't preclude all configurations. It merely ensures that a phy is part | ||
81 | * of the allowable set of phy identifiers for that port. For example, one | ||
82 | * could assign phy 3 to port 0 and no other phys. Please refer to | ||
83 | * scic_sds_port_is_phy_mask_valid() for information regarding whether the | ||
84 | * phy_mask for a port can be supported. bool true if this is a valid phy | ||
85 | * assignment for the port false if this is not a valid phy assignment for the | ||
86 | * port | ||
87 | */ | ||
88 | bool scic_sds_port_is_valid_phy_assignment( | ||
89 | struct scic_sds_port *sci_port, | ||
90 | u32 phy_index) | ||
91 | { | ||
92 | /* Initialize to invalid value. */ | ||
93 | u32 existing_phy_index = SCI_MAX_PHYS; | ||
94 | u32 index; | ||
95 | |||
96 | if ((sci_port->physical_port_index == 1) && (phy_index != 1)) { | ||
97 | return false; | ||
98 | } | ||
99 | |||
100 | if (sci_port->physical_port_index == 3 && phy_index != 3) { | ||
101 | return false; | ||
102 | } | ||
103 | |||
104 | if ( | ||
105 | (sci_port->physical_port_index == 2) | ||
106 | && ((phy_index == 0) || (phy_index == 1)) | ||
107 | ) { | ||
108 | return false; | ||
109 | } | ||
110 | |||
111 | for (index = 0; index < SCI_MAX_PHYS; index++) { | ||
112 | if ((sci_port->phy_table[index] != NULL) | ||
113 | && (index != phy_index)) { | ||
114 | existing_phy_index = index; | ||
115 | } | ||
116 | } | ||
117 | |||
118 | /* | ||
119 | * Ensure that all of the phys in the port are capable of | ||
120 | * operating at the same maximum link rate. */ | ||
121 | if ( | ||
122 | (existing_phy_index < SCI_MAX_PHYS) | ||
123 | && (sci_port->owning_controller->user_parameters.sds1.phys[ | ||
124 | phy_index].max_speed_generation != | ||
125 | sci_port->owning_controller->user_parameters.sds1.phys[ | ||
126 | existing_phy_index].max_speed_generation) | ||
127 | ) | ||
128 | return false; | ||
129 | |||
130 | return true; | ||
131 | } | ||
132 | |||
133 | /** | ||
134 | * This method requests a list (mask) of the phys contained in the supplied SAS | ||
135 | * port. | ||
136 | * @sci_port: a handle corresponding to the SAS port for which to return the | ||
137 | * phy mask. | ||
138 | * | ||
139 | * Return a bit mask indicating which phys are a part of this port. Each bit | ||
140 | * corresponds to a phy identifier (e.g. bit 0 = phy id 0). | ||
141 | */ | ||
142 | static u32 scic_sds_port_get_phys(struct scic_sds_port *sci_port) | ||
143 | { | ||
144 | u32 index; | ||
145 | u32 mask; | ||
146 | |||
147 | mask = 0; | ||
148 | |||
149 | for (index = 0; index < SCI_MAX_PHYS; index++) { | ||
150 | if (sci_port->phy_table[index] != NULL) { | ||
151 | mask |= (1 << index); | ||
152 | } | ||
153 | } | ||
154 | |||
155 | return mask; | ||
156 | } | ||
157 | |||
158 | /** | ||
159 | * | ||
160 | * @sci_port: This is the port object for which to determine if the phy mask | ||
161 | * can be supported. | ||
162 | * | ||
163 | * This method will return a true value if the port's phy mask can be supported | ||
164 | * by the SCU. The following is a list of valid PHY mask configurations for | ||
165 | * each port: - Port 0 - [[3 2] 1] 0 - Port 1 - [1] - Port 2 - [[3] 2] | ||
166 | * - Port 3 - [3] This method returns a boolean indication specifying if the | ||
167 | * phy mask can be supported. true if this is a valid phy assignment for the | ||
168 | * port false if this is not a valid phy assignment for the port | ||
169 | */ | ||
170 | static bool scic_sds_port_is_phy_mask_valid( | ||
171 | struct scic_sds_port *sci_port, | ||
172 | u32 phy_mask) | ||
173 | { | ||
174 | if (sci_port->physical_port_index == 0) { | ||
175 | if (((phy_mask & 0x0F) == 0x0F) | ||
176 | || ((phy_mask & 0x03) == 0x03) | ||
177 | || ((phy_mask & 0x01) == 0x01) | ||
178 | || (phy_mask == 0)) | ||
179 | return true; | ||
180 | } else if (sci_port->physical_port_index == 1) { | ||
181 | if (((phy_mask & 0x02) == 0x02) | ||
182 | || (phy_mask == 0)) | ||
183 | return true; | ||
184 | } else if (sci_port->physical_port_index == 2) { | ||
185 | if (((phy_mask & 0x0C) == 0x0C) | ||
186 | || ((phy_mask & 0x04) == 0x04) | ||
187 | || (phy_mask == 0)) | ||
188 | return true; | ||
189 | } else if (sci_port->physical_port_index == 3) { | ||
190 | if (((phy_mask & 0x08) == 0x08) | ||
191 | || (phy_mask == 0)) | ||
192 | return true; | ||
193 | } | ||
194 | |||
195 | return false; | ||
196 | } | ||
197 | |||
198 | /** | ||
199 | * | ||
200 | * @sci_port: This parameter specifies the port from which to return a | ||
201 | * connected phy. | ||
202 | * | ||
203 | * This method retrieves a currently active (i.e. connected) phy contained in | ||
204 | * the port. Currently, the lowest order phy that is connected is returned. | ||
205 | * This method returns a pointer to a SCIS_SDS_PHY object. NULL This value is | ||
206 | * returned if there are no currently active (i.e. connected to a remote end | ||
207 | * point) phys contained in the port. All other values specify a struct scic_sds_phy | ||
208 | * object that is active in the port. | ||
209 | */ | ||
210 | static struct scic_sds_phy *scic_sds_port_get_a_connected_phy( | ||
211 | struct scic_sds_port *sci_port | ||
212 | ) { | ||
213 | u32 index; | ||
214 | struct scic_sds_phy *phy; | ||
215 | |||
216 | for (index = 0; index < SCI_MAX_PHYS; index++) { | ||
217 | /* | ||
218 | * Ensure that the phy is both part of the port and currently | ||
219 | * connected to the remote end-point. */ | ||
220 | phy = sci_port->phy_table[index]; | ||
221 | if ( | ||
222 | (phy != NULL) | ||
223 | && scic_sds_port_active_phy(sci_port, phy) | ||
224 | ) { | ||
225 | return phy; | ||
226 | } | ||
227 | } | ||
228 | |||
229 | return NULL; | ||
230 | } | ||
231 | |||
232 | /** | ||
233 | * scic_sds_port_set_phy() - | ||
234 | * @out]: port The port object to which the phy assignement is being made. | ||
235 | * @out]: phy The phy which is being assigned to the port. | ||
236 | * | ||
237 | * This method attempts to make the assignment of the phy to the port. If | ||
238 | * successful the phy is assigned to the ports phy table. bool true if the phy | ||
239 | * assignment can be made. false if the phy assignement can not be made. This | ||
240 | * is a functional test that only fails if the phy is currently assigned to a | ||
241 | * different port. | ||
242 | */ | ||
243 | static enum sci_status scic_sds_port_set_phy( | ||
244 | struct scic_sds_port *port, | ||
245 | struct scic_sds_phy *phy) | ||
246 | { | ||
247 | /* | ||
248 | * Check to see if we can add this phy to a port | ||
249 | * that means that the phy is not part of a port and that the port does | ||
250 | * not already have a phy assinged to the phy index. */ | ||
251 | if ( | ||
252 | (port->phy_table[phy->phy_index] == NULL) | ||
253 | && (scic_sds_phy_get_port(phy) == NULL) | ||
254 | && scic_sds_port_is_valid_phy_assignment(port, phy->phy_index) | ||
255 | ) { | ||
256 | /* | ||
257 | * Phy is being added in the stopped state so we are in MPC mode | ||
258 | * make logical port index = physical port index */ | ||
259 | port->logical_port_index = port->physical_port_index; | ||
260 | port->phy_table[phy->phy_index] = phy; | ||
261 | scic_sds_phy_set_port(phy, port); | ||
262 | |||
263 | return SCI_SUCCESS; | ||
264 | } | ||
265 | |||
266 | return SCI_FAILURE; | ||
267 | } | ||
268 | |||
269 | /** | ||
270 | * scic_sds_port_clear_phy() - | ||
271 | * @out]: port The port from which the phy is being cleared. | ||
272 | * @out]: phy The phy being cleared from the port. | ||
273 | * | ||
274 | * This method will clear the phy assigned to this port. This method fails if | ||
275 | * this phy is not currently assinged to this port. bool true if the phy is | ||
276 | * removed from the port. false if this phy is not assined to this port. | ||
277 | */ | ||
278 | static enum sci_status scic_sds_port_clear_phy( | ||
279 | struct scic_sds_port *port, | ||
280 | struct scic_sds_phy *phy) | ||
281 | { | ||
282 | /* Make sure that this phy is part of this port */ | ||
283 | if (port->phy_table[phy->phy_index] == phy && | ||
284 | scic_sds_phy_get_port(phy) == port) { | ||
285 | struct scic_sds_controller *scic = port->owning_controller; | ||
286 | struct isci_host *ihost = scic_to_ihost(scic); | ||
287 | |||
288 | /* Yep it is assigned to this port so remove it */ | ||
289 | scic_sds_phy_set_port(phy, &ihost->ports[SCI_MAX_PORTS].sci); | ||
290 | port->phy_table[phy->phy_index] = NULL; | ||
291 | return SCI_SUCCESS; | ||
292 | } | ||
293 | |||
294 | return SCI_FAILURE; | ||
295 | } | ||
296 | |||
297 | /** | ||
298 | * scic_sds_port_add_phy() - | ||
299 | * @sci_port: This parameter specifies the port in which the phy will be added. | ||
300 | * @sci_phy: This parameter is the phy which is to be added to the port. | ||
301 | * | ||
302 | * This method will add a PHY to the selected port. This method returns an | ||
303 | * enum sci_status. SCI_SUCCESS the phy has been added to the port. Any other status | ||
304 | * is failre to add the phy to the port. | ||
305 | */ | ||
306 | enum sci_status scic_sds_port_add_phy( | ||
307 | struct scic_sds_port *sci_port, | ||
308 | struct scic_sds_phy *sci_phy) | ||
309 | { | ||
310 | return sci_port->state_handlers->add_phy_handler( | ||
311 | sci_port, sci_phy); | ||
312 | } | ||
313 | |||
314 | |||
315 | /** | ||
316 | * scic_sds_port_remove_phy() - | ||
317 | * @sci_port: This parameter specifies the port in which the phy will be added. | ||
318 | * @sci_phy: This parameter is the phy which is to be added to the port. | ||
319 | * | ||
320 | * This method will remove the PHY from the selected PORT. This method returns | ||
321 | * an enum sci_status. SCI_SUCCESS the phy has been removed from the port. Any other | ||
322 | * status is failre to add the phy to the port. | ||
323 | */ | ||
324 | enum sci_status scic_sds_port_remove_phy( | ||
325 | struct scic_sds_port *sci_port, | ||
326 | struct scic_sds_phy *sci_phy) | ||
327 | { | ||
328 | return sci_port->state_handlers->remove_phy_handler( | ||
329 | sci_port, sci_phy); | ||
330 | } | ||
331 | |||
332 | /** | ||
333 | * This method requests the SAS address for the supplied SAS port from the SCI | ||
334 | * implementation. | ||
335 | * @sci_port: a handle corresponding to the SAS port for which to return the | ||
336 | * SAS address. | ||
337 | * @sas_address: This parameter specifies a pointer to a SAS address structure | ||
338 | * into which the core will copy the SAS address for the port. | ||
339 | * | ||
340 | */ | ||
341 | void scic_sds_port_get_sas_address( | ||
342 | struct scic_sds_port *sci_port, | ||
343 | struct sci_sas_address *sas_address) | ||
344 | { | ||
345 | u32 index; | ||
346 | |||
347 | sas_address->high = 0; | ||
348 | sas_address->low = 0; | ||
349 | |||
350 | for (index = 0; index < SCI_MAX_PHYS; index++) { | ||
351 | if (sci_port->phy_table[index] != NULL) { | ||
352 | scic_sds_phy_get_sas_address(sci_port->phy_table[index], sas_address); | ||
353 | } | ||
354 | } | ||
355 | } | ||
356 | |||
357 | /* | ||
358 | * This function will indicate which protocols are supported by this port. | ||
359 | * @sci_port: a handle corresponding to the SAS port for which to return the | ||
360 | * supported protocols. | ||
361 | * @protocols: This parameter specifies a pointer to a data structure | ||
362 | * which the core will copy the protocol values for the port from the | ||
363 | * transmit_identification register. | ||
364 | */ | ||
365 | static void | ||
366 | scic_sds_port_get_protocols(struct scic_sds_port *sci_port, | ||
367 | struct scic_phy_proto *protocols) | ||
368 | { | ||
369 | u8 index; | ||
370 | |||
371 | protocols->all = 0; | ||
372 | |||
373 | for (index = 0; index < SCI_MAX_PHYS; index++) { | ||
374 | if (sci_port->phy_table[index] != NULL) { | ||
375 | scic_sds_phy_get_protocols(sci_port->phy_table[index], | ||
376 | protocols); | ||
377 | } | ||
378 | } | ||
379 | } | ||
380 | |||
381 | /* | ||
382 | * This function requests the SAS address for the device directly attached to | ||
383 | * this SAS port. | ||
384 | * @sci_port: a handle corresponding to the SAS port for which to return the | ||
385 | * SAS address. | ||
386 | * @sas_address: This parameter specifies a pointer to a SAS address structure | ||
387 | * into which the core will copy the SAS address for the device directly | ||
388 | * attached to the port. | ||
389 | * | ||
390 | */ | ||
391 | void scic_sds_port_get_attached_sas_address( | ||
392 | struct scic_sds_port *sci_port, | ||
393 | struct sci_sas_address *sas_address) | ||
394 | { | ||
395 | struct scic_sds_phy *sci_phy; | ||
396 | |||
397 | /* | ||
398 | * Ensure that the phy is both part of the port and currently | ||
399 | * connected to the remote end-point. | ||
400 | */ | ||
401 | sci_phy = scic_sds_port_get_a_connected_phy(sci_port); | ||
402 | if (sci_phy) { | ||
403 | if (sci_phy->protocol != SCIC_SDS_PHY_PROTOCOL_SATA) { | ||
404 | scic_sds_phy_get_attached_sas_address(sci_phy, | ||
405 | sas_address); | ||
406 | } else { | ||
407 | scic_sds_phy_get_sas_address(sci_phy, sas_address); | ||
408 | sas_address->low += sci_phy->phy_index; | ||
409 | } | ||
410 | } else { | ||
411 | sas_address->high = 0; | ||
412 | sas_address->low = 0; | ||
413 | } | ||
414 | } | ||
415 | |||
416 | /** | ||
417 | * scic_sds_port_construct_dummy_rnc() - create dummy rnc for si workaround | ||
418 | * | ||
419 | * @sci_port: logical port on which we need to create the remote node context | ||
420 | * @rni: remote node index for this remote node context. | ||
421 | * | ||
422 | * This routine will construct a dummy remote node context data structure | ||
423 | * This structure will be posted to the hardware to work around a scheduler | ||
424 | * error in the hardware. | ||
425 | */ | ||
426 | static void scic_sds_port_construct_dummy_rnc(struct scic_sds_port *sci_port, u16 rni) | ||
427 | { | ||
428 | union scu_remote_node_context *rnc; | ||
429 | |||
430 | rnc = &sci_port->owning_controller->remote_node_context_table[rni]; | ||
431 | |||
432 | memset(rnc, 0, sizeof(union scu_remote_node_context)); | ||
433 | |||
434 | rnc->ssp.remote_sas_address_hi = 0; | ||
435 | rnc->ssp.remote_sas_address_lo = 0; | ||
436 | |||
437 | rnc->ssp.remote_node_index = rni; | ||
438 | rnc->ssp.remote_node_port_width = 1; | ||
439 | rnc->ssp.logical_port_index = sci_port->physical_port_index; | ||
440 | |||
441 | rnc->ssp.nexus_loss_timer_enable = false; | ||
442 | rnc->ssp.check_bit = false; | ||
443 | rnc->ssp.is_valid = true; | ||
444 | rnc->ssp.is_remote_node_context = true; | ||
445 | rnc->ssp.function_number = 0; | ||
446 | rnc->ssp.arbitration_wait_time = 0; | ||
447 | } | ||
448 | |||
449 | /** | ||
450 | * scic_sds_port_construct_dummy_task() - create dummy task for si workaround | ||
451 | * @sci_port The logical port on which we need to create the | ||
452 | * remote node context. | ||
453 | * context. | ||
454 | * @tci The remote node index for this remote node context. | ||
455 | * | ||
456 | * This routine will construct a dummy task context data structure. This | ||
457 | * structure will be posted to the hardwre to work around a scheduler error | ||
458 | * in the hardware. | ||
459 | * | ||
460 | */ | ||
461 | static void scic_sds_port_construct_dummy_task(struct scic_sds_port *sci_port, u16 tci) | ||
462 | { | ||
463 | struct scu_task_context *task_context; | ||
464 | |||
465 | task_context = scic_sds_controller_get_task_context_buffer(sci_port->owning_controller, tci); | ||
466 | |||
467 | memset(task_context, 0, sizeof(struct scu_task_context)); | ||
468 | |||
469 | task_context->abort = 0; | ||
470 | task_context->priority = 0; | ||
471 | task_context->initiator_request = 1; | ||
472 | task_context->connection_rate = 1; | ||
473 | task_context->protocol_engine_index = 0; | ||
474 | task_context->logical_port_index = sci_port->physical_port_index; | ||
475 | task_context->protocol_type = SCU_TASK_CONTEXT_PROTOCOL_SSP; | ||
476 | task_context->task_index = scic_sds_io_tag_get_index(tci); | ||
477 | task_context->valid = SCU_TASK_CONTEXT_VALID; | ||
478 | task_context->context_type = SCU_TASK_CONTEXT_TYPE; | ||
479 | |||
480 | task_context->remote_node_index = sci_port->reserved_rni; | ||
481 | task_context->command_code = 0; | ||
482 | |||
483 | task_context->link_layer_control = 0; | ||
484 | task_context->do_not_dma_ssp_good_response = 1; | ||
485 | task_context->strict_ordering = 0; | ||
486 | task_context->control_frame = 0; | ||
487 | task_context->timeout_enable = 0; | ||
488 | task_context->block_guard_enable = 0; | ||
489 | |||
490 | task_context->address_modifier = 0; | ||
491 | |||
492 | task_context->task_phase = 0x01; | ||
493 | } | ||
494 | |||
495 | static void scic_sds_port_destroy_dummy_resources(struct scic_sds_port *sci_port) | ||
496 | { | ||
497 | struct scic_sds_controller *scic = sci_port->owning_controller; | ||
498 | |||
499 | if (sci_port->reserved_tci != SCU_DUMMY_INDEX) | ||
500 | scic_controller_free_io_tag(scic, sci_port->reserved_tci); | ||
501 | |||
502 | if (sci_port->reserved_rni != SCU_DUMMY_INDEX) | ||
503 | scic_sds_remote_node_table_release_remote_node_index(&scic->available_remote_nodes, | ||
504 | 1, sci_port->reserved_rni); | ||
505 | |||
506 | sci_port->reserved_rni = SCU_DUMMY_INDEX; | ||
507 | sci_port->reserved_tci = SCU_DUMMY_INDEX; | ||
508 | } | ||
509 | |||
510 | /** | ||
511 | * This method performs initialization of the supplied port. Initialization | ||
512 | * includes: - state machine initialization - member variable initialization | ||
513 | * - configuring the phy_mask | ||
514 | * @sci_port: | ||
515 | * @transport_layer_registers: | ||
516 | * @port_task_scheduler_registers: | ||
517 | * @port_configuration_regsiter: | ||
518 | * | ||
519 | * enum sci_status SCI_FAILURE_UNSUPPORTED_PORT_CONFIGURATION This value is returned | ||
520 | * if the phy being added to the port | ||
521 | */ | ||
522 | enum sci_status scic_sds_port_initialize( | ||
523 | struct scic_sds_port *sci_port, | ||
524 | void __iomem *port_task_scheduler_registers, | ||
525 | void __iomem *port_configuration_regsiter, | ||
526 | void __iomem *viit_registers) | ||
527 | { | ||
528 | sci_port->port_task_scheduler_registers = port_task_scheduler_registers; | ||
529 | sci_port->port_pe_configuration_register = port_configuration_regsiter; | ||
530 | sci_port->viit_registers = viit_registers; | ||
531 | |||
532 | return SCI_SUCCESS; | ||
533 | } | ||
534 | |||
535 | /** | ||
536 | * scic_port_get_properties() - This method simply returns the properties | ||
537 | * regarding the port, such as: physical index, protocols, sas address, etc. | ||
538 | * @port: this parameter specifies the port for which to retrieve the physical | ||
539 | * index. | ||
540 | * @properties: This parameter specifies the properties structure into which to | ||
541 | * copy the requested information. | ||
542 | * | ||
543 | * Indicate if the user specified a valid port. SCI_SUCCESS This value is | ||
544 | * returned if the specified port was valid. SCI_FAILURE_INVALID_PORT This | ||
545 | * value is returned if the specified port is not valid. When this value is | ||
546 | * returned, no data is copied to the properties output parameter. | ||
547 | */ | ||
548 | enum sci_status scic_port_get_properties( | ||
549 | struct scic_sds_port *port, | ||
550 | struct scic_port_properties *prop) | ||
551 | { | ||
552 | if ((port == NULL) || | ||
553 | (port->logical_port_index == SCIC_SDS_DUMMY_PORT)) | ||
554 | return SCI_FAILURE_INVALID_PORT; | ||
555 | |||
556 | prop->index = port->logical_port_index; | ||
557 | prop->phy_mask = scic_sds_port_get_phys(port); | ||
558 | scic_sds_port_get_sas_address(port, &prop->local.sas_address); | ||
559 | scic_sds_port_get_protocols(port, &prop->local.protocols); | ||
560 | scic_sds_port_get_attached_sas_address(port, &prop->remote.sas_address); | ||
561 | |||
562 | return SCI_SUCCESS; | ||
563 | } | ||
564 | |||
565 | /** | ||
566 | * scic_port_hard_reset() - perform port hard reset | ||
567 | * @port: a handle corresponding to the SAS port to be hard reset. | ||
568 | * @reset_timeout: This parameter specifies the number of milliseconds in which | ||
569 | * the port reset operation should complete. | ||
570 | * | ||
571 | * The SCI User callback in scic_user_callbacks_t will only be called once for | ||
572 | * each phy in the SAS Port at completion of the hard reset sequence. Return a | ||
573 | * status indicating whether the hard reset started successfully. SCI_SUCCESS | ||
574 | * This value is returned if the hard reset operation started successfully. | ||
575 | */ | ||
576 | enum sci_status scic_port_hard_reset( | ||
577 | struct scic_sds_port *port, | ||
578 | u32 reset_timeout) | ||
579 | { | ||
580 | return port->state_handlers->reset_handler( | ||
581 | port, reset_timeout); | ||
582 | } | ||
583 | |||
584 | /** | ||
585 | * This method assigns the direct attached device ID for this port. | ||
586 | * | ||
587 | * @param[in] sci_port The port for which the direct attached device id is to | ||
588 | * be assigned. | ||
589 | * @param[in] device_id The direct attached device ID to assign to the port. | ||
590 | * This will be the RNi for the device | ||
591 | */ | ||
592 | void scic_sds_port_setup_transports( | ||
593 | struct scic_sds_port *sci_port, | ||
594 | u32 device_id) | ||
595 | { | ||
596 | u8 index; | ||
597 | |||
598 | for (index = 0; index < SCI_MAX_PHYS; index++) { | ||
599 | if (sci_port->active_phy_mask & (1 << index)) | ||
600 | scic_sds_phy_setup_transport(sci_port->phy_table[index], device_id); | ||
601 | } | ||
602 | } | ||
603 | |||
604 | /** | ||
605 | * | ||
606 | * @sci_port: This is the port on which the phy should be enabled. | ||
607 | * @sci_phy: This is the specific phy which to enable. | ||
608 | * @do_notify_user: This parameter specifies whether to inform the user (via | ||
609 | * scic_cb_port_link_up()) as to the fact that a new phy as become ready. | ||
610 | * | ||
611 | * This function will activate the phy in the port. | ||
612 | * Activation includes: - adding | ||
613 | * the phy to the port - enabling the Protocol Engine in the silicon. - | ||
614 | * notifying the user that the link is up. none | ||
615 | */ | ||
616 | static void scic_sds_port_activate_phy(struct scic_sds_port *sci_port, | ||
617 | struct scic_sds_phy *sci_phy, | ||
618 | bool do_notify_user) | ||
619 | { | ||
620 | struct scic_sds_controller *scic = sci_port->owning_controller; | ||
621 | struct isci_host *ihost = scic_to_ihost(scic); | ||
622 | |||
623 | if (sci_phy->protocol != SCIC_SDS_PHY_PROTOCOL_SATA) | ||
624 | scic_sds_phy_resume(sci_phy); | ||
625 | |||
626 | sci_port->active_phy_mask |= 1 << sci_phy->phy_index; | ||
627 | |||
628 | scic_sds_controller_clear_invalid_phy(scic, sci_phy); | ||
629 | |||
630 | if (do_notify_user == true) | ||
631 | isci_port_link_up(ihost, sci_port, sci_phy); | ||
632 | } | ||
633 | |||
634 | void scic_sds_port_deactivate_phy(struct scic_sds_port *sci_port, | ||
635 | struct scic_sds_phy *sci_phy, | ||
636 | bool do_notify_user) | ||
637 | { | ||
638 | struct scic_sds_controller *scic = scic_sds_port_get_controller(sci_port); | ||
639 | struct isci_port *iport = sci_port_to_iport(sci_port); | ||
640 | struct isci_host *ihost = scic_to_ihost(scic); | ||
641 | struct isci_phy *iphy = sci_phy_to_iphy(sci_phy); | ||
642 | |||
643 | sci_port->active_phy_mask &= ~(1 << sci_phy->phy_index); | ||
644 | |||
645 | sci_phy->max_negotiated_speed = SAS_LINK_RATE_UNKNOWN; | ||
646 | |||
647 | /* Re-assign the phy back to the LP as if it were a narrow port */ | ||
648 | writel(sci_phy->phy_index, | ||
649 | &sci_port->port_pe_configuration_register[sci_phy->phy_index]); | ||
650 | |||
651 | if (do_notify_user == true) | ||
652 | isci_port_link_down(ihost, iphy, iport); | ||
653 | } | ||
654 | |||
655 | /** | ||
656 | * | ||
657 | * @sci_port: This is the port on which the phy should be disabled. | ||
658 | * @sci_phy: This is the specific phy which to disabled. | ||
659 | * | ||
660 | * This function will disable the phy and report that the phy is not valid for | ||
661 | * this port object. None | ||
662 | */ | ||
663 | static void scic_sds_port_invalid_link_up(struct scic_sds_port *sci_port, | ||
664 | struct scic_sds_phy *sci_phy) | ||
665 | { | ||
666 | struct scic_sds_controller *scic = sci_port->owning_controller; | ||
667 | |||
668 | /* | ||
669 | * Check to see if we have alreay reported this link as bad and if | ||
670 | * not go ahead and tell the SCI_USER that we have discovered an | ||
671 | * invalid link. | ||
672 | */ | ||
673 | if ((scic->invalid_phy_mask & (1 << sci_phy->phy_index)) == 0) { | ||
674 | scic_sds_controller_set_invalid_phy(scic, sci_phy); | ||
675 | dev_warn(&scic_to_ihost(scic)->pdev->dev, "Invalid link up!\n"); | ||
676 | } | ||
677 | } | ||
678 | |||
679 | /** | ||
680 | * scic_sds_port_general_link_up_handler - phy can be assigned to port? | ||
681 | * @sci_port: scic_sds_port object for which has a phy that has gone link up. | ||
682 | * @sci_phy: This is the struct scic_sds_phy object that has gone link up. | ||
683 | * @do_notify_user: This parameter specifies whether to inform the user (via | ||
684 | * scic_cb_port_link_up()) as to the fact that a new phy as become ready. | ||
685 | * | ||
686 | * Determine if this phy can be assigned to this | ||
687 | * port . If the phy is not a valid PHY for | ||
688 | * this port then the function will notify the user. A PHY can only be | ||
689 | * part of a port if it's attached SAS ADDRESS is the same as all other PHYs in | ||
690 | * the same port. none | ||
691 | */ | ||
692 | static void scic_sds_port_general_link_up_handler(struct scic_sds_port *sci_port, | ||
693 | struct scic_sds_phy *sci_phy, | ||
694 | bool do_notify_user) | ||
695 | { | ||
696 | struct sci_sas_address port_sas_address; | ||
697 | struct sci_sas_address phy_sas_address; | ||
698 | |||
699 | scic_sds_port_get_attached_sas_address(sci_port, &port_sas_address); | ||
700 | scic_sds_phy_get_attached_sas_address(sci_phy, &phy_sas_address); | ||
701 | |||
702 | /* If the SAS address of the new phy matches the SAS address of | ||
703 | * other phys in the port OR this is the first phy in the port, | ||
704 | * then activate the phy and allow it to be used for operations | ||
705 | * in this port. | ||
706 | */ | ||
707 | if ((phy_sas_address.high == port_sas_address.high && | ||
708 | phy_sas_address.low == port_sas_address.low) || | ||
709 | sci_port->active_phy_mask == 0) { | ||
710 | struct sci_base_state_machine *sm = &sci_port->state_machine; | ||
711 | |||
712 | scic_sds_port_activate_phy(sci_port, sci_phy, do_notify_user); | ||
713 | if (sm->current_state_id == SCI_BASE_PORT_STATE_RESETTING) | ||
714 | sci_base_state_machine_change_state(sm, SCI_BASE_PORT_STATE_READY); | ||
715 | } else | ||
716 | scic_sds_port_invalid_link_up(sci_port, sci_phy); | ||
717 | } | ||
718 | |||
719 | |||
720 | |||
721 | /** | ||
722 | * This method returns false if the port only has a single phy object assigned. | ||
723 | * If there are no phys or more than one phy then the method will return | ||
724 | * true. | ||
725 | * @sci_port: The port for which the wide port condition is to be checked. | ||
726 | * | ||
727 | * bool true Is returned if this is a wide ported port. false Is returned if | ||
728 | * this is a narrow port. | ||
729 | */ | ||
730 | static bool scic_sds_port_is_wide(struct scic_sds_port *sci_port) | ||
731 | { | ||
732 | u32 index; | ||
733 | u32 phy_count = 0; | ||
734 | |||
735 | for (index = 0; index < SCI_MAX_PHYS; index++) { | ||
736 | if (sci_port->phy_table[index] != NULL) { | ||
737 | phy_count++; | ||
738 | } | ||
739 | } | ||
740 | |||
741 | return phy_count != 1; | ||
742 | } | ||
743 | |||
744 | /** | ||
745 | * This method is called by the PHY object when the link is detected. if the | ||
746 | * port wants the PHY to continue on to the link up state then the port | ||
747 | * layer must return true. If the port object returns false the phy object | ||
748 | * must halt its attempt to go link up. | ||
749 | * @sci_port: The port associated with the phy object. | ||
750 | * @sci_phy: The phy object that is trying to go link up. | ||
751 | * | ||
752 | * true if the phy object can continue to the link up condition. true Is | ||
753 | * returned if this phy can continue to the ready state. false Is returned if | ||
754 | * can not continue on to the ready state. This notification is in place for | ||
755 | * wide ports and direct attached phys. Since there are no wide ported SATA | ||
756 | * devices this could become an invalid port configuration. | ||
757 | */ | ||
758 | bool scic_sds_port_link_detected( | ||
759 | struct scic_sds_port *sci_port, | ||
760 | struct scic_sds_phy *sci_phy) | ||
761 | { | ||
762 | if ((sci_port->logical_port_index != SCIC_SDS_DUMMY_PORT) && | ||
763 | (sci_phy->protocol == SCIC_SDS_PHY_PROTOCOL_SATA) && | ||
764 | scic_sds_port_is_wide(sci_port)) { | ||
765 | scic_sds_port_invalid_link_up(sci_port, sci_phy); | ||
766 | |||
767 | return false; | ||
768 | } | ||
769 | |||
770 | return true; | ||
771 | } | ||
772 | |||
773 | /** | ||
774 | * This method is the entry point for the phy to inform the port that it is now | ||
775 | * in a ready state | ||
776 | * @sci_port: | ||
777 | * | ||
778 | * | ||
779 | */ | ||
780 | void scic_sds_port_link_up( | ||
781 | struct scic_sds_port *sci_port, | ||
782 | struct scic_sds_phy *sci_phy) | ||
783 | { | ||
784 | sci_phy->is_in_link_training = false; | ||
785 | |||
786 | sci_port->state_handlers->link_up_handler(sci_port, sci_phy); | ||
787 | } | ||
788 | |||
789 | /** | ||
790 | * This method is the entry point for the phy to inform the port that it is no | ||
791 | * longer in a ready state | ||
792 | * @sci_port: | ||
793 | * | ||
794 | * | ||
795 | */ | ||
796 | void scic_sds_port_link_down( | ||
797 | struct scic_sds_port *sci_port, | ||
798 | struct scic_sds_phy *sci_phy) | ||
799 | { | ||
800 | sci_port->state_handlers->link_down_handler(sci_port, sci_phy); | ||
801 | } | ||
802 | |||
803 | /** | ||
804 | * This method is called to start an IO request on this port. | ||
805 | * @sci_port: | ||
806 | * @sci_dev: | ||
807 | * @sci_req: | ||
808 | * | ||
809 | * enum sci_status | ||
810 | */ | ||
811 | enum sci_status scic_sds_port_start_io( | ||
812 | struct scic_sds_port *sci_port, | ||
813 | struct scic_sds_remote_device *sci_dev, | ||
814 | struct scic_sds_request *sci_req) | ||
815 | { | ||
816 | return sci_port->state_handlers->start_io_handler( | ||
817 | sci_port, sci_dev, sci_req); | ||
818 | } | ||
819 | |||
820 | /** | ||
821 | * This method is called to complete an IO request to the port. | ||
822 | * @sci_port: | ||
823 | * @sci_dev: | ||
824 | * @sci_req: | ||
825 | * | ||
826 | * enum sci_status | ||
827 | */ | ||
828 | enum sci_status scic_sds_port_complete_io( | ||
829 | struct scic_sds_port *sci_port, | ||
830 | struct scic_sds_remote_device *sci_dev, | ||
831 | struct scic_sds_request *sci_req) | ||
832 | { | ||
833 | return sci_port->state_handlers->complete_io_handler( | ||
834 | sci_port, sci_dev, sci_req); | ||
835 | } | ||
836 | |||
837 | /** | ||
838 | * This method is provided to timeout requests for port operations. Mostly its | ||
839 | * for the port reset operation. | ||
840 | * | ||
841 | * | ||
842 | */ | ||
843 | static void scic_sds_port_timeout_handler(void *port) | ||
844 | { | ||
845 | struct scic_sds_port *sci_port = port; | ||
846 | u32 current_state; | ||
847 | |||
848 | current_state = sci_base_state_machine_get_state( | ||
849 | &sci_port->state_machine); | ||
850 | |||
851 | if (current_state == SCI_BASE_PORT_STATE_RESETTING) { | ||
852 | /* | ||
853 | * if the port is still in the resetting state then the | ||
854 | * timeout fired before the reset completed. | ||
855 | */ | ||
856 | sci_base_state_machine_change_state( | ||
857 | &sci_port->state_machine, | ||
858 | SCI_BASE_PORT_STATE_FAILED); | ||
859 | } else if (current_state == SCI_BASE_PORT_STATE_STOPPED) { | ||
860 | /* | ||
861 | * if the port is stopped then the start request failed | ||
862 | * In this case stay in the stopped state. | ||
863 | */ | ||
864 | dev_err(sciport_to_dev(sci_port), | ||
865 | "%s: SCIC Port 0x%p failed to stop before tiemout.\n", | ||
866 | __func__, | ||
867 | sci_port); | ||
868 | } else if (current_state == SCI_BASE_PORT_STATE_STOPPING) { | ||
869 | /* | ||
870 | * if the port is still stopping then the stop has not | ||
871 | * completed | ||
872 | */ | ||
873 | isci_port_stop_complete( | ||
874 | scic_sds_port_get_controller(sci_port), | ||
875 | sci_port, | ||
876 | SCI_FAILURE_TIMEOUT); | ||
877 | } else { | ||
878 | /* | ||
879 | * The port is in the ready state and we have a timer | ||
880 | * reporting a timeout this should not happen. | ||
881 | */ | ||
882 | dev_err(sciport_to_dev(sci_port), | ||
883 | "%s: SCIC Port 0x%p is processing a timeout operation " | ||
884 | "in state %d.\n", | ||
885 | __func__, | ||
886 | sci_port, | ||
887 | current_state); | ||
888 | } | ||
889 | } | ||
890 | |||
891 | /* --------------------------------------------------------------------------- */ | ||
892 | |||
893 | /** | ||
894 | * This function updates the hardwares VIIT entry for this port. | ||
895 | * | ||
896 | * | ||
897 | */ | ||
898 | static void scic_sds_port_update_viit_entry(struct scic_sds_port *sci_port) | ||
899 | { | ||
900 | struct sci_sas_address sas_address; | ||
901 | |||
902 | scic_sds_port_get_sas_address(sci_port, &sas_address); | ||
903 | |||
904 | writel(sas_address.high, | ||
905 | &sci_port->viit_registers->initiator_sas_address_hi); | ||
906 | writel(sas_address.low, | ||
907 | &sci_port->viit_registers->initiator_sas_address_lo); | ||
908 | |||
909 | /* This value get cleared just in case its not already cleared */ | ||
910 | writel(0, &sci_port->viit_registers->reserved); | ||
911 | |||
912 | /* We are required to update the status register last */ | ||
913 | writel(SCU_VIIT_ENTRY_ID_VIIT | | ||
914 | SCU_VIIT_IPPT_INITIATOR | | ||
915 | ((1 << sci_port->physical_port_index) << SCU_VIIT_ENTRY_LPVIE_SHIFT) | | ||
916 | SCU_VIIT_STATUS_ALL_VALID, | ||
917 | &sci_port->viit_registers->status); | ||
918 | } | ||
919 | |||
920 | /** | ||
921 | * This method returns the maximum allowed speed for data transfers on this | ||
922 | * port. This maximum allowed speed evaluates to the maximum speed of the | ||
923 | * slowest phy in the port. | ||
924 | * @sci_port: This parameter specifies the port for which to retrieve the | ||
925 | * maximum allowed speed. | ||
926 | * | ||
927 | * This method returns the maximum negotiated speed of the slowest phy in the | ||
928 | * port. | ||
929 | */ | ||
930 | enum sas_linkrate scic_sds_port_get_max_allowed_speed( | ||
931 | struct scic_sds_port *sci_port) | ||
932 | { | ||
933 | u16 index; | ||
934 | enum sas_linkrate max_allowed_speed = SAS_LINK_RATE_6_0_GBPS; | ||
935 | struct scic_sds_phy *phy = NULL; | ||
936 | |||
937 | /* | ||
938 | * Loop through all of the phys in this port and find the phy with the | ||
939 | * lowest maximum link rate. */ | ||
940 | for (index = 0; index < SCI_MAX_PHYS; index++) { | ||
941 | phy = sci_port->phy_table[index]; | ||
942 | if ( | ||
943 | (phy != NULL) | ||
944 | && (scic_sds_port_active_phy(sci_port, phy) == true) | ||
945 | && (phy->max_negotiated_speed < max_allowed_speed) | ||
946 | ) | ||
947 | max_allowed_speed = phy->max_negotiated_speed; | ||
948 | } | ||
949 | |||
950 | return max_allowed_speed; | ||
951 | } | ||
952 | |||
953 | |||
954 | /** | ||
955 | * This method passes the event to core user. | ||
956 | * @sci_port: The port that a BCN happens. | ||
957 | * @sci_phy: The phy that receives BCN. | ||
958 | * | ||
959 | */ | ||
960 | void scic_sds_port_broadcast_change_received( | ||
961 | struct scic_sds_port *sci_port, | ||
962 | struct scic_sds_phy *sci_phy) | ||
963 | { | ||
964 | struct scic_sds_controller *scic = sci_port->owning_controller; | ||
965 | struct isci_host *ihost = scic_to_ihost(scic); | ||
966 | |||
967 | /* notify the user. */ | ||
968 | isci_port_bc_change_received(ihost, sci_port, sci_phy); | ||
969 | } | ||
970 | |||
971 | |||
972 | /** | ||
973 | * This API methhod enables the broadcast change notification from underneath | ||
974 | * hardware. | ||
975 | * @sci_port: The port that a BCN had been disabled from. | ||
976 | * | ||
977 | */ | ||
978 | void scic_port_enable_broadcast_change_notification( | ||
979 | struct scic_sds_port *port) | ||
980 | { | ||
981 | struct scic_sds_phy *phy; | ||
982 | u32 register_value; | ||
983 | u8 index; | ||
984 | |||
985 | /* Loop through all of the phys to enable BCN. */ | ||
986 | for (index = 0; index < SCI_MAX_PHYS; index++) { | ||
987 | phy = port->phy_table[index]; | ||
988 | if (phy != NULL) { | ||
989 | register_value = | ||
990 | readl(&phy->link_layer_registers->link_layer_control); | ||
991 | |||
992 | /* clear the bit by writing 1. */ | ||
993 | writel(register_value, | ||
994 | &phy->link_layer_registers->link_layer_control); | ||
995 | } | ||
996 | } | ||
997 | } | ||
998 | |||
999 | /* | ||
1000 | * **************************************************************************** | ||
1001 | * * READY SUBSTATE HANDLERS | ||
1002 | * **************************************************************************** */ | ||
1003 | |||
1004 | /* | ||
1005 | * This method is the general ready state stop handler for the struct scic_sds_port | ||
1006 | * object. This function will transition the ready substate machine to its | ||
1007 | * final state. enum sci_status SCI_SUCCESS | ||
1008 | */ | ||
1009 | static enum sci_status scic_sds_port_ready_substate_stop_handler( | ||
1010 | struct scic_sds_port *port) | ||
1011 | { | ||
1012 | sci_base_state_machine_change_state( | ||
1013 | &port->state_machine, | ||
1014 | SCI_BASE_PORT_STATE_STOPPING | ||
1015 | ); | ||
1016 | |||
1017 | return SCI_SUCCESS; | ||
1018 | } | ||
1019 | |||
1020 | /* | ||
1021 | * This method is the general ready substate complete io handler for the | ||
1022 | * struct scic_sds_port object. This function decrments the outstanding request count | ||
1023 | * for this port object. enum sci_status SCI_SUCCESS | ||
1024 | */ | ||
1025 | static enum sci_status scic_sds_port_ready_substate_complete_io_handler( | ||
1026 | struct scic_sds_port *port, | ||
1027 | struct scic_sds_remote_device *device, | ||
1028 | struct scic_sds_request *io_request) | ||
1029 | { | ||
1030 | scic_sds_port_decrement_request_count(port); | ||
1031 | |||
1032 | return SCI_SUCCESS; | ||
1033 | } | ||
1034 | |||
1035 | static enum sci_status scic_sds_port_ready_substate_add_phy_handler( | ||
1036 | struct scic_sds_port *port, | ||
1037 | struct scic_sds_phy *phy) | ||
1038 | { | ||
1039 | enum sci_status status; | ||
1040 | |||
1041 | status = scic_sds_port_set_phy(port, phy); | ||
1042 | |||
1043 | if (status == SCI_SUCCESS) { | ||
1044 | scic_sds_port_general_link_up_handler(port, phy, true); | ||
1045 | |||
1046 | port->not_ready_reason = SCIC_PORT_NOT_READY_RECONFIGURING; | ||
1047 | |||
1048 | sci_base_state_machine_change_state( | ||
1049 | &port->ready_substate_machine, | ||
1050 | SCIC_SDS_PORT_READY_SUBSTATE_CONFIGURING | ||
1051 | ); | ||
1052 | } | ||
1053 | |||
1054 | return status; | ||
1055 | } | ||
1056 | |||
1057 | |||
1058 | static enum sci_status scic_sds_port_ready_substate_remove_phy_handler( | ||
1059 | struct scic_sds_port *port, | ||
1060 | struct scic_sds_phy *phy) | ||
1061 | { | ||
1062 | enum sci_status status; | ||
1063 | |||
1064 | status = scic_sds_port_clear_phy(port, phy); | ||
1065 | |||
1066 | if (status == SCI_SUCCESS) { | ||
1067 | scic_sds_port_deactivate_phy(port, phy, true); | ||
1068 | |||
1069 | port->not_ready_reason = SCIC_PORT_NOT_READY_RECONFIGURING; | ||
1070 | |||
1071 | sci_base_state_machine_change_state( | ||
1072 | &port->ready_substate_machine, | ||
1073 | SCIC_SDS_PORT_READY_SUBSTATE_CONFIGURING | ||
1074 | ); | ||
1075 | } | ||
1076 | |||
1077 | return status; | ||
1078 | } | ||
1079 | |||
1080 | /* | ||
1081 | * **************************************************************************** | ||
1082 | * * READY SUBSTATE WAITING HANDLERS | ||
1083 | * **************************************************************************** */ | ||
1084 | |||
1085 | /** | ||
1086 | * | ||
1087 | * @sci_port: This is the struct scic_sds_port object that which has a phy that has | ||
1088 | * gone link up. | ||
1089 | * @sci_phy: This is the struct scic_sds_phy object that has gone link up. | ||
1090 | * | ||
1091 | * This method is the ready waiting substate link up handler for the | ||
1092 | * struct scic_sds_port object. This methos will report the link up condition for | ||
1093 | * this port and will transition to the ready operational substate. none | ||
1094 | */ | ||
1095 | static void scic_sds_port_ready_waiting_substate_link_up_handler( | ||
1096 | struct scic_sds_port *sci_port, | ||
1097 | struct scic_sds_phy *sci_phy) | ||
1098 | { | ||
1099 | /* | ||
1100 | * Since this is the first phy going link up for the port we can just enable | ||
1101 | * it and continue. */ | ||
1102 | scic_sds_port_activate_phy(sci_port, sci_phy, true); | ||
1103 | |||
1104 | sci_base_state_machine_change_state( | ||
1105 | &sci_port->ready_substate_machine, | ||
1106 | SCIC_SDS_PORT_READY_SUBSTATE_OPERATIONAL | ||
1107 | ); | ||
1108 | } | ||
1109 | |||
1110 | /* | ||
1111 | * This method is the ready waiting substate start io handler for the | ||
1112 | * struct scic_sds_port object. The port object can not accept new requests so the | ||
1113 | * request is failed. enum sci_status SCI_FAILURE_INVALID_STATE | ||
1114 | */ | ||
1115 | static enum sci_status scic_sds_port_ready_waiting_substate_start_io_handler( | ||
1116 | struct scic_sds_port *port, | ||
1117 | struct scic_sds_remote_device *device, | ||
1118 | struct scic_sds_request *io_request) | ||
1119 | { | ||
1120 | return SCI_FAILURE_INVALID_STATE; | ||
1121 | } | ||
1122 | |||
1123 | /* | ||
1124 | * **************************************************************************** | ||
1125 | * * READY SUBSTATE OPERATIONAL HANDLERS | ||
1126 | * **************************************************************************** */ | ||
1127 | |||
1128 | /* | ||
1129 | * This method will casue the port to reset. enum sci_status SCI_SUCCESS | ||
1130 | */ | ||
1131 | static enum | ||
1132 | sci_status scic_sds_port_ready_operational_substate_reset_handler( | ||
1133 | struct scic_sds_port *port, | ||
1134 | u32 timeout) | ||
1135 | { | ||
1136 | enum sci_status status = SCI_FAILURE_INVALID_PHY; | ||
1137 | u32 phy_index; | ||
1138 | struct scic_sds_phy *selected_phy = NULL; | ||
1139 | |||
1140 | |||
1141 | /* Select a phy on which we can send the hard reset request. */ | ||
1142 | for (phy_index = 0; | ||
1143 | (phy_index < SCI_MAX_PHYS) && (selected_phy == NULL); | ||
1144 | phy_index++) { | ||
1145 | selected_phy = port->phy_table[phy_index]; | ||
1146 | |||
1147 | if ((selected_phy != NULL) && | ||
1148 | !scic_sds_port_active_phy(port, selected_phy)) { | ||
1149 | /* | ||
1150 | * We found a phy but it is not ready select | ||
1151 | * different phy | ||
1152 | */ | ||
1153 | selected_phy = NULL; | ||
1154 | } | ||
1155 | } | ||
1156 | |||
1157 | /* If we have a phy then go ahead and start the reset procedure */ | ||
1158 | if (selected_phy != NULL) { | ||
1159 | status = scic_sds_phy_reset(selected_phy); | ||
1160 | |||
1161 | if (status == SCI_SUCCESS) { | ||
1162 | isci_timer_start(port->timer_handle, timeout); | ||
1163 | port->not_ready_reason = | ||
1164 | SCIC_PORT_NOT_READY_HARD_RESET_REQUESTED; | ||
1165 | |||
1166 | sci_base_state_machine_change_state( | ||
1167 | &port->state_machine, | ||
1168 | SCI_BASE_PORT_STATE_RESETTING); | ||
1169 | } | ||
1170 | } | ||
1171 | |||
1172 | return status; | ||
1173 | } | ||
1174 | |||
1175 | /** | ||
1176 | * scic_sds_port_ready_operational_substate_link_up_handler() - | ||
1177 | * @sci_port: This is the struct scic_sds_port object that which has a phy that has | ||
1178 | * gone link up. | ||
1179 | * @sci_phy: This is the struct scic_sds_phy object that has gone link up. | ||
1180 | * | ||
1181 | * This method is the ready operational substate link up handler for the | ||
1182 | * struct scic_sds_port object. This function notifies the SCI User that the phy has | ||
1183 | * gone link up. none | ||
1184 | */ | ||
1185 | static void scic_sds_port_ready_operational_substate_link_up_handler( | ||
1186 | struct scic_sds_port *sci_port, | ||
1187 | struct scic_sds_phy *sci_phy) | ||
1188 | { | ||
1189 | scic_sds_port_general_link_up_handler(sci_port, sci_phy, true); | ||
1190 | } | ||
1191 | |||
1192 | /** | ||
1193 | * scic_sds_port_ready_operational_substate_link_down_handler() - | ||
1194 | * @sci_port: This is the struct scic_sds_port object that which has a phy that has | ||
1195 | * gone link down. | ||
1196 | * @sci_phy: This is the struct scic_sds_phy object that has gone link down. | ||
1197 | * | ||
1198 | * This method is the ready operational substate link down handler for the | ||
1199 | * struct scic_sds_port object. This function notifies the SCI User that the phy has | ||
1200 | * gone link down and if this is the last phy in the port the port will change | ||
1201 | * state to the ready waiting substate. none | ||
1202 | */ | ||
1203 | static void scic_sds_port_ready_operational_substate_link_down_handler( | ||
1204 | struct scic_sds_port *sci_port, | ||
1205 | struct scic_sds_phy *sci_phy) | ||
1206 | { | ||
1207 | scic_sds_port_deactivate_phy(sci_port, sci_phy, true); | ||
1208 | |||
1209 | /* | ||
1210 | * If there are no active phys left in the port, then transition | ||
1211 | * the port to the WAITING state until such time as a phy goes | ||
1212 | * link up. */ | ||
1213 | if (sci_port->active_phy_mask == 0) | ||
1214 | sci_base_state_machine_change_state(&sci_port->ready_substate_machine, | ||
1215 | SCIC_SDS_PORT_READY_SUBSTATE_WAITING); | ||
1216 | } | ||
1217 | |||
1218 | /* | ||
1219 | * This method is the ready operational substate start io handler for the | ||
1220 | * struct scic_sds_port object. This function incremetns the outstanding request | ||
1221 | * count for this port object. enum sci_status SCI_SUCCESS | ||
1222 | */ | ||
1223 | static enum sci_status scic_sds_port_ready_operational_substate_start_io_handler( | ||
1224 | struct scic_sds_port *port, | ||
1225 | struct scic_sds_remote_device *device, | ||
1226 | struct scic_sds_request *io_request) | ||
1227 | { | ||
1228 | port->started_request_count++; | ||
1229 | return SCI_SUCCESS; | ||
1230 | } | ||
1231 | |||
1232 | /* | ||
1233 | * **************************************************************************** | ||
1234 | * * READY SUBSTATE OPERATIONAL HANDLERS | ||
1235 | * **************************************************************************** */ | ||
1236 | |||
1237 | /* | ||
1238 | * This is the default method for a port add phy request. It will report a | ||
1239 | * warning and exit. enum sci_status SCI_FAILURE_INVALID_STATE | ||
1240 | */ | ||
1241 | static enum sci_status scic_sds_port_ready_configuring_substate_add_phy_handler( | ||
1242 | struct scic_sds_port *port, | ||
1243 | struct scic_sds_phy *phy) | ||
1244 | { | ||
1245 | enum sci_status status; | ||
1246 | |||
1247 | status = scic_sds_port_set_phy(port, phy); | ||
1248 | |||
1249 | if (status == SCI_SUCCESS) { | ||
1250 | scic_sds_port_general_link_up_handler(port, phy, true); | ||
1251 | |||
1252 | /* | ||
1253 | * Re-enter the configuring state since this may be the last phy in | ||
1254 | * the port. */ | ||
1255 | sci_base_state_machine_change_state( | ||
1256 | &port->ready_substate_machine, | ||
1257 | SCIC_SDS_PORT_READY_SUBSTATE_CONFIGURING | ||
1258 | ); | ||
1259 | } | ||
1260 | |||
1261 | return status; | ||
1262 | } | ||
1263 | |||
1264 | /* | ||
1265 | * This is the default method for a port remove phy request. It will report a | ||
1266 | * warning and exit. enum sci_status SCI_FAILURE_INVALID_STATE | ||
1267 | */ | ||
1268 | static enum sci_status scic_sds_port_ready_configuring_substate_remove_phy_handler( | ||
1269 | struct scic_sds_port *port, | ||
1270 | struct scic_sds_phy *phy) | ||
1271 | { | ||
1272 | enum sci_status status; | ||
1273 | |||
1274 | status = scic_sds_port_clear_phy(port, phy); | ||
1275 | |||
1276 | if (status == SCI_SUCCESS) { | ||
1277 | scic_sds_port_deactivate_phy(port, phy, true); | ||
1278 | |||
1279 | /* | ||
1280 | * Re-enter the configuring state since this may be the last phy in | ||
1281 | * the port. */ | ||
1282 | sci_base_state_machine_change_state( | ||
1283 | &port->ready_substate_machine, | ||
1284 | SCIC_SDS_PORT_READY_SUBSTATE_CONFIGURING | ||
1285 | ); | ||
1286 | } | ||
1287 | |||
1288 | return status; | ||
1289 | } | ||
1290 | |||
1291 | /** | ||
1292 | * scic_sds_port_ready_configuring_substate_complete_io_handler() - | ||
1293 | * @port: This is the port that is being requested to complete the io request. | ||
1294 | * @device: This is the device on which the io is completing. | ||
1295 | * | ||
1296 | * This method will decrement the outstanding request count for this port. If | ||
1297 | * the request count goes to 0 then the port can be reprogrammed with its new | ||
1298 | * phy data. | ||
1299 | */ | ||
1300 | static enum sci_status | ||
1301 | scic_sds_port_ready_configuring_substate_complete_io_handler( | ||
1302 | struct scic_sds_port *port, | ||
1303 | struct scic_sds_remote_device *device, | ||
1304 | struct scic_sds_request *io_request) | ||
1305 | { | ||
1306 | scic_sds_port_decrement_request_count(port); | ||
1307 | |||
1308 | if (port->started_request_count == 0) { | ||
1309 | sci_base_state_machine_change_state( | ||
1310 | &port->ready_substate_machine, | ||
1311 | SCIC_SDS_PORT_READY_SUBSTATE_OPERATIONAL | ||
1312 | ); | ||
1313 | } | ||
1314 | |||
1315 | return SCI_SUCCESS; | ||
1316 | } | ||
1317 | |||
1318 | static enum sci_status default_port_handler(struct scic_sds_port *sci_port, | ||
1319 | const char *func) | ||
1320 | { | ||
1321 | dev_warn(sciport_to_dev(sci_port), | ||
1322 | "%s: in wrong state: %d\n", func, | ||
1323 | sci_base_state_machine_get_state(&sci_port->state_machine)); | ||
1324 | return SCI_FAILURE_INVALID_STATE; | ||
1325 | } | ||
1326 | |||
1327 | static enum sci_status | ||
1328 | scic_sds_port_default_start_handler(struct scic_sds_port *sci_port) | ||
1329 | { | ||
1330 | return default_port_handler(sci_port, __func__); | ||
1331 | } | ||
1332 | |||
1333 | static enum sci_status | ||
1334 | scic_sds_port_default_stop_handler(struct scic_sds_port *sci_port) | ||
1335 | { | ||
1336 | return default_port_handler(sci_port, __func__); | ||
1337 | } | ||
1338 | |||
1339 | static enum sci_status | ||
1340 | scic_sds_port_default_destruct_handler(struct scic_sds_port *sci_port) | ||
1341 | { | ||
1342 | return default_port_handler(sci_port, __func__); | ||
1343 | } | ||
1344 | |||
1345 | static enum sci_status | ||
1346 | scic_sds_port_default_reset_handler(struct scic_sds_port *sci_port, | ||
1347 | u32 timeout) | ||
1348 | { | ||
1349 | return default_port_handler(sci_port, __func__); | ||
1350 | } | ||
1351 | |||
1352 | static enum sci_status | ||
1353 | scic_sds_port_default_add_phy_handler(struct scic_sds_port *sci_port, | ||
1354 | struct scic_sds_phy *base_phy) | ||
1355 | { | ||
1356 | return default_port_handler(sci_port, __func__); | ||
1357 | } | ||
1358 | |||
1359 | static enum sci_status | ||
1360 | scic_sds_port_default_remove_phy_handler(struct scic_sds_port *sci_port, | ||
1361 | struct scic_sds_phy *base_phy) | ||
1362 | { | ||
1363 | return default_port_handler(sci_port, __func__); | ||
1364 | } | ||
1365 | |||
1366 | /* | ||
1367 | * This is the default method for a port unsolicited frame request. It will | ||
1368 | * report a warning and exit. enum sci_status SCI_FAILURE_INVALID_STATE Is it even | ||
1369 | * possible to receive an unsolicited frame directed to a port object? It | ||
1370 | * seems possible if we implementing virtual functions but until then? | ||
1371 | */ | ||
1372 | static enum sci_status | ||
1373 | scic_sds_port_default_frame_handler(struct scic_sds_port *sci_port, | ||
1374 | u32 frame_index) | ||
1375 | { | ||
1376 | struct scic_sds_controller *scic = scic_sds_port_get_controller(sci_port); | ||
1377 | |||
1378 | default_port_handler(sci_port, __func__); | ||
1379 | scic_sds_controller_release_frame(scic, frame_index); | ||
1380 | |||
1381 | return SCI_FAILURE_INVALID_STATE; | ||
1382 | } | ||
1383 | |||
1384 | static enum sci_status scic_sds_port_default_event_handler(struct scic_sds_port *sci_port, | ||
1385 | u32 event_code) | ||
1386 | { | ||
1387 | return default_port_handler(sci_port, __func__); | ||
1388 | } | ||
1389 | |||
1390 | static void scic_sds_port_default_link_up_handler(struct scic_sds_port *sci_port, | ||
1391 | struct scic_sds_phy *sci_phy) | ||
1392 | { | ||
1393 | default_port_handler(sci_port, __func__); | ||
1394 | } | ||
1395 | |||
1396 | static void scic_sds_port_default_link_down_handler(struct scic_sds_port *sci_port, | ||
1397 | struct scic_sds_phy *sci_phy) | ||
1398 | { | ||
1399 | default_port_handler(sci_port, __func__); | ||
1400 | } | ||
1401 | |||
1402 | static enum sci_status scic_sds_port_default_start_io_handler(struct scic_sds_port *sci_port, | ||
1403 | struct scic_sds_remote_device *sci_dev, | ||
1404 | struct scic_sds_request *sci_req) | ||
1405 | { | ||
1406 | return default_port_handler(sci_port, __func__); | ||
1407 | } | ||
1408 | |||
1409 | static enum sci_status scic_sds_port_default_complete_io_handler(struct scic_sds_port *sci_port, | ||
1410 | struct scic_sds_remote_device *sci_dev, | ||
1411 | struct scic_sds_request *sci_req) | ||
1412 | { | ||
1413 | return default_port_handler(sci_port, __func__); | ||
1414 | } | ||
1415 | |||
1416 | |||
1417 | |||
1418 | static struct scic_sds_port_state_handler | ||
1419 | scic_sds_port_ready_substate_handler_table[SCIC_SDS_PORT_READY_MAX_SUBSTATES] = { | ||
1420 | { | ||
1421 | /* SCIC_SDS_PORT_READY_SUBSTATE_WAITING */ | ||
1422 | scic_sds_port_default_start_handler, | ||
1423 | scic_sds_port_ready_substate_stop_handler, | ||
1424 | scic_sds_port_default_destruct_handler, | ||
1425 | scic_sds_port_default_reset_handler, | ||
1426 | scic_sds_port_ready_substate_add_phy_handler, | ||
1427 | scic_sds_port_default_remove_phy_handler, | ||
1428 | scic_sds_port_default_frame_handler, | ||
1429 | scic_sds_port_default_event_handler, | ||
1430 | scic_sds_port_ready_waiting_substate_link_up_handler, | ||
1431 | scic_sds_port_default_link_down_handler, | ||
1432 | scic_sds_port_ready_waiting_substate_start_io_handler, | ||
1433 | scic_sds_port_ready_substate_complete_io_handler, | ||
1434 | }, | ||
1435 | |||
1436 | { | ||
1437 | /* SCIC_SDS_PORT_READY_SUBSTATE_OPERATIONAL */ | ||
1438 | scic_sds_port_default_start_handler, | ||
1439 | scic_sds_port_ready_substate_stop_handler, | ||
1440 | scic_sds_port_default_destruct_handler, | ||
1441 | scic_sds_port_ready_operational_substate_reset_handler, | ||
1442 | scic_sds_port_ready_substate_add_phy_handler, | ||
1443 | scic_sds_port_ready_substate_remove_phy_handler, | ||
1444 | scic_sds_port_default_frame_handler, | ||
1445 | scic_sds_port_default_event_handler, | ||
1446 | scic_sds_port_ready_operational_substate_link_up_handler, | ||
1447 | scic_sds_port_ready_operational_substate_link_down_handler, | ||
1448 | scic_sds_port_ready_operational_substate_start_io_handler, | ||
1449 | scic_sds_port_ready_substate_complete_io_handler, | ||
1450 | }, | ||
1451 | |||
1452 | { | ||
1453 | /* SCIC_SDS_PORT_READY_SUBSTATE_CONFIGURING */ | ||
1454 | scic_sds_port_default_start_handler, | ||
1455 | scic_sds_port_ready_substate_stop_handler, | ||
1456 | scic_sds_port_default_destruct_handler, | ||
1457 | scic_sds_port_default_reset_handler, | ||
1458 | scic_sds_port_ready_configuring_substate_add_phy_handler, | ||
1459 | scic_sds_port_ready_configuring_substate_remove_phy_handler, | ||
1460 | scic_sds_port_default_frame_handler, | ||
1461 | scic_sds_port_default_event_handler, | ||
1462 | scic_sds_port_default_link_up_handler, | ||
1463 | scic_sds_port_default_link_down_handler, | ||
1464 | scic_sds_port_default_start_io_handler, | ||
1465 | scic_sds_port_ready_configuring_substate_complete_io_handler | ||
1466 | } | ||
1467 | }; | ||
1468 | |||
1469 | /** | ||
1470 | * scic_sds_port_set_ready_state_handlers() - | ||
1471 | * | ||
1472 | * This macro sets the port ready substate handlers. | ||
1473 | */ | ||
1474 | #define scic_sds_port_set_ready_state_handlers(port, state_id) \ | ||
1475 | scic_sds_port_set_state_handlers(\ | ||
1476 | port, &scic_sds_port_ready_substate_handler_table[(state_id)] \ | ||
1477 | ) | ||
1478 | |||
1479 | /* | ||
1480 | * ****************************************************************************** | ||
1481 | * * PORT STATE PRIVATE METHODS | ||
1482 | * ****************************************************************************** */ | ||
1483 | |||
1484 | /** | ||
1485 | * | ||
1486 | * @sci_port: This is the struct scic_sds_port object to suspend. | ||
1487 | * | ||
1488 | * This method will susped the port task scheduler for this port object. none | ||
1489 | */ | ||
1490 | static void | ||
1491 | scic_sds_port_suspend_port_task_scheduler(struct scic_sds_port *port) | ||
1492 | { | ||
1493 | u32 pts_control_value; | ||
1494 | |||
1495 | pts_control_value = readl(&port->port_task_scheduler_registers->control); | ||
1496 | pts_control_value |= SCU_PTSxCR_GEN_BIT(SUSPEND); | ||
1497 | writel(pts_control_value, &port->port_task_scheduler_registers->control); | ||
1498 | } | ||
1499 | |||
1500 | /** | ||
1501 | * scic_sds_port_post_dummy_request() - post dummy/workaround request | ||
1502 | * @sci_port: port to post task | ||
1503 | * | ||
1504 | * Prevent the hardware scheduler from posting new requests to the front | ||
1505 | * of the scheduler queue causing a starvation problem for currently | ||
1506 | * ongoing requests. | ||
1507 | * | ||
1508 | */ | ||
1509 | static void scic_sds_port_post_dummy_request(struct scic_sds_port *sci_port) | ||
1510 | { | ||
1511 | u32 command; | ||
1512 | struct scu_task_context *task_context; | ||
1513 | struct scic_sds_controller *scic = sci_port->owning_controller; | ||
1514 | u16 tci = sci_port->reserved_tci; | ||
1515 | |||
1516 | task_context = scic_sds_controller_get_task_context_buffer(scic, tci); | ||
1517 | |||
1518 | task_context->abort = 0; | ||
1519 | |||
1520 | command = SCU_CONTEXT_COMMAND_REQUEST_TYPE_POST_TC | | ||
1521 | sci_port->physical_port_index << SCU_CONTEXT_COMMAND_LOGICAL_PORT_SHIFT | | ||
1522 | tci; | ||
1523 | |||
1524 | scic_sds_controller_post_request(scic, command); | ||
1525 | } | ||
1526 | |||
1527 | /** | ||
1528 | * This routine will abort the dummy request. This will alow the hardware to | ||
1529 | * power down parts of the silicon to save power. | ||
1530 | * | ||
1531 | * @sci_port: The port on which the task must be aborted. | ||
1532 | * | ||
1533 | */ | ||
1534 | static void scic_sds_port_abort_dummy_request(struct scic_sds_port *sci_port) | ||
1535 | { | ||
1536 | struct scic_sds_controller *scic = sci_port->owning_controller; | ||
1537 | u16 tci = sci_port->reserved_tci; | ||
1538 | struct scu_task_context *tc; | ||
1539 | u32 command; | ||
1540 | |||
1541 | tc = scic_sds_controller_get_task_context_buffer(scic, tci); | ||
1542 | |||
1543 | tc->abort = 1; | ||
1544 | |||
1545 | command = SCU_CONTEXT_COMMAND_REQUEST_POST_TC_ABORT | | ||
1546 | sci_port->physical_port_index << SCU_CONTEXT_COMMAND_LOGICAL_PORT_SHIFT | | ||
1547 | tci; | ||
1548 | |||
1549 | scic_sds_controller_post_request(scic, command); | ||
1550 | } | ||
1551 | |||
1552 | /** | ||
1553 | * | ||
1554 | * @sci_port: This is the struct scic_sds_port object to resume. | ||
1555 | * | ||
1556 | * This method will resume the port task scheduler for this port object. none | ||
1557 | */ | ||
1558 | static void | ||
1559 | scic_sds_port_resume_port_task_scheduler(struct scic_sds_port *port) | ||
1560 | { | ||
1561 | u32 pts_control_value; | ||
1562 | |||
1563 | pts_control_value = readl(&port->port_task_scheduler_registers->control); | ||
1564 | pts_control_value &= ~SCU_PTSxCR_GEN_BIT(SUSPEND); | ||
1565 | writel(pts_control_value, &port->port_task_scheduler_registers->control); | ||
1566 | } | ||
1567 | |||
1568 | /* | ||
1569 | * ****************************************************************************** | ||
1570 | * * PORT READY SUBSTATE METHODS | ||
1571 | * ****************************************************************************** */ | ||
1572 | |||
1573 | /** | ||
1574 | * | ||
1575 | * @object: This is the object which is cast to a struct scic_sds_port object. | ||
1576 | * | ||
1577 | * This method will perform the actions required by the struct scic_sds_port on | ||
1578 | * entering the SCIC_SDS_PORT_READY_SUBSTATE_WAITING. This function checks the | ||
1579 | * port for any ready phys. If there is at least one phy in a ready state then | ||
1580 | * the port transitions to the ready operational substate. none | ||
1581 | */ | ||
1582 | static void scic_sds_port_ready_substate_waiting_enter(void *object) | ||
1583 | { | ||
1584 | struct scic_sds_port *sci_port = object; | ||
1585 | |||
1586 | scic_sds_port_set_ready_state_handlers( | ||
1587 | sci_port, SCIC_SDS_PORT_READY_SUBSTATE_WAITING | ||
1588 | ); | ||
1589 | |||
1590 | scic_sds_port_suspend_port_task_scheduler(sci_port); | ||
1591 | |||
1592 | sci_port->not_ready_reason = SCIC_PORT_NOT_READY_NO_ACTIVE_PHYS; | ||
1593 | |||
1594 | if (sci_port->active_phy_mask != 0) { | ||
1595 | /* At least one of the phys on the port is ready */ | ||
1596 | sci_base_state_machine_change_state( | ||
1597 | &sci_port->ready_substate_machine, | ||
1598 | SCIC_SDS_PORT_READY_SUBSTATE_OPERATIONAL | ||
1599 | ); | ||
1600 | } | ||
1601 | } | ||
1602 | |||
1603 | /** | ||
1604 | * | ||
1605 | * @object: This is the object which is cast to a struct scic_sds_port object. | ||
1606 | * | ||
1607 | * This function will perform the actions required by the struct scic_sds_port | ||
1608 | * on entering the SCIC_SDS_PORT_READY_SUBSTATE_OPERATIONAL. This function sets | ||
1609 | * the state handlers for the port object, notifies the SCI User that the port | ||
1610 | * is ready, and resumes port operations. none | ||
1611 | */ | ||
1612 | static void scic_sds_port_ready_substate_operational_enter(void *object) | ||
1613 | { | ||
1614 | u32 index; | ||
1615 | struct scic_sds_port *sci_port = object; | ||
1616 | struct scic_sds_controller *scic = sci_port->owning_controller; | ||
1617 | struct isci_host *ihost = scic_to_ihost(scic); | ||
1618 | struct isci_port *iport = sci_port_to_iport(sci_port); | ||
1619 | |||
1620 | scic_sds_port_set_ready_state_handlers( | ||
1621 | sci_port, | ||
1622 | SCIC_SDS_PORT_READY_SUBSTATE_OPERATIONAL); | ||
1623 | |||
1624 | isci_port_ready(ihost, iport); | ||
1625 | |||
1626 | for (index = 0; index < SCI_MAX_PHYS; index++) { | ||
1627 | if (sci_port->phy_table[index]) { | ||
1628 | writel(sci_port->physical_port_index, | ||
1629 | &sci_port->port_pe_configuration_register[ | ||
1630 | sci_port->phy_table[index]->phy_index]); | ||
1631 | } | ||
1632 | } | ||
1633 | |||
1634 | scic_sds_port_update_viit_entry(sci_port); | ||
1635 | |||
1636 | scic_sds_port_resume_port_task_scheduler(sci_port); | ||
1637 | |||
1638 | /* | ||
1639 | * Post the dummy task for the port so the hardware can schedule | ||
1640 | * io correctly | ||
1641 | */ | ||
1642 | scic_sds_port_post_dummy_request(sci_port); | ||
1643 | } | ||
1644 | |||
1645 | /** | ||
1646 | * | ||
1647 | * @object: This is the object which is cast to a struct scic_sds_port object. | ||
1648 | * | ||
1649 | * This method will perform the actions required by the struct scic_sds_port on | ||
1650 | * exiting the SCIC_SDS_PORT_READY_SUBSTATE_OPERATIONAL. This function reports | ||
1651 | * the port not ready and suspends the port task scheduler. none | ||
1652 | */ | ||
1653 | static void scic_sds_port_ready_substate_operational_exit(void *object) | ||
1654 | { | ||
1655 | struct scic_sds_port *sci_port = object; | ||
1656 | struct scic_sds_controller *scic = sci_port->owning_controller; | ||
1657 | struct isci_host *ihost = scic_to_ihost(scic); | ||
1658 | struct isci_port *iport = sci_port_to_iport(sci_port); | ||
1659 | |||
1660 | /* | ||
1661 | * Kill the dummy task for this port if it has not yet posted | ||
1662 | * the hardware will treat this as a NOP and just return abort | ||
1663 | * complete. | ||
1664 | */ | ||
1665 | scic_sds_port_abort_dummy_request(sci_port); | ||
1666 | |||
1667 | isci_port_not_ready(ihost, iport); | ||
1668 | } | ||
1669 | |||
1670 | /* | ||
1671 | * ****************************************************************************** | ||
1672 | * * PORT READY CONFIGURING METHODS | ||
1673 | * ****************************************************************************** */ | ||
1674 | |||
1675 | /** | ||
1676 | * scic_sds_port_ready_substate_configuring_enter() - | ||
1677 | * @object: This is the object which is cast to a struct scic_sds_port object. | ||
1678 | * | ||
1679 | * This method will perform the actions required by the struct scic_sds_port on | ||
1680 | * exiting the SCIC_SDS_PORT_READY_SUBSTATE_OPERATIONAL. This function reports | ||
1681 | * the port not ready and suspends the port task scheduler. none | ||
1682 | */ | ||
1683 | static void scic_sds_port_ready_substate_configuring_enter(void *object) | ||
1684 | { | ||
1685 | struct scic_sds_port *sci_port = object; | ||
1686 | struct scic_sds_controller *scic = sci_port->owning_controller; | ||
1687 | struct isci_host *ihost = scic_to_ihost(scic); | ||
1688 | struct isci_port *iport = sci_port_to_iport(sci_port); | ||
1689 | |||
1690 | scic_sds_port_set_ready_state_handlers( | ||
1691 | sci_port, | ||
1692 | SCIC_SDS_PORT_READY_SUBSTATE_CONFIGURING); | ||
1693 | |||
1694 | if (sci_port->active_phy_mask == 0) { | ||
1695 | isci_port_not_ready(ihost, iport); | ||
1696 | |||
1697 | sci_base_state_machine_change_state( | ||
1698 | &sci_port->ready_substate_machine, | ||
1699 | SCIC_SDS_PORT_READY_SUBSTATE_WAITING); | ||
1700 | } else if (sci_port->started_request_count == 0) | ||
1701 | sci_base_state_machine_change_state( | ||
1702 | &sci_port->ready_substate_machine, | ||
1703 | SCIC_SDS_PORT_READY_SUBSTATE_OPERATIONAL); | ||
1704 | } | ||
1705 | |||
1706 | static void scic_sds_port_ready_substate_configuring_exit(void *object) | ||
1707 | { | ||
1708 | struct scic_sds_port *sci_port = object; | ||
1709 | |||
1710 | scic_sds_port_suspend_port_task_scheduler(sci_port); | ||
1711 | } | ||
1712 | |||
1713 | /* --------------------------------------------------------------------------- */ | ||
1714 | |||
1715 | static const struct sci_base_state scic_sds_port_ready_substate_table[] = { | ||
1716 | [SCIC_SDS_PORT_READY_SUBSTATE_WAITING] = { | ||
1717 | .enter_state = scic_sds_port_ready_substate_waiting_enter, | ||
1718 | }, | ||
1719 | [SCIC_SDS_PORT_READY_SUBSTATE_OPERATIONAL] = { | ||
1720 | .enter_state = scic_sds_port_ready_substate_operational_enter, | ||
1721 | .exit_state = scic_sds_port_ready_substate_operational_exit | ||
1722 | }, | ||
1723 | [SCIC_SDS_PORT_READY_SUBSTATE_CONFIGURING] = { | ||
1724 | .enter_state = scic_sds_port_ready_substate_configuring_enter, | ||
1725 | .exit_state = scic_sds_port_ready_substate_configuring_exit | ||
1726 | }, | ||
1727 | }; | ||
1728 | |||
1729 | /** | ||
1730 | * | ||
1731 | * @port: This is the struct scic_sds_port object on which the io request count will | ||
1732 | * be decremented. | ||
1733 | * @device: This is the struct scic_sds_remote_device object to which the io request | ||
1734 | * is being directed. This parameter is not required to complete this | ||
1735 | * operation. | ||
1736 | * @io_request: This is the request that is being completed on this port | ||
1737 | * object. This parameter is not required to complete this operation. | ||
1738 | * | ||
1739 | * This is a general complete io request handler for the struct scic_sds_port object. | ||
1740 | * enum sci_status SCI_SUCCESS | ||
1741 | */ | ||
1742 | static enum sci_status scic_sds_port_general_complete_io_handler( | ||
1743 | struct scic_sds_port *port, | ||
1744 | struct scic_sds_remote_device *device, | ||
1745 | struct scic_sds_request *io_request) | ||
1746 | { | ||
1747 | scic_sds_port_decrement_request_count(port); | ||
1748 | |||
1749 | return SCI_SUCCESS; | ||
1750 | } | ||
1751 | |||
1752 | /** | ||
1753 | * scic_sds_port_stopped_state_start_handler() - stop a port from "started" | ||
1754 | * | ||
1755 | * @port: This is the struct scic_sds_port object which is cast into a | ||
1756 | * struct scic_sds_port object. | ||
1757 | * | ||
1758 | * This function takes the struct scic_sds_port from a stopped state and | ||
1759 | * attempts to start it. To start a port it must have no assiged devices and | ||
1760 | * it must have at least one phy assigned to it. If those conditions are | ||
1761 | * met then the port can transition to the ready state. | ||
1762 | * enum sci_status | ||
1763 | * SCI_FAILURE_UNSUPPORTED_PORT_CONFIGURATION | ||
1764 | * This struct scic_sds_port object could not be started because the port | ||
1765 | * configuration is not valid. | ||
1766 | * SCI_SUCCESS | ||
1767 | * the start request is successful and the struct scic_sds_port object | ||
1768 | * has transitioned to the SCI_BASE_PORT_STATE_READY. | ||
1769 | */ | ||
1770 | static enum sci_status | ||
1771 | scic_sds_port_stopped_state_start_handler(struct scic_sds_port *sci_port) | ||
1772 | { | ||
1773 | struct scic_sds_controller *scic = sci_port->owning_controller; | ||
1774 | struct isci_host *ihost = scic_to_ihost(scic); | ||
1775 | enum sci_status status = SCI_SUCCESS; | ||
1776 | u32 phy_mask; | ||
1777 | |||
1778 | if (sci_port->assigned_device_count > 0) { | ||
1779 | /* | ||
1780 | * @todo This is a start failure operation because | ||
1781 | * there are still devices assigned to this port. | ||
1782 | * There must be no devices assigned to a port on a | ||
1783 | * start operation. | ||
1784 | */ | ||
1785 | return SCI_FAILURE_UNSUPPORTED_PORT_CONFIGURATION; | ||
1786 | } | ||
1787 | |||
1788 | sci_port->timer_handle = | ||
1789 | isci_timer_create(ihost, | ||
1790 | sci_port, | ||
1791 | scic_sds_port_timeout_handler); | ||
1792 | |||
1793 | if (!sci_port->timer_handle) | ||
1794 | return SCI_FAILURE_INSUFFICIENT_RESOURCES; | ||
1795 | |||
1796 | if (sci_port->reserved_rni == SCU_DUMMY_INDEX) { | ||
1797 | u16 rni = scic_sds_remote_node_table_allocate_remote_node( | ||
1798 | &scic->available_remote_nodes, 1); | ||
1799 | |||
1800 | if (rni != SCU_DUMMY_INDEX) | ||
1801 | scic_sds_port_construct_dummy_rnc(sci_port, rni); | ||
1802 | else | ||
1803 | status = SCI_FAILURE_INSUFFICIENT_RESOURCES; | ||
1804 | sci_port->reserved_rni = rni; | ||
1805 | } | ||
1806 | |||
1807 | if (sci_port->reserved_tci == SCU_DUMMY_INDEX) { | ||
1808 | /* Allocate a TCI and remove the sequence nibble */ | ||
1809 | u16 tci = scic_controller_allocate_io_tag(scic); | ||
1810 | |||
1811 | if (tci != SCU_DUMMY_INDEX) | ||
1812 | scic_sds_port_construct_dummy_task(sci_port, tci); | ||
1813 | else | ||
1814 | status = SCI_FAILURE_INSUFFICIENT_RESOURCES; | ||
1815 | sci_port->reserved_tci = tci; | ||
1816 | } | ||
1817 | |||
1818 | if (status == SCI_SUCCESS) { | ||
1819 | phy_mask = scic_sds_port_get_phys(sci_port); | ||
1820 | |||
1821 | /* | ||
1822 | * There are one or more phys assigned to this port. Make sure | ||
1823 | * the port's phy mask is in fact legal and supported by the | ||
1824 | * silicon. | ||
1825 | */ | ||
1826 | if (scic_sds_port_is_phy_mask_valid(sci_port, phy_mask) == true) { | ||
1827 | sci_base_state_machine_change_state( | ||
1828 | &sci_port->state_machine, | ||
1829 | SCI_BASE_PORT_STATE_READY); | ||
1830 | |||
1831 | return SCI_SUCCESS; | ||
1832 | } else | ||
1833 | status = SCI_FAILURE; | ||
1834 | } | ||
1835 | |||
1836 | if (status != SCI_SUCCESS) | ||
1837 | scic_sds_port_destroy_dummy_resources(sci_port); | ||
1838 | |||
1839 | return status; | ||
1840 | } | ||
1841 | |||
1842 | /* | ||
1843 | * This method takes the struct scic_sds_port that is in a stopped state and handles a | ||
1844 | * stop request. This function takes no action. enum sci_status SCI_SUCCESS the | ||
1845 | * stop request is successful as the struct scic_sds_port object is already stopped. | ||
1846 | */ | ||
1847 | static enum sci_status scic_sds_port_stopped_state_stop_handler( | ||
1848 | struct scic_sds_port *port) | ||
1849 | { | ||
1850 | /* We are already stopped so there is nothing to do here */ | ||
1851 | return SCI_SUCCESS; | ||
1852 | } | ||
1853 | |||
1854 | /* | ||
1855 | * This method takes the struct scic_sds_port that is in a stopped state and handles | ||
1856 | * the destruct request. The stopped state is the only state in which the | ||
1857 | * struct scic_sds_port can be destroyed. This function causes the port object to | ||
1858 | * transition to the SCI_BASE_PORT_STATE_FINAL. enum sci_status SCI_SUCCESS | ||
1859 | */ | ||
1860 | static enum sci_status scic_sds_port_stopped_state_destruct_handler( | ||
1861 | struct scic_sds_port *port) | ||
1862 | { | ||
1863 | sci_base_state_machine_stop(&port->state_machine); | ||
1864 | |||
1865 | return SCI_SUCCESS; | ||
1866 | } | ||
1867 | |||
1868 | /* | ||
1869 | * This method takes the struct scic_sds_port that is in a stopped state and handles | ||
1870 | * the add phy request. In MPC mode the only time a phy can be added to a port | ||
1871 | * is in the SCI_BASE_PORT_STATE_STOPPED. enum sci_status | ||
1872 | * SCI_FAILURE_UNSUPPORTED_PORT_CONFIGURATION is returned when the phy can not | ||
1873 | * be added to the port. SCI_SUCCESS if the phy is added to the port. | ||
1874 | */ | ||
1875 | static enum sci_status scic_sds_port_stopped_state_add_phy_handler( | ||
1876 | struct scic_sds_port *port, | ||
1877 | struct scic_sds_phy *phy) | ||
1878 | { | ||
1879 | struct sci_sas_address port_sas_address; | ||
1880 | |||
1881 | /* Read the port assigned SAS Address if there is one */ | ||
1882 | scic_sds_port_get_sas_address(port, &port_sas_address); | ||
1883 | |||
1884 | if (port_sas_address.high != 0 && port_sas_address.low != 0) { | ||
1885 | struct sci_sas_address phy_sas_address; | ||
1886 | |||
1887 | /* | ||
1888 | * Make sure that the PHY SAS Address matches the SAS Address | ||
1889 | * for this port. */ | ||
1890 | scic_sds_phy_get_sas_address(phy, &phy_sas_address); | ||
1891 | |||
1892 | if ( | ||
1893 | (port_sas_address.high != phy_sas_address.high) | ||
1894 | || (port_sas_address.low != phy_sas_address.low) | ||
1895 | ) { | ||
1896 | return SCI_FAILURE_UNSUPPORTED_PORT_CONFIGURATION; | ||
1897 | } | ||
1898 | } | ||
1899 | |||
1900 | return scic_sds_port_set_phy(port, phy); | ||
1901 | } | ||
1902 | |||
1903 | /* | ||
1904 | * This method takes the struct scic_sds_port that is in a stopped state and handles | ||
1905 | * the remove phy request. In MPC mode the only time a phy can be removed from | ||
1906 | * a port is in the SCI_BASE_PORT_STATE_STOPPED. enum sci_status | ||
1907 | * SCI_FAILURE_UNSUPPORTED_PORT_CONFIGURATION is returned when the phy can not | ||
1908 | * be added to the port. SCI_SUCCESS if the phy is added to the port. | ||
1909 | */ | ||
1910 | static enum sci_status scic_sds_port_stopped_state_remove_phy_handler( | ||
1911 | struct scic_sds_port *port, | ||
1912 | struct scic_sds_phy *phy) | ||
1913 | { | ||
1914 | return scic_sds_port_clear_phy(port, phy); | ||
1915 | } | ||
1916 | |||
1917 | /* | ||
1918 | * **************************************************************************** | ||
1919 | * * READY STATE HANDLERS | ||
1920 | * **************************************************************************** */ | ||
1921 | |||
1922 | /* | ||
1923 | * **************************************************************************** | ||
1924 | * * RESETTING STATE HANDLERS | ||
1925 | * **************************************************************************** */ | ||
1926 | |||
1927 | /* | ||
1928 | * **************************************************************************** | ||
1929 | * * STOPPING STATE HANDLERS | ||
1930 | * **************************************************************************** */ | ||
1931 | |||
1932 | /* | ||
1933 | * This method takes the struct scic_sds_port that is in a stopping state and handles | ||
1934 | * the complete io request. Should the request count reach 0 then the port | ||
1935 | * object will transition to the stopped state. enum sci_status SCI_SUCCESS | ||
1936 | */ | ||
1937 | static enum sci_status scic_sds_port_stopping_state_complete_io_handler( | ||
1938 | struct scic_sds_port *sci_port, | ||
1939 | struct scic_sds_remote_device *device, | ||
1940 | struct scic_sds_request *io_request) | ||
1941 | { | ||
1942 | scic_sds_port_decrement_request_count(sci_port); | ||
1943 | |||
1944 | if (sci_port->started_request_count == 0) { | ||
1945 | sci_base_state_machine_change_state(&sci_port->state_machine, | ||
1946 | SCI_BASE_PORT_STATE_STOPPED); | ||
1947 | } | ||
1948 | |||
1949 | return SCI_SUCCESS; | ||
1950 | } | ||
1951 | |||
1952 | /* | ||
1953 | * **************************************************************************** | ||
1954 | * * RESETTING STATE HANDLERS | ||
1955 | * **************************************************************************** */ | ||
1956 | |||
1957 | /** | ||
1958 | * | ||
1959 | * @port: This is the port object which is being requested to stop. | ||
1960 | * | ||
1961 | * This method will stop a failed port. This causes a transition to the | ||
1962 | * stopping state. enum sci_status SCI_SUCCESS | ||
1963 | */ | ||
1964 | static enum sci_status scic_sds_port_reset_state_stop_handler( | ||
1965 | struct scic_sds_port *port) | ||
1966 | { | ||
1967 | sci_base_state_machine_change_state( | ||
1968 | &port->state_machine, | ||
1969 | SCI_BASE_PORT_STATE_STOPPING | ||
1970 | ); | ||
1971 | |||
1972 | return SCI_SUCCESS; | ||
1973 | } | ||
1974 | |||
1975 | /* | ||
1976 | * This method will transition a failed port to its ready state. The port | ||
1977 | * failed because a hard reset request timed out but at some time later one or | ||
1978 | * more phys in the port became ready. enum sci_status SCI_SUCCESS | ||
1979 | */ | ||
1980 | static void scic_sds_port_reset_state_link_up_handler( | ||
1981 | struct scic_sds_port *port, | ||
1982 | struct scic_sds_phy *phy) | ||
1983 | { | ||
1984 | /* | ||
1985 | * / @todo We should make sure that the phy that has gone link up is the same | ||
1986 | * / one on which we sent the reset. It is possible that the phy on | ||
1987 | * / which we sent the reset is not the one that has gone link up and we | ||
1988 | * / want to make sure that phy being reset comes back. Consider the | ||
1989 | * / case where a reset is sent but before the hardware processes the | ||
1990 | * / reset it get a link up on the port because of a hot plug event. | ||
1991 | * / because of the reset request this phy will go link down almost | ||
1992 | * / immediately. */ | ||
1993 | |||
1994 | /* | ||
1995 | * In the resetting state we don't notify the user regarding | ||
1996 | * link up and link down notifications. */ | ||
1997 | scic_sds_port_general_link_up_handler(port, phy, false); | ||
1998 | } | ||
1999 | |||
2000 | /* | ||
2001 | * This method process link down notifications that occur during a port reset | ||
2002 | * operation. Link downs can occur during the reset operation. enum sci_status | ||
2003 | * SCI_SUCCESS | ||
2004 | */ | ||
2005 | static void scic_sds_port_reset_state_link_down_handler( | ||
2006 | struct scic_sds_port *port, | ||
2007 | struct scic_sds_phy *phy) | ||
2008 | { | ||
2009 | /* | ||
2010 | * In the resetting state we don't notify the user regarding | ||
2011 | * link up and link down notifications. */ | ||
2012 | scic_sds_port_deactivate_phy(port, phy, false); | ||
2013 | } | ||
2014 | |||
2015 | static struct scic_sds_port_state_handler | ||
2016 | scic_sds_port_state_handler_table[SCI_BASE_PORT_MAX_STATES] = | ||
2017 | { | ||
2018 | /* SCI_BASE_PORT_STATE_STOPPED */ | ||
2019 | { | ||
2020 | scic_sds_port_stopped_state_start_handler, | ||
2021 | scic_sds_port_stopped_state_stop_handler, | ||
2022 | scic_sds_port_stopped_state_destruct_handler, | ||
2023 | scic_sds_port_default_reset_handler, | ||
2024 | scic_sds_port_stopped_state_add_phy_handler, | ||
2025 | scic_sds_port_stopped_state_remove_phy_handler, | ||
2026 | scic_sds_port_default_frame_handler, | ||
2027 | scic_sds_port_default_event_handler, | ||
2028 | scic_sds_port_default_link_up_handler, | ||
2029 | scic_sds_port_default_link_down_handler, | ||
2030 | scic_sds_port_default_start_io_handler, | ||
2031 | scic_sds_port_default_complete_io_handler | ||
2032 | }, | ||
2033 | /* SCI_BASE_PORT_STATE_STOPPING */ | ||
2034 | { | ||
2035 | scic_sds_port_default_start_handler, | ||
2036 | scic_sds_port_default_stop_handler, | ||
2037 | scic_sds_port_default_destruct_handler, | ||
2038 | scic_sds_port_default_reset_handler, | ||
2039 | scic_sds_port_default_add_phy_handler, | ||
2040 | scic_sds_port_default_remove_phy_handler, | ||
2041 | scic_sds_port_default_frame_handler, | ||
2042 | scic_sds_port_default_event_handler, | ||
2043 | scic_sds_port_default_link_up_handler, | ||
2044 | scic_sds_port_default_link_down_handler, | ||
2045 | scic_sds_port_default_start_io_handler, | ||
2046 | scic_sds_port_stopping_state_complete_io_handler | ||
2047 | }, | ||
2048 | /* SCI_BASE_PORT_STATE_READY */ | ||
2049 | { | ||
2050 | scic_sds_port_default_start_handler, | ||
2051 | scic_sds_port_default_stop_handler, | ||
2052 | scic_sds_port_default_destruct_handler, | ||
2053 | scic_sds_port_default_reset_handler, | ||
2054 | scic_sds_port_default_add_phy_handler, | ||
2055 | scic_sds_port_default_remove_phy_handler, | ||
2056 | scic_sds_port_default_frame_handler, | ||
2057 | scic_sds_port_default_event_handler, | ||
2058 | scic_sds_port_default_link_up_handler, | ||
2059 | scic_sds_port_default_link_down_handler, | ||
2060 | scic_sds_port_default_start_io_handler, | ||
2061 | scic_sds_port_general_complete_io_handler | ||
2062 | }, | ||
2063 | /* SCI_BASE_PORT_STATE_RESETTING */ | ||
2064 | { | ||
2065 | scic_sds_port_default_start_handler, | ||
2066 | scic_sds_port_reset_state_stop_handler, | ||
2067 | scic_sds_port_default_destruct_handler, | ||
2068 | scic_sds_port_default_reset_handler, | ||
2069 | scic_sds_port_default_add_phy_handler, | ||
2070 | scic_sds_port_default_remove_phy_handler, | ||
2071 | scic_sds_port_default_frame_handler, | ||
2072 | scic_sds_port_default_event_handler, | ||
2073 | scic_sds_port_reset_state_link_up_handler, | ||
2074 | scic_sds_port_reset_state_link_down_handler, | ||
2075 | scic_sds_port_default_start_io_handler, | ||
2076 | scic_sds_port_general_complete_io_handler | ||
2077 | }, | ||
2078 | /* SCI_BASE_PORT_STATE_FAILED */ | ||
2079 | { | ||
2080 | scic_sds_port_default_start_handler, | ||
2081 | scic_sds_port_default_stop_handler, | ||
2082 | scic_sds_port_default_destruct_handler, | ||
2083 | scic_sds_port_default_reset_handler, | ||
2084 | scic_sds_port_default_add_phy_handler, | ||
2085 | scic_sds_port_default_remove_phy_handler, | ||
2086 | scic_sds_port_default_frame_handler, | ||
2087 | scic_sds_port_default_event_handler, | ||
2088 | scic_sds_port_default_link_up_handler, | ||
2089 | scic_sds_port_default_link_down_handler, | ||
2090 | scic_sds_port_default_start_io_handler, | ||
2091 | scic_sds_port_general_complete_io_handler | ||
2092 | } | ||
2093 | }; | ||
2094 | |||
2095 | /* | ||
2096 | * ****************************************************************************** | ||
2097 | * * PORT STATE PRIVATE METHODS | ||
2098 | * ****************************************************************************** */ | ||
2099 | |||
2100 | /** | ||
2101 | * | ||
2102 | * @sci_port: This is the port object which to suspend. | ||
2103 | * | ||
2104 | * This method will enable the SCU Port Task Scheduler for this port object but | ||
2105 | * will leave the port task scheduler in a suspended state. none | ||
2106 | */ | ||
2107 | static void | ||
2108 | scic_sds_port_enable_port_task_scheduler(struct scic_sds_port *port) | ||
2109 | { | ||
2110 | u32 pts_control_value; | ||
2111 | |||
2112 | pts_control_value = readl(&port->port_task_scheduler_registers->control); | ||
2113 | pts_control_value |= SCU_PTSxCR_GEN_BIT(ENABLE) | SCU_PTSxCR_GEN_BIT(SUSPEND); | ||
2114 | writel(pts_control_value, &port->port_task_scheduler_registers->control); | ||
2115 | } | ||
2116 | |||
2117 | /** | ||
2118 | * | ||
2119 | * @sci_port: This is the port object which to resume. | ||
2120 | * | ||
2121 | * This method will disable the SCU port task scheduler for this port object. | ||
2122 | * none | ||
2123 | */ | ||
2124 | static void | ||
2125 | scic_sds_port_disable_port_task_scheduler(struct scic_sds_port *port) | ||
2126 | { | ||
2127 | u32 pts_control_value; | ||
2128 | |||
2129 | pts_control_value = readl(&port->port_task_scheduler_registers->control); | ||
2130 | pts_control_value &= | ||
2131 | ~(SCU_PTSxCR_GEN_BIT(ENABLE) | SCU_PTSxCR_GEN_BIT(SUSPEND)); | ||
2132 | writel(pts_control_value, &port->port_task_scheduler_registers->control); | ||
2133 | } | ||
2134 | |||
2135 | static void scic_sds_port_post_dummy_remote_node(struct scic_sds_port *sci_port) | ||
2136 | { | ||
2137 | struct scic_sds_controller *scic = sci_port->owning_controller; | ||
2138 | u8 phys_index = sci_port->physical_port_index; | ||
2139 | union scu_remote_node_context *rnc; | ||
2140 | u16 rni = sci_port->reserved_rni; | ||
2141 | u32 command; | ||
2142 | |||
2143 | rnc = &scic->remote_node_context_table[rni]; | ||
2144 | rnc->ssp.is_valid = true; | ||
2145 | |||
2146 | command = SCU_CONTEXT_COMMAND_POST_RNC_32 | | ||
2147 | phys_index << SCU_CONTEXT_COMMAND_LOGICAL_PORT_SHIFT | rni; | ||
2148 | |||
2149 | scic_sds_controller_post_request(scic, command); | ||
2150 | |||
2151 | /* ensure hardware has seen the post rnc command and give it | ||
2152 | * ample time to act before sending the suspend | ||
2153 | */ | ||
2154 | readl(&scic->smu_registers->interrupt_status); /* flush */ | ||
2155 | udelay(10); | ||
2156 | |||
2157 | command = SCU_CONTEXT_COMMAND_POST_RNC_SUSPEND_TX_RX | | ||
2158 | phys_index << SCU_CONTEXT_COMMAND_LOGICAL_PORT_SHIFT | rni; | ||
2159 | |||
2160 | scic_sds_controller_post_request(scic, command); | ||
2161 | } | ||
2162 | |||
2163 | static void scic_sds_port_invalidate_dummy_remote_node(struct scic_sds_port *sci_port) | ||
2164 | { | ||
2165 | struct scic_sds_controller *scic = sci_port->owning_controller; | ||
2166 | u8 phys_index = sci_port->physical_port_index; | ||
2167 | union scu_remote_node_context *rnc; | ||
2168 | u16 rni = sci_port->reserved_rni; | ||
2169 | u32 command; | ||
2170 | |||
2171 | rnc = &scic->remote_node_context_table[rni]; | ||
2172 | |||
2173 | rnc->ssp.is_valid = false; | ||
2174 | |||
2175 | /* ensure the preceding tc abort request has reached the | ||
2176 | * controller and give it ample time to act before posting the rnc | ||
2177 | * invalidate | ||
2178 | */ | ||
2179 | readl(&scic->smu_registers->interrupt_status); /* flush */ | ||
2180 | udelay(10); | ||
2181 | |||
2182 | command = SCU_CONTEXT_COMMAND_POST_RNC_INVALIDATE | | ||
2183 | phys_index << SCU_CONTEXT_COMMAND_LOGICAL_PORT_SHIFT | rni; | ||
2184 | |||
2185 | scic_sds_controller_post_request(scic, command); | ||
2186 | } | ||
2187 | |||
2188 | /* | ||
2189 | * ****************************************************************************** | ||
2190 | * * PORT STATE METHODS | ||
2191 | * ****************************************************************************** */ | ||
2192 | |||
2193 | /** | ||
2194 | * | ||
2195 | * @object: This is the object which is cast to a struct scic_sds_port object. | ||
2196 | * | ||
2197 | * This method will perform the actions required by the struct scic_sds_port on | ||
2198 | * entering the SCI_BASE_PORT_STATE_STOPPED. This function sets the stopped | ||
2199 | * state handlers for the struct scic_sds_port object and disables the port task | ||
2200 | * scheduler in the hardware. none | ||
2201 | */ | ||
2202 | static void scic_sds_port_stopped_state_enter(void *object) | ||
2203 | { | ||
2204 | struct scic_sds_port *sci_port = object; | ||
2205 | |||
2206 | scic_sds_port_set_base_state_handlers( | ||
2207 | sci_port, SCI_BASE_PORT_STATE_STOPPED | ||
2208 | ); | ||
2209 | |||
2210 | if ( | ||
2211 | SCI_BASE_PORT_STATE_STOPPING | ||
2212 | == sci_port->state_machine.previous_state_id | ||
2213 | ) { | ||
2214 | /* | ||
2215 | * If we enter this state becasuse of a request to stop | ||
2216 | * the port then we want to disable the hardwares port | ||
2217 | * task scheduler. */ | ||
2218 | scic_sds_port_disable_port_task_scheduler(sci_port); | ||
2219 | } | ||
2220 | } | ||
2221 | |||
2222 | /** | ||
2223 | * | ||
2224 | * @object: This is the object which is cast to a struct scic_sds_port object. | ||
2225 | * | ||
2226 | * This method will perform the actions required by the struct scic_sds_port on | ||
2227 | * exiting the SCI_BASE_STATE_STOPPED. This function enables the SCU hardware | ||
2228 | * port task scheduler. none | ||
2229 | */ | ||
2230 | static void scic_sds_port_stopped_state_exit(void *object) | ||
2231 | { | ||
2232 | struct scic_sds_port *sci_port = object; | ||
2233 | |||
2234 | /* Enable and suspend the port task scheduler */ | ||
2235 | scic_sds_port_enable_port_task_scheduler(sci_port); | ||
2236 | } | ||
2237 | |||
2238 | /** | ||
2239 | * scic_sds_port_ready_state_enter - | ||
2240 | * @object: This is the object which is cast to a struct scic_sds_port object. | ||
2241 | * | ||
2242 | * This method will perform the actions required by the struct scic_sds_port on | ||
2243 | * entering the SCI_BASE_PORT_STATE_READY. This function sets the ready state | ||
2244 | * handlers for the struct scic_sds_port object, reports the port object as | ||
2245 | * not ready and starts the ready substate machine. none | ||
2246 | */ | ||
2247 | static void scic_sds_port_ready_state_enter(void *object) | ||
2248 | { | ||
2249 | struct scic_sds_port *sci_port = object; | ||
2250 | struct scic_sds_controller *scic = sci_port->owning_controller; | ||
2251 | struct isci_host *ihost = scic_to_ihost(scic); | ||
2252 | struct isci_port *iport = sci_port_to_iport(sci_port); | ||
2253 | u32 prev_state; | ||
2254 | |||
2255 | /* Put the ready state handlers in place though they will not be there long */ | ||
2256 | scic_sds_port_set_base_state_handlers(sci_port, SCI_BASE_PORT_STATE_READY); | ||
2257 | |||
2258 | prev_state = sci_port->state_machine.previous_state_id; | ||
2259 | if (prev_state == SCI_BASE_PORT_STATE_RESETTING) | ||
2260 | isci_port_hard_reset_complete(iport, SCI_SUCCESS); | ||
2261 | else | ||
2262 | isci_port_not_ready(ihost, iport); | ||
2263 | |||
2264 | /* Post and suspend the dummy remote node context for this port. */ | ||
2265 | scic_sds_port_post_dummy_remote_node(sci_port); | ||
2266 | |||
2267 | /* Start the ready substate machine */ | ||
2268 | sci_base_state_machine_start(&sci_port->ready_substate_machine); | ||
2269 | } | ||
2270 | |||
2271 | static void scic_sds_port_ready_state_exit(void *object) | ||
2272 | { | ||
2273 | struct scic_sds_port *sci_port = object; | ||
2274 | |||
2275 | sci_base_state_machine_stop(&sci_port->ready_substate_machine); | ||
2276 | scic_sds_port_invalidate_dummy_remote_node(sci_port); | ||
2277 | } | ||
2278 | |||
2279 | /** | ||
2280 | * | ||
2281 | * @object: This is the object which is cast to a struct scic_sds_port object. | ||
2282 | * | ||
2283 | * This method will perform the actions required by the struct scic_sds_port on | ||
2284 | * entering the SCI_BASE_PORT_STATE_RESETTING. This function sets the resetting | ||
2285 | * state handlers for the struct scic_sds_port object. none | ||
2286 | */ | ||
2287 | static void scic_sds_port_resetting_state_enter(void *object) | ||
2288 | { | ||
2289 | struct scic_sds_port *sci_port = object; | ||
2290 | |||
2291 | scic_sds_port_set_base_state_handlers( | ||
2292 | sci_port, SCI_BASE_PORT_STATE_RESETTING | ||
2293 | ); | ||
2294 | } | ||
2295 | |||
2296 | /** | ||
2297 | * | ||
2298 | * @object: This is the object which is cast to a struct scic_sds_port object. | ||
2299 | * | ||
2300 | * This function will perform the actions required by the | ||
2301 | * struct scic_sds_port on | ||
2302 | * exiting the SCI_BASE_STATE_RESETTING. This function does nothing. none | ||
2303 | */ | ||
2304 | static inline void scic_sds_port_resetting_state_exit(void *object) | ||
2305 | { | ||
2306 | struct scic_sds_port *sci_port = object; | ||
2307 | |||
2308 | isci_timer_stop(sci_port->timer_handle); | ||
2309 | } | ||
2310 | |||
2311 | /** | ||
2312 | * | ||
2313 | * @object: This is the void object which is cast to a | ||
2314 | * struct scic_sds_port object. | ||
2315 | * | ||
2316 | * This method will perform the actions required by the struct scic_sds_port on | ||
2317 | * entering the SCI_BASE_PORT_STATE_STOPPING. This function sets the stopping | ||
2318 | * state handlers for the struct scic_sds_port object. none | ||
2319 | */ | ||
2320 | static void scic_sds_port_stopping_state_enter(void *object) | ||
2321 | { | ||
2322 | struct scic_sds_port *sci_port = object; | ||
2323 | |||
2324 | scic_sds_port_set_base_state_handlers( | ||
2325 | sci_port, SCI_BASE_PORT_STATE_STOPPING | ||
2326 | ); | ||
2327 | } | ||
2328 | |||
2329 | /** | ||
2330 | * | ||
2331 | * @object: This is the object which is cast to a struct scic_sds_port object. | ||
2332 | * | ||
2333 | * This function will perform the actions required by the | ||
2334 | * struct scic_sds_port on | ||
2335 | * exiting the SCI_BASE_STATE_STOPPING. This function does nothing. none | ||
2336 | */ | ||
2337 | static inline void | ||
2338 | scic_sds_port_stopping_state_exit(void *object) | ||
2339 | { | ||
2340 | struct scic_sds_port *sci_port = object; | ||
2341 | |||
2342 | isci_timer_stop(sci_port->timer_handle); | ||
2343 | |||
2344 | scic_sds_port_destroy_dummy_resources(sci_port); | ||
2345 | } | ||
2346 | |||
2347 | /** | ||
2348 | * | ||
2349 | * @object: This is the object which is cast to a struct scic_sds_port object. | ||
2350 | * | ||
2351 | * This function will perform the actions required by the | ||
2352 | * struct scic_sds_port on | ||
2353 | * entering the SCI_BASE_PORT_STATE_STOPPING. This function sets the stopping | ||
2354 | * state handlers for the struct scic_sds_port object. none | ||
2355 | */ | ||
2356 | static void scic_sds_port_failed_state_enter(void *object) | ||
2357 | { | ||
2358 | struct scic_sds_port *sci_port = object; | ||
2359 | struct isci_port *iport = sci_port_to_iport(sci_port); | ||
2360 | |||
2361 | scic_sds_port_set_base_state_handlers(sci_port, | ||
2362 | SCI_BASE_PORT_STATE_FAILED); | ||
2363 | |||
2364 | isci_port_hard_reset_complete(iport, SCI_FAILURE_TIMEOUT); | ||
2365 | } | ||
2366 | |||
2367 | /* --------------------------------------------------------------------------- */ | ||
2368 | |||
2369 | static const struct sci_base_state scic_sds_port_state_table[] = { | ||
2370 | [SCI_BASE_PORT_STATE_STOPPED] = { | ||
2371 | .enter_state = scic_sds_port_stopped_state_enter, | ||
2372 | .exit_state = scic_sds_port_stopped_state_exit | ||
2373 | }, | ||
2374 | [SCI_BASE_PORT_STATE_STOPPING] = { | ||
2375 | .enter_state = scic_sds_port_stopping_state_enter, | ||
2376 | .exit_state = scic_sds_port_stopping_state_exit | ||
2377 | }, | ||
2378 | [SCI_BASE_PORT_STATE_READY] = { | ||
2379 | .enter_state = scic_sds_port_ready_state_enter, | ||
2380 | .exit_state = scic_sds_port_ready_state_exit | ||
2381 | }, | ||
2382 | [SCI_BASE_PORT_STATE_RESETTING] = { | ||
2383 | .enter_state = scic_sds_port_resetting_state_enter, | ||
2384 | .exit_state = scic_sds_port_resetting_state_exit | ||
2385 | }, | ||
2386 | [SCI_BASE_PORT_STATE_FAILED] = { | ||
2387 | .enter_state = scic_sds_port_failed_state_enter, | ||
2388 | } | ||
2389 | }; | ||
2390 | |||
2391 | void scic_sds_port_construct(struct scic_sds_port *sci_port, u8 index, | ||
2392 | struct scic_sds_controller *scic) | ||
2393 | { | ||
2394 | sci_base_state_machine_construct(&sci_port->state_machine, | ||
2395 | sci_port, | ||
2396 | scic_sds_port_state_table, | ||
2397 | SCI_BASE_PORT_STATE_STOPPED); | ||
2398 | |||
2399 | sci_base_state_machine_start(&sci_port->state_machine); | ||
2400 | |||
2401 | sci_base_state_machine_construct(&sci_port->ready_substate_machine, | ||
2402 | sci_port, | ||
2403 | scic_sds_port_ready_substate_table, | ||
2404 | SCIC_SDS_PORT_READY_SUBSTATE_WAITING); | ||
2405 | |||
2406 | sci_port->logical_port_index = SCIC_SDS_DUMMY_PORT; | ||
2407 | sci_port->physical_port_index = index; | ||
2408 | sci_port->active_phy_mask = 0; | ||
2409 | |||
2410 | sci_port->owning_controller = scic; | ||
2411 | |||
2412 | sci_port->started_request_count = 0; | ||
2413 | sci_port->assigned_device_count = 0; | ||
2414 | |||
2415 | sci_port->reserved_rni = SCU_DUMMY_INDEX; | ||
2416 | sci_port->reserved_tci = SCU_DUMMY_INDEX; | ||
2417 | |||
2418 | sci_port->timer_handle = NULL; | ||
2419 | sci_port->port_task_scheduler_registers = NULL; | ||
2420 | |||
2421 | for (index = 0; index < SCI_MAX_PHYS; index++) | ||
2422 | sci_port->phy_table[index] = NULL; | ||
2423 | } | ||
diff --git a/drivers/scsi/isci/core/scic_sds_port.h b/drivers/scsi/isci/core/scic_sds_port.h deleted file mode 100644 index a351525b1c49..000000000000 --- a/drivers/scsi/isci/core/scic_sds_port.h +++ /dev/null | |||
@@ -1,435 +0,0 @@ | |||
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 | #ifndef _SCIC_SDS_PORT_H_ | ||
57 | #define _SCIC_SDS_PORT_H_ | ||
58 | |||
59 | #include <linux/kernel.h> | ||
60 | #include "isci.h" | ||
61 | #include "sas.h" | ||
62 | #include "registers.h" | ||
63 | #include "state_machine.h" | ||
64 | |||
65 | struct scic_sds_controller; | ||
66 | struct scic_sds_phy; | ||
67 | struct scic_sds_remote_device; | ||
68 | struct scic_sds_request; | ||
69 | |||
70 | #define SCIC_SDS_DUMMY_PORT 0xFF | ||
71 | |||
72 | /** | ||
73 | * enum SCIC_SDS_PORT_READY_SUBSTATES - | ||
74 | * | ||
75 | * This enumeration depicts all of the states for the core port ready substate | ||
76 | * machine. | ||
77 | */ | ||
78 | enum scic_sds_port_ready_substates { | ||
79 | /** | ||
80 | * The substate where the port is started and ready but has no | ||
81 | * active phys. | ||
82 | */ | ||
83 | SCIC_SDS_PORT_READY_SUBSTATE_WAITING, | ||
84 | |||
85 | /** | ||
86 | * The substate where the port is started and ready and there is | ||
87 | * at least one phy operational. | ||
88 | */ | ||
89 | SCIC_SDS_PORT_READY_SUBSTATE_OPERATIONAL, | ||
90 | |||
91 | /** | ||
92 | * The substate where the port is started and there was an | ||
93 | * add/remove phy event. This state is only used in Automatic | ||
94 | * Port Configuration Mode (APC) | ||
95 | */ | ||
96 | SCIC_SDS_PORT_READY_SUBSTATE_CONFIGURING, | ||
97 | |||
98 | SCIC_SDS_PORT_READY_MAX_SUBSTATES | ||
99 | }; | ||
100 | |||
101 | /** | ||
102 | * enum scic_sds_port_states - This enumeration depicts all the states for the | ||
103 | * common port state machine. | ||
104 | * | ||
105 | * | ||
106 | */ | ||
107 | enum scic_sds_port_states { | ||
108 | /** | ||
109 | * This state indicates that the port has successfully been stopped. | ||
110 | * In this state no new IO operations are permitted. | ||
111 | * This state is entered from the STOPPING state. | ||
112 | */ | ||
113 | SCI_BASE_PORT_STATE_STOPPED, | ||
114 | |||
115 | /** | ||
116 | * This state indicates that the port is in the process of stopping. | ||
117 | * In this state no new IO operations are permitted, but existing IO | ||
118 | * operations are allowed to complete. | ||
119 | * This state is entered from the READY state. | ||
120 | */ | ||
121 | SCI_BASE_PORT_STATE_STOPPING, | ||
122 | |||
123 | /** | ||
124 | * This state indicates the port is now ready. Thus, the user is | ||
125 | * able to perform IO operations on this port. | ||
126 | * This state is entered from the STARTING state. | ||
127 | */ | ||
128 | SCI_BASE_PORT_STATE_READY, | ||
129 | |||
130 | /** | ||
131 | * This state indicates the port is in the process of performing a hard | ||
132 | * reset. Thus, the user is unable to perform IO operations on this | ||
133 | * port. | ||
134 | * This state is entered from the READY state. | ||
135 | */ | ||
136 | SCI_BASE_PORT_STATE_RESETTING, | ||
137 | |||
138 | /** | ||
139 | * This state indicates the port has failed a reset request. This state | ||
140 | * is entered when a port reset request times out. | ||
141 | * This state is entered from the RESETTING state. | ||
142 | */ | ||
143 | SCI_BASE_PORT_STATE_FAILED, | ||
144 | |||
145 | SCI_BASE_PORT_MAX_STATES | ||
146 | |||
147 | }; | ||
148 | |||
149 | /** | ||
150 | * struct scic_sds_port | ||
151 | * | ||
152 | * The core port object provides the the abstraction for an SCU port. | ||
153 | */ | ||
154 | struct scic_sds_port { | ||
155 | |||
156 | /** | ||
157 | * This field contains the information for the base port state machine. | ||
158 | */ | ||
159 | struct sci_base_state_machine state_machine; | ||
160 | |||
161 | /** | ||
162 | * This field is the port index that is reported to the SCI USER. | ||
163 | * This allows the actual hardware physical port to change without | ||
164 | * the SCI USER getting a different answer for the get port index. | ||
165 | */ | ||
166 | u8 logical_port_index; | ||
167 | |||
168 | /** | ||
169 | * This field is the port index used to program the SCU hardware. | ||
170 | */ | ||
171 | u8 physical_port_index; | ||
172 | |||
173 | /** | ||
174 | * This field contains the active phy mask for the port. | ||
175 | * This mask is used in conjunction with the phy state to determine | ||
176 | * which phy to select for some port operations. | ||
177 | */ | ||
178 | u8 active_phy_mask; | ||
179 | |||
180 | u16 reserved_rni; | ||
181 | u16 reserved_tci; | ||
182 | |||
183 | /** | ||
184 | * This field contains the count of the io requests started on this port | ||
185 | * object. It is used to control controller shutdown. | ||
186 | */ | ||
187 | u32 started_request_count; | ||
188 | |||
189 | /** | ||
190 | * This field contains the number of devices assigned to this port. | ||
191 | * It is used to control port start requests. | ||
192 | */ | ||
193 | u32 assigned_device_count; | ||
194 | |||
195 | /** | ||
196 | * This field contains the reason for the port not going ready. It is | ||
197 | * assigned in the state handlers and used in the state transition. | ||
198 | */ | ||
199 | u32 not_ready_reason; | ||
200 | |||
201 | /** | ||
202 | * This field is the table of phys assigned to the port. | ||
203 | */ | ||
204 | struct scic_sds_phy *phy_table[SCI_MAX_PHYS]; | ||
205 | |||
206 | /** | ||
207 | * This field is a pointer back to the controller that owns this | ||
208 | * port object. | ||
209 | */ | ||
210 | struct scic_sds_controller *owning_controller; | ||
211 | |||
212 | /** | ||
213 | * This field contains the port start/stop timer handle. | ||
214 | */ | ||
215 | void *timer_handle; | ||
216 | |||
217 | /** | ||
218 | * This field points to the current set of state handlers for this port | ||
219 | * object. These state handlers are assigned at each enter state of | ||
220 | * the state machine. | ||
221 | */ | ||
222 | struct scic_sds_port_state_handler *state_handlers; | ||
223 | |||
224 | /** | ||
225 | * This field is the ready substate machine for the port. | ||
226 | */ | ||
227 | struct sci_base_state_machine ready_substate_machine; | ||
228 | |||
229 | /* / Memory mapped hardware register space */ | ||
230 | |||
231 | /** | ||
232 | * This field is the pointer to the port task scheduler registers | ||
233 | * for the SCU hardware. | ||
234 | */ | ||
235 | struct scu_port_task_scheduler_registers __iomem | ||
236 | *port_task_scheduler_registers; | ||
237 | |||
238 | /** | ||
239 | * This field is identical for all port objects and points to the port | ||
240 | * task scheduler group PE configuration registers. | ||
241 | * It is used to assign PEs to a port. | ||
242 | */ | ||
243 | u32 __iomem *port_pe_configuration_register; | ||
244 | |||
245 | /** | ||
246 | * This field is the VIIT register space for ths port object. | ||
247 | */ | ||
248 | struct scu_viit_entry __iomem *viit_registers; | ||
249 | |||
250 | }; | ||
251 | |||
252 | typedef enum sci_status (*scic_sds_port_handler_t)(struct scic_sds_port *); | ||
253 | |||
254 | typedef enum sci_status (*scic_sds_port_phy_handler_t)(struct scic_sds_port *, | ||
255 | struct scic_sds_phy *); | ||
256 | |||
257 | typedef enum sci_status (*scic_sds_port_reset_handler_t)(struct scic_sds_port *, | ||
258 | u32 timeout); | ||
259 | |||
260 | typedef enum sci_status (*scic_sds_port_event_handler_t)(struct scic_sds_port *, u32); | ||
261 | |||
262 | typedef enum sci_status (*scic_sds_port_frame_handler_t)(struct scic_sds_port *, u32); | ||
263 | |||
264 | typedef void (*scic_sds_port_link_handler_t)(struct scic_sds_port *, struct scic_sds_phy *); | ||
265 | |||
266 | typedef enum sci_status (*scic_sds_port_io_request_handler_t)(struct scic_sds_port *, | ||
267 | struct scic_sds_remote_device *, | ||
268 | struct scic_sds_request *); | ||
269 | |||
270 | struct scic_sds_port_state_handler { | ||
271 | /** | ||
272 | * The start_handler specifies the method invoked when a user | ||
273 | * attempts to start a port. | ||
274 | */ | ||
275 | scic_sds_port_handler_t start_handler; | ||
276 | |||
277 | /** | ||
278 | * The stop_handler specifies the method invoked when a user | ||
279 | * attempts to stop a port. | ||
280 | */ | ||
281 | scic_sds_port_handler_t stop_handler; | ||
282 | |||
283 | /** | ||
284 | * The destruct_handler specifies the method invoked when attempting to | ||
285 | * destruct a port. | ||
286 | */ | ||
287 | scic_sds_port_handler_t destruct_handler; | ||
288 | |||
289 | /** | ||
290 | * The reset_handler specifies the method invoked when a user | ||
291 | * attempts to hard reset a port. | ||
292 | */ | ||
293 | scic_sds_port_reset_handler_t reset_handler; | ||
294 | |||
295 | /** | ||
296 | * The add_phy_handler specifies the method invoked when a user | ||
297 | * attempts to add another phy into the port. | ||
298 | */ | ||
299 | scic_sds_port_phy_handler_t add_phy_handler; | ||
300 | |||
301 | /** | ||
302 | * The remove_phy_handler specifies the method invoked when a user | ||
303 | * attempts to remove a phy from the port. | ||
304 | */ | ||
305 | scic_sds_port_phy_handler_t remove_phy_handler; | ||
306 | |||
307 | scic_sds_port_frame_handler_t frame_handler; | ||
308 | scic_sds_port_event_handler_t event_handler; | ||
309 | |||
310 | scic_sds_port_link_handler_t link_up_handler; | ||
311 | scic_sds_port_link_handler_t link_down_handler; | ||
312 | |||
313 | scic_sds_port_io_request_handler_t start_io_handler; | ||
314 | scic_sds_port_io_request_handler_t complete_io_handler; | ||
315 | |||
316 | }; | ||
317 | |||
318 | /** | ||
319 | * scic_sds_port_get_controller() - | ||
320 | * | ||
321 | * Helper macro to get the owning controller of this port | ||
322 | */ | ||
323 | #define scic_sds_port_get_controller(this_port) \ | ||
324 | ((this_port)->owning_controller) | ||
325 | |||
326 | /** | ||
327 | * scic_sds_port_set_base_state_handlers() - | ||
328 | * | ||
329 | * This macro will change the state handlers to those of the specified state id | ||
330 | */ | ||
331 | #define scic_sds_port_set_base_state_handlers(this_port, state_id) \ | ||
332 | scic_sds_port_set_state_handlers(\ | ||
333 | (this_port), &scic_sds_port_state_handler_table[(state_id)]) | ||
334 | |||
335 | /** | ||
336 | * scic_sds_port_set_state_handlers() - | ||
337 | * | ||
338 | * Helper macro to set the port object state handlers | ||
339 | */ | ||
340 | #define scic_sds_port_set_state_handlers(this_port, handlers) \ | ||
341 | ((this_port)->state_handlers = (handlers)) | ||
342 | |||
343 | /** | ||
344 | * scic_sds_port_get_index() - | ||
345 | * | ||
346 | * This macro returns the physical port index for this port object | ||
347 | */ | ||
348 | #define scic_sds_port_get_index(this_port) \ | ||
349 | ((this_port)->physical_port_index) | ||
350 | |||
351 | |||
352 | static inline void scic_sds_port_decrement_request_count(struct scic_sds_port *sci_port) | ||
353 | { | ||
354 | if (WARN_ONCE(sci_port->started_request_count == 0, | ||
355 | "%s: tried to decrement started_request_count past 0!?", | ||
356 | __func__)) | ||
357 | /* pass */; | ||
358 | else | ||
359 | sci_port->started_request_count--; | ||
360 | } | ||
361 | |||
362 | #define scic_sds_port_active_phy(port, phy) \ | ||
363 | (((port)->active_phy_mask & (1 << (phy)->phy_index)) != 0) | ||
364 | |||
365 | void scic_sds_port_construct( | ||
366 | struct scic_sds_port *sci_port, | ||
367 | u8 port_index, | ||
368 | struct scic_sds_controller *scic); | ||
369 | |||
370 | enum sci_status scic_sds_port_initialize( | ||
371 | struct scic_sds_port *sci_port, | ||
372 | void __iomem *port_task_scheduler_registers, | ||
373 | void __iomem *port_configuration_regsiter, | ||
374 | void __iomem *viit_registers); | ||
375 | |||
376 | enum sci_status scic_sds_port_add_phy( | ||
377 | struct scic_sds_port *sci_port, | ||
378 | struct scic_sds_phy *sci_phy); | ||
379 | |||
380 | enum sci_status scic_sds_port_remove_phy( | ||
381 | struct scic_sds_port *sci_port, | ||
382 | struct scic_sds_phy *sci_phy); | ||
383 | |||
384 | void scic_sds_port_setup_transports( | ||
385 | struct scic_sds_port *sci_port, | ||
386 | u32 device_id); | ||
387 | |||
388 | |||
389 | void scic_sds_port_deactivate_phy( | ||
390 | struct scic_sds_port *sci_port, | ||
391 | struct scic_sds_phy *sci_phy, | ||
392 | bool do_notify_user); | ||
393 | |||
394 | bool scic_sds_port_link_detected( | ||
395 | struct scic_sds_port *sci_port, | ||
396 | struct scic_sds_phy *sci_phy); | ||
397 | |||
398 | void scic_sds_port_link_up( | ||
399 | struct scic_sds_port *sci_port, | ||
400 | struct scic_sds_phy *sci_phy); | ||
401 | |||
402 | void scic_sds_port_link_down( | ||
403 | struct scic_sds_port *sci_port, | ||
404 | struct scic_sds_phy *sci_phy); | ||
405 | |||
406 | enum sci_status scic_sds_port_start_io( | ||
407 | struct scic_sds_port *sci_port, | ||
408 | struct scic_sds_remote_device *sci_dev, | ||
409 | struct scic_sds_request *sci_req); | ||
410 | |||
411 | enum sci_status scic_sds_port_complete_io( | ||
412 | struct scic_sds_port *sci_port, | ||
413 | struct scic_sds_remote_device *sci_dev, | ||
414 | struct scic_sds_request *sci_req); | ||
415 | |||
416 | enum sas_linkrate scic_sds_port_get_max_allowed_speed( | ||
417 | struct scic_sds_port *sci_port); | ||
418 | |||
419 | void scic_sds_port_broadcast_change_received( | ||
420 | struct scic_sds_port *sci_port, | ||
421 | struct scic_sds_phy *sci_phy); | ||
422 | |||
423 | bool scic_sds_port_is_valid_phy_assignment( | ||
424 | struct scic_sds_port *sci_port, | ||
425 | u32 phy_index); | ||
426 | |||
427 | void scic_sds_port_get_sas_address( | ||
428 | struct scic_sds_port *sci_port, | ||
429 | struct sci_sas_address *sas_address); | ||
430 | |||
431 | void scic_sds_port_get_attached_sas_address( | ||
432 | struct scic_sds_port *sci_port, | ||
433 | struct sci_sas_address *sas_address); | ||
434 | |||
435 | #endif /* _SCIC_SDS_PORT_H_ */ | ||
diff --git a/drivers/scsi/isci/core/scic_sds_port_configuration_agent.h b/drivers/scsi/isci/core/scic_sds_port_configuration_agent.h deleted file mode 100644 index 7fd161700475..000000000000 --- a/drivers/scsi/isci/core/scic_sds_port_configuration_agent.h +++ /dev/null | |||
@@ -1,107 +0,0 @@ | |||
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 | #ifndef _SCIC_SDS_PORT_CONFIGURATION_AGENT_H_ | ||
57 | #define _SCIC_SDS_PORT_CONFIGURATION_AGENT_H_ | ||
58 | |||
59 | /** | ||
60 | * This file contains the structures, constants and prototypes used for the | ||
61 | * core controller automatic port configuration engine. | ||
62 | * | ||
63 | * | ||
64 | */ | ||
65 | |||
66 | #include "scic_sds_port.h" | ||
67 | |||
68 | struct scic_sds_controller; | ||
69 | struct scic_sds_port_configuration_agent; | ||
70 | struct scic_sds_port; | ||
71 | struct scic_sds_phy; | ||
72 | |||
73 | typedef void (*scic_sds_port_configuration_agent_phy_handler_t)( | ||
74 | struct scic_sds_controller *, | ||
75 | struct scic_sds_port_configuration_agent *, | ||
76 | struct scic_sds_port *, | ||
77 | struct scic_sds_phy * | ||
78 | ); | ||
79 | |||
80 | struct SCIC_SDS_PORT_RANGE { | ||
81 | u8 min_index; | ||
82 | u8 max_index; | ||
83 | }; | ||
84 | |||
85 | struct scic_sds_port_configuration_agent { | ||
86 | u16 phy_configured_mask; | ||
87 | u16 phy_ready_mask; | ||
88 | |||
89 | struct SCIC_SDS_PORT_RANGE phy_valid_port_range[SCI_MAX_PHYS]; | ||
90 | |||
91 | bool timer_pending; | ||
92 | |||
93 | scic_sds_port_configuration_agent_phy_handler_t link_up_handler; | ||
94 | scic_sds_port_configuration_agent_phy_handler_t link_down_handler; | ||
95 | |||
96 | void *timer; | ||
97 | |||
98 | }; | ||
99 | |||
100 | void scic_sds_port_configuration_agent_construct( | ||
101 | struct scic_sds_port_configuration_agent *port_agent); | ||
102 | |||
103 | enum sci_status scic_sds_port_configuration_agent_initialize( | ||
104 | struct scic_sds_controller *controller, | ||
105 | struct scic_sds_port_configuration_agent *port_agent); | ||
106 | |||
107 | #endif /* _SCIC_SDS_PORT_CONFIGURATION_AGENT_H_ */ | ||
diff --git a/drivers/scsi/isci/host.c b/drivers/scsi/isci/host.c index e1930da08d4e..2bb9f1073e73 100644 --- a/drivers/scsi/isci/host.c +++ b/drivers/scsi/isci/host.c | |||
@@ -61,7 +61,6 @@ | |||
61 | #include "probe_roms.h" | 61 | #include "probe_roms.h" |
62 | #include "remote_device.h" | 62 | #include "remote_device.h" |
63 | #include "request.h" | 63 | #include "request.h" |
64 | #include "scic_sds_port_configuration_agent.h" | ||
65 | #include "scu_completion_codes.h" | 64 | #include "scu_completion_codes.h" |
66 | #include "scu_event_codes.h" | 65 | #include "scu_event_codes.h" |
67 | #include "registers.h" | 66 | #include "registers.h" |
diff --git a/drivers/scsi/isci/host.h b/drivers/scsi/isci/host.h index 9c5d121ce791..784e1355e8ec 100644 --- a/drivers/scsi/isci/host.h +++ b/drivers/scsi/isci/host.h | |||
@@ -55,7 +55,6 @@ | |||
55 | #ifndef _SCI_HOST_H_ | 55 | #ifndef _SCI_HOST_H_ |
56 | #define _SCI_HOST_H_ | 56 | #define _SCI_HOST_H_ |
57 | 57 | ||
58 | #include "scic_config_parameters.h" | ||
59 | #include "remote_device.h" | 58 | #include "remote_device.h" |
60 | #include "phy.h" | 59 | #include "phy.h" |
61 | #include "pool.h" | 60 | #include "pool.h" |
@@ -64,11 +63,12 @@ | |||
64 | #include "registers.h" | 63 | #include "registers.h" |
65 | #include "scu_unsolicited_frame.h" | 64 | #include "scu_unsolicited_frame.h" |
66 | #include "unsolicited_frame_control.h" | 65 | #include "unsolicited_frame_control.h" |
67 | #include "scic_sds_port_configuration_agent.h" | 66 | #include "probe_roms.h" |
68 | 67 | ||
69 | struct scic_sds_request; | 68 | struct scic_sds_request; |
70 | struct scu_task_context; | 69 | struct scu_task_context; |
71 | 70 | ||
71 | |||
72 | /** | 72 | /** |
73 | * struct scic_power_control - | 73 | * struct scic_power_control - |
74 | * | 74 | * |
@@ -107,6 +107,24 @@ struct scic_power_control { | |||
107 | 107 | ||
108 | }; | 108 | }; |
109 | 109 | ||
110 | struct scic_sds_port_configuration_agent; | ||
111 | typedef void (*port_config_fn)(struct scic_sds_controller *, | ||
112 | struct scic_sds_port_configuration_agent *, | ||
113 | struct scic_sds_port *, struct scic_sds_phy *); | ||
114 | |||
115 | struct scic_sds_port_configuration_agent { | ||
116 | u16 phy_configured_mask; | ||
117 | u16 phy_ready_mask; | ||
118 | struct { | ||
119 | u8 min_index; | ||
120 | u8 max_index; | ||
121 | } phy_valid_port_range[SCI_MAX_PHYS]; | ||
122 | bool timer_pending; | ||
123 | port_config_fn link_up_handler; | ||
124 | port_config_fn link_down_handler; | ||
125 | void *timer; | ||
126 | }; | ||
127 | |||
110 | /** | 128 | /** |
111 | * struct scic_sds_controller - | 129 | * struct scic_sds_controller - |
112 | * | 130 | * |
@@ -800,4 +818,11 @@ u16 scic_controller_allocate_io_tag( | |||
800 | enum sci_status scic_controller_free_io_tag( | 818 | enum sci_status scic_controller_free_io_tag( |
801 | struct scic_sds_controller *scic, | 819 | struct scic_sds_controller *scic, |
802 | u16 io_tag); | 820 | u16 io_tag); |
821 | |||
822 | void scic_sds_port_configuration_agent_construct( | ||
823 | struct scic_sds_port_configuration_agent *port_agent); | ||
824 | |||
825 | enum sci_status scic_sds_port_configuration_agent_initialize( | ||
826 | struct scic_sds_controller *controller, | ||
827 | struct scic_sds_port_configuration_agent *port_agent); | ||
803 | #endif | 828 | #endif |
diff --git a/drivers/scsi/isci/phy.c b/drivers/scsi/isci/phy.c index b92d51f25481..0f64605200ff 100644 --- a/drivers/scsi/isci/phy.c +++ b/drivers/scsi/isci/phy.c | |||
@@ -57,9 +57,8 @@ | |||
57 | #include "host.h" | 57 | #include "host.h" |
58 | #include "phy.h" | 58 | #include "phy.h" |
59 | #include "scu_event_codes.h" | 59 | #include "scu_event_codes.h" |
60 | #include "scic_port.h" | ||
61 | #include "scic_config_parameters.h" | ||
62 | #include "timers.h" | 60 | #include "timers.h" |
61 | #include "probe_roms.h" | ||
63 | 62 | ||
64 | /* Maximum arbitration wait time in micro-seconds */ | 63 | /* Maximum arbitration wait time in micro-seconds */ |
65 | #define SCIC_SDS_PHY_MAX_ARBITRATION_WAIT_TIME (700) | 64 | #define SCIC_SDS_PHY_MAX_ARBITRATION_WAIT_TIME (700) |
diff --git a/drivers/scsi/isci/phy.h b/drivers/scsi/isci/phy.h index 093fd473366c..f1800368eda5 100644 --- a/drivers/scsi/isci/phy.h +++ b/drivers/scsi/isci/phy.h | |||
@@ -58,6 +58,7 @@ | |||
58 | #include <scsi/sas.h> | 58 | #include <scsi/sas.h> |
59 | #include <scsi/libsas.h> | 59 | #include <scsi/libsas.h> |
60 | #include "state_machine.h" | 60 | #include "state_machine.h" |
61 | #include "sas.h" | ||
61 | 62 | ||
62 | /* This is the timeout value for the SATA phy to wait for a SIGNATURE FIS | 63 | /* This is the timeout value for the SATA phy to wait for a SIGNATURE FIS |
63 | * before restarting the starting state machine. Technically, the old parallel | 64 | * before restarting the starting state machine. Technically, the old parallel |
diff --git a/drivers/scsi/isci/port.c b/drivers/scsi/isci/port.c index 321935d9560b..dbff28396dd8 100644 --- a/drivers/scsi/isci/port.c +++ b/drivers/scsi/isci/port.c | |||
@@ -53,11 +53,13 @@ | |||
53 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 53 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
54 | */ | 54 | */ |
55 | 55 | ||
56 | #include <linux/workqueue.h> | ||
57 | #include "isci.h" | 56 | #include "isci.h" |
58 | #include "scic_port.h" | ||
59 | #include "port.h" | 57 | #include "port.h" |
60 | #include "request.h" | 58 | #include "request.h" |
59 | #include "timers.h" | ||
60 | |||
61 | #define SCIC_SDS_PORT_HARD_RESET_TIMEOUT (1000) | ||
62 | #define SCU_DUMMY_INDEX (0xFFFF) | ||
61 | 63 | ||
62 | static void isci_port_change_state(struct isci_port *iport, enum isci_status status) | 64 | static void isci_port_change_state(struct isci_port *iport, enum isci_status status) |
63 | { | 65 | { |
@@ -73,44 +75,87 @@ static void isci_port_change_state(struct isci_port *iport, enum isci_status sta | |||
73 | spin_unlock_irqrestore(&iport->state_lock, flags); | 75 | spin_unlock_irqrestore(&iport->state_lock, flags); |
74 | } | 76 | } |
75 | 77 | ||
76 | void isci_port_init(struct isci_port *iport, struct isci_host *ihost, int index) | 78 | /* |
79 | * This function will indicate which protocols are supported by this port. | ||
80 | * @sci_port: a handle corresponding to the SAS port for which to return the | ||
81 | * supported protocols. | ||
82 | * @protocols: This parameter specifies a pointer to a data structure | ||
83 | * which the core will copy the protocol values for the port from the | ||
84 | * transmit_identification register. | ||
85 | */ | ||
86 | static void | ||
87 | scic_sds_port_get_protocols(struct scic_sds_port *sci_port, | ||
88 | struct scic_phy_proto *protocols) | ||
77 | { | 89 | { |
78 | INIT_LIST_HEAD(&iport->remote_dev_list); | 90 | u8 index; |
79 | INIT_LIST_HEAD(&iport->domain_dev_list); | 91 | |
80 | spin_lock_init(&iport->state_lock); | 92 | protocols->all = 0; |
81 | init_completion(&iport->start_complete); | 93 | |
82 | iport->isci_host = ihost; | 94 | for (index = 0; index < SCI_MAX_PHYS; index++) { |
83 | isci_port_change_state(iport, isci_freed); | 95 | if (sci_port->phy_table[index] != NULL) { |
96 | scic_sds_phy_get_protocols(sci_port->phy_table[index], | ||
97 | protocols); | ||
98 | } | ||
99 | } | ||
84 | } | 100 | } |
85 | 101 | ||
86 | /** | 102 | /** |
87 | * isci_port_get_state() - This function gets the status of the port object. | 103 | * This method requests a list (mask) of the phys contained in the supplied SAS |
88 | * @isci_port: This parameter points to the isci_port object | 104 | * port. |
105 | * @sci_port: a handle corresponding to the SAS port for which to return the | ||
106 | * phy mask. | ||
89 | * | 107 | * |
90 | * status of the object as a isci_status enum. | 108 | * Return a bit mask indicating which phys are a part of this port. Each bit |
109 | * corresponds to a phy identifier (e.g. bit 0 = phy id 0). | ||
91 | */ | 110 | */ |
92 | enum isci_status isci_port_get_state( | 111 | static u32 scic_sds_port_get_phys(struct scic_sds_port *sci_port) |
93 | struct isci_port *isci_port) | ||
94 | { | 112 | { |
95 | return isci_port->status; | 113 | u32 index; |
114 | u32 mask; | ||
115 | |||
116 | mask = 0; | ||
117 | |||
118 | for (index = 0; index < SCI_MAX_PHYS; index++) { | ||
119 | if (sci_port->phy_table[index] != NULL) { | ||
120 | mask |= (1 << index); | ||
121 | } | ||
122 | } | ||
123 | |||
124 | return mask; | ||
96 | } | 125 | } |
97 | 126 | ||
98 | void isci_port_bc_change_received(struct isci_host *ihost, | 127 | /** |
99 | struct scic_sds_port *sci_port, | 128 | * scic_port_get_properties() - This method simply returns the properties |
100 | struct scic_sds_phy *sci_phy) | 129 | * regarding the port, such as: physical index, protocols, sas address, etc. |
130 | * @port: this parameter specifies the port for which to retrieve the physical | ||
131 | * index. | ||
132 | * @properties: This parameter specifies the properties structure into which to | ||
133 | * copy the requested information. | ||
134 | * | ||
135 | * Indicate if the user specified a valid port. SCI_SUCCESS This value is | ||
136 | * returned if the specified port was valid. SCI_FAILURE_INVALID_PORT This | ||
137 | * value is returned if the specified port is not valid. When this value is | ||
138 | * returned, no data is copied to the properties output parameter. | ||
139 | */ | ||
140 | static enum sci_status scic_port_get_properties(struct scic_sds_port *port, | ||
141 | struct scic_port_properties *prop) | ||
101 | { | 142 | { |
102 | struct isci_phy *iphy = sci_phy_to_iphy(sci_phy); | 143 | if ((port == NULL) || |
144 | (port->logical_port_index == SCIC_SDS_DUMMY_PORT)) | ||
145 | return SCI_FAILURE_INVALID_PORT; | ||
103 | 146 | ||
104 | dev_dbg(&ihost->pdev->dev, "%s: iphy = %p, sas_phy = %p\n", | 147 | prop->index = port->logical_port_index; |
105 | __func__, iphy, &iphy->sas_phy); | 148 | prop->phy_mask = scic_sds_port_get_phys(port); |
149 | scic_sds_port_get_sas_address(port, &prop->local.sas_address); | ||
150 | scic_sds_port_get_protocols(port, &prop->local.protocols); | ||
151 | scic_sds_port_get_attached_sas_address(port, &prop->remote.sas_address); | ||
106 | 152 | ||
107 | ihost->sas_ha.notify_port_event(&iphy->sas_phy, PORTE_BROADCAST_RCVD); | 153 | return SCI_SUCCESS; |
108 | scic_port_enable_broadcast_change_notification(sci_port); | ||
109 | } | 154 | } |
110 | 155 | ||
111 | void isci_port_link_up(struct isci_host *isci_host, | 156 | static void isci_port_link_up(struct isci_host *isci_host, |
112 | struct scic_sds_port *port, | 157 | struct scic_sds_port *port, |
113 | struct scic_sds_phy *phy) | 158 | struct scic_sds_phy *phy) |
114 | { | 159 | { |
115 | unsigned long flags; | 160 | unsigned long flags; |
116 | struct scic_port_properties properties; | 161 | struct scic_port_properties properties; |
@@ -184,8 +229,9 @@ void isci_port_link_up(struct isci_host *isci_host, | |||
184 | * @port: This parameter specifies the isci port with the active link. | 229 | * @port: This parameter specifies the isci port with the active link. |
185 | * | 230 | * |
186 | */ | 231 | */ |
187 | void isci_port_link_down(struct isci_host *isci_host, struct isci_phy *isci_phy, | 232 | static void isci_port_link_down(struct isci_host *isci_host, |
188 | struct isci_port *isci_port) | 233 | struct isci_phy *isci_phy, |
234 | struct isci_port *isci_port) | ||
189 | { | 235 | { |
190 | struct isci_remote_device *isci_device; | 236 | struct isci_remote_device *isci_device; |
191 | 237 | ||
@@ -231,37 +277,13 @@ void isci_port_link_down(struct isci_host *isci_host, struct isci_phy *isci_phy, | |||
231 | 277 | ||
232 | 278 | ||
233 | /** | 279 | /** |
234 | * isci_port_deformed() - This function is called by libsas when a port becomes | ||
235 | * inactive. | ||
236 | * @phy: This parameter specifies the libsas phy with the inactive port. | ||
237 | * | ||
238 | */ | ||
239 | void isci_port_deformed( | ||
240 | struct asd_sas_phy *phy) | ||
241 | { | ||
242 | pr_debug("%s: sas_phy = %p\n", __func__, phy); | ||
243 | } | ||
244 | |||
245 | /** | ||
246 | * isci_port_formed() - This function is called by libsas when a port becomes | ||
247 | * active. | ||
248 | * @phy: This parameter specifies the libsas phy with the active port. | ||
249 | * | ||
250 | */ | ||
251 | void isci_port_formed( | ||
252 | struct asd_sas_phy *phy) | ||
253 | { | ||
254 | pr_debug("%s: sas_phy = %p, sas_port = %p\n", __func__, phy, phy->port); | ||
255 | } | ||
256 | |||
257 | /** | ||
258 | * isci_port_ready() - This function is called by the sci core when a link | 280 | * isci_port_ready() - This function is called by the sci core when a link |
259 | * becomes ready. | 281 | * becomes ready. |
260 | * @isci_host: This parameter specifies the isci host object. | 282 | * @isci_host: This parameter specifies the isci host object. |
261 | * @port: This parameter specifies the sci port with the active link. | 283 | * @port: This parameter specifies the sci port with the active link. |
262 | * | 284 | * |
263 | */ | 285 | */ |
264 | void isci_port_ready(struct isci_host *isci_host, struct isci_port *isci_port) | 286 | static void isci_port_ready(struct isci_host *isci_host, struct isci_port *isci_port) |
265 | { | 287 | { |
266 | dev_dbg(&isci_host->pdev->dev, | 288 | dev_dbg(&isci_host->pdev->dev, |
267 | "%s: isci_port = %p\n", __func__, isci_port); | 289 | "%s: isci_port = %p\n", __func__, isci_port); |
@@ -279,12 +301,19 @@ void isci_port_ready(struct isci_host *isci_host, struct isci_port *isci_port) | |||
279 | * @port: This parameter specifies the sci port with the active link. | 301 | * @port: This parameter specifies the sci port with the active link. |
280 | * | 302 | * |
281 | */ | 303 | */ |
282 | void isci_port_not_ready(struct isci_host *isci_host, struct isci_port *isci_port) | 304 | static void isci_port_not_ready(struct isci_host *isci_host, struct isci_port *isci_port) |
283 | { | 305 | { |
284 | dev_dbg(&isci_host->pdev->dev, | 306 | dev_dbg(&isci_host->pdev->dev, |
285 | "%s: isci_port = %p\n", __func__, isci_port); | 307 | "%s: isci_port = %p\n", __func__, isci_port); |
286 | } | 308 | } |
287 | 309 | ||
310 | static void isci_port_stop_complete(struct scic_sds_controller *scic, | ||
311 | struct scic_sds_port *sci_port, | ||
312 | enum sci_status completion_status) | ||
313 | { | ||
314 | dev_dbg(&scic_to_ihost(scic)->pdev->dev, "Port stop complete\n"); | ||
315 | } | ||
316 | |||
288 | /** | 317 | /** |
289 | * isci_port_hard_reset_complete() - This function is called by the sci core | 318 | * isci_port_hard_reset_complete() - This function is called by the sci core |
290 | * when the hard reset complete notification has been received. | 319 | * when the hard reset complete notification has been received. |
@@ -293,8 +322,8 @@ void isci_port_not_ready(struct isci_host *isci_host, struct isci_port *isci_por | |||
293 | * process. | 322 | * process. |
294 | * | 323 | * |
295 | */ | 324 | */ |
296 | void isci_port_hard_reset_complete(struct isci_port *isci_port, | 325 | static void isci_port_hard_reset_complete(struct isci_port *isci_port, |
297 | enum sci_status completion_status) | 326 | enum sci_status completion_status) |
298 | { | 327 | { |
299 | dev_dbg(&isci_port->isci_host->pdev->dev, | 328 | dev_dbg(&isci_port->isci_host->pdev->dev, |
300 | "%s: isci_port = %p, completion_status=%x\n", | 329 | "%s: isci_port = %p, completion_status=%x\n", |
@@ -306,6 +335,2293 @@ void isci_port_hard_reset_complete(struct isci_port *isci_port, | |||
306 | complete_all(&isci_port->hard_reset_complete); | 335 | complete_all(&isci_port->hard_reset_complete); |
307 | } | 336 | } |
308 | 337 | ||
338 | /* This method will return a true value if the specified phy can be assigned to | ||
339 | * this port The following is a list of phys for each port that are allowed: - | ||
340 | * Port 0 - 3 2 1 0 - Port 1 - 1 - Port 2 - 3 2 - Port 3 - 3 This method | ||
341 | * doesn't preclude all configurations. It merely ensures that a phy is part | ||
342 | * of the allowable set of phy identifiers for that port. For example, one | ||
343 | * could assign phy 3 to port 0 and no other phys. Please refer to | ||
344 | * scic_sds_port_is_phy_mask_valid() for information regarding whether the | ||
345 | * phy_mask for a port can be supported. bool true if this is a valid phy | ||
346 | * assignment for the port false if this is not a valid phy assignment for the | ||
347 | * port | ||
348 | */ | ||
349 | bool scic_sds_port_is_valid_phy_assignment(struct scic_sds_port *sci_port, | ||
350 | u32 phy_index) | ||
351 | { | ||
352 | /* Initialize to invalid value. */ | ||
353 | u32 existing_phy_index = SCI_MAX_PHYS; | ||
354 | u32 index; | ||
355 | |||
356 | if ((sci_port->physical_port_index == 1) && (phy_index != 1)) { | ||
357 | return false; | ||
358 | } | ||
359 | |||
360 | if (sci_port->physical_port_index == 3 && phy_index != 3) { | ||
361 | return false; | ||
362 | } | ||
363 | |||
364 | if ( | ||
365 | (sci_port->physical_port_index == 2) | ||
366 | && ((phy_index == 0) || (phy_index == 1)) | ||
367 | ) { | ||
368 | return false; | ||
369 | } | ||
370 | |||
371 | for (index = 0; index < SCI_MAX_PHYS; index++) { | ||
372 | if ((sci_port->phy_table[index] != NULL) | ||
373 | && (index != phy_index)) { | ||
374 | existing_phy_index = index; | ||
375 | } | ||
376 | } | ||
377 | |||
378 | /* | ||
379 | * Ensure that all of the phys in the port are capable of | ||
380 | * operating at the same maximum link rate. */ | ||
381 | if ( | ||
382 | (existing_phy_index < SCI_MAX_PHYS) | ||
383 | && (sci_port->owning_controller->user_parameters.sds1.phys[ | ||
384 | phy_index].max_speed_generation != | ||
385 | sci_port->owning_controller->user_parameters.sds1.phys[ | ||
386 | existing_phy_index].max_speed_generation) | ||
387 | ) | ||
388 | return false; | ||
389 | |||
390 | return true; | ||
391 | } | ||
392 | |||
393 | /** | ||
394 | * | ||
395 | * @sci_port: This is the port object for which to determine if the phy mask | ||
396 | * can be supported. | ||
397 | * | ||
398 | * This method will return a true value if the port's phy mask can be supported | ||
399 | * by the SCU. The following is a list of valid PHY mask configurations for | ||
400 | * each port: - Port 0 - [[3 2] 1] 0 - Port 1 - [1] - Port 2 - [[3] 2] | ||
401 | * - Port 3 - [3] This method returns a boolean indication specifying if the | ||
402 | * phy mask can be supported. true if this is a valid phy assignment for the | ||
403 | * port false if this is not a valid phy assignment for the port | ||
404 | */ | ||
405 | static bool scic_sds_port_is_phy_mask_valid( | ||
406 | struct scic_sds_port *sci_port, | ||
407 | u32 phy_mask) | ||
408 | { | ||
409 | if (sci_port->physical_port_index == 0) { | ||
410 | if (((phy_mask & 0x0F) == 0x0F) | ||
411 | || ((phy_mask & 0x03) == 0x03) | ||
412 | || ((phy_mask & 0x01) == 0x01) | ||
413 | || (phy_mask == 0)) | ||
414 | return true; | ||
415 | } else if (sci_port->physical_port_index == 1) { | ||
416 | if (((phy_mask & 0x02) == 0x02) | ||
417 | || (phy_mask == 0)) | ||
418 | return true; | ||
419 | } else if (sci_port->physical_port_index == 2) { | ||
420 | if (((phy_mask & 0x0C) == 0x0C) | ||
421 | || ((phy_mask & 0x04) == 0x04) | ||
422 | || (phy_mask == 0)) | ||
423 | return true; | ||
424 | } else if (sci_port->physical_port_index == 3) { | ||
425 | if (((phy_mask & 0x08) == 0x08) | ||
426 | || (phy_mask == 0)) | ||
427 | return true; | ||
428 | } | ||
429 | |||
430 | return false; | ||
431 | } | ||
432 | |||
433 | /** | ||
434 | * | ||
435 | * @sci_port: This parameter specifies the port from which to return a | ||
436 | * connected phy. | ||
437 | * | ||
438 | * This method retrieves a currently active (i.e. connected) phy contained in | ||
439 | * the port. Currently, the lowest order phy that is connected is returned. | ||
440 | * This method returns a pointer to a SCIS_SDS_PHY object. NULL This value is | ||
441 | * returned if there are no currently active (i.e. connected to a remote end | ||
442 | * point) phys contained in the port. All other values specify a struct scic_sds_phy | ||
443 | * object that is active in the port. | ||
444 | */ | ||
445 | static struct scic_sds_phy *scic_sds_port_get_a_connected_phy( | ||
446 | struct scic_sds_port *sci_port | ||
447 | ) { | ||
448 | u32 index; | ||
449 | struct scic_sds_phy *phy; | ||
450 | |||
451 | for (index = 0; index < SCI_MAX_PHYS; index++) { | ||
452 | /* | ||
453 | * Ensure that the phy is both part of the port and currently | ||
454 | * connected to the remote end-point. */ | ||
455 | phy = sci_port->phy_table[index]; | ||
456 | if ( | ||
457 | (phy != NULL) | ||
458 | && scic_sds_port_active_phy(sci_port, phy) | ||
459 | ) { | ||
460 | return phy; | ||
461 | } | ||
462 | } | ||
463 | |||
464 | return NULL; | ||
465 | } | ||
466 | |||
467 | /** | ||
468 | * scic_sds_port_set_phy() - | ||
469 | * @out]: port The port object to which the phy assignement is being made. | ||
470 | * @out]: phy The phy which is being assigned to the port. | ||
471 | * | ||
472 | * This method attempts to make the assignment of the phy to the port. If | ||
473 | * successful the phy is assigned to the ports phy table. bool true if the phy | ||
474 | * assignment can be made. false if the phy assignement can not be made. This | ||
475 | * is a functional test that only fails if the phy is currently assigned to a | ||
476 | * different port. | ||
477 | */ | ||
478 | static enum sci_status scic_sds_port_set_phy( | ||
479 | struct scic_sds_port *port, | ||
480 | struct scic_sds_phy *phy) | ||
481 | { | ||
482 | /* | ||
483 | * Check to see if we can add this phy to a port | ||
484 | * that means that the phy is not part of a port and that the port does | ||
485 | * not already have a phy assinged to the phy index. */ | ||
486 | if ( | ||
487 | (port->phy_table[phy->phy_index] == NULL) | ||
488 | && (scic_sds_phy_get_port(phy) == NULL) | ||
489 | && scic_sds_port_is_valid_phy_assignment(port, phy->phy_index) | ||
490 | ) { | ||
491 | /* | ||
492 | * Phy is being added in the stopped state so we are in MPC mode | ||
493 | * make logical port index = physical port index */ | ||
494 | port->logical_port_index = port->physical_port_index; | ||
495 | port->phy_table[phy->phy_index] = phy; | ||
496 | scic_sds_phy_set_port(phy, port); | ||
497 | |||
498 | return SCI_SUCCESS; | ||
499 | } | ||
500 | |||
501 | return SCI_FAILURE; | ||
502 | } | ||
503 | |||
504 | /** | ||
505 | * scic_sds_port_clear_phy() - | ||
506 | * @out]: port The port from which the phy is being cleared. | ||
507 | * @out]: phy The phy being cleared from the port. | ||
508 | * | ||
509 | * This method will clear the phy assigned to this port. This method fails if | ||
510 | * this phy is not currently assinged to this port. bool true if the phy is | ||
511 | * removed from the port. false if this phy is not assined to this port. | ||
512 | */ | ||
513 | static enum sci_status scic_sds_port_clear_phy( | ||
514 | struct scic_sds_port *port, | ||
515 | struct scic_sds_phy *phy) | ||
516 | { | ||
517 | /* Make sure that this phy is part of this port */ | ||
518 | if (port->phy_table[phy->phy_index] == phy && | ||
519 | scic_sds_phy_get_port(phy) == port) { | ||
520 | struct scic_sds_controller *scic = port->owning_controller; | ||
521 | struct isci_host *ihost = scic_to_ihost(scic); | ||
522 | |||
523 | /* Yep it is assigned to this port so remove it */ | ||
524 | scic_sds_phy_set_port(phy, &ihost->ports[SCI_MAX_PORTS].sci); | ||
525 | port->phy_table[phy->phy_index] = NULL; | ||
526 | return SCI_SUCCESS; | ||
527 | } | ||
528 | |||
529 | return SCI_FAILURE; | ||
530 | } | ||
531 | |||
532 | /** | ||
533 | * scic_sds_port_add_phy() - | ||
534 | * @sci_port: This parameter specifies the port in which the phy will be added. | ||
535 | * @sci_phy: This parameter is the phy which is to be added to the port. | ||
536 | * | ||
537 | * This method will add a PHY to the selected port. This method returns an | ||
538 | * enum sci_status. SCI_SUCCESS the phy has been added to the port. Any other status | ||
539 | * is failre to add the phy to the port. | ||
540 | */ | ||
541 | enum sci_status scic_sds_port_add_phy( | ||
542 | struct scic_sds_port *sci_port, | ||
543 | struct scic_sds_phy *sci_phy) | ||
544 | { | ||
545 | return sci_port->state_handlers->add_phy_handler( | ||
546 | sci_port, sci_phy); | ||
547 | } | ||
548 | |||
549 | |||
550 | /** | ||
551 | * scic_sds_port_remove_phy() - | ||
552 | * @sci_port: This parameter specifies the port in which the phy will be added. | ||
553 | * @sci_phy: This parameter is the phy which is to be added to the port. | ||
554 | * | ||
555 | * This method will remove the PHY from the selected PORT. This method returns | ||
556 | * an enum sci_status. SCI_SUCCESS the phy has been removed from the port. Any other | ||
557 | * status is failre to add the phy to the port. | ||
558 | */ | ||
559 | enum sci_status scic_sds_port_remove_phy( | ||
560 | struct scic_sds_port *sci_port, | ||
561 | struct scic_sds_phy *sci_phy) | ||
562 | { | ||
563 | return sci_port->state_handlers->remove_phy_handler( | ||
564 | sci_port, sci_phy); | ||
565 | } | ||
566 | |||
567 | /** | ||
568 | * This method requests the SAS address for the supplied SAS port from the SCI | ||
569 | * implementation. | ||
570 | * @sci_port: a handle corresponding to the SAS port for which to return the | ||
571 | * SAS address. | ||
572 | * @sas_address: This parameter specifies a pointer to a SAS address structure | ||
573 | * into which the core will copy the SAS address for the port. | ||
574 | * | ||
575 | */ | ||
576 | void scic_sds_port_get_sas_address( | ||
577 | struct scic_sds_port *sci_port, | ||
578 | struct sci_sas_address *sas_address) | ||
579 | { | ||
580 | u32 index; | ||
581 | |||
582 | sas_address->high = 0; | ||
583 | sas_address->low = 0; | ||
584 | |||
585 | for (index = 0; index < SCI_MAX_PHYS; index++) { | ||
586 | if (sci_port->phy_table[index] != NULL) { | ||
587 | scic_sds_phy_get_sas_address(sci_port->phy_table[index], sas_address); | ||
588 | } | ||
589 | } | ||
590 | } | ||
591 | |||
592 | /* | ||
593 | * This function requests the SAS address for the device directly attached to | ||
594 | * this SAS port. | ||
595 | * @sci_port: a handle corresponding to the SAS port for which to return the | ||
596 | * SAS address. | ||
597 | * @sas_address: This parameter specifies a pointer to a SAS address structure | ||
598 | * into which the core will copy the SAS address for the device directly | ||
599 | * attached to the port. | ||
600 | * | ||
601 | */ | ||
602 | void scic_sds_port_get_attached_sas_address( | ||
603 | struct scic_sds_port *sci_port, | ||
604 | struct sci_sas_address *sas_address) | ||
605 | { | ||
606 | struct scic_sds_phy *sci_phy; | ||
607 | |||
608 | /* | ||
609 | * Ensure that the phy is both part of the port and currently | ||
610 | * connected to the remote end-point. | ||
611 | */ | ||
612 | sci_phy = scic_sds_port_get_a_connected_phy(sci_port); | ||
613 | if (sci_phy) { | ||
614 | if (sci_phy->protocol != SCIC_SDS_PHY_PROTOCOL_SATA) { | ||
615 | scic_sds_phy_get_attached_sas_address(sci_phy, | ||
616 | sas_address); | ||
617 | } else { | ||
618 | scic_sds_phy_get_sas_address(sci_phy, sas_address); | ||
619 | sas_address->low += sci_phy->phy_index; | ||
620 | } | ||
621 | } else { | ||
622 | sas_address->high = 0; | ||
623 | sas_address->low = 0; | ||
624 | } | ||
625 | } | ||
626 | |||
627 | /** | ||
628 | * scic_sds_port_construct_dummy_rnc() - create dummy rnc for si workaround | ||
629 | * | ||
630 | * @sci_port: logical port on which we need to create the remote node context | ||
631 | * @rni: remote node index for this remote node context. | ||
632 | * | ||
633 | * This routine will construct a dummy remote node context data structure | ||
634 | * This structure will be posted to the hardware to work around a scheduler | ||
635 | * error in the hardware. | ||
636 | */ | ||
637 | static void scic_sds_port_construct_dummy_rnc(struct scic_sds_port *sci_port, u16 rni) | ||
638 | { | ||
639 | union scu_remote_node_context *rnc; | ||
640 | |||
641 | rnc = &sci_port->owning_controller->remote_node_context_table[rni]; | ||
642 | |||
643 | memset(rnc, 0, sizeof(union scu_remote_node_context)); | ||
644 | |||
645 | rnc->ssp.remote_sas_address_hi = 0; | ||
646 | rnc->ssp.remote_sas_address_lo = 0; | ||
647 | |||
648 | rnc->ssp.remote_node_index = rni; | ||
649 | rnc->ssp.remote_node_port_width = 1; | ||
650 | rnc->ssp.logical_port_index = sci_port->physical_port_index; | ||
651 | |||
652 | rnc->ssp.nexus_loss_timer_enable = false; | ||
653 | rnc->ssp.check_bit = false; | ||
654 | rnc->ssp.is_valid = true; | ||
655 | rnc->ssp.is_remote_node_context = true; | ||
656 | rnc->ssp.function_number = 0; | ||
657 | rnc->ssp.arbitration_wait_time = 0; | ||
658 | } | ||
659 | |||
660 | /** | ||
661 | * scic_sds_port_construct_dummy_task() - create dummy task for si workaround | ||
662 | * @sci_port The logical port on which we need to create the | ||
663 | * remote node context. | ||
664 | * context. | ||
665 | * @tci The remote node index for this remote node context. | ||
666 | * | ||
667 | * This routine will construct a dummy task context data structure. This | ||
668 | * structure will be posted to the hardwre to work around a scheduler error | ||
669 | * in the hardware. | ||
670 | * | ||
671 | */ | ||
672 | static void scic_sds_port_construct_dummy_task(struct scic_sds_port *sci_port, u16 tci) | ||
673 | { | ||
674 | struct scu_task_context *task_context; | ||
675 | |||
676 | task_context = scic_sds_controller_get_task_context_buffer(sci_port->owning_controller, tci); | ||
677 | |||
678 | memset(task_context, 0, sizeof(struct scu_task_context)); | ||
679 | |||
680 | task_context->abort = 0; | ||
681 | task_context->priority = 0; | ||
682 | task_context->initiator_request = 1; | ||
683 | task_context->connection_rate = 1; | ||
684 | task_context->protocol_engine_index = 0; | ||
685 | task_context->logical_port_index = sci_port->physical_port_index; | ||
686 | task_context->protocol_type = SCU_TASK_CONTEXT_PROTOCOL_SSP; | ||
687 | task_context->task_index = scic_sds_io_tag_get_index(tci); | ||
688 | task_context->valid = SCU_TASK_CONTEXT_VALID; | ||
689 | task_context->context_type = SCU_TASK_CONTEXT_TYPE; | ||
690 | |||
691 | task_context->remote_node_index = sci_port->reserved_rni; | ||
692 | task_context->command_code = 0; | ||
693 | |||
694 | task_context->link_layer_control = 0; | ||
695 | task_context->do_not_dma_ssp_good_response = 1; | ||
696 | task_context->strict_ordering = 0; | ||
697 | task_context->control_frame = 0; | ||
698 | task_context->timeout_enable = 0; | ||
699 | task_context->block_guard_enable = 0; | ||
700 | |||
701 | task_context->address_modifier = 0; | ||
702 | |||
703 | task_context->task_phase = 0x01; | ||
704 | } | ||
705 | |||
706 | static void scic_sds_port_destroy_dummy_resources(struct scic_sds_port *sci_port) | ||
707 | { | ||
708 | struct scic_sds_controller *scic = sci_port->owning_controller; | ||
709 | |||
710 | if (sci_port->reserved_tci != SCU_DUMMY_INDEX) | ||
711 | scic_controller_free_io_tag(scic, sci_port->reserved_tci); | ||
712 | |||
713 | if (sci_port->reserved_rni != SCU_DUMMY_INDEX) | ||
714 | scic_sds_remote_node_table_release_remote_node_index(&scic->available_remote_nodes, | ||
715 | 1, sci_port->reserved_rni); | ||
716 | |||
717 | sci_port->reserved_rni = SCU_DUMMY_INDEX; | ||
718 | sci_port->reserved_tci = SCU_DUMMY_INDEX; | ||
719 | } | ||
720 | |||
721 | /** | ||
722 | * This method performs initialization of the supplied port. Initialization | ||
723 | * includes: - state machine initialization - member variable initialization | ||
724 | * - configuring the phy_mask | ||
725 | * @sci_port: | ||
726 | * @transport_layer_registers: | ||
727 | * @port_task_scheduler_registers: | ||
728 | * @port_configuration_regsiter: | ||
729 | * | ||
730 | * enum sci_status SCI_FAILURE_UNSUPPORTED_PORT_CONFIGURATION This value is returned | ||
731 | * if the phy being added to the port | ||
732 | */ | ||
733 | enum sci_status scic_sds_port_initialize( | ||
734 | struct scic_sds_port *sci_port, | ||
735 | void __iomem *port_task_scheduler_registers, | ||
736 | void __iomem *port_configuration_regsiter, | ||
737 | void __iomem *viit_registers) | ||
738 | { | ||
739 | sci_port->port_task_scheduler_registers = port_task_scheduler_registers; | ||
740 | sci_port->port_pe_configuration_register = port_configuration_regsiter; | ||
741 | sci_port->viit_registers = viit_registers; | ||
742 | |||
743 | return SCI_SUCCESS; | ||
744 | } | ||
745 | |||
746 | /** | ||
747 | * scic_port_hard_reset() - perform port hard reset | ||
748 | * @port: a handle corresponding to the SAS port to be hard reset. | ||
749 | * @reset_timeout: This parameter specifies the number of milliseconds in which | ||
750 | * the port reset operation should complete. | ||
751 | * | ||
752 | * The SCI User callback in scic_user_callbacks_t will only be called once for | ||
753 | * each phy in the SAS Port at completion of the hard reset sequence. Return a | ||
754 | * status indicating whether the hard reset started successfully. SCI_SUCCESS | ||
755 | * This value is returned if the hard reset operation started successfully. | ||
756 | */ | ||
757 | static enum sci_status scic_port_hard_reset(struct scic_sds_port *port, | ||
758 | u32 reset_timeout) | ||
759 | { | ||
760 | return port->state_handlers->reset_handler( | ||
761 | port, reset_timeout); | ||
762 | } | ||
763 | |||
764 | /** | ||
765 | * This method assigns the direct attached device ID for this port. | ||
766 | * | ||
767 | * @param[in] sci_port The port for which the direct attached device id is to | ||
768 | * be assigned. | ||
769 | * @param[in] device_id The direct attached device ID to assign to the port. | ||
770 | * This will be the RNi for the device | ||
771 | */ | ||
772 | void scic_sds_port_setup_transports( | ||
773 | struct scic_sds_port *sci_port, | ||
774 | u32 device_id) | ||
775 | { | ||
776 | u8 index; | ||
777 | |||
778 | for (index = 0; index < SCI_MAX_PHYS; index++) { | ||
779 | if (sci_port->active_phy_mask & (1 << index)) | ||
780 | scic_sds_phy_setup_transport(sci_port->phy_table[index], device_id); | ||
781 | } | ||
782 | } | ||
783 | |||
784 | /** | ||
785 | * | ||
786 | * @sci_port: This is the port on which the phy should be enabled. | ||
787 | * @sci_phy: This is the specific phy which to enable. | ||
788 | * @do_notify_user: This parameter specifies whether to inform the user (via | ||
789 | * scic_cb_port_link_up()) as to the fact that a new phy as become ready. | ||
790 | * | ||
791 | * This function will activate the phy in the port. | ||
792 | * Activation includes: - adding | ||
793 | * the phy to the port - enabling the Protocol Engine in the silicon. - | ||
794 | * notifying the user that the link is up. none | ||
795 | */ | ||
796 | static void scic_sds_port_activate_phy(struct scic_sds_port *sci_port, | ||
797 | struct scic_sds_phy *sci_phy, | ||
798 | bool do_notify_user) | ||
799 | { | ||
800 | struct scic_sds_controller *scic = sci_port->owning_controller; | ||
801 | struct isci_host *ihost = scic_to_ihost(scic); | ||
802 | |||
803 | if (sci_phy->protocol != SCIC_SDS_PHY_PROTOCOL_SATA) | ||
804 | scic_sds_phy_resume(sci_phy); | ||
805 | |||
806 | sci_port->active_phy_mask |= 1 << sci_phy->phy_index; | ||
807 | |||
808 | scic_sds_controller_clear_invalid_phy(scic, sci_phy); | ||
809 | |||
810 | if (do_notify_user == true) | ||
811 | isci_port_link_up(ihost, sci_port, sci_phy); | ||
812 | } | ||
813 | |||
814 | void scic_sds_port_deactivate_phy(struct scic_sds_port *sci_port, | ||
815 | struct scic_sds_phy *sci_phy, | ||
816 | bool do_notify_user) | ||
817 | { | ||
818 | struct scic_sds_controller *scic = scic_sds_port_get_controller(sci_port); | ||
819 | struct isci_port *iport = sci_port_to_iport(sci_port); | ||
820 | struct isci_host *ihost = scic_to_ihost(scic); | ||
821 | struct isci_phy *iphy = sci_phy_to_iphy(sci_phy); | ||
822 | |||
823 | sci_port->active_phy_mask &= ~(1 << sci_phy->phy_index); | ||
824 | |||
825 | sci_phy->max_negotiated_speed = SAS_LINK_RATE_UNKNOWN; | ||
826 | |||
827 | /* Re-assign the phy back to the LP as if it were a narrow port */ | ||
828 | writel(sci_phy->phy_index, | ||
829 | &sci_port->port_pe_configuration_register[sci_phy->phy_index]); | ||
830 | |||
831 | if (do_notify_user == true) | ||
832 | isci_port_link_down(ihost, iphy, iport); | ||
833 | } | ||
834 | |||
835 | /** | ||
836 | * | ||
837 | * @sci_port: This is the port on which the phy should be disabled. | ||
838 | * @sci_phy: This is the specific phy which to disabled. | ||
839 | * | ||
840 | * This function will disable the phy and report that the phy is not valid for | ||
841 | * this port object. None | ||
842 | */ | ||
843 | static void scic_sds_port_invalid_link_up(struct scic_sds_port *sci_port, | ||
844 | struct scic_sds_phy *sci_phy) | ||
845 | { | ||
846 | struct scic_sds_controller *scic = sci_port->owning_controller; | ||
847 | |||
848 | /* | ||
849 | * Check to see if we have alreay reported this link as bad and if | ||
850 | * not go ahead and tell the SCI_USER that we have discovered an | ||
851 | * invalid link. | ||
852 | */ | ||
853 | if ((scic->invalid_phy_mask & (1 << sci_phy->phy_index)) == 0) { | ||
854 | scic_sds_controller_set_invalid_phy(scic, sci_phy); | ||
855 | dev_warn(&scic_to_ihost(scic)->pdev->dev, "Invalid link up!\n"); | ||
856 | } | ||
857 | } | ||
858 | |||
859 | /** | ||
860 | * scic_sds_port_general_link_up_handler - phy can be assigned to port? | ||
861 | * @sci_port: scic_sds_port object for which has a phy that has gone link up. | ||
862 | * @sci_phy: This is the struct scic_sds_phy object that has gone link up. | ||
863 | * @do_notify_user: This parameter specifies whether to inform the user (via | ||
864 | * scic_cb_port_link_up()) as to the fact that a new phy as become ready. | ||
865 | * | ||
866 | * Determine if this phy can be assigned to this | ||
867 | * port . If the phy is not a valid PHY for | ||
868 | * this port then the function will notify the user. A PHY can only be | ||
869 | * part of a port if it's attached SAS ADDRESS is the same as all other PHYs in | ||
870 | * the same port. none | ||
871 | */ | ||
872 | static void scic_sds_port_general_link_up_handler(struct scic_sds_port *sci_port, | ||
873 | struct scic_sds_phy *sci_phy, | ||
874 | bool do_notify_user) | ||
875 | { | ||
876 | struct sci_sas_address port_sas_address; | ||
877 | struct sci_sas_address phy_sas_address; | ||
878 | |||
879 | scic_sds_port_get_attached_sas_address(sci_port, &port_sas_address); | ||
880 | scic_sds_phy_get_attached_sas_address(sci_phy, &phy_sas_address); | ||
881 | |||
882 | /* If the SAS address of the new phy matches the SAS address of | ||
883 | * other phys in the port OR this is the first phy in the port, | ||
884 | * then activate the phy and allow it to be used for operations | ||
885 | * in this port. | ||
886 | */ | ||
887 | if ((phy_sas_address.high == port_sas_address.high && | ||
888 | phy_sas_address.low == port_sas_address.low) || | ||
889 | sci_port->active_phy_mask == 0) { | ||
890 | struct sci_base_state_machine *sm = &sci_port->state_machine; | ||
891 | |||
892 | scic_sds_port_activate_phy(sci_port, sci_phy, do_notify_user); | ||
893 | if (sm->current_state_id == SCI_BASE_PORT_STATE_RESETTING) | ||
894 | sci_base_state_machine_change_state(sm, SCI_BASE_PORT_STATE_READY); | ||
895 | } else | ||
896 | scic_sds_port_invalid_link_up(sci_port, sci_phy); | ||
897 | } | ||
898 | |||
899 | |||
900 | |||
901 | /** | ||
902 | * This method returns false if the port only has a single phy object assigned. | ||
903 | * If there are no phys or more than one phy then the method will return | ||
904 | * true. | ||
905 | * @sci_port: The port for which the wide port condition is to be checked. | ||
906 | * | ||
907 | * bool true Is returned if this is a wide ported port. false Is returned if | ||
908 | * this is a narrow port. | ||
909 | */ | ||
910 | static bool scic_sds_port_is_wide(struct scic_sds_port *sci_port) | ||
911 | { | ||
912 | u32 index; | ||
913 | u32 phy_count = 0; | ||
914 | |||
915 | for (index = 0; index < SCI_MAX_PHYS; index++) { | ||
916 | if (sci_port->phy_table[index] != NULL) { | ||
917 | phy_count++; | ||
918 | } | ||
919 | } | ||
920 | |||
921 | return phy_count != 1; | ||
922 | } | ||
923 | |||
924 | /** | ||
925 | * This method is called by the PHY object when the link is detected. if the | ||
926 | * port wants the PHY to continue on to the link up state then the port | ||
927 | * layer must return true. If the port object returns false the phy object | ||
928 | * must halt its attempt to go link up. | ||
929 | * @sci_port: The port associated with the phy object. | ||
930 | * @sci_phy: The phy object that is trying to go link up. | ||
931 | * | ||
932 | * true if the phy object can continue to the link up condition. true Is | ||
933 | * returned if this phy can continue to the ready state. false Is returned if | ||
934 | * can not continue on to the ready state. This notification is in place for | ||
935 | * wide ports and direct attached phys. Since there are no wide ported SATA | ||
936 | * devices this could become an invalid port configuration. | ||
937 | */ | ||
938 | bool scic_sds_port_link_detected( | ||
939 | struct scic_sds_port *sci_port, | ||
940 | struct scic_sds_phy *sci_phy) | ||
941 | { | ||
942 | if ((sci_port->logical_port_index != SCIC_SDS_DUMMY_PORT) && | ||
943 | (sci_phy->protocol == SCIC_SDS_PHY_PROTOCOL_SATA) && | ||
944 | scic_sds_port_is_wide(sci_port)) { | ||
945 | scic_sds_port_invalid_link_up(sci_port, sci_phy); | ||
946 | |||
947 | return false; | ||
948 | } | ||
949 | |||
950 | return true; | ||
951 | } | ||
952 | |||
953 | /** | ||
954 | * This method is the entry point for the phy to inform the port that it is now | ||
955 | * in a ready state | ||
956 | * @sci_port: | ||
957 | * | ||
958 | * | ||
959 | */ | ||
960 | void scic_sds_port_link_up( | ||
961 | struct scic_sds_port *sci_port, | ||
962 | struct scic_sds_phy *sci_phy) | ||
963 | { | ||
964 | sci_phy->is_in_link_training = false; | ||
965 | |||
966 | sci_port->state_handlers->link_up_handler(sci_port, sci_phy); | ||
967 | } | ||
968 | |||
969 | /** | ||
970 | * This method is the entry point for the phy to inform the port that it is no | ||
971 | * longer in a ready state | ||
972 | * @sci_port: | ||
973 | * | ||
974 | * | ||
975 | */ | ||
976 | void scic_sds_port_link_down( | ||
977 | struct scic_sds_port *sci_port, | ||
978 | struct scic_sds_phy *sci_phy) | ||
979 | { | ||
980 | sci_port->state_handlers->link_down_handler(sci_port, sci_phy); | ||
981 | } | ||
982 | |||
983 | /** | ||
984 | * This method is called to start an IO request on this port. | ||
985 | * @sci_port: | ||
986 | * @sci_dev: | ||
987 | * @sci_req: | ||
988 | * | ||
989 | * enum sci_status | ||
990 | */ | ||
991 | enum sci_status scic_sds_port_start_io( | ||
992 | struct scic_sds_port *sci_port, | ||
993 | struct scic_sds_remote_device *sci_dev, | ||
994 | struct scic_sds_request *sci_req) | ||
995 | { | ||
996 | return sci_port->state_handlers->start_io_handler( | ||
997 | sci_port, sci_dev, sci_req); | ||
998 | } | ||
999 | |||
1000 | /** | ||
1001 | * This method is called to complete an IO request to the port. | ||
1002 | * @sci_port: | ||
1003 | * @sci_dev: | ||
1004 | * @sci_req: | ||
1005 | * | ||
1006 | * enum sci_status | ||
1007 | */ | ||
1008 | enum sci_status scic_sds_port_complete_io( | ||
1009 | struct scic_sds_port *sci_port, | ||
1010 | struct scic_sds_remote_device *sci_dev, | ||
1011 | struct scic_sds_request *sci_req) | ||
1012 | { | ||
1013 | return sci_port->state_handlers->complete_io_handler( | ||
1014 | sci_port, sci_dev, sci_req); | ||
1015 | } | ||
1016 | |||
1017 | /** | ||
1018 | * This method is provided to timeout requests for port operations. Mostly its | ||
1019 | * for the port reset operation. | ||
1020 | * | ||
1021 | * | ||
1022 | */ | ||
1023 | static void scic_sds_port_timeout_handler(void *port) | ||
1024 | { | ||
1025 | struct scic_sds_port *sci_port = port; | ||
1026 | u32 current_state; | ||
1027 | |||
1028 | current_state = sci_base_state_machine_get_state( | ||
1029 | &sci_port->state_machine); | ||
1030 | |||
1031 | if (current_state == SCI_BASE_PORT_STATE_RESETTING) { | ||
1032 | /* | ||
1033 | * if the port is still in the resetting state then the | ||
1034 | * timeout fired before the reset completed. | ||
1035 | */ | ||
1036 | sci_base_state_machine_change_state( | ||
1037 | &sci_port->state_machine, | ||
1038 | SCI_BASE_PORT_STATE_FAILED); | ||
1039 | } else if (current_state == SCI_BASE_PORT_STATE_STOPPED) { | ||
1040 | /* | ||
1041 | * if the port is stopped then the start request failed | ||
1042 | * In this case stay in the stopped state. | ||
1043 | */ | ||
1044 | dev_err(sciport_to_dev(sci_port), | ||
1045 | "%s: SCIC Port 0x%p failed to stop before tiemout.\n", | ||
1046 | __func__, | ||
1047 | sci_port); | ||
1048 | } else if (current_state == SCI_BASE_PORT_STATE_STOPPING) { | ||
1049 | /* | ||
1050 | * if the port is still stopping then the stop has not | ||
1051 | * completed | ||
1052 | */ | ||
1053 | isci_port_stop_complete( | ||
1054 | scic_sds_port_get_controller(sci_port), | ||
1055 | sci_port, | ||
1056 | SCI_FAILURE_TIMEOUT); | ||
1057 | } else { | ||
1058 | /* | ||
1059 | * The port is in the ready state and we have a timer | ||
1060 | * reporting a timeout this should not happen. | ||
1061 | */ | ||
1062 | dev_err(sciport_to_dev(sci_port), | ||
1063 | "%s: SCIC Port 0x%p is processing a timeout operation " | ||
1064 | "in state %d.\n", | ||
1065 | __func__, | ||
1066 | sci_port, | ||
1067 | current_state); | ||
1068 | } | ||
1069 | } | ||
1070 | |||
1071 | /* --------------------------------------------------------------------------- */ | ||
1072 | |||
1073 | /** | ||
1074 | * This function updates the hardwares VIIT entry for this port. | ||
1075 | * | ||
1076 | * | ||
1077 | */ | ||
1078 | static void scic_sds_port_update_viit_entry(struct scic_sds_port *sci_port) | ||
1079 | { | ||
1080 | struct sci_sas_address sas_address; | ||
1081 | |||
1082 | scic_sds_port_get_sas_address(sci_port, &sas_address); | ||
1083 | |||
1084 | writel(sas_address.high, | ||
1085 | &sci_port->viit_registers->initiator_sas_address_hi); | ||
1086 | writel(sas_address.low, | ||
1087 | &sci_port->viit_registers->initiator_sas_address_lo); | ||
1088 | |||
1089 | /* This value get cleared just in case its not already cleared */ | ||
1090 | writel(0, &sci_port->viit_registers->reserved); | ||
1091 | |||
1092 | /* We are required to update the status register last */ | ||
1093 | writel(SCU_VIIT_ENTRY_ID_VIIT | | ||
1094 | SCU_VIIT_IPPT_INITIATOR | | ||
1095 | ((1 << sci_port->physical_port_index) << SCU_VIIT_ENTRY_LPVIE_SHIFT) | | ||
1096 | SCU_VIIT_STATUS_ALL_VALID, | ||
1097 | &sci_port->viit_registers->status); | ||
1098 | } | ||
1099 | |||
1100 | /** | ||
1101 | * This method returns the maximum allowed speed for data transfers on this | ||
1102 | * port. This maximum allowed speed evaluates to the maximum speed of the | ||
1103 | * slowest phy in the port. | ||
1104 | * @sci_port: This parameter specifies the port for which to retrieve the | ||
1105 | * maximum allowed speed. | ||
1106 | * | ||
1107 | * This method returns the maximum negotiated speed of the slowest phy in the | ||
1108 | * port. | ||
1109 | */ | ||
1110 | enum sas_linkrate scic_sds_port_get_max_allowed_speed( | ||
1111 | struct scic_sds_port *sci_port) | ||
1112 | { | ||
1113 | u16 index; | ||
1114 | enum sas_linkrate max_allowed_speed = SAS_LINK_RATE_6_0_GBPS; | ||
1115 | struct scic_sds_phy *phy = NULL; | ||
1116 | |||
1117 | /* | ||
1118 | * Loop through all of the phys in this port and find the phy with the | ||
1119 | * lowest maximum link rate. */ | ||
1120 | for (index = 0; index < SCI_MAX_PHYS; index++) { | ||
1121 | phy = sci_port->phy_table[index]; | ||
1122 | if ( | ||
1123 | (phy != NULL) | ||
1124 | && (scic_sds_port_active_phy(sci_port, phy) == true) | ||
1125 | && (phy->max_negotiated_speed < max_allowed_speed) | ||
1126 | ) | ||
1127 | max_allowed_speed = phy->max_negotiated_speed; | ||
1128 | } | ||
1129 | |||
1130 | return max_allowed_speed; | ||
1131 | } | ||
1132 | |||
1133 | static void scic_port_enable_broadcast_change_notification(struct scic_sds_port *port) | ||
1134 | { | ||
1135 | struct scic_sds_phy *phy; | ||
1136 | u32 register_value; | ||
1137 | u8 index; | ||
1138 | |||
1139 | /* Loop through all of the phys to enable BCN. */ | ||
1140 | for (index = 0; index < SCI_MAX_PHYS; index++) { | ||
1141 | phy = port->phy_table[index]; | ||
1142 | if (phy != NULL) { | ||
1143 | register_value = | ||
1144 | readl(&phy->link_layer_registers->link_layer_control); | ||
1145 | |||
1146 | /* clear the bit by writing 1. */ | ||
1147 | writel(register_value, | ||
1148 | &phy->link_layer_registers->link_layer_control); | ||
1149 | } | ||
1150 | } | ||
1151 | } | ||
1152 | |||
1153 | /* | ||
1154 | * **************************************************************************** | ||
1155 | * * READY SUBSTATE HANDLERS | ||
1156 | * **************************************************************************** */ | ||
1157 | |||
1158 | /* | ||
1159 | * This method is the general ready state stop handler for the struct scic_sds_port | ||
1160 | * object. This function will transition the ready substate machine to its | ||
1161 | * final state. enum sci_status SCI_SUCCESS | ||
1162 | */ | ||
1163 | static enum sci_status scic_sds_port_ready_substate_stop_handler( | ||
1164 | struct scic_sds_port *port) | ||
1165 | { | ||
1166 | sci_base_state_machine_change_state( | ||
1167 | &port->state_machine, | ||
1168 | SCI_BASE_PORT_STATE_STOPPING | ||
1169 | ); | ||
1170 | |||
1171 | return SCI_SUCCESS; | ||
1172 | } | ||
1173 | |||
1174 | /* | ||
1175 | * This method is the general ready substate complete io handler for the | ||
1176 | * struct scic_sds_port object. This function decrments the outstanding request count | ||
1177 | * for this port object. enum sci_status SCI_SUCCESS | ||
1178 | */ | ||
1179 | static enum sci_status scic_sds_port_ready_substate_complete_io_handler( | ||
1180 | struct scic_sds_port *port, | ||
1181 | struct scic_sds_remote_device *device, | ||
1182 | struct scic_sds_request *io_request) | ||
1183 | { | ||
1184 | scic_sds_port_decrement_request_count(port); | ||
1185 | |||
1186 | return SCI_SUCCESS; | ||
1187 | } | ||
1188 | |||
1189 | static enum sci_status scic_sds_port_ready_substate_add_phy_handler( | ||
1190 | struct scic_sds_port *port, | ||
1191 | struct scic_sds_phy *phy) | ||
1192 | { | ||
1193 | enum sci_status status; | ||
1194 | |||
1195 | status = scic_sds_port_set_phy(port, phy); | ||
1196 | |||
1197 | if (status == SCI_SUCCESS) { | ||
1198 | scic_sds_port_general_link_up_handler(port, phy, true); | ||
1199 | |||
1200 | port->not_ready_reason = SCIC_PORT_NOT_READY_RECONFIGURING; | ||
1201 | |||
1202 | sci_base_state_machine_change_state( | ||
1203 | &port->ready_substate_machine, | ||
1204 | SCIC_SDS_PORT_READY_SUBSTATE_CONFIGURING | ||
1205 | ); | ||
1206 | } | ||
1207 | |||
1208 | return status; | ||
1209 | } | ||
1210 | |||
1211 | |||
1212 | static enum sci_status scic_sds_port_ready_substate_remove_phy_handler( | ||
1213 | struct scic_sds_port *port, | ||
1214 | struct scic_sds_phy *phy) | ||
1215 | { | ||
1216 | enum sci_status status; | ||
1217 | |||
1218 | status = scic_sds_port_clear_phy(port, phy); | ||
1219 | |||
1220 | if (status == SCI_SUCCESS) { | ||
1221 | scic_sds_port_deactivate_phy(port, phy, true); | ||
1222 | |||
1223 | port->not_ready_reason = SCIC_PORT_NOT_READY_RECONFIGURING; | ||
1224 | |||
1225 | sci_base_state_machine_change_state( | ||
1226 | &port->ready_substate_machine, | ||
1227 | SCIC_SDS_PORT_READY_SUBSTATE_CONFIGURING | ||
1228 | ); | ||
1229 | } | ||
1230 | |||
1231 | return status; | ||
1232 | } | ||
1233 | |||
1234 | /* | ||
1235 | * **************************************************************************** | ||
1236 | * * READY SUBSTATE WAITING HANDLERS | ||
1237 | * **************************************************************************** */ | ||
1238 | |||
1239 | /** | ||
1240 | * | ||
1241 | * @sci_port: This is the struct scic_sds_port object that which has a phy that has | ||
1242 | * gone link up. | ||
1243 | * @sci_phy: This is the struct scic_sds_phy object that has gone link up. | ||
1244 | * | ||
1245 | * This method is the ready waiting substate link up handler for the | ||
1246 | * struct scic_sds_port object. This methos will report the link up condition for | ||
1247 | * this port and will transition to the ready operational substate. none | ||
1248 | */ | ||
1249 | static void scic_sds_port_ready_waiting_substate_link_up_handler( | ||
1250 | struct scic_sds_port *sci_port, | ||
1251 | struct scic_sds_phy *sci_phy) | ||
1252 | { | ||
1253 | /* | ||
1254 | * Since this is the first phy going link up for the port we can just enable | ||
1255 | * it and continue. */ | ||
1256 | scic_sds_port_activate_phy(sci_port, sci_phy, true); | ||
1257 | |||
1258 | sci_base_state_machine_change_state( | ||
1259 | &sci_port->ready_substate_machine, | ||
1260 | SCIC_SDS_PORT_READY_SUBSTATE_OPERATIONAL | ||
1261 | ); | ||
1262 | } | ||
1263 | |||
1264 | /* | ||
1265 | * This method is the ready waiting substate start io handler for the | ||
1266 | * struct scic_sds_port object. The port object can not accept new requests so the | ||
1267 | * request is failed. enum sci_status SCI_FAILURE_INVALID_STATE | ||
1268 | */ | ||
1269 | static enum sci_status scic_sds_port_ready_waiting_substate_start_io_handler( | ||
1270 | struct scic_sds_port *port, | ||
1271 | struct scic_sds_remote_device *device, | ||
1272 | struct scic_sds_request *io_request) | ||
1273 | { | ||
1274 | return SCI_FAILURE_INVALID_STATE; | ||
1275 | } | ||
1276 | |||
1277 | /* | ||
1278 | * **************************************************************************** | ||
1279 | * * READY SUBSTATE OPERATIONAL HANDLERS | ||
1280 | * **************************************************************************** */ | ||
1281 | |||
1282 | /* | ||
1283 | * This method will casue the port to reset. enum sci_status SCI_SUCCESS | ||
1284 | */ | ||
1285 | static enum | ||
1286 | sci_status scic_sds_port_ready_operational_substate_reset_handler( | ||
1287 | struct scic_sds_port *port, | ||
1288 | u32 timeout) | ||
1289 | { | ||
1290 | enum sci_status status = SCI_FAILURE_INVALID_PHY; | ||
1291 | u32 phy_index; | ||
1292 | struct scic_sds_phy *selected_phy = NULL; | ||
1293 | |||
1294 | |||
1295 | /* Select a phy on which we can send the hard reset request. */ | ||
1296 | for (phy_index = 0; | ||
1297 | (phy_index < SCI_MAX_PHYS) && (selected_phy == NULL); | ||
1298 | phy_index++) { | ||
1299 | selected_phy = port->phy_table[phy_index]; | ||
1300 | |||
1301 | if ((selected_phy != NULL) && | ||
1302 | !scic_sds_port_active_phy(port, selected_phy)) { | ||
1303 | /* | ||
1304 | * We found a phy but it is not ready select | ||
1305 | * different phy | ||
1306 | */ | ||
1307 | selected_phy = NULL; | ||
1308 | } | ||
1309 | } | ||
1310 | |||
1311 | /* If we have a phy then go ahead and start the reset procedure */ | ||
1312 | if (selected_phy != NULL) { | ||
1313 | status = scic_sds_phy_reset(selected_phy); | ||
1314 | |||
1315 | if (status == SCI_SUCCESS) { | ||
1316 | isci_timer_start(port->timer_handle, timeout); | ||
1317 | port->not_ready_reason = | ||
1318 | SCIC_PORT_NOT_READY_HARD_RESET_REQUESTED; | ||
1319 | |||
1320 | sci_base_state_machine_change_state( | ||
1321 | &port->state_machine, | ||
1322 | SCI_BASE_PORT_STATE_RESETTING); | ||
1323 | } | ||
1324 | } | ||
1325 | |||
1326 | return status; | ||
1327 | } | ||
1328 | |||
1329 | /** | ||
1330 | * scic_sds_port_ready_operational_substate_link_up_handler() - | ||
1331 | * @sci_port: This is the struct scic_sds_port object that which has a phy that has | ||
1332 | * gone link up. | ||
1333 | * @sci_phy: This is the struct scic_sds_phy object that has gone link up. | ||
1334 | * | ||
1335 | * This method is the ready operational substate link up handler for the | ||
1336 | * struct scic_sds_port object. This function notifies the SCI User that the phy has | ||
1337 | * gone link up. none | ||
1338 | */ | ||
1339 | static void scic_sds_port_ready_operational_substate_link_up_handler( | ||
1340 | struct scic_sds_port *sci_port, | ||
1341 | struct scic_sds_phy *sci_phy) | ||
1342 | { | ||
1343 | scic_sds_port_general_link_up_handler(sci_port, sci_phy, true); | ||
1344 | } | ||
1345 | |||
1346 | /** | ||
1347 | * scic_sds_port_ready_operational_substate_link_down_handler() - | ||
1348 | * @sci_port: This is the struct scic_sds_port object that which has a phy that has | ||
1349 | * gone link down. | ||
1350 | * @sci_phy: This is the struct scic_sds_phy object that has gone link down. | ||
1351 | * | ||
1352 | * This method is the ready operational substate link down handler for the | ||
1353 | * struct scic_sds_port object. This function notifies the SCI User that the phy has | ||
1354 | * gone link down and if this is the last phy in the port the port will change | ||
1355 | * state to the ready waiting substate. none | ||
1356 | */ | ||
1357 | static void scic_sds_port_ready_operational_substate_link_down_handler( | ||
1358 | struct scic_sds_port *sci_port, | ||
1359 | struct scic_sds_phy *sci_phy) | ||
1360 | { | ||
1361 | scic_sds_port_deactivate_phy(sci_port, sci_phy, true); | ||
1362 | |||
1363 | /* | ||
1364 | * If there are no active phys left in the port, then transition | ||
1365 | * the port to the WAITING state until such time as a phy goes | ||
1366 | * link up. */ | ||
1367 | if (sci_port->active_phy_mask == 0) | ||
1368 | sci_base_state_machine_change_state(&sci_port->ready_substate_machine, | ||
1369 | SCIC_SDS_PORT_READY_SUBSTATE_WAITING); | ||
1370 | } | ||
1371 | |||
1372 | /* | ||
1373 | * This method is the ready operational substate start io handler for the | ||
1374 | * struct scic_sds_port object. This function incremetns the outstanding request | ||
1375 | * count for this port object. enum sci_status SCI_SUCCESS | ||
1376 | */ | ||
1377 | static enum sci_status scic_sds_port_ready_operational_substate_start_io_handler( | ||
1378 | struct scic_sds_port *port, | ||
1379 | struct scic_sds_remote_device *device, | ||
1380 | struct scic_sds_request *io_request) | ||
1381 | { | ||
1382 | port->started_request_count++; | ||
1383 | return SCI_SUCCESS; | ||
1384 | } | ||
1385 | |||
1386 | /* | ||
1387 | * **************************************************************************** | ||
1388 | * * READY SUBSTATE OPERATIONAL HANDLERS | ||
1389 | * **************************************************************************** */ | ||
1390 | |||
1391 | /* | ||
1392 | * This is the default method for a port add phy request. It will report a | ||
1393 | * warning and exit. enum sci_status SCI_FAILURE_INVALID_STATE | ||
1394 | */ | ||
1395 | static enum sci_status scic_sds_port_ready_configuring_substate_add_phy_handler( | ||
1396 | struct scic_sds_port *port, | ||
1397 | struct scic_sds_phy *phy) | ||
1398 | { | ||
1399 | enum sci_status status; | ||
1400 | |||
1401 | status = scic_sds_port_set_phy(port, phy); | ||
1402 | |||
1403 | if (status == SCI_SUCCESS) { | ||
1404 | scic_sds_port_general_link_up_handler(port, phy, true); | ||
1405 | |||
1406 | /* | ||
1407 | * Re-enter the configuring state since this may be the last phy in | ||
1408 | * the port. */ | ||
1409 | sci_base_state_machine_change_state( | ||
1410 | &port->ready_substate_machine, | ||
1411 | SCIC_SDS_PORT_READY_SUBSTATE_CONFIGURING | ||
1412 | ); | ||
1413 | } | ||
1414 | |||
1415 | return status; | ||
1416 | } | ||
1417 | |||
1418 | /* | ||
1419 | * This is the default method for a port remove phy request. It will report a | ||
1420 | * warning and exit. enum sci_status SCI_FAILURE_INVALID_STATE | ||
1421 | */ | ||
1422 | static enum sci_status scic_sds_port_ready_configuring_substate_remove_phy_handler( | ||
1423 | struct scic_sds_port *port, | ||
1424 | struct scic_sds_phy *phy) | ||
1425 | { | ||
1426 | enum sci_status status; | ||
1427 | |||
1428 | status = scic_sds_port_clear_phy(port, phy); | ||
1429 | |||
1430 | if (status == SCI_SUCCESS) { | ||
1431 | scic_sds_port_deactivate_phy(port, phy, true); | ||
1432 | |||
1433 | /* | ||
1434 | * Re-enter the configuring state since this may be the last phy in | ||
1435 | * the port. */ | ||
1436 | sci_base_state_machine_change_state( | ||
1437 | &port->ready_substate_machine, | ||
1438 | SCIC_SDS_PORT_READY_SUBSTATE_CONFIGURING | ||
1439 | ); | ||
1440 | } | ||
1441 | |||
1442 | return status; | ||
1443 | } | ||
1444 | |||
1445 | /** | ||
1446 | * scic_sds_port_ready_configuring_substate_complete_io_handler() - | ||
1447 | * @port: This is the port that is being requested to complete the io request. | ||
1448 | * @device: This is the device on which the io is completing. | ||
1449 | * | ||
1450 | * This method will decrement the outstanding request count for this port. If | ||
1451 | * the request count goes to 0 then the port can be reprogrammed with its new | ||
1452 | * phy data. | ||
1453 | */ | ||
1454 | static enum sci_status | ||
1455 | scic_sds_port_ready_configuring_substate_complete_io_handler( | ||
1456 | struct scic_sds_port *port, | ||
1457 | struct scic_sds_remote_device *device, | ||
1458 | struct scic_sds_request *io_request) | ||
1459 | { | ||
1460 | scic_sds_port_decrement_request_count(port); | ||
1461 | |||
1462 | if (port->started_request_count == 0) { | ||
1463 | sci_base_state_machine_change_state( | ||
1464 | &port->ready_substate_machine, | ||
1465 | SCIC_SDS_PORT_READY_SUBSTATE_OPERATIONAL | ||
1466 | ); | ||
1467 | } | ||
1468 | |||
1469 | return SCI_SUCCESS; | ||
1470 | } | ||
1471 | |||
1472 | static enum sci_status default_port_handler(struct scic_sds_port *sci_port, | ||
1473 | const char *func) | ||
1474 | { | ||
1475 | dev_warn(sciport_to_dev(sci_port), | ||
1476 | "%s: in wrong state: %d\n", func, | ||
1477 | sci_base_state_machine_get_state(&sci_port->state_machine)); | ||
1478 | return SCI_FAILURE_INVALID_STATE; | ||
1479 | } | ||
1480 | |||
1481 | static enum sci_status | ||
1482 | scic_sds_port_default_start_handler(struct scic_sds_port *sci_port) | ||
1483 | { | ||
1484 | return default_port_handler(sci_port, __func__); | ||
1485 | } | ||
1486 | |||
1487 | static enum sci_status | ||
1488 | scic_sds_port_default_stop_handler(struct scic_sds_port *sci_port) | ||
1489 | { | ||
1490 | return default_port_handler(sci_port, __func__); | ||
1491 | } | ||
1492 | |||
1493 | static enum sci_status | ||
1494 | scic_sds_port_default_destruct_handler(struct scic_sds_port *sci_port) | ||
1495 | { | ||
1496 | return default_port_handler(sci_port, __func__); | ||
1497 | } | ||
1498 | |||
1499 | static enum sci_status | ||
1500 | scic_sds_port_default_reset_handler(struct scic_sds_port *sci_port, | ||
1501 | u32 timeout) | ||
1502 | { | ||
1503 | return default_port_handler(sci_port, __func__); | ||
1504 | } | ||
1505 | |||
1506 | static enum sci_status | ||
1507 | scic_sds_port_default_add_phy_handler(struct scic_sds_port *sci_port, | ||
1508 | struct scic_sds_phy *base_phy) | ||
1509 | { | ||
1510 | return default_port_handler(sci_port, __func__); | ||
1511 | } | ||
1512 | |||
1513 | static enum sci_status | ||
1514 | scic_sds_port_default_remove_phy_handler(struct scic_sds_port *sci_port, | ||
1515 | struct scic_sds_phy *base_phy) | ||
1516 | { | ||
1517 | return default_port_handler(sci_port, __func__); | ||
1518 | } | ||
1519 | |||
1520 | /* | ||
1521 | * This is the default method for a port unsolicited frame request. It will | ||
1522 | * report a warning and exit. enum sci_status SCI_FAILURE_INVALID_STATE Is it even | ||
1523 | * possible to receive an unsolicited frame directed to a port object? It | ||
1524 | * seems possible if we implementing virtual functions but until then? | ||
1525 | */ | ||
1526 | static enum sci_status | ||
1527 | scic_sds_port_default_frame_handler(struct scic_sds_port *sci_port, | ||
1528 | u32 frame_index) | ||
1529 | { | ||
1530 | struct scic_sds_controller *scic = scic_sds_port_get_controller(sci_port); | ||
1531 | |||
1532 | default_port_handler(sci_port, __func__); | ||
1533 | scic_sds_controller_release_frame(scic, frame_index); | ||
1534 | |||
1535 | return SCI_FAILURE_INVALID_STATE; | ||
1536 | } | ||
1537 | |||
1538 | static enum sci_status scic_sds_port_default_event_handler(struct scic_sds_port *sci_port, | ||
1539 | u32 event_code) | ||
1540 | { | ||
1541 | return default_port_handler(sci_port, __func__); | ||
1542 | } | ||
1543 | |||
1544 | static void scic_sds_port_default_link_up_handler(struct scic_sds_port *sci_port, | ||
1545 | struct scic_sds_phy *sci_phy) | ||
1546 | { | ||
1547 | default_port_handler(sci_port, __func__); | ||
1548 | } | ||
1549 | |||
1550 | static void scic_sds_port_default_link_down_handler(struct scic_sds_port *sci_port, | ||
1551 | struct scic_sds_phy *sci_phy) | ||
1552 | { | ||
1553 | default_port_handler(sci_port, __func__); | ||
1554 | } | ||
1555 | |||
1556 | static enum sci_status scic_sds_port_default_start_io_handler(struct scic_sds_port *sci_port, | ||
1557 | struct scic_sds_remote_device *sci_dev, | ||
1558 | struct scic_sds_request *sci_req) | ||
1559 | { | ||
1560 | return default_port_handler(sci_port, __func__); | ||
1561 | } | ||
1562 | |||
1563 | static enum sci_status scic_sds_port_default_complete_io_handler(struct scic_sds_port *sci_port, | ||
1564 | struct scic_sds_remote_device *sci_dev, | ||
1565 | struct scic_sds_request *sci_req) | ||
1566 | { | ||
1567 | return default_port_handler(sci_port, __func__); | ||
1568 | } | ||
1569 | |||
1570 | |||
1571 | |||
1572 | static struct scic_sds_port_state_handler | ||
1573 | scic_sds_port_ready_substate_handler_table[SCIC_SDS_PORT_READY_MAX_SUBSTATES] = { | ||
1574 | { | ||
1575 | /* SCIC_SDS_PORT_READY_SUBSTATE_WAITING */ | ||
1576 | scic_sds_port_default_start_handler, | ||
1577 | scic_sds_port_ready_substate_stop_handler, | ||
1578 | scic_sds_port_default_destruct_handler, | ||
1579 | scic_sds_port_default_reset_handler, | ||
1580 | scic_sds_port_ready_substate_add_phy_handler, | ||
1581 | scic_sds_port_default_remove_phy_handler, | ||
1582 | scic_sds_port_default_frame_handler, | ||
1583 | scic_sds_port_default_event_handler, | ||
1584 | scic_sds_port_ready_waiting_substate_link_up_handler, | ||
1585 | scic_sds_port_default_link_down_handler, | ||
1586 | scic_sds_port_ready_waiting_substate_start_io_handler, | ||
1587 | scic_sds_port_ready_substate_complete_io_handler, | ||
1588 | }, | ||
1589 | |||
1590 | { | ||
1591 | /* SCIC_SDS_PORT_READY_SUBSTATE_OPERATIONAL */ | ||
1592 | scic_sds_port_default_start_handler, | ||
1593 | scic_sds_port_ready_substate_stop_handler, | ||
1594 | scic_sds_port_default_destruct_handler, | ||
1595 | scic_sds_port_ready_operational_substate_reset_handler, | ||
1596 | scic_sds_port_ready_substate_add_phy_handler, | ||
1597 | scic_sds_port_ready_substate_remove_phy_handler, | ||
1598 | scic_sds_port_default_frame_handler, | ||
1599 | scic_sds_port_default_event_handler, | ||
1600 | scic_sds_port_ready_operational_substate_link_up_handler, | ||
1601 | scic_sds_port_ready_operational_substate_link_down_handler, | ||
1602 | scic_sds_port_ready_operational_substate_start_io_handler, | ||
1603 | scic_sds_port_ready_substate_complete_io_handler, | ||
1604 | }, | ||
1605 | |||
1606 | { | ||
1607 | /* SCIC_SDS_PORT_READY_SUBSTATE_CONFIGURING */ | ||
1608 | scic_sds_port_default_start_handler, | ||
1609 | scic_sds_port_ready_substate_stop_handler, | ||
1610 | scic_sds_port_default_destruct_handler, | ||
1611 | scic_sds_port_default_reset_handler, | ||
1612 | scic_sds_port_ready_configuring_substate_add_phy_handler, | ||
1613 | scic_sds_port_ready_configuring_substate_remove_phy_handler, | ||
1614 | scic_sds_port_default_frame_handler, | ||
1615 | scic_sds_port_default_event_handler, | ||
1616 | scic_sds_port_default_link_up_handler, | ||
1617 | scic_sds_port_default_link_down_handler, | ||
1618 | scic_sds_port_default_start_io_handler, | ||
1619 | scic_sds_port_ready_configuring_substate_complete_io_handler | ||
1620 | } | ||
1621 | }; | ||
1622 | |||
1623 | /** | ||
1624 | * scic_sds_port_set_ready_state_handlers() - | ||
1625 | * | ||
1626 | * This macro sets the port ready substate handlers. | ||
1627 | */ | ||
1628 | #define scic_sds_port_set_ready_state_handlers(port, state_id) \ | ||
1629 | scic_sds_port_set_state_handlers(\ | ||
1630 | port, &scic_sds_port_ready_substate_handler_table[(state_id)] \ | ||
1631 | ) | ||
1632 | |||
1633 | /* | ||
1634 | * ****************************************************************************** | ||
1635 | * * PORT STATE PRIVATE METHODS | ||
1636 | * ****************************************************************************** */ | ||
1637 | |||
1638 | /** | ||
1639 | * | ||
1640 | * @sci_port: This is the struct scic_sds_port object to suspend. | ||
1641 | * | ||
1642 | * This method will susped the port task scheduler for this port object. none | ||
1643 | */ | ||
1644 | static void | ||
1645 | scic_sds_port_suspend_port_task_scheduler(struct scic_sds_port *port) | ||
1646 | { | ||
1647 | u32 pts_control_value; | ||
1648 | |||
1649 | pts_control_value = readl(&port->port_task_scheduler_registers->control); | ||
1650 | pts_control_value |= SCU_PTSxCR_GEN_BIT(SUSPEND); | ||
1651 | writel(pts_control_value, &port->port_task_scheduler_registers->control); | ||
1652 | } | ||
1653 | |||
1654 | /** | ||
1655 | * scic_sds_port_post_dummy_request() - post dummy/workaround request | ||
1656 | * @sci_port: port to post task | ||
1657 | * | ||
1658 | * Prevent the hardware scheduler from posting new requests to the front | ||
1659 | * of the scheduler queue causing a starvation problem for currently | ||
1660 | * ongoing requests. | ||
1661 | * | ||
1662 | */ | ||
1663 | static void scic_sds_port_post_dummy_request(struct scic_sds_port *sci_port) | ||
1664 | { | ||
1665 | u32 command; | ||
1666 | struct scu_task_context *task_context; | ||
1667 | struct scic_sds_controller *scic = sci_port->owning_controller; | ||
1668 | u16 tci = sci_port->reserved_tci; | ||
1669 | |||
1670 | task_context = scic_sds_controller_get_task_context_buffer(scic, tci); | ||
1671 | |||
1672 | task_context->abort = 0; | ||
1673 | |||
1674 | command = SCU_CONTEXT_COMMAND_REQUEST_TYPE_POST_TC | | ||
1675 | sci_port->physical_port_index << SCU_CONTEXT_COMMAND_LOGICAL_PORT_SHIFT | | ||
1676 | tci; | ||
1677 | |||
1678 | scic_sds_controller_post_request(scic, command); | ||
1679 | } | ||
1680 | |||
1681 | /** | ||
1682 | * This routine will abort the dummy request. This will alow the hardware to | ||
1683 | * power down parts of the silicon to save power. | ||
1684 | * | ||
1685 | * @sci_port: The port on which the task must be aborted. | ||
1686 | * | ||
1687 | */ | ||
1688 | static void scic_sds_port_abort_dummy_request(struct scic_sds_port *sci_port) | ||
1689 | { | ||
1690 | struct scic_sds_controller *scic = sci_port->owning_controller; | ||
1691 | u16 tci = sci_port->reserved_tci; | ||
1692 | struct scu_task_context *tc; | ||
1693 | u32 command; | ||
1694 | |||
1695 | tc = scic_sds_controller_get_task_context_buffer(scic, tci); | ||
1696 | |||
1697 | tc->abort = 1; | ||
1698 | |||
1699 | command = SCU_CONTEXT_COMMAND_REQUEST_POST_TC_ABORT | | ||
1700 | sci_port->physical_port_index << SCU_CONTEXT_COMMAND_LOGICAL_PORT_SHIFT | | ||
1701 | tci; | ||
1702 | |||
1703 | scic_sds_controller_post_request(scic, command); | ||
1704 | } | ||
1705 | |||
1706 | /** | ||
1707 | * | ||
1708 | * @sci_port: This is the struct scic_sds_port object to resume. | ||
1709 | * | ||
1710 | * This method will resume the port task scheduler for this port object. none | ||
1711 | */ | ||
1712 | static void | ||
1713 | scic_sds_port_resume_port_task_scheduler(struct scic_sds_port *port) | ||
1714 | { | ||
1715 | u32 pts_control_value; | ||
1716 | |||
1717 | pts_control_value = readl(&port->port_task_scheduler_registers->control); | ||
1718 | pts_control_value &= ~SCU_PTSxCR_GEN_BIT(SUSPEND); | ||
1719 | writel(pts_control_value, &port->port_task_scheduler_registers->control); | ||
1720 | } | ||
1721 | |||
1722 | /* | ||
1723 | * ****************************************************************************** | ||
1724 | * * PORT READY SUBSTATE METHODS | ||
1725 | * ****************************************************************************** */ | ||
1726 | |||
1727 | /** | ||
1728 | * | ||
1729 | * @object: This is the object which is cast to a struct scic_sds_port object. | ||
1730 | * | ||
1731 | * This method will perform the actions required by the struct scic_sds_port on | ||
1732 | * entering the SCIC_SDS_PORT_READY_SUBSTATE_WAITING. This function checks the | ||
1733 | * port for any ready phys. If there is at least one phy in a ready state then | ||
1734 | * the port transitions to the ready operational substate. none | ||
1735 | */ | ||
1736 | static void scic_sds_port_ready_substate_waiting_enter(void *object) | ||
1737 | { | ||
1738 | struct scic_sds_port *sci_port = object; | ||
1739 | |||
1740 | scic_sds_port_set_ready_state_handlers( | ||
1741 | sci_port, SCIC_SDS_PORT_READY_SUBSTATE_WAITING | ||
1742 | ); | ||
1743 | |||
1744 | scic_sds_port_suspend_port_task_scheduler(sci_port); | ||
1745 | |||
1746 | sci_port->not_ready_reason = SCIC_PORT_NOT_READY_NO_ACTIVE_PHYS; | ||
1747 | |||
1748 | if (sci_port->active_phy_mask != 0) { | ||
1749 | /* At least one of the phys on the port is ready */ | ||
1750 | sci_base_state_machine_change_state( | ||
1751 | &sci_port->ready_substate_machine, | ||
1752 | SCIC_SDS_PORT_READY_SUBSTATE_OPERATIONAL | ||
1753 | ); | ||
1754 | } | ||
1755 | } | ||
1756 | |||
1757 | /** | ||
1758 | * | ||
1759 | * @object: This is the object which is cast to a struct scic_sds_port object. | ||
1760 | * | ||
1761 | * This function will perform the actions required by the struct scic_sds_port | ||
1762 | * on entering the SCIC_SDS_PORT_READY_SUBSTATE_OPERATIONAL. This function sets | ||
1763 | * the state handlers for the port object, notifies the SCI User that the port | ||
1764 | * is ready, and resumes port operations. none | ||
1765 | */ | ||
1766 | static void scic_sds_port_ready_substate_operational_enter(void *object) | ||
1767 | { | ||
1768 | u32 index; | ||
1769 | struct scic_sds_port *sci_port = object; | ||
1770 | struct scic_sds_controller *scic = sci_port->owning_controller; | ||
1771 | struct isci_host *ihost = scic_to_ihost(scic); | ||
1772 | struct isci_port *iport = sci_port_to_iport(sci_port); | ||
1773 | |||
1774 | scic_sds_port_set_ready_state_handlers( | ||
1775 | sci_port, | ||
1776 | SCIC_SDS_PORT_READY_SUBSTATE_OPERATIONAL); | ||
1777 | |||
1778 | isci_port_ready(ihost, iport); | ||
1779 | |||
1780 | for (index = 0; index < SCI_MAX_PHYS; index++) { | ||
1781 | if (sci_port->phy_table[index]) { | ||
1782 | writel(sci_port->physical_port_index, | ||
1783 | &sci_port->port_pe_configuration_register[ | ||
1784 | sci_port->phy_table[index]->phy_index]); | ||
1785 | } | ||
1786 | } | ||
1787 | |||
1788 | scic_sds_port_update_viit_entry(sci_port); | ||
1789 | |||
1790 | scic_sds_port_resume_port_task_scheduler(sci_port); | ||
1791 | |||
1792 | /* | ||
1793 | * Post the dummy task for the port so the hardware can schedule | ||
1794 | * io correctly | ||
1795 | */ | ||
1796 | scic_sds_port_post_dummy_request(sci_port); | ||
1797 | } | ||
1798 | |||
1799 | /** | ||
1800 | * | ||
1801 | * @object: This is the object which is cast to a struct scic_sds_port object. | ||
1802 | * | ||
1803 | * This method will perform the actions required by the struct scic_sds_port on | ||
1804 | * exiting the SCIC_SDS_PORT_READY_SUBSTATE_OPERATIONAL. This function reports | ||
1805 | * the port not ready and suspends the port task scheduler. none | ||
1806 | */ | ||
1807 | static void scic_sds_port_ready_substate_operational_exit(void *object) | ||
1808 | { | ||
1809 | struct scic_sds_port *sci_port = object; | ||
1810 | struct scic_sds_controller *scic = sci_port->owning_controller; | ||
1811 | struct isci_host *ihost = scic_to_ihost(scic); | ||
1812 | struct isci_port *iport = sci_port_to_iport(sci_port); | ||
1813 | |||
1814 | /* | ||
1815 | * Kill the dummy task for this port if it has not yet posted | ||
1816 | * the hardware will treat this as a NOP and just return abort | ||
1817 | * complete. | ||
1818 | */ | ||
1819 | scic_sds_port_abort_dummy_request(sci_port); | ||
1820 | |||
1821 | isci_port_not_ready(ihost, iport); | ||
1822 | } | ||
1823 | |||
1824 | /* | ||
1825 | * ****************************************************************************** | ||
1826 | * * PORT READY CONFIGURING METHODS | ||
1827 | * ****************************************************************************** */ | ||
1828 | |||
1829 | /** | ||
1830 | * scic_sds_port_ready_substate_configuring_enter() - | ||
1831 | * @object: This is the object which is cast to a struct scic_sds_port object. | ||
1832 | * | ||
1833 | * This method will perform the actions required by the struct scic_sds_port on | ||
1834 | * exiting the SCIC_SDS_PORT_READY_SUBSTATE_OPERATIONAL. This function reports | ||
1835 | * the port not ready and suspends the port task scheduler. none | ||
1836 | */ | ||
1837 | static void scic_sds_port_ready_substate_configuring_enter(void *object) | ||
1838 | { | ||
1839 | struct scic_sds_port *sci_port = object; | ||
1840 | struct scic_sds_controller *scic = sci_port->owning_controller; | ||
1841 | struct isci_host *ihost = scic_to_ihost(scic); | ||
1842 | struct isci_port *iport = sci_port_to_iport(sci_port); | ||
1843 | |||
1844 | scic_sds_port_set_ready_state_handlers( | ||
1845 | sci_port, | ||
1846 | SCIC_SDS_PORT_READY_SUBSTATE_CONFIGURING); | ||
1847 | |||
1848 | if (sci_port->active_phy_mask == 0) { | ||
1849 | isci_port_not_ready(ihost, iport); | ||
1850 | |||
1851 | sci_base_state_machine_change_state( | ||
1852 | &sci_port->ready_substate_machine, | ||
1853 | SCIC_SDS_PORT_READY_SUBSTATE_WAITING); | ||
1854 | } else if (sci_port->started_request_count == 0) | ||
1855 | sci_base_state_machine_change_state( | ||
1856 | &sci_port->ready_substate_machine, | ||
1857 | SCIC_SDS_PORT_READY_SUBSTATE_OPERATIONAL); | ||
1858 | } | ||
1859 | |||
1860 | static void scic_sds_port_ready_substate_configuring_exit(void *object) | ||
1861 | { | ||
1862 | struct scic_sds_port *sci_port = object; | ||
1863 | |||
1864 | scic_sds_port_suspend_port_task_scheduler(sci_port); | ||
1865 | } | ||
1866 | |||
1867 | /* --------------------------------------------------------------------------- */ | ||
1868 | |||
1869 | static const struct sci_base_state scic_sds_port_ready_substate_table[] = { | ||
1870 | [SCIC_SDS_PORT_READY_SUBSTATE_WAITING] = { | ||
1871 | .enter_state = scic_sds_port_ready_substate_waiting_enter, | ||
1872 | }, | ||
1873 | [SCIC_SDS_PORT_READY_SUBSTATE_OPERATIONAL] = { | ||
1874 | .enter_state = scic_sds_port_ready_substate_operational_enter, | ||
1875 | .exit_state = scic_sds_port_ready_substate_operational_exit | ||
1876 | }, | ||
1877 | [SCIC_SDS_PORT_READY_SUBSTATE_CONFIGURING] = { | ||
1878 | .enter_state = scic_sds_port_ready_substate_configuring_enter, | ||
1879 | .exit_state = scic_sds_port_ready_substate_configuring_exit | ||
1880 | }, | ||
1881 | }; | ||
1882 | |||
1883 | /** | ||
1884 | * | ||
1885 | * @port: This is the struct scic_sds_port object on which the io request count will | ||
1886 | * be decremented. | ||
1887 | * @device: This is the struct scic_sds_remote_device object to which the io request | ||
1888 | * is being directed. This parameter is not required to complete this | ||
1889 | * operation. | ||
1890 | * @io_request: This is the request that is being completed on this port | ||
1891 | * object. This parameter is not required to complete this operation. | ||
1892 | * | ||
1893 | * This is a general complete io request handler for the struct scic_sds_port object. | ||
1894 | * enum sci_status SCI_SUCCESS | ||
1895 | */ | ||
1896 | static enum sci_status scic_sds_port_general_complete_io_handler( | ||
1897 | struct scic_sds_port *port, | ||
1898 | struct scic_sds_remote_device *device, | ||
1899 | struct scic_sds_request *io_request) | ||
1900 | { | ||
1901 | scic_sds_port_decrement_request_count(port); | ||
1902 | |||
1903 | return SCI_SUCCESS; | ||
1904 | } | ||
1905 | |||
1906 | /** | ||
1907 | * scic_sds_port_stopped_state_start_handler() - stop a port from "started" | ||
1908 | * | ||
1909 | * @port: This is the struct scic_sds_port object which is cast into a | ||
1910 | * struct scic_sds_port object. | ||
1911 | * | ||
1912 | * This function takes the struct scic_sds_port from a stopped state and | ||
1913 | * attempts to start it. To start a port it must have no assiged devices and | ||
1914 | * it must have at least one phy assigned to it. If those conditions are | ||
1915 | * met then the port can transition to the ready state. | ||
1916 | * enum sci_status | ||
1917 | * SCI_FAILURE_UNSUPPORTED_PORT_CONFIGURATION | ||
1918 | * This struct scic_sds_port object could not be started because the port | ||
1919 | * configuration is not valid. | ||
1920 | * SCI_SUCCESS | ||
1921 | * the start request is successful and the struct scic_sds_port object | ||
1922 | * has transitioned to the SCI_BASE_PORT_STATE_READY. | ||
1923 | */ | ||
1924 | static enum sci_status | ||
1925 | scic_sds_port_stopped_state_start_handler(struct scic_sds_port *sci_port) | ||
1926 | { | ||
1927 | struct scic_sds_controller *scic = sci_port->owning_controller; | ||
1928 | struct isci_host *ihost = scic_to_ihost(scic); | ||
1929 | enum sci_status status = SCI_SUCCESS; | ||
1930 | u32 phy_mask; | ||
1931 | |||
1932 | if (sci_port->assigned_device_count > 0) { | ||
1933 | /* | ||
1934 | * @todo This is a start failure operation because | ||
1935 | * there are still devices assigned to this port. | ||
1936 | * There must be no devices assigned to a port on a | ||
1937 | * start operation. | ||
1938 | */ | ||
1939 | return SCI_FAILURE_UNSUPPORTED_PORT_CONFIGURATION; | ||
1940 | } | ||
1941 | |||
1942 | sci_port->timer_handle = | ||
1943 | isci_timer_create(ihost, | ||
1944 | sci_port, | ||
1945 | scic_sds_port_timeout_handler); | ||
1946 | |||
1947 | if (!sci_port->timer_handle) | ||
1948 | return SCI_FAILURE_INSUFFICIENT_RESOURCES; | ||
1949 | |||
1950 | if (sci_port->reserved_rni == SCU_DUMMY_INDEX) { | ||
1951 | u16 rni = scic_sds_remote_node_table_allocate_remote_node( | ||
1952 | &scic->available_remote_nodes, 1); | ||
1953 | |||
1954 | if (rni != SCU_DUMMY_INDEX) | ||
1955 | scic_sds_port_construct_dummy_rnc(sci_port, rni); | ||
1956 | else | ||
1957 | status = SCI_FAILURE_INSUFFICIENT_RESOURCES; | ||
1958 | sci_port->reserved_rni = rni; | ||
1959 | } | ||
1960 | |||
1961 | if (sci_port->reserved_tci == SCU_DUMMY_INDEX) { | ||
1962 | /* Allocate a TCI and remove the sequence nibble */ | ||
1963 | u16 tci = scic_controller_allocate_io_tag(scic); | ||
1964 | |||
1965 | if (tci != SCU_DUMMY_INDEX) | ||
1966 | scic_sds_port_construct_dummy_task(sci_port, tci); | ||
1967 | else | ||
1968 | status = SCI_FAILURE_INSUFFICIENT_RESOURCES; | ||
1969 | sci_port->reserved_tci = tci; | ||
1970 | } | ||
1971 | |||
1972 | if (status == SCI_SUCCESS) { | ||
1973 | phy_mask = scic_sds_port_get_phys(sci_port); | ||
1974 | |||
1975 | /* | ||
1976 | * There are one or more phys assigned to this port. Make sure | ||
1977 | * the port's phy mask is in fact legal and supported by the | ||
1978 | * silicon. | ||
1979 | */ | ||
1980 | if (scic_sds_port_is_phy_mask_valid(sci_port, phy_mask) == true) { | ||
1981 | sci_base_state_machine_change_state( | ||
1982 | &sci_port->state_machine, | ||
1983 | SCI_BASE_PORT_STATE_READY); | ||
1984 | |||
1985 | return SCI_SUCCESS; | ||
1986 | } else | ||
1987 | status = SCI_FAILURE; | ||
1988 | } | ||
1989 | |||
1990 | if (status != SCI_SUCCESS) | ||
1991 | scic_sds_port_destroy_dummy_resources(sci_port); | ||
1992 | |||
1993 | return status; | ||
1994 | } | ||
1995 | |||
1996 | /* | ||
1997 | * This method takes the struct scic_sds_port that is in a stopped state and handles a | ||
1998 | * stop request. This function takes no action. enum sci_status SCI_SUCCESS the | ||
1999 | * stop request is successful as the struct scic_sds_port object is already stopped. | ||
2000 | */ | ||
2001 | static enum sci_status scic_sds_port_stopped_state_stop_handler( | ||
2002 | struct scic_sds_port *port) | ||
2003 | { | ||
2004 | /* We are already stopped so there is nothing to do here */ | ||
2005 | return SCI_SUCCESS; | ||
2006 | } | ||
2007 | |||
2008 | /* | ||
2009 | * This method takes the struct scic_sds_port that is in a stopped state and handles | ||
2010 | * the destruct request. The stopped state is the only state in which the | ||
2011 | * struct scic_sds_port can be destroyed. This function causes the port object to | ||
2012 | * transition to the SCI_BASE_PORT_STATE_FINAL. enum sci_status SCI_SUCCESS | ||
2013 | */ | ||
2014 | static enum sci_status scic_sds_port_stopped_state_destruct_handler( | ||
2015 | struct scic_sds_port *port) | ||
2016 | { | ||
2017 | sci_base_state_machine_stop(&port->state_machine); | ||
2018 | |||
2019 | return SCI_SUCCESS; | ||
2020 | } | ||
2021 | |||
2022 | /* | ||
2023 | * This method takes the struct scic_sds_port that is in a stopped state and handles | ||
2024 | * the add phy request. In MPC mode the only time a phy can be added to a port | ||
2025 | * is in the SCI_BASE_PORT_STATE_STOPPED. enum sci_status | ||
2026 | * SCI_FAILURE_UNSUPPORTED_PORT_CONFIGURATION is returned when the phy can not | ||
2027 | * be added to the port. SCI_SUCCESS if the phy is added to the port. | ||
2028 | */ | ||
2029 | static enum sci_status scic_sds_port_stopped_state_add_phy_handler( | ||
2030 | struct scic_sds_port *port, | ||
2031 | struct scic_sds_phy *phy) | ||
2032 | { | ||
2033 | struct sci_sas_address port_sas_address; | ||
2034 | |||
2035 | /* Read the port assigned SAS Address if there is one */ | ||
2036 | scic_sds_port_get_sas_address(port, &port_sas_address); | ||
2037 | |||
2038 | if (port_sas_address.high != 0 && port_sas_address.low != 0) { | ||
2039 | struct sci_sas_address phy_sas_address; | ||
2040 | |||
2041 | /* | ||
2042 | * Make sure that the PHY SAS Address matches the SAS Address | ||
2043 | * for this port. */ | ||
2044 | scic_sds_phy_get_sas_address(phy, &phy_sas_address); | ||
2045 | |||
2046 | if ( | ||
2047 | (port_sas_address.high != phy_sas_address.high) | ||
2048 | || (port_sas_address.low != phy_sas_address.low) | ||
2049 | ) { | ||
2050 | return SCI_FAILURE_UNSUPPORTED_PORT_CONFIGURATION; | ||
2051 | } | ||
2052 | } | ||
2053 | |||
2054 | return scic_sds_port_set_phy(port, phy); | ||
2055 | } | ||
2056 | |||
2057 | /* | ||
2058 | * This method takes the struct scic_sds_port that is in a stopped state and handles | ||
2059 | * the remove phy request. In MPC mode the only time a phy can be removed from | ||
2060 | * a port is in the SCI_BASE_PORT_STATE_STOPPED. enum sci_status | ||
2061 | * SCI_FAILURE_UNSUPPORTED_PORT_CONFIGURATION is returned when the phy can not | ||
2062 | * be added to the port. SCI_SUCCESS if the phy is added to the port. | ||
2063 | */ | ||
2064 | static enum sci_status scic_sds_port_stopped_state_remove_phy_handler( | ||
2065 | struct scic_sds_port *port, | ||
2066 | struct scic_sds_phy *phy) | ||
2067 | { | ||
2068 | return scic_sds_port_clear_phy(port, phy); | ||
2069 | } | ||
2070 | |||
2071 | /* | ||
2072 | * **************************************************************************** | ||
2073 | * * READY STATE HANDLERS | ||
2074 | * **************************************************************************** */ | ||
2075 | |||
2076 | /* | ||
2077 | * **************************************************************************** | ||
2078 | * * RESETTING STATE HANDLERS | ||
2079 | * **************************************************************************** */ | ||
2080 | |||
2081 | /* | ||
2082 | * **************************************************************************** | ||
2083 | * * STOPPING STATE HANDLERS | ||
2084 | * **************************************************************************** */ | ||
2085 | |||
2086 | /* | ||
2087 | * This method takes the struct scic_sds_port that is in a stopping state and handles | ||
2088 | * the complete io request. Should the request count reach 0 then the port | ||
2089 | * object will transition to the stopped state. enum sci_status SCI_SUCCESS | ||
2090 | */ | ||
2091 | static enum sci_status scic_sds_port_stopping_state_complete_io_handler( | ||
2092 | struct scic_sds_port *sci_port, | ||
2093 | struct scic_sds_remote_device *device, | ||
2094 | struct scic_sds_request *io_request) | ||
2095 | { | ||
2096 | scic_sds_port_decrement_request_count(sci_port); | ||
2097 | |||
2098 | if (sci_port->started_request_count == 0) { | ||
2099 | sci_base_state_machine_change_state(&sci_port->state_machine, | ||
2100 | SCI_BASE_PORT_STATE_STOPPED); | ||
2101 | } | ||
2102 | |||
2103 | return SCI_SUCCESS; | ||
2104 | } | ||
2105 | |||
2106 | /* | ||
2107 | * **************************************************************************** | ||
2108 | * * RESETTING STATE HANDLERS | ||
2109 | * **************************************************************************** */ | ||
2110 | |||
2111 | /** | ||
2112 | * | ||
2113 | * @port: This is the port object which is being requested to stop. | ||
2114 | * | ||
2115 | * This method will stop a failed port. This causes a transition to the | ||
2116 | * stopping state. enum sci_status SCI_SUCCESS | ||
2117 | */ | ||
2118 | static enum sci_status scic_sds_port_reset_state_stop_handler( | ||
2119 | struct scic_sds_port *port) | ||
2120 | { | ||
2121 | sci_base_state_machine_change_state( | ||
2122 | &port->state_machine, | ||
2123 | SCI_BASE_PORT_STATE_STOPPING | ||
2124 | ); | ||
2125 | |||
2126 | return SCI_SUCCESS; | ||
2127 | } | ||
2128 | |||
2129 | /* | ||
2130 | * This method will transition a failed port to its ready state. The port | ||
2131 | * failed because a hard reset request timed out but at some time later one or | ||
2132 | * more phys in the port became ready. enum sci_status SCI_SUCCESS | ||
2133 | */ | ||
2134 | static void scic_sds_port_reset_state_link_up_handler( | ||
2135 | struct scic_sds_port *port, | ||
2136 | struct scic_sds_phy *phy) | ||
2137 | { | ||
2138 | /* | ||
2139 | * / @todo We should make sure that the phy that has gone link up is the same | ||
2140 | * / one on which we sent the reset. It is possible that the phy on | ||
2141 | * / which we sent the reset is not the one that has gone link up and we | ||
2142 | * / want to make sure that phy being reset comes back. Consider the | ||
2143 | * / case where a reset is sent but before the hardware processes the | ||
2144 | * / reset it get a link up on the port because of a hot plug event. | ||
2145 | * / because of the reset request this phy will go link down almost | ||
2146 | * / immediately. */ | ||
2147 | |||
2148 | /* | ||
2149 | * In the resetting state we don't notify the user regarding | ||
2150 | * link up and link down notifications. */ | ||
2151 | scic_sds_port_general_link_up_handler(port, phy, false); | ||
2152 | } | ||
2153 | |||
2154 | /* | ||
2155 | * This method process link down notifications that occur during a port reset | ||
2156 | * operation. Link downs can occur during the reset operation. enum sci_status | ||
2157 | * SCI_SUCCESS | ||
2158 | */ | ||
2159 | static void scic_sds_port_reset_state_link_down_handler( | ||
2160 | struct scic_sds_port *port, | ||
2161 | struct scic_sds_phy *phy) | ||
2162 | { | ||
2163 | /* | ||
2164 | * In the resetting state we don't notify the user regarding | ||
2165 | * link up and link down notifications. */ | ||
2166 | scic_sds_port_deactivate_phy(port, phy, false); | ||
2167 | } | ||
2168 | |||
2169 | static struct scic_sds_port_state_handler | ||
2170 | scic_sds_port_state_handler_table[SCI_BASE_PORT_MAX_STATES] = | ||
2171 | { | ||
2172 | /* SCI_BASE_PORT_STATE_STOPPED */ | ||
2173 | { | ||
2174 | scic_sds_port_stopped_state_start_handler, | ||
2175 | scic_sds_port_stopped_state_stop_handler, | ||
2176 | scic_sds_port_stopped_state_destruct_handler, | ||
2177 | scic_sds_port_default_reset_handler, | ||
2178 | scic_sds_port_stopped_state_add_phy_handler, | ||
2179 | scic_sds_port_stopped_state_remove_phy_handler, | ||
2180 | scic_sds_port_default_frame_handler, | ||
2181 | scic_sds_port_default_event_handler, | ||
2182 | scic_sds_port_default_link_up_handler, | ||
2183 | scic_sds_port_default_link_down_handler, | ||
2184 | scic_sds_port_default_start_io_handler, | ||
2185 | scic_sds_port_default_complete_io_handler | ||
2186 | }, | ||
2187 | /* SCI_BASE_PORT_STATE_STOPPING */ | ||
2188 | { | ||
2189 | scic_sds_port_default_start_handler, | ||
2190 | scic_sds_port_default_stop_handler, | ||
2191 | scic_sds_port_default_destruct_handler, | ||
2192 | scic_sds_port_default_reset_handler, | ||
2193 | scic_sds_port_default_add_phy_handler, | ||
2194 | scic_sds_port_default_remove_phy_handler, | ||
2195 | scic_sds_port_default_frame_handler, | ||
2196 | scic_sds_port_default_event_handler, | ||
2197 | scic_sds_port_default_link_up_handler, | ||
2198 | scic_sds_port_default_link_down_handler, | ||
2199 | scic_sds_port_default_start_io_handler, | ||
2200 | scic_sds_port_stopping_state_complete_io_handler | ||
2201 | }, | ||
2202 | /* SCI_BASE_PORT_STATE_READY */ | ||
2203 | { | ||
2204 | scic_sds_port_default_start_handler, | ||
2205 | scic_sds_port_default_stop_handler, | ||
2206 | scic_sds_port_default_destruct_handler, | ||
2207 | scic_sds_port_default_reset_handler, | ||
2208 | scic_sds_port_default_add_phy_handler, | ||
2209 | scic_sds_port_default_remove_phy_handler, | ||
2210 | scic_sds_port_default_frame_handler, | ||
2211 | scic_sds_port_default_event_handler, | ||
2212 | scic_sds_port_default_link_up_handler, | ||
2213 | scic_sds_port_default_link_down_handler, | ||
2214 | scic_sds_port_default_start_io_handler, | ||
2215 | scic_sds_port_general_complete_io_handler | ||
2216 | }, | ||
2217 | /* SCI_BASE_PORT_STATE_RESETTING */ | ||
2218 | { | ||
2219 | scic_sds_port_default_start_handler, | ||
2220 | scic_sds_port_reset_state_stop_handler, | ||
2221 | scic_sds_port_default_destruct_handler, | ||
2222 | scic_sds_port_default_reset_handler, | ||
2223 | scic_sds_port_default_add_phy_handler, | ||
2224 | scic_sds_port_default_remove_phy_handler, | ||
2225 | scic_sds_port_default_frame_handler, | ||
2226 | scic_sds_port_default_event_handler, | ||
2227 | scic_sds_port_reset_state_link_up_handler, | ||
2228 | scic_sds_port_reset_state_link_down_handler, | ||
2229 | scic_sds_port_default_start_io_handler, | ||
2230 | scic_sds_port_general_complete_io_handler | ||
2231 | }, | ||
2232 | /* SCI_BASE_PORT_STATE_FAILED */ | ||
2233 | { | ||
2234 | scic_sds_port_default_start_handler, | ||
2235 | scic_sds_port_default_stop_handler, | ||
2236 | scic_sds_port_default_destruct_handler, | ||
2237 | scic_sds_port_default_reset_handler, | ||
2238 | scic_sds_port_default_add_phy_handler, | ||
2239 | scic_sds_port_default_remove_phy_handler, | ||
2240 | scic_sds_port_default_frame_handler, | ||
2241 | scic_sds_port_default_event_handler, | ||
2242 | scic_sds_port_default_link_up_handler, | ||
2243 | scic_sds_port_default_link_down_handler, | ||
2244 | scic_sds_port_default_start_io_handler, | ||
2245 | scic_sds_port_general_complete_io_handler | ||
2246 | } | ||
2247 | }; | ||
2248 | |||
2249 | /* | ||
2250 | * ****************************************************************************** | ||
2251 | * * PORT STATE PRIVATE METHODS | ||
2252 | * ****************************************************************************** */ | ||
2253 | |||
2254 | /** | ||
2255 | * | ||
2256 | * @sci_port: This is the port object which to suspend. | ||
2257 | * | ||
2258 | * This method will enable the SCU Port Task Scheduler for this port object but | ||
2259 | * will leave the port task scheduler in a suspended state. none | ||
2260 | */ | ||
2261 | static void | ||
2262 | scic_sds_port_enable_port_task_scheduler(struct scic_sds_port *port) | ||
2263 | { | ||
2264 | u32 pts_control_value; | ||
2265 | |||
2266 | pts_control_value = readl(&port->port_task_scheduler_registers->control); | ||
2267 | pts_control_value |= SCU_PTSxCR_GEN_BIT(ENABLE) | SCU_PTSxCR_GEN_BIT(SUSPEND); | ||
2268 | writel(pts_control_value, &port->port_task_scheduler_registers->control); | ||
2269 | } | ||
2270 | |||
2271 | /** | ||
2272 | * | ||
2273 | * @sci_port: This is the port object which to resume. | ||
2274 | * | ||
2275 | * This method will disable the SCU port task scheduler for this port object. | ||
2276 | * none | ||
2277 | */ | ||
2278 | static void | ||
2279 | scic_sds_port_disable_port_task_scheduler(struct scic_sds_port *port) | ||
2280 | { | ||
2281 | u32 pts_control_value; | ||
2282 | |||
2283 | pts_control_value = readl(&port->port_task_scheduler_registers->control); | ||
2284 | pts_control_value &= | ||
2285 | ~(SCU_PTSxCR_GEN_BIT(ENABLE) | SCU_PTSxCR_GEN_BIT(SUSPEND)); | ||
2286 | writel(pts_control_value, &port->port_task_scheduler_registers->control); | ||
2287 | } | ||
2288 | |||
2289 | static void scic_sds_port_post_dummy_remote_node(struct scic_sds_port *sci_port) | ||
2290 | { | ||
2291 | struct scic_sds_controller *scic = sci_port->owning_controller; | ||
2292 | u8 phys_index = sci_port->physical_port_index; | ||
2293 | union scu_remote_node_context *rnc; | ||
2294 | u16 rni = sci_port->reserved_rni; | ||
2295 | u32 command; | ||
2296 | |||
2297 | rnc = &scic->remote_node_context_table[rni]; | ||
2298 | rnc->ssp.is_valid = true; | ||
2299 | |||
2300 | command = SCU_CONTEXT_COMMAND_POST_RNC_32 | | ||
2301 | phys_index << SCU_CONTEXT_COMMAND_LOGICAL_PORT_SHIFT | rni; | ||
2302 | |||
2303 | scic_sds_controller_post_request(scic, command); | ||
2304 | |||
2305 | /* ensure hardware has seen the post rnc command and give it | ||
2306 | * ample time to act before sending the suspend | ||
2307 | */ | ||
2308 | readl(&scic->smu_registers->interrupt_status); /* flush */ | ||
2309 | udelay(10); | ||
2310 | |||
2311 | command = SCU_CONTEXT_COMMAND_POST_RNC_SUSPEND_TX_RX | | ||
2312 | phys_index << SCU_CONTEXT_COMMAND_LOGICAL_PORT_SHIFT | rni; | ||
2313 | |||
2314 | scic_sds_controller_post_request(scic, command); | ||
2315 | } | ||
2316 | |||
2317 | static void scic_sds_port_invalidate_dummy_remote_node(struct scic_sds_port *sci_port) | ||
2318 | { | ||
2319 | struct scic_sds_controller *scic = sci_port->owning_controller; | ||
2320 | u8 phys_index = sci_port->physical_port_index; | ||
2321 | union scu_remote_node_context *rnc; | ||
2322 | u16 rni = sci_port->reserved_rni; | ||
2323 | u32 command; | ||
2324 | |||
2325 | rnc = &scic->remote_node_context_table[rni]; | ||
2326 | |||
2327 | rnc->ssp.is_valid = false; | ||
2328 | |||
2329 | /* ensure the preceding tc abort request has reached the | ||
2330 | * controller and give it ample time to act before posting the rnc | ||
2331 | * invalidate | ||
2332 | */ | ||
2333 | readl(&scic->smu_registers->interrupt_status); /* flush */ | ||
2334 | udelay(10); | ||
2335 | |||
2336 | command = SCU_CONTEXT_COMMAND_POST_RNC_INVALIDATE | | ||
2337 | phys_index << SCU_CONTEXT_COMMAND_LOGICAL_PORT_SHIFT | rni; | ||
2338 | |||
2339 | scic_sds_controller_post_request(scic, command); | ||
2340 | } | ||
2341 | |||
2342 | /* | ||
2343 | * ****************************************************************************** | ||
2344 | * * PORT STATE METHODS | ||
2345 | * ****************************************************************************** */ | ||
2346 | |||
2347 | /** | ||
2348 | * | ||
2349 | * @object: This is the object which is cast to a struct scic_sds_port object. | ||
2350 | * | ||
2351 | * This method will perform the actions required by the struct scic_sds_port on | ||
2352 | * entering the SCI_BASE_PORT_STATE_STOPPED. This function sets the stopped | ||
2353 | * state handlers for the struct scic_sds_port object and disables the port task | ||
2354 | * scheduler in the hardware. none | ||
2355 | */ | ||
2356 | static void scic_sds_port_stopped_state_enter(void *object) | ||
2357 | { | ||
2358 | struct scic_sds_port *sci_port = object; | ||
2359 | |||
2360 | scic_sds_port_set_base_state_handlers( | ||
2361 | sci_port, SCI_BASE_PORT_STATE_STOPPED | ||
2362 | ); | ||
2363 | |||
2364 | if ( | ||
2365 | SCI_BASE_PORT_STATE_STOPPING | ||
2366 | == sci_port->state_machine.previous_state_id | ||
2367 | ) { | ||
2368 | /* | ||
2369 | * If we enter this state becasuse of a request to stop | ||
2370 | * the port then we want to disable the hardwares port | ||
2371 | * task scheduler. */ | ||
2372 | scic_sds_port_disable_port_task_scheduler(sci_port); | ||
2373 | } | ||
2374 | } | ||
2375 | |||
2376 | /** | ||
2377 | * | ||
2378 | * @object: This is the object which is cast to a struct scic_sds_port object. | ||
2379 | * | ||
2380 | * This method will perform the actions required by the struct scic_sds_port on | ||
2381 | * exiting the SCI_BASE_STATE_STOPPED. This function enables the SCU hardware | ||
2382 | * port task scheduler. none | ||
2383 | */ | ||
2384 | static void scic_sds_port_stopped_state_exit(void *object) | ||
2385 | { | ||
2386 | struct scic_sds_port *sci_port = object; | ||
2387 | |||
2388 | /* Enable and suspend the port task scheduler */ | ||
2389 | scic_sds_port_enable_port_task_scheduler(sci_port); | ||
2390 | } | ||
2391 | |||
2392 | /** | ||
2393 | * scic_sds_port_ready_state_enter - | ||
2394 | * @object: This is the object which is cast to a struct scic_sds_port object. | ||
2395 | * | ||
2396 | * This method will perform the actions required by the struct scic_sds_port on | ||
2397 | * entering the SCI_BASE_PORT_STATE_READY. This function sets the ready state | ||
2398 | * handlers for the struct scic_sds_port object, reports the port object as | ||
2399 | * not ready and starts the ready substate machine. none | ||
2400 | */ | ||
2401 | static void scic_sds_port_ready_state_enter(void *object) | ||
2402 | { | ||
2403 | struct scic_sds_port *sci_port = object; | ||
2404 | struct scic_sds_controller *scic = sci_port->owning_controller; | ||
2405 | struct isci_host *ihost = scic_to_ihost(scic); | ||
2406 | struct isci_port *iport = sci_port_to_iport(sci_port); | ||
2407 | u32 prev_state; | ||
2408 | |||
2409 | /* Put the ready state handlers in place though they will not be there long */ | ||
2410 | scic_sds_port_set_base_state_handlers(sci_port, SCI_BASE_PORT_STATE_READY); | ||
2411 | |||
2412 | prev_state = sci_port->state_machine.previous_state_id; | ||
2413 | if (prev_state == SCI_BASE_PORT_STATE_RESETTING) | ||
2414 | isci_port_hard_reset_complete(iport, SCI_SUCCESS); | ||
2415 | else | ||
2416 | isci_port_not_ready(ihost, iport); | ||
2417 | |||
2418 | /* Post and suspend the dummy remote node context for this port. */ | ||
2419 | scic_sds_port_post_dummy_remote_node(sci_port); | ||
2420 | |||
2421 | /* Start the ready substate machine */ | ||
2422 | sci_base_state_machine_start(&sci_port->ready_substate_machine); | ||
2423 | } | ||
2424 | |||
2425 | static void scic_sds_port_ready_state_exit(void *object) | ||
2426 | { | ||
2427 | struct scic_sds_port *sci_port = object; | ||
2428 | |||
2429 | sci_base_state_machine_stop(&sci_port->ready_substate_machine); | ||
2430 | scic_sds_port_invalidate_dummy_remote_node(sci_port); | ||
2431 | } | ||
2432 | |||
2433 | /** | ||
2434 | * | ||
2435 | * @object: This is the object which is cast to a struct scic_sds_port object. | ||
2436 | * | ||
2437 | * This method will perform the actions required by the struct scic_sds_port on | ||
2438 | * entering the SCI_BASE_PORT_STATE_RESETTING. This function sets the resetting | ||
2439 | * state handlers for the struct scic_sds_port object. none | ||
2440 | */ | ||
2441 | static void scic_sds_port_resetting_state_enter(void *object) | ||
2442 | { | ||
2443 | struct scic_sds_port *sci_port = object; | ||
2444 | |||
2445 | scic_sds_port_set_base_state_handlers( | ||
2446 | sci_port, SCI_BASE_PORT_STATE_RESETTING | ||
2447 | ); | ||
2448 | } | ||
2449 | |||
2450 | /** | ||
2451 | * | ||
2452 | * @object: This is the object which is cast to a struct scic_sds_port object. | ||
2453 | * | ||
2454 | * This function will perform the actions required by the | ||
2455 | * struct scic_sds_port on | ||
2456 | * exiting the SCI_BASE_STATE_RESETTING. This function does nothing. none | ||
2457 | */ | ||
2458 | static inline void scic_sds_port_resetting_state_exit(void *object) | ||
2459 | { | ||
2460 | struct scic_sds_port *sci_port = object; | ||
2461 | |||
2462 | isci_timer_stop(sci_port->timer_handle); | ||
2463 | } | ||
2464 | |||
2465 | /** | ||
2466 | * | ||
2467 | * @object: This is the void object which is cast to a | ||
2468 | * struct scic_sds_port object. | ||
2469 | * | ||
2470 | * This method will perform the actions required by the struct scic_sds_port on | ||
2471 | * entering the SCI_BASE_PORT_STATE_STOPPING. This function sets the stopping | ||
2472 | * state handlers for the struct scic_sds_port object. none | ||
2473 | */ | ||
2474 | static void scic_sds_port_stopping_state_enter(void *object) | ||
2475 | { | ||
2476 | struct scic_sds_port *sci_port = object; | ||
2477 | |||
2478 | scic_sds_port_set_base_state_handlers( | ||
2479 | sci_port, SCI_BASE_PORT_STATE_STOPPING | ||
2480 | ); | ||
2481 | } | ||
2482 | |||
2483 | /** | ||
2484 | * | ||
2485 | * @object: This is the object which is cast to a struct scic_sds_port object. | ||
2486 | * | ||
2487 | * This function will perform the actions required by the | ||
2488 | * struct scic_sds_port on | ||
2489 | * exiting the SCI_BASE_STATE_STOPPING. This function does nothing. none | ||
2490 | */ | ||
2491 | static inline void | ||
2492 | scic_sds_port_stopping_state_exit(void *object) | ||
2493 | { | ||
2494 | struct scic_sds_port *sci_port = object; | ||
2495 | |||
2496 | isci_timer_stop(sci_port->timer_handle); | ||
2497 | |||
2498 | scic_sds_port_destroy_dummy_resources(sci_port); | ||
2499 | } | ||
2500 | |||
2501 | /** | ||
2502 | * | ||
2503 | * @object: This is the object which is cast to a struct scic_sds_port object. | ||
2504 | * | ||
2505 | * This function will perform the actions required by the | ||
2506 | * struct scic_sds_port on | ||
2507 | * entering the SCI_BASE_PORT_STATE_STOPPING. This function sets the stopping | ||
2508 | * state handlers for the struct scic_sds_port object. none | ||
2509 | */ | ||
2510 | static void scic_sds_port_failed_state_enter(void *object) | ||
2511 | { | ||
2512 | struct scic_sds_port *sci_port = object; | ||
2513 | struct isci_port *iport = sci_port_to_iport(sci_port); | ||
2514 | |||
2515 | scic_sds_port_set_base_state_handlers(sci_port, | ||
2516 | SCI_BASE_PORT_STATE_FAILED); | ||
2517 | |||
2518 | isci_port_hard_reset_complete(iport, SCI_FAILURE_TIMEOUT); | ||
2519 | } | ||
2520 | |||
2521 | /* --------------------------------------------------------------------------- */ | ||
2522 | |||
2523 | static const struct sci_base_state scic_sds_port_state_table[] = { | ||
2524 | [SCI_BASE_PORT_STATE_STOPPED] = { | ||
2525 | .enter_state = scic_sds_port_stopped_state_enter, | ||
2526 | .exit_state = scic_sds_port_stopped_state_exit | ||
2527 | }, | ||
2528 | [SCI_BASE_PORT_STATE_STOPPING] = { | ||
2529 | .enter_state = scic_sds_port_stopping_state_enter, | ||
2530 | .exit_state = scic_sds_port_stopping_state_exit | ||
2531 | }, | ||
2532 | [SCI_BASE_PORT_STATE_READY] = { | ||
2533 | .enter_state = scic_sds_port_ready_state_enter, | ||
2534 | .exit_state = scic_sds_port_ready_state_exit | ||
2535 | }, | ||
2536 | [SCI_BASE_PORT_STATE_RESETTING] = { | ||
2537 | .enter_state = scic_sds_port_resetting_state_enter, | ||
2538 | .exit_state = scic_sds_port_resetting_state_exit | ||
2539 | }, | ||
2540 | [SCI_BASE_PORT_STATE_FAILED] = { | ||
2541 | .enter_state = scic_sds_port_failed_state_enter, | ||
2542 | } | ||
2543 | }; | ||
2544 | |||
2545 | void scic_sds_port_construct(struct scic_sds_port *sci_port, u8 index, | ||
2546 | struct scic_sds_controller *scic) | ||
2547 | { | ||
2548 | sci_base_state_machine_construct(&sci_port->state_machine, | ||
2549 | sci_port, | ||
2550 | scic_sds_port_state_table, | ||
2551 | SCI_BASE_PORT_STATE_STOPPED); | ||
2552 | |||
2553 | sci_base_state_machine_start(&sci_port->state_machine); | ||
2554 | |||
2555 | sci_base_state_machine_construct(&sci_port->ready_substate_machine, | ||
2556 | sci_port, | ||
2557 | scic_sds_port_ready_substate_table, | ||
2558 | SCIC_SDS_PORT_READY_SUBSTATE_WAITING); | ||
2559 | |||
2560 | sci_port->logical_port_index = SCIC_SDS_DUMMY_PORT; | ||
2561 | sci_port->physical_port_index = index; | ||
2562 | sci_port->active_phy_mask = 0; | ||
2563 | |||
2564 | sci_port->owning_controller = scic; | ||
2565 | |||
2566 | sci_port->started_request_count = 0; | ||
2567 | sci_port->assigned_device_count = 0; | ||
2568 | |||
2569 | sci_port->reserved_rni = SCU_DUMMY_INDEX; | ||
2570 | sci_port->reserved_tci = SCU_DUMMY_INDEX; | ||
2571 | |||
2572 | sci_port->timer_handle = NULL; | ||
2573 | sci_port->port_task_scheduler_registers = NULL; | ||
2574 | |||
2575 | for (index = 0; index < SCI_MAX_PHYS; index++) | ||
2576 | sci_port->phy_table[index] = NULL; | ||
2577 | } | ||
2578 | |||
2579 | void isci_port_init(struct isci_port *iport, struct isci_host *ihost, int index) | ||
2580 | { | ||
2581 | INIT_LIST_HEAD(&iport->remote_dev_list); | ||
2582 | INIT_LIST_HEAD(&iport->domain_dev_list); | ||
2583 | spin_lock_init(&iport->state_lock); | ||
2584 | init_completion(&iport->start_complete); | ||
2585 | iport->isci_host = ihost; | ||
2586 | isci_port_change_state(iport, isci_freed); | ||
2587 | } | ||
2588 | |||
2589 | /** | ||
2590 | * isci_port_get_state() - This function gets the status of the port object. | ||
2591 | * @isci_port: This parameter points to the isci_port object | ||
2592 | * | ||
2593 | * status of the object as a isci_status enum. | ||
2594 | */ | ||
2595 | enum isci_status isci_port_get_state( | ||
2596 | struct isci_port *isci_port) | ||
2597 | { | ||
2598 | return isci_port->status; | ||
2599 | } | ||
2600 | |||
2601 | static void isci_port_bc_change_received(struct isci_host *ihost, | ||
2602 | struct scic_sds_port *sci_port, | ||
2603 | struct scic_sds_phy *sci_phy) | ||
2604 | { | ||
2605 | struct isci_phy *iphy = sci_phy_to_iphy(sci_phy); | ||
2606 | |||
2607 | dev_dbg(&ihost->pdev->dev, "%s: iphy = %p, sas_phy = %p\n", | ||
2608 | __func__, iphy, &iphy->sas_phy); | ||
2609 | |||
2610 | ihost->sas_ha.notify_port_event(&iphy->sas_phy, PORTE_BROADCAST_RCVD); | ||
2611 | scic_port_enable_broadcast_change_notification(sci_port); | ||
2612 | } | ||
2613 | |||
2614 | void scic_sds_port_broadcast_change_received( | ||
2615 | struct scic_sds_port *sci_port, | ||
2616 | struct scic_sds_phy *sci_phy) | ||
2617 | { | ||
2618 | struct scic_sds_controller *scic = sci_port->owning_controller; | ||
2619 | struct isci_host *ihost = scic_to_ihost(scic); | ||
2620 | |||
2621 | /* notify the user. */ | ||
2622 | isci_port_bc_change_received(ihost, sci_port, sci_phy); | ||
2623 | } | ||
2624 | |||
309 | int isci_port_perform_hard_reset(struct isci_host *ihost, struct isci_port *iport, | 2625 | int isci_port_perform_hard_reset(struct isci_host *ihost, struct isci_port *iport, |
310 | struct isci_phy *iphy) | 2626 | struct isci_phy *iphy) |
311 | { | 2627 | { |
@@ -359,9 +2675,24 @@ int isci_port_perform_hard_reset(struct isci_host *ihost, struct isci_port *ipor | |||
359 | return ret; | 2675 | return ret; |
360 | } | 2676 | } |
361 | 2677 | ||
362 | void isci_port_stop_complete(struct scic_sds_controller *scic, | 2678 | /** |
363 | struct scic_sds_port *sci_port, | 2679 | * isci_port_deformed() - This function is called by libsas when a port becomes |
364 | enum sci_status completion_status) | 2680 | * inactive. |
2681 | * @phy: This parameter specifies the libsas phy with the inactive port. | ||
2682 | * | ||
2683 | */ | ||
2684 | void isci_port_deformed(struct asd_sas_phy *phy) | ||
365 | { | 2685 | { |
366 | dev_dbg(&scic_to_ihost(scic)->pdev->dev, "Port stop complete\n"); | 2686 | pr_debug("%s: sas_phy = %p\n", __func__, phy); |
2687 | } | ||
2688 | |||
2689 | /** | ||
2690 | * isci_port_formed() - This function is called by libsas when a port becomes | ||
2691 | * active. | ||
2692 | * @phy: This parameter specifies the libsas phy with the active port. | ||
2693 | * | ||
2694 | */ | ||
2695 | void isci_port_formed(struct asd_sas_phy *phy) | ||
2696 | { | ||
2697 | pr_debug("%s: sas_phy = %p, sas_port = %p\n", __func__, phy, phy->port); | ||
367 | } | 2698 | } |
diff --git a/drivers/scsi/isci/port.h b/drivers/scsi/isci/port.h index 59505cbf2bb3..ea41dcead3ae 100644 --- a/drivers/scsi/isci/port.h +++ b/drivers/scsi/isci/port.h | |||
@@ -58,7 +58,10 @@ | |||
58 | 58 | ||
59 | #include <scsi/libsas.h> | 59 | #include <scsi/libsas.h> |
60 | #include "isci.h" | 60 | #include "isci.h" |
61 | #include "scic_sds_port.h" | 61 | #include "sas.h" |
62 | #include "phy.h" | ||
63 | |||
64 | #define SCIC_SDS_DUMMY_PORT 0xFF | ||
62 | 65 | ||
63 | struct isci_phy; | 66 | struct isci_phy; |
64 | struct isci_host; | 67 | struct isci_host; |
@@ -73,6 +76,111 @@ enum isci_status { | |||
73 | }; | 76 | }; |
74 | 77 | ||
75 | /** | 78 | /** |
79 | * struct scic_sds_port | ||
80 | * | ||
81 | * The core port object provides the the abstraction for an SCU port. | ||
82 | */ | ||
83 | struct scic_sds_port { | ||
84 | |||
85 | /** | ||
86 | * This field contains the information for the base port state machine. | ||
87 | */ | ||
88 | struct sci_base_state_machine state_machine; | ||
89 | |||
90 | /** | ||
91 | * This field is the port index that is reported to the SCI USER. | ||
92 | * This allows the actual hardware physical port to change without | ||
93 | * the SCI USER getting a different answer for the get port index. | ||
94 | */ | ||
95 | u8 logical_port_index; | ||
96 | |||
97 | /** | ||
98 | * This field is the port index used to program the SCU hardware. | ||
99 | */ | ||
100 | u8 physical_port_index; | ||
101 | |||
102 | /** | ||
103 | * This field contains the active phy mask for the port. | ||
104 | * This mask is used in conjunction with the phy state to determine | ||
105 | * which phy to select for some port operations. | ||
106 | */ | ||
107 | u8 active_phy_mask; | ||
108 | |||
109 | u16 reserved_rni; | ||
110 | u16 reserved_tci; | ||
111 | |||
112 | /** | ||
113 | * This field contains the count of the io requests started on this port | ||
114 | * object. It is used to control controller shutdown. | ||
115 | */ | ||
116 | u32 started_request_count; | ||
117 | |||
118 | /** | ||
119 | * This field contains the number of devices assigned to this port. | ||
120 | * It is used to control port start requests. | ||
121 | */ | ||
122 | u32 assigned_device_count; | ||
123 | |||
124 | /** | ||
125 | * This field contains the reason for the port not going ready. It is | ||
126 | * assigned in the state handlers and used in the state transition. | ||
127 | */ | ||
128 | u32 not_ready_reason; | ||
129 | |||
130 | /** | ||
131 | * This field is the table of phys assigned to the port. | ||
132 | */ | ||
133 | struct scic_sds_phy *phy_table[SCI_MAX_PHYS]; | ||
134 | |||
135 | /** | ||
136 | * This field is a pointer back to the controller that owns this | ||
137 | * port object. | ||
138 | */ | ||
139 | struct scic_sds_controller *owning_controller; | ||
140 | |||
141 | /** | ||
142 | * This field contains the port start/stop timer handle. | ||
143 | */ | ||
144 | void *timer_handle; | ||
145 | |||
146 | /** | ||
147 | * This field points to the current set of state handlers for this port | ||
148 | * object. These state handlers are assigned at each enter state of | ||
149 | * the state machine. | ||
150 | */ | ||
151 | struct scic_sds_port_state_handler *state_handlers; | ||
152 | |||
153 | /** | ||
154 | * This field is the ready substate machine for the port. | ||
155 | */ | ||
156 | struct sci_base_state_machine ready_substate_machine; | ||
157 | |||
158 | /* / Memory mapped hardware register space */ | ||
159 | |||
160 | /** | ||
161 | * This field is the pointer to the port task scheduler registers | ||
162 | * for the SCU hardware. | ||
163 | */ | ||
164 | struct scu_port_task_scheduler_registers __iomem | ||
165 | *port_task_scheduler_registers; | ||
166 | |||
167 | /** | ||
168 | * This field is identical for all port objects and points to the port | ||
169 | * task scheduler group PE configuration registers. | ||
170 | * It is used to assign PEs to a port. | ||
171 | */ | ||
172 | u32 __iomem *port_pe_configuration_register; | ||
173 | |||
174 | /** | ||
175 | * This field is the VIIT register space for ths port object. | ||
176 | */ | ||
177 | struct scu_viit_entry __iomem *viit_registers; | ||
178 | |||
179 | }; | ||
180 | |||
181 | |||
182 | |||
183 | /** | ||
76 | * struct isci_port - This class represents the port object used to internally | 184 | * struct isci_port - This class represents the port object used to internally |
77 | * represent libsas port objects. It also keeps a list of remote device | 185 | * represent libsas port objects. It also keeps a list of remote device |
78 | * objects. | 186 | * objects. |
@@ -99,54 +207,301 @@ static inline struct isci_port *sci_port_to_iport(struct scic_sds_port *sci_port | |||
99 | return iport; | 207 | return iport; |
100 | } | 208 | } |
101 | 209 | ||
102 | enum isci_status isci_port_get_state( | 210 | enum scic_port_not_ready_reason_code { |
103 | struct isci_port *isci_port); | 211 | SCIC_PORT_NOT_READY_NO_ACTIVE_PHYS, |
212 | SCIC_PORT_NOT_READY_HARD_RESET_REQUESTED, | ||
213 | SCIC_PORT_NOT_READY_INVALID_PORT_CONFIGURATION, | ||
214 | SCIC_PORT_NOT_READY_RECONFIGURING, | ||
215 | |||
216 | SCIC_PORT_NOT_READY_REASON_CODE_MAX | ||
217 | }; | ||
218 | |||
219 | struct scic_port_end_point_properties { | ||
220 | struct sci_sas_address sas_address; | ||
221 | struct scic_phy_proto protocols; | ||
222 | }; | ||
223 | |||
224 | struct scic_port_properties { | ||
225 | u32 index; | ||
226 | struct scic_port_end_point_properties local; | ||
227 | struct scic_port_end_point_properties remote; | ||
228 | u32 phy_mask; | ||
229 | }; | ||
230 | |||
231 | /** | ||
232 | * enum SCIC_SDS_PORT_READY_SUBSTATES - | ||
233 | * | ||
234 | * This enumeration depicts all of the states for the core port ready substate | ||
235 | * machine. | ||
236 | */ | ||
237 | enum scic_sds_port_ready_substates { | ||
238 | /** | ||
239 | * The substate where the port is started and ready but has no | ||
240 | * active phys. | ||
241 | */ | ||
242 | SCIC_SDS_PORT_READY_SUBSTATE_WAITING, | ||
243 | |||
244 | /** | ||
245 | * The substate where the port is started and ready and there is | ||
246 | * at least one phy operational. | ||
247 | */ | ||
248 | SCIC_SDS_PORT_READY_SUBSTATE_OPERATIONAL, | ||
249 | |||
250 | /** | ||
251 | * The substate where the port is started and there was an | ||
252 | * add/remove phy event. This state is only used in Automatic | ||
253 | * Port Configuration Mode (APC) | ||
254 | */ | ||
255 | SCIC_SDS_PORT_READY_SUBSTATE_CONFIGURING, | ||
256 | |||
257 | SCIC_SDS_PORT_READY_MAX_SUBSTATES | ||
258 | }; | ||
259 | |||
260 | /** | ||
261 | * enum scic_sds_port_states - This enumeration depicts all the states for the | ||
262 | * common port state machine. | ||
263 | * | ||
264 | * | ||
265 | */ | ||
266 | enum scic_sds_port_states { | ||
267 | /** | ||
268 | * This state indicates that the port has successfully been stopped. | ||
269 | * In this state no new IO operations are permitted. | ||
270 | * This state is entered from the STOPPING state. | ||
271 | */ | ||
272 | SCI_BASE_PORT_STATE_STOPPED, | ||
273 | |||
274 | /** | ||
275 | * This state indicates that the port is in the process of stopping. | ||
276 | * In this state no new IO operations are permitted, but existing IO | ||
277 | * operations are allowed to complete. | ||
278 | * This state is entered from the READY state. | ||
279 | */ | ||
280 | SCI_BASE_PORT_STATE_STOPPING, | ||
281 | |||
282 | /** | ||
283 | * This state indicates the port is now ready. Thus, the user is | ||
284 | * able to perform IO operations on this port. | ||
285 | * This state is entered from the STARTING state. | ||
286 | */ | ||
287 | SCI_BASE_PORT_STATE_READY, | ||
288 | |||
289 | /** | ||
290 | * This state indicates the port is in the process of performing a hard | ||
291 | * reset. Thus, the user is unable to perform IO operations on this | ||
292 | * port. | ||
293 | * This state is entered from the READY state. | ||
294 | */ | ||
295 | SCI_BASE_PORT_STATE_RESETTING, | ||
296 | |||
297 | /** | ||
298 | * This state indicates the port has failed a reset request. This state | ||
299 | * is entered when a port reset request times out. | ||
300 | * This state is entered from the RESETTING state. | ||
301 | */ | ||
302 | SCI_BASE_PORT_STATE_FAILED, | ||
303 | |||
304 | SCI_BASE_PORT_MAX_STATES | ||
305 | |||
306 | }; | ||
307 | |||
308 | struct scic_sds_remote_device; | ||
309 | struct scic_sds_request; | ||
310 | |||
311 | typedef enum sci_status (*scic_sds_port_handler_t)(struct scic_sds_port *); | ||
104 | 312 | ||
105 | void isci_port_formed( | 313 | typedef enum sci_status (*scic_sds_port_phy_handler_t)(struct scic_sds_port *, |
106 | struct asd_sas_phy *); | 314 | struct scic_sds_phy *); |
107 | 315 | ||
108 | void isci_port_deformed( | 316 | typedef enum sci_status (*scic_sds_port_reset_handler_t)(struct scic_sds_port *, |
109 | struct asd_sas_phy *); | 317 | u32 timeout); |
110 | 318 | ||
111 | void isci_port_bc_change_received( | 319 | typedef enum sci_status (*scic_sds_port_event_handler_t)(struct scic_sds_port *, u32); |
112 | struct isci_host *isci_host, | ||
113 | struct scic_sds_port *port, | ||
114 | struct scic_sds_phy *phy); | ||
115 | 320 | ||
116 | void isci_port_link_up( | 321 | typedef enum sci_status (*scic_sds_port_frame_handler_t)(struct scic_sds_port *, u32); |
117 | struct isci_host *isci_host, | ||
118 | struct scic_sds_port *port, | ||
119 | struct scic_sds_phy *phy); | ||
120 | 322 | ||
121 | void isci_port_link_down( | 323 | typedef void (*scic_sds_port_link_handler_t)(struct scic_sds_port *, struct scic_sds_phy *); |
122 | struct isci_host *isci_host, | ||
123 | struct isci_phy *isci_phy, | ||
124 | struct isci_port *port); | ||
125 | 324 | ||
126 | void isci_port_ready( | 325 | typedef enum sci_status (*scic_sds_port_io_request_handler_t)(struct scic_sds_port *, |
127 | struct isci_host *isci_host, | 326 | struct scic_sds_remote_device *, |
327 | struct scic_sds_request *); | ||
328 | |||
329 | struct scic_sds_port_state_handler { | ||
330 | /** | ||
331 | * The start_handler specifies the method invoked when a user | ||
332 | * attempts to start a port. | ||
333 | */ | ||
334 | scic_sds_port_handler_t start_handler; | ||
335 | |||
336 | /** | ||
337 | * The stop_handler specifies the method invoked when a user | ||
338 | * attempts to stop a port. | ||
339 | */ | ||
340 | scic_sds_port_handler_t stop_handler; | ||
341 | |||
342 | /** | ||
343 | * The destruct_handler specifies the method invoked when attempting to | ||
344 | * destruct a port. | ||
345 | */ | ||
346 | scic_sds_port_handler_t destruct_handler; | ||
347 | |||
348 | /** | ||
349 | * The reset_handler specifies the method invoked when a user | ||
350 | * attempts to hard reset a port. | ||
351 | */ | ||
352 | scic_sds_port_reset_handler_t reset_handler; | ||
353 | |||
354 | /** | ||
355 | * The add_phy_handler specifies the method invoked when a user | ||
356 | * attempts to add another phy into the port. | ||
357 | */ | ||
358 | scic_sds_port_phy_handler_t add_phy_handler; | ||
359 | |||
360 | /** | ||
361 | * The remove_phy_handler specifies the method invoked when a user | ||
362 | * attempts to remove a phy from the port. | ||
363 | */ | ||
364 | scic_sds_port_phy_handler_t remove_phy_handler; | ||
365 | |||
366 | scic_sds_port_frame_handler_t frame_handler; | ||
367 | scic_sds_port_event_handler_t event_handler; | ||
368 | |||
369 | scic_sds_port_link_handler_t link_up_handler; | ||
370 | scic_sds_port_link_handler_t link_down_handler; | ||
371 | |||
372 | scic_sds_port_io_request_handler_t start_io_handler; | ||
373 | scic_sds_port_io_request_handler_t complete_io_handler; | ||
374 | |||
375 | }; | ||
376 | |||
377 | /** | ||
378 | * scic_sds_port_get_controller() - | ||
379 | * | ||
380 | * Helper macro to get the owning controller of this port | ||
381 | */ | ||
382 | #define scic_sds_port_get_controller(this_port) \ | ||
383 | ((this_port)->owning_controller) | ||
384 | |||
385 | /** | ||
386 | * scic_sds_port_set_base_state_handlers() - | ||
387 | * | ||
388 | * This macro will change the state handlers to those of the specified state id | ||
389 | */ | ||
390 | #define scic_sds_port_set_base_state_handlers(this_port, state_id) \ | ||
391 | scic_sds_port_set_state_handlers(\ | ||
392 | (this_port), &scic_sds_port_state_handler_table[(state_id)]) | ||
393 | |||
394 | /** | ||
395 | * scic_sds_port_set_state_handlers() - | ||
396 | * | ||
397 | * Helper macro to set the port object state handlers | ||
398 | */ | ||
399 | #define scic_sds_port_set_state_handlers(this_port, handlers) \ | ||
400 | ((this_port)->state_handlers = (handlers)) | ||
401 | |||
402 | /** | ||
403 | * scic_sds_port_get_index() - | ||
404 | * | ||
405 | * This macro returns the physical port index for this port object | ||
406 | */ | ||
407 | #define scic_sds_port_get_index(this_port) \ | ||
408 | ((this_port)->physical_port_index) | ||
409 | |||
410 | |||
411 | static inline void scic_sds_port_decrement_request_count(struct scic_sds_port *sci_port) | ||
412 | { | ||
413 | if (WARN_ONCE(sci_port->started_request_count == 0, | ||
414 | "%s: tried to decrement started_request_count past 0!?", | ||
415 | __func__)) | ||
416 | /* pass */; | ||
417 | else | ||
418 | sci_port->started_request_count--; | ||
419 | } | ||
420 | |||
421 | #define scic_sds_port_active_phy(port, phy) \ | ||
422 | (((port)->active_phy_mask & (1 << (phy)->phy_index)) != 0) | ||
423 | |||
424 | void scic_sds_port_construct( | ||
425 | struct scic_sds_port *sci_port, | ||
426 | u8 port_index, | ||
427 | struct scic_sds_controller *scic); | ||
428 | |||
429 | enum sci_status scic_sds_port_initialize( | ||
430 | struct scic_sds_port *sci_port, | ||
431 | void __iomem *port_task_scheduler_registers, | ||
432 | void __iomem *port_configuration_regsiter, | ||
433 | void __iomem *viit_registers); | ||
434 | |||
435 | enum sci_status scic_sds_port_add_phy( | ||
436 | struct scic_sds_port *sci_port, | ||
437 | struct scic_sds_phy *sci_phy); | ||
438 | |||
439 | enum sci_status scic_sds_port_remove_phy( | ||
440 | struct scic_sds_port *sci_port, | ||
441 | struct scic_sds_phy *sci_phy); | ||
442 | |||
443 | void scic_sds_port_setup_transports( | ||
444 | struct scic_sds_port *sci_port, | ||
445 | u32 device_id); | ||
446 | |||
447 | |||
448 | void scic_sds_port_deactivate_phy( | ||
449 | struct scic_sds_port *sci_port, | ||
450 | struct scic_sds_phy *sci_phy, | ||
451 | bool do_notify_user); | ||
452 | |||
453 | bool scic_sds_port_link_detected( | ||
454 | struct scic_sds_port *sci_port, | ||
455 | struct scic_sds_phy *sci_phy); | ||
456 | |||
457 | void scic_sds_port_link_up( | ||
458 | struct scic_sds_port *sci_port, | ||
459 | struct scic_sds_phy *sci_phy); | ||
460 | |||
461 | void scic_sds_port_link_down( | ||
462 | struct scic_sds_port *sci_port, | ||
463 | struct scic_sds_phy *sci_phy); | ||
464 | |||
465 | enum sci_status scic_sds_port_start_io( | ||
466 | struct scic_sds_port *sci_port, | ||
467 | struct scic_sds_remote_device *sci_dev, | ||
468 | struct scic_sds_request *sci_req); | ||
469 | |||
470 | enum sci_status scic_sds_port_complete_io( | ||
471 | struct scic_sds_port *sci_port, | ||
472 | struct scic_sds_remote_device *sci_dev, | ||
473 | struct scic_sds_request *sci_req); | ||
474 | |||
475 | enum sas_linkrate scic_sds_port_get_max_allowed_speed( | ||
476 | struct scic_sds_port *sci_port); | ||
477 | |||
478 | void scic_sds_port_broadcast_change_received( | ||
479 | struct scic_sds_port *sci_port, | ||
480 | struct scic_sds_phy *sci_phy); | ||
481 | |||
482 | bool scic_sds_port_is_valid_phy_assignment( | ||
483 | struct scic_sds_port *sci_port, | ||
484 | u32 phy_index); | ||
485 | |||
486 | void scic_sds_port_get_sas_address( | ||
487 | struct scic_sds_port *sci_port, | ||
488 | struct sci_sas_address *sas_address); | ||
489 | |||
490 | void scic_sds_port_get_attached_sas_address( | ||
491 | struct scic_sds_port *sci_port, | ||
492 | struct sci_sas_address *sas_address); | ||
493 | |||
494 | enum isci_status isci_port_get_state( | ||
128 | struct isci_port *isci_port); | 495 | struct isci_port *isci_port); |
129 | 496 | ||
130 | void isci_port_not_ready( | 497 | void isci_port_formed(struct asd_sas_phy *); |
131 | struct isci_host *isci_host, | 498 | void isci_port_deformed(struct asd_sas_phy *); |
132 | struct isci_port *port); | ||
133 | 499 | ||
134 | void isci_port_init( | 500 | void isci_port_init( |
135 | struct isci_port *port, | 501 | struct isci_port *port, |
136 | struct isci_host *host, | 502 | struct isci_host *host, |
137 | int index); | 503 | int index); |
138 | 504 | ||
139 | void isci_port_hard_reset_complete( | ||
140 | struct isci_port *isci_port, | ||
141 | enum sci_status completion_status); | ||
142 | |||
143 | int isci_port_perform_hard_reset(struct isci_host *ihost, struct isci_port *iport, | 505 | int isci_port_perform_hard_reset(struct isci_host *ihost, struct isci_port *iport, |
144 | struct isci_phy *iphy); | 506 | struct isci_phy *iphy); |
145 | |||
146 | void isci_port_stop_complete( | ||
147 | struct scic_sds_controller *scic, | ||
148 | struct scic_sds_port *sci_port, | ||
149 | enum sci_status completion_status); | ||
150 | |||
151 | #endif /* !defined(_ISCI_PORT_H_) */ | 507 | #endif /* !defined(_ISCI_PORT_H_) */ |
152 | |||
diff --git a/drivers/scsi/isci/core/scic_sds_port_configuration_agent.c b/drivers/scsi/isci/port_config.c index a5871fddc09a..028ffa370c90 100644 --- a/drivers/scsi/isci/core/scic_sds_port_configuration_agent.c +++ b/drivers/scsi/isci/port_config.c | |||
@@ -54,7 +54,6 @@ | |||
54 | */ | 54 | */ |
55 | 55 | ||
56 | #include "host.h" | 56 | #include "host.h" |
57 | #include "scic_sds_port_configuration_agent.h" | ||
58 | #include "timers.h" | 57 | #include "timers.h" |
59 | 58 | ||
60 | #define SCIC_SDS_MPC_RECONFIGURATION_TIMEOUT (10) | 59 | #define SCIC_SDS_MPC_RECONFIGURATION_TIMEOUT (10) |
diff --git a/drivers/scsi/isci/probe_roms.h b/drivers/scsi/isci/probe_roms.h index f4ef19ac281c..7e3e6d7a0a47 100644 --- a/drivers/scsi/isci/probe_roms.h +++ b/drivers/scsi/isci/probe_roms.h | |||
@@ -60,15 +60,117 @@ | |||
60 | #include <linux/pci.h> | 60 | #include <linux/pci.h> |
61 | #include "isci.h" | 61 | #include "isci.h" |
62 | 62 | ||
63 | struct isci_orom *isci_request_oprom(struct pci_dev *pdev); | 63 | #define SCIC_SDS_PARM_NO_SPEED 0 |
64 | |||
65 | /* generation 1 (i.e. 1.5 Gb/s) */ | ||
66 | #define SCIC_SDS_PARM_GEN1_SPEED 1 | ||
67 | |||
68 | /* generation 2 (i.e. 3.0 Gb/s) */ | ||
69 | #define SCIC_SDS_PARM_GEN2_SPEED 2 | ||
70 | |||
71 | /* generation 3 (i.e. 6.0 Gb/s) */ | ||
72 | #define SCIC_SDS_PARM_GEN3_SPEED 3 | ||
73 | #define SCIC_SDS_PARM_MAX_SPEED SCIC_SDS_PARM_GEN3_SPEED | ||
74 | |||
75 | /* parameters that can be set by module parameters */ | ||
76 | struct scic_sds_user_parameters { | ||
77 | struct sci_phy_user_params { | ||
78 | /** | ||
79 | * This field specifies the NOTIFY (ENABLE SPIN UP) primitive | ||
80 | * insertion frequency for this phy index. | ||
81 | */ | ||
82 | u32 notify_enable_spin_up_insertion_frequency; | ||
83 | |||
84 | /** | ||
85 | * This method specifies the number of transmitted DWORDs within which | ||
86 | * to transmit a single ALIGN primitive. This value applies regardless | ||
87 | * of what type of device is attached or connection state. A value of | ||
88 | * 0 indicates that no ALIGN primitives will be inserted. | ||
89 | */ | ||
90 | u16 align_insertion_frequency; | ||
91 | |||
92 | /** | ||
93 | * This method specifies the number of transmitted DWORDs within which | ||
94 | * to transmit 2 ALIGN primitives. This applies for SAS connections | ||
95 | * only. A minimum value of 3 is required for this field. | ||
96 | */ | ||
97 | u16 in_connection_align_insertion_frequency; | ||
98 | |||
99 | /** | ||
100 | * This field indicates the maximum speed generation to be utilized | ||
101 | * by phys in the supplied port. | ||
102 | * - A value of 1 indicates generation 1 (i.e. 1.5 Gb/s). | ||
103 | * - A value of 2 indicates generation 2 (i.e. 3.0 Gb/s). | ||
104 | * - A value of 3 indicates generation 3 (i.e. 6.0 Gb/s). | ||
105 | */ | ||
106 | u8 max_speed_generation; | ||
107 | |||
108 | } phys[SCI_MAX_PHYS]; | ||
109 | |||
110 | /** | ||
111 | * This field specifies the maximum number of direct attached devices | ||
112 | * that can have power supplied to them simultaneously. | ||
113 | */ | ||
114 | u8 max_number_concurrent_device_spin_up; | ||
115 | |||
116 | /** | ||
117 | * This field specifies the number of seconds to allow a phy to consume | ||
118 | * power before yielding to another phy. | ||
119 | * | ||
120 | */ | ||
121 | u8 phy_spin_up_delay_interval; | ||
122 | |||
123 | /** | ||
124 | * These timer values specifies how long a link will remain open with no | ||
125 | * activity in increments of a microsecond, it can be in increments of | ||
126 | * 100 microseconds if the upper most bit is set. | ||
127 | * | ||
128 | */ | ||
129 | u16 stp_inactivity_timeout; | ||
130 | u16 ssp_inactivity_timeout; | ||
131 | |||
132 | /** | ||
133 | * These timer values specifies how long a link will remain open in increments | ||
134 | * of 100 microseconds. | ||
135 | * | ||
136 | */ | ||
137 | u16 stp_max_occupancy_timeout; | ||
138 | u16 ssp_max_occupancy_timeout; | ||
139 | |||
140 | /** | ||
141 | * This timer value specifies how long a link will remain open with no | ||
142 | * outbound traffic in increments of a microsecond. | ||
143 | * | ||
144 | */ | ||
145 | u8 no_outbound_task_timeout; | ||
146 | |||
147 | }; | ||
148 | |||
149 | /* XXX kill this union */ | ||
150 | union scic_user_parameters { | ||
151 | /** | ||
152 | * This field specifies the user parameters specific to the | ||
153 | * Storage Controller Unit (SCU) Driver Standard (SDS) version | ||
154 | * 1. | ||
155 | */ | ||
156 | struct scic_sds_user_parameters sds1; | ||
157 | }; | ||
158 | |||
159 | #define SCIC_SDS_PARM_PHY_MASK_MIN 0x0 | ||
160 | #define SCIC_SDS_PARM_PHY_MASK_MAX 0xF | ||
161 | #define MAX_CONCURRENT_DEVICE_SPIN_UP_COUNT 4 | ||
162 | |||
163 | struct scic_sds_oem_params; | ||
164 | int scic_oem_parameters_validate(struct scic_sds_oem_params *oem); | ||
64 | 165 | ||
65 | union scic_oem_parameters; | 166 | union scic_oem_parameters; |
66 | struct isci_orom; | 167 | void scic_oem_parameters_get(struct scic_sds_controller *scic, |
168 | union scic_oem_parameters *oem); | ||
67 | 169 | ||
68 | enum sci_status isci_parse_oem_parameters( | 170 | struct isci_orom; |
69 | union scic_oem_parameters *oem_params, | 171 | struct isci_orom *isci_request_oprom(struct pci_dev *pdev); |
70 | struct isci_orom *orom, | 172 | enum sci_status isci_parse_oem_parameters(union scic_oem_parameters *oem, |
71 | int scu_index); | 173 | struct isci_orom *orom, int scu_index); |
72 | struct isci_orom *isci_request_firmware(struct pci_dev *pdev, const struct firmware *fw); | 174 | struct isci_orom *isci_request_firmware(struct pci_dev *pdev, const struct firmware *fw); |
73 | struct isci_orom *isci_get_efi_var(struct pci_dev *pdev); | 175 | struct isci_orom *isci_get_efi_var(struct pci_dev *pdev); |
74 | 176 | ||
@@ -153,6 +255,16 @@ struct scic_sds_oem_params { | |||
153 | } phys[SCI_MAX_PHYS]; | 255 | } phys[SCI_MAX_PHYS]; |
154 | } __attribute__ ((packed)); | 256 | } __attribute__ ((packed)); |
155 | 257 | ||
258 | /* XXX kill this union */ | ||
259 | union scic_oem_parameters { | ||
260 | /** | ||
261 | * This field specifies the OEM parameters specific to the | ||
262 | * Storage Controller Unit (SCU) Driver Standard (SDS) version | ||
263 | * 1. | ||
264 | */ | ||
265 | struct scic_sds_oem_params sds1; | ||
266 | }; | ||
267 | |||
156 | struct isci_orom { | 268 | struct isci_orom { |
157 | struct sci_bios_oem_param_block_hdr hdr; | 269 | struct sci_bios_oem_param_block_hdr hdr; |
158 | struct scic_sds_oem_params ctrl[SCI_MAX_CONTROLLERS]; | 270 | struct scic_sds_oem_params ctrl[SCI_MAX_CONTROLLERS]; |
diff --git a/drivers/scsi/isci/remote_device.c b/drivers/scsi/isci/remote_device.c index 2baa215cb275..0bb639dfbada 100644 --- a/drivers/scsi/isci/remote_device.c +++ b/drivers/scsi/isci/remote_device.c | |||
@@ -57,8 +57,6 @@ | |||
57 | #include "port.h" | 57 | #include "port.h" |
58 | #include "remote_device.h" | 58 | #include "remote_device.h" |
59 | #include "request.h" | 59 | #include "request.h" |
60 | #include "scic_port.h" | ||
61 | #include "scic_sds_port.h" | ||
62 | #include "remote_node_context.h" | 60 | #include "remote_node_context.h" |
63 | #include "scu_event_codes.h" | 61 | #include "scu_event_codes.h" |
64 | #include "task.h" | 62 | #include "task.h" |
diff --git a/drivers/scsi/isci/remote_node_context.c b/drivers/scsi/isci/remote_node_context.c index 35231e7407b1..aef258b959f8 100644 --- a/drivers/scsi/isci/remote_node_context.c +++ b/drivers/scsi/isci/remote_node_context.c | |||
@@ -55,7 +55,6 @@ | |||
55 | 55 | ||
56 | #include "host.h" | 56 | #include "host.h" |
57 | #include "state_machine.h" | 57 | #include "state_machine.h" |
58 | #include "scic_sds_port.h" | ||
59 | #include "remote_device.h" | 58 | #include "remote_device.h" |
60 | #include "remote_node_context.h" | 59 | #include "remote_node_context.h" |
61 | #include "scu_event_codes.h" | 60 | #include "scu_event_codes.h" |
diff --git a/drivers/scsi/isci/request.c b/drivers/scsi/isci/request.c index 857ad067f11c..48e2dac72528 100644 --- a/drivers/scsi/isci/request.c +++ b/drivers/scsi/isci/request.c | |||
@@ -54,7 +54,6 @@ | |||
54 | */ | 54 | */ |
55 | 55 | ||
56 | #include "isci.h" | 56 | #include "isci.h" |
57 | #include "scic_port.h" | ||
58 | #include "task.h" | 57 | #include "task.h" |
59 | #include "request.h" | 58 | #include "request.h" |
60 | #include "sata.h" | 59 | #include "sata.h" |