Commit | Line | Data |
---|---|---|
6f231dda DW |
1 | /* |
2 | * This file is provided under a dual BSD/GPLv2 license. When using or | |
3 | * redistributing this file, you may do so under either license. | |
4 | * | |
5 | * GPL LICENSE SUMMARY | |
6 | * | |
7 | * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. | |
8 | * | |
9 | * This program is free software; you can redistribute it and/or modify | |
10 | * it under the terms of version 2 of the GNU General Public License as | |
11 | * published by the Free Software Foundation. | |
12 | * | |
13 | * This program is distributed in the hope that it will be useful, but | |
14 | * WITHOUT ANY WARRANTY; without even the implied warranty of | |
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
16 | * General Public License for more details. | |
17 | * | |
18 | * You should have received a copy of the GNU General Public License | |
19 | * along with this program; if not, write to the Free Software | |
20 | * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. | |
21 | * The full GNU General Public License is included in this distribution | |
22 | * in the file called LICENSE.GPL. | |
23 | * | |
24 | * BSD LICENSE | |
25 | * | |
26 | * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. | |
27 | * All rights reserved. | |
28 | * | |
29 | * Redistribution and use in source and binary forms, with or without | |
30 | * modification, are permitted provided that the following conditions | |
31 | * are met: | |
32 | * | |
33 | * * Redistributions of source code must retain the above copyright | |
34 | * notice, this list of conditions and the following disclaimer. | |
35 | * * Redistributions in binary form must reproduce the above copyright | |
36 | * notice, this list of conditions and the following disclaimer in | |
37 | * the documentation and/or other materials provided with the | |
38 | * distribution. | |
39 | * * Neither the name of Intel Corporation nor the names of its | |
40 | * contributors may be used to endorse or promote products derived | |
41 | * from this software without specific prior written permission. | |
42 | * | |
43 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
44 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
45 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | |
46 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | |
47 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
48 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |
49 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |
50 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |
51 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
52 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |
53 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
54 | */ | |
2d9c2240 | 55 | #include <scsi/sas.h> |
88f3b62a DW |
56 | #include "isci.h" |
57 | #include "port.h" | |
58 | #include "remote_device.h" | |
59 | #include "request.h" | |
60 | #include "scic_controller.h" | |
61 | #include "scic_io_request.h" | |
62 | #include "scic_phy.h" | |
63 | #include "scic_port.h" | |
64 | #include "scic_sds_controller.h" | |
65 | #include "scic_sds_phy.h" | |
66 | #include "scic_sds_port.h" | |
67 | #include "remote_node_context.h" | |
68 | #include "scic_sds_request.h" | |
69 | #include "sci_environment.h" | |
70 | #include "sci_util.h" | |
71 | #include "scu_event_codes.h" | |
72 | #include "task.h" | |
73 | ||
ab2e8f7d DW |
74 | /** |
75 | * isci_remote_device_change_state() - This function gets the status of the | |
76 | * remote_device object. | |
77 | * @isci_device: This parameter points to the isci_remote_device object | |
78 | * | |
79 | * status of the object as a isci_status enum. | |
80 | */ | |
81 | void isci_remote_device_change_state( | |
82 | struct isci_remote_device *isci_device, | |
83 | enum isci_status status) | |
84 | { | |
85 | unsigned long flags; | |
86 | ||
87 | spin_lock_irqsave(&isci_device->state_lock, flags); | |
88 | isci_device->status = status; | |
89 | spin_unlock_irqrestore(&isci_device->state_lock, flags); | |
90 | } | |
91 | ||
92 | /** | |
93 | * isci_remote_device_not_ready() - This function is called by the scic when | |
94 | * the remote device is not ready. We mark the isci device as ready (not | |
95 | * "ready_for_io") and signal the waiting proccess. | |
96 | * @isci_host: This parameter specifies the isci host object. | |
97 | * @isci_device: This parameter specifies the remote device | |
98 | * | |
99 | */ | |
100 | static void isci_remote_device_not_ready(struct isci_host *ihost, | |
101 | struct isci_remote_device *idev, u32 reason) | |
102 | { | |
103 | dev_dbg(&ihost->pdev->dev, | |
104 | "%s: isci_device = %p\n", __func__, idev); | |
105 | ||
106 | if (reason == SCIC_REMOTE_DEVICE_NOT_READY_STOP_REQUESTED) | |
107 | isci_remote_device_change_state(idev, isci_stopping); | |
108 | else | |
109 | /* device ready is actually a "not ready for io" state. */ | |
110 | isci_remote_device_change_state(idev, isci_ready); | |
111 | } | |
112 | ||
113 | /** | |
114 | * isci_remote_device_ready() - This function is called by the scic when the | |
115 | * remote device is ready. We mark the isci device as ready and signal the | |
116 | * waiting proccess. | |
117 | * @ihost: our valid isci_host | |
118 | * @idev: remote device | |
119 | * | |
120 | */ | |
121 | static void isci_remote_device_ready(struct isci_host *ihost, struct isci_remote_device *idev) | |
122 | { | |
123 | dev_dbg(&ihost->pdev->dev, | |
124 | "%s: idev = %p\n", __func__, idev); | |
125 | ||
126 | isci_remote_device_change_state(idev, isci_ready_for_io); | |
127 | if (test_and_clear_bit(IDEV_START_PENDING, &idev->flags)) | |
128 | wake_up(&ihost->eventq); | |
129 | } | |
130 | ||
ec575669 DW |
131 | /* called once the remote node context is ready to be freed. |
132 | * The remote device can now report that its stop operation is complete. none | |
133 | */ | |
134 | static void rnc_destruct_done(void *_dev) | |
135 | { | |
136 | struct scic_sds_remote_device *sci_dev = _dev; | |
ab2e8f7d | 137 | |
ec575669 DW |
138 | BUG_ON(sci_dev->started_request_count != 0); |
139 | sci_base_state_machine_change_state(&sci_dev->state_machine, | |
140 | SCI_BASE_REMOTE_DEVICE_STATE_STOPPED); | |
141 | } | |
ab2e8f7d | 142 | |
ec575669 DW |
143 | static enum sci_status scic_sds_remote_device_terminate_requests(struct scic_sds_remote_device *sci_dev) |
144 | { | |
145 | struct scic_sds_controller *scic = sci_dev->owning_port->owning_controller; | |
146 | u32 i, request_count = sci_dev->started_request_count; | |
147 | enum sci_status status = SCI_SUCCESS; | |
148 | ||
149 | for (i = 0; i < SCI_MAX_IO_REQUESTS && i < request_count; i++) { | |
150 | struct scic_sds_request *sci_req; | |
151 | enum sci_status s; | |
152 | ||
153 | sci_req = scic->io_request_table[i]; | |
154 | if (!sci_req || sci_req->target_device != sci_dev) | |
155 | continue; | |
156 | s = scic_controller_terminate_request(scic, sci_dev, sci_req); | |
157 | if (s != SCI_SUCCESS) | |
158 | status = s; | |
159 | } | |
160 | ||
161 | return status; | |
162 | } | |
163 | ||
164 | enum sci_status scic_remote_device_stop(struct scic_sds_remote_device *sci_dev, | |
165 | u32 timeout) | |
88f3b62a | 166 | { |
ec575669 DW |
167 | struct sci_base_state_machine *sm = &sci_dev->state_machine; |
168 | enum scic_sds_remote_device_states state = sm->current_state_id; | |
169 | ||
170 | switch (state) { | |
171 | case SCI_BASE_REMOTE_DEVICE_STATE_INITIAL: | |
172 | case SCI_BASE_REMOTE_DEVICE_STATE_FAILED: | |
173 | case SCI_BASE_REMOTE_DEVICE_STATE_FINAL: | |
174 | default: | |
175 | dev_warn(scirdev_to_dev(sci_dev), "%s: in wrong state: %d\n", | |
176 | __func__, state); | |
177 | return SCI_FAILURE_INVALID_STATE; | |
178 | case SCI_BASE_REMOTE_DEVICE_STATE_STOPPED: | |
179 | return SCI_SUCCESS; | |
180 | case SCI_BASE_REMOTE_DEVICE_STATE_STARTING: | |
181 | /* device not started so there had better be no requests */ | |
182 | BUG_ON(sci_dev->started_request_count != 0); | |
183 | scic_sds_remote_node_context_destruct(&sci_dev->rnc, | |
184 | rnc_destruct_done, sci_dev); | |
185 | /* Transition to the stopping state and wait for the | |
186 | * remote node to complete being posted and invalidated. | |
187 | */ | |
188 | sci_base_state_machine_change_state(sm, SCI_BASE_REMOTE_DEVICE_STATE_STOPPING); | |
189 | return SCI_SUCCESS; | |
190 | case SCI_BASE_REMOTE_DEVICE_STATE_READY: | |
191 | case SCIC_SDS_STP_REMOTE_DEVICE_READY_SUBSTATE_IDLE: | |
192 | case SCIC_SDS_STP_REMOTE_DEVICE_READY_SUBSTATE_CMD: | |
193 | case SCIC_SDS_STP_REMOTE_DEVICE_READY_SUBSTATE_NCQ: | |
194 | case SCIC_SDS_STP_REMOTE_DEVICE_READY_SUBSTATE_NCQ_ERROR: | |
195 | case SCIC_SDS_STP_REMOTE_DEVICE_READY_SUBSTATE_AWAIT_RESET: | |
196 | case SCIC_SDS_SMP_REMOTE_DEVICE_READY_SUBSTATE_IDLE: | |
197 | case SCIC_SDS_SMP_REMOTE_DEVICE_READY_SUBSTATE_CMD: | |
198 | sci_base_state_machine_change_state(sm, SCI_BASE_REMOTE_DEVICE_STATE_STOPPING); | |
199 | if (sci_dev->started_request_count == 0) { | |
200 | scic_sds_remote_node_context_destruct(&sci_dev->rnc, | |
201 | rnc_destruct_done, sci_dev); | |
202 | return SCI_SUCCESS; | |
203 | } else | |
204 | return scic_sds_remote_device_terminate_requests(sci_dev); | |
205 | break; | |
206 | case SCI_BASE_REMOTE_DEVICE_STATE_STOPPING: | |
207 | /* All requests should have been terminated, but if there is an | |
208 | * attempt to stop a device already in the stopping state, then | |
209 | * try again to terminate. | |
210 | */ | |
211 | return scic_sds_remote_device_terminate_requests(sci_dev); | |
212 | case SCI_BASE_REMOTE_DEVICE_STATE_RESETTING: | |
213 | sci_base_state_machine_change_state(sm, SCI_BASE_REMOTE_DEVICE_STATE_STOPPING); | |
214 | return SCI_SUCCESS; | |
215 | } | |
88f3b62a DW |
216 | } |
217 | ||
4fd0d2e9 | 218 | enum sci_status scic_remote_device_reset(struct scic_sds_remote_device *sci_dev) |
88f3b62a | 219 | { |
4fd0d2e9 DW |
220 | struct sci_base_state_machine *sm = &sci_dev->state_machine; |
221 | enum scic_sds_remote_device_states state = sm->current_state_id; | |
222 | ||
223 | switch (state) { | |
224 | case SCI_BASE_REMOTE_DEVICE_STATE_INITIAL: | |
225 | case SCI_BASE_REMOTE_DEVICE_STATE_STOPPED: | |
226 | case SCI_BASE_REMOTE_DEVICE_STATE_STARTING: | |
227 | case SCIC_SDS_SMP_REMOTE_DEVICE_READY_SUBSTATE_IDLE: | |
228 | case SCIC_SDS_SMP_REMOTE_DEVICE_READY_SUBSTATE_CMD: | |
229 | case SCI_BASE_REMOTE_DEVICE_STATE_STOPPING: | |
230 | case SCI_BASE_REMOTE_DEVICE_STATE_FAILED: | |
231 | case SCI_BASE_REMOTE_DEVICE_STATE_RESETTING: | |
232 | case SCI_BASE_REMOTE_DEVICE_STATE_FINAL: | |
233 | default: | |
234 | dev_warn(scirdev_to_dev(sci_dev), "%s: in wrong state: %d\n", | |
235 | __func__, state); | |
236 | return SCI_FAILURE_INVALID_STATE; | |
237 | case SCI_BASE_REMOTE_DEVICE_STATE_READY: | |
238 | case SCIC_SDS_STP_REMOTE_DEVICE_READY_SUBSTATE_IDLE: | |
239 | case SCIC_SDS_STP_REMOTE_DEVICE_READY_SUBSTATE_CMD: | |
240 | case SCIC_SDS_STP_REMOTE_DEVICE_READY_SUBSTATE_NCQ: | |
241 | case SCIC_SDS_STP_REMOTE_DEVICE_READY_SUBSTATE_NCQ_ERROR: | |
242 | case SCIC_SDS_STP_REMOTE_DEVICE_READY_SUBSTATE_AWAIT_RESET: | |
243 | sci_base_state_machine_change_state(sm, SCI_BASE_REMOTE_DEVICE_STATE_RESETTING); | |
244 | return SCI_SUCCESS; | |
245 | } | |
88f3b62a DW |
246 | } |
247 | ||
81515182 | 248 | enum sci_status scic_remote_device_reset_complete(struct scic_sds_remote_device *sci_dev) |
88f3b62a | 249 | { |
81515182 DW |
250 | struct sci_base_state_machine *sm = &sci_dev->state_machine; |
251 | enum scic_sds_remote_device_states state = sm->current_state_id; | |
252 | ||
253 | if (state != SCI_BASE_REMOTE_DEVICE_STATE_RESETTING) { | |
254 | dev_warn(scirdev_to_dev(sci_dev), "%s: in wrong state: %d\n", | |
255 | __func__, state); | |
256 | return SCI_FAILURE_INVALID_STATE; | |
257 | } | |
88f3b62a | 258 | |
81515182 DW |
259 | sci_base_state_machine_change_state(sm, SCI_BASE_REMOTE_DEVICE_STATE_READY); |
260 | return SCI_SUCCESS; | |
261 | } | |
88f3b62a | 262 | |
323f0ec0 DW |
263 | enum sci_status scic_sds_remote_device_suspend(struct scic_sds_remote_device *sci_dev, |
264 | u32 suspend_type) | |
88f3b62a | 265 | { |
323f0ec0 DW |
266 | struct sci_base_state_machine *sm = &sci_dev->state_machine; |
267 | enum scic_sds_remote_device_states state = sm->current_state_id; | |
268 | ||
269 | if (state != SCIC_SDS_STP_REMOTE_DEVICE_READY_SUBSTATE_CMD) { | |
270 | dev_warn(scirdev_to_dev(sci_dev), "%s: in wrong state: %d\n", | |
271 | __func__, state); | |
272 | return SCI_FAILURE_INVALID_STATE; | |
273 | } | |
274 | ||
275 | return scic_sds_remote_node_context_suspend(&sci_dev->rnc, | |
276 | suspend_type, NULL, NULL); | |
88f3b62a DW |
277 | } |
278 | ||
01bec778 DW |
279 | enum sci_status scic_sds_remote_device_frame_handler(struct scic_sds_remote_device *sci_dev, |
280 | u32 frame_index) | |
88f3b62a | 281 | { |
01bec778 DW |
282 | struct sci_base_state_machine *sm = &sci_dev->state_machine; |
283 | enum scic_sds_remote_device_states state = sm->current_state_id; | |
284 | struct scic_sds_controller *scic = sci_dev->owning_port->owning_controller; | |
285 | enum sci_status status; | |
286 | ||
287 | switch (state) { | |
288 | case SCI_BASE_REMOTE_DEVICE_STATE_INITIAL: | |
289 | case SCI_BASE_REMOTE_DEVICE_STATE_STOPPED: | |
290 | case SCI_BASE_REMOTE_DEVICE_STATE_STARTING: | |
291 | case SCIC_SDS_STP_REMOTE_DEVICE_READY_SUBSTATE_IDLE: | |
292 | case SCIC_SDS_SMP_REMOTE_DEVICE_READY_SUBSTATE_IDLE: | |
293 | case SCI_BASE_REMOTE_DEVICE_STATE_FINAL: | |
294 | default: | |
295 | dev_warn(scirdev_to_dev(sci_dev), "%s: in wrong state: %d\n", | |
296 | __func__, state); | |
297 | /* Return the frame back to the controller */ | |
298 | scic_sds_controller_release_frame(scic, frame_index); | |
299 | return SCI_FAILURE_INVALID_STATE; | |
300 | case SCI_BASE_REMOTE_DEVICE_STATE_READY: | |
301 | case SCIC_SDS_STP_REMOTE_DEVICE_READY_SUBSTATE_NCQ_ERROR: | |
302 | case SCIC_SDS_STP_REMOTE_DEVICE_READY_SUBSTATE_AWAIT_RESET: | |
303 | case SCI_BASE_REMOTE_DEVICE_STATE_STOPPING: | |
304 | case SCI_BASE_REMOTE_DEVICE_STATE_FAILED: | |
305 | case SCI_BASE_REMOTE_DEVICE_STATE_RESETTING: { | |
306 | struct scic_sds_request *sci_req; | |
2d9c2240 DJ |
307 | struct ssp_frame_hdr hdr; |
308 | void *frame_header; | |
309 | ssize_t word_cnt; | |
01bec778 DW |
310 | |
311 | status = scic_sds_unsolicited_frame_control_get_header(&scic->uf_control, | |
312 | frame_index, | |
2d9c2240 | 313 | &frame_header); |
01bec778 DW |
314 | if (status != SCI_SUCCESS) |
315 | return status; | |
316 | ||
2d9c2240 DJ |
317 | word_cnt = sizeof(hdr) / sizeof(u32); |
318 | sci_swab32_cpy(&hdr, frame_header, word_cnt); | |
319 | ||
320 | sci_req = scic_request_by_tag(scic, be16_to_cpu(hdr.tag)); | |
01bec778 DW |
321 | if (sci_req && sci_req->target_device == sci_dev) { |
322 | /* The IO request is now in charge of releasing the frame */ | |
323 | status = sci_req->state_handlers->frame_handler(sci_req, | |
324 | frame_index); | |
325 | } else { | |
326 | /* We could not map this tag to a valid IO | |
327 | * request Just toss the frame and continue | |
328 | */ | |
329 | scic_sds_controller_release_frame(scic, frame_index); | |
330 | } | |
331 | break; | |
332 | } | |
333 | case SCIC_SDS_STP_REMOTE_DEVICE_READY_SUBSTATE_NCQ: { | |
e76d6180 | 334 | struct dev_to_host_fis *hdr; |
01bec778 DW |
335 | |
336 | status = scic_sds_unsolicited_frame_control_get_header(&scic->uf_control, | |
337 | frame_index, | |
338 | (void **)&hdr); | |
339 | if (status != SCI_SUCCESS) | |
340 | return status; | |
341 | ||
e76d6180 DJ |
342 | if (hdr->fis_type == FIS_SETDEVBITS && |
343 | (hdr->status & ATA_ERR)) { | |
01bec778 DW |
344 | sci_dev->not_ready_reason = SCIC_REMOTE_DEVICE_NOT_READY_SATA_SDB_ERROR_FIS_RECEIVED; |
345 | ||
346 | /* TODO Check sactive and complete associated IO if any. */ | |
347 | sci_base_state_machine_change_state(sm, SCIC_SDS_STP_REMOTE_DEVICE_READY_SUBSTATE_NCQ_ERROR); | |
e76d6180 DJ |
348 | } else if (hdr->fis_type == FIS_REGD2H && |
349 | (hdr->status & ATA_ERR)) { | |
01bec778 DW |
350 | /* |
351 | * Some devices return D2H FIS when an NCQ error is detected. | |
352 | * Treat this like an SDB error FIS ready reason. | |
353 | */ | |
354 | sci_dev->not_ready_reason = SCIC_REMOTE_DEVICE_NOT_READY_SATA_SDB_ERROR_FIS_RECEIVED; | |
355 | sci_base_state_machine_change_state(&sci_dev->state_machine, | |
356 | SCIC_SDS_STP_REMOTE_DEVICE_READY_SUBSTATE_NCQ_ERROR); | |
357 | } else | |
358 | status = SCI_FAILURE; | |
359 | ||
360 | scic_sds_controller_release_frame(scic, frame_index); | |
361 | break; | |
362 | } | |
363 | case SCIC_SDS_STP_REMOTE_DEVICE_READY_SUBSTATE_CMD: | |
364 | case SCIC_SDS_SMP_REMOTE_DEVICE_READY_SUBSTATE_CMD: | |
365 | /* The device does not process any UF received from the hardware while | |
366 | * in this state. All unsolicited frames are forwarded to the io request | |
367 | * object. | |
368 | */ | |
369 | status = scic_sds_io_request_frame_handler(sci_dev->working_request, frame_index); | |
370 | break; | |
371 | } | |
372 | ||
373 | return status; | |
88f3b62a DW |
374 | } |
375 | ||
e622571f | 376 | static bool is_remote_device_ready(struct scic_sds_remote_device *sci_dev) |
88f3b62a | 377 | { |
e622571f DW |
378 | |
379 | struct sci_base_state_machine *sm = &sci_dev->state_machine; | |
380 | enum scic_sds_remote_device_states state = sm->current_state_id; | |
381 | ||
382 | switch (state) { | |
383 | case SCI_BASE_REMOTE_DEVICE_STATE_READY: | |
384 | case SCIC_SDS_STP_REMOTE_DEVICE_READY_SUBSTATE_IDLE: | |
385 | case SCIC_SDS_STP_REMOTE_DEVICE_READY_SUBSTATE_CMD: | |
386 | case SCIC_SDS_STP_REMOTE_DEVICE_READY_SUBSTATE_NCQ: | |
387 | case SCIC_SDS_STP_REMOTE_DEVICE_READY_SUBSTATE_NCQ_ERROR: | |
388 | case SCIC_SDS_STP_REMOTE_DEVICE_READY_SUBSTATE_AWAIT_RESET: | |
389 | case SCIC_SDS_SMP_REMOTE_DEVICE_READY_SUBSTATE_IDLE: | |
390 | case SCIC_SDS_SMP_REMOTE_DEVICE_READY_SUBSTATE_CMD: | |
391 | return true; | |
392 | default: | |
393 | return false; | |
394 | } | |
395 | } | |
396 | ||
397 | enum sci_status scic_sds_remote_device_event_handler(struct scic_sds_remote_device *sci_dev, | |
398 | u32 event_code) | |
399 | { | |
400 | struct sci_base_state_machine *sm = &sci_dev->state_machine; | |
401 | enum scic_sds_remote_device_states state = sm->current_state_id; | |
402 | enum sci_status status; | |
403 | ||
404 | switch (scu_get_event_type(event_code)) { | |
405 | case SCU_EVENT_TYPE_RNC_OPS_MISC: | |
406 | case SCU_EVENT_TYPE_RNC_SUSPEND_TX: | |
407 | case SCU_EVENT_TYPE_RNC_SUSPEND_TX_RX: | |
408 | status = scic_sds_remote_node_context_event_handler(&sci_dev->rnc, event_code); | |
409 | break; | |
410 | case SCU_EVENT_TYPE_PTX_SCHEDULE_EVENT: | |
411 | if (scu_get_event_code(event_code) == SCU_EVENT_IT_NEXUS_TIMEOUT) { | |
412 | status = SCI_SUCCESS; | |
413 | ||
414 | /* Suspend the associated RNC */ | |
415 | scic_sds_remote_node_context_suspend(&sci_dev->rnc, | |
416 | SCI_SOFTWARE_SUSPENSION, | |
417 | NULL, NULL); | |
418 | ||
419 | dev_dbg(scirdev_to_dev(sci_dev), | |
420 | "%s: device: %p event code: %x: %s\n", | |
421 | __func__, sci_dev, event_code, | |
422 | is_remote_device_ready(sci_dev) | |
423 | ? "I_T_Nexus_Timeout event" | |
424 | : "I_T_Nexus_Timeout event in wrong state"); | |
425 | ||
426 | break; | |
427 | } | |
428 | /* Else, fall through and treat as unhandled... */ | |
429 | default: | |
430 | dev_dbg(scirdev_to_dev(sci_dev), | |
431 | "%s: device: %p event code: %x: %s\n", | |
432 | __func__, sci_dev, event_code, | |
433 | is_remote_device_ready(sci_dev) | |
434 | ? "unexpected event" | |
435 | : "unexpected event in wrong state"); | |
436 | status = SCI_FAILURE_INVALID_STATE; | |
437 | break; | |
438 | } | |
439 | ||
440 | if (status != SCI_SUCCESS) | |
441 | return status; | |
442 | ||
443 | if (state == SCIC_SDS_STP_REMOTE_DEVICE_READY_SUBSTATE_IDLE) { | |
444 | ||
445 | /* We pick up suspension events to handle specifically to this | |
446 | * state. We resume the RNC right away. | |
447 | */ | |
448 | if (scu_get_event_type(event_code) == SCU_EVENT_TYPE_RNC_SUSPEND_TX || | |
449 | scu_get_event_type(event_code) == SCU_EVENT_TYPE_RNC_SUSPEND_TX_RX) | |
450 | status = scic_sds_remote_node_context_resume(&sci_dev->rnc, NULL, NULL); | |
451 | } | |
452 | ||
453 | return status; | |
88f3b62a DW |
454 | } |
455 | ||
18606557 DW |
456 | static void scic_sds_remote_device_start_request(struct scic_sds_remote_device *sci_dev, |
457 | struct scic_sds_request *sci_req, | |
458 | enum sci_status status) | |
88f3b62a | 459 | { |
18606557 DW |
460 | struct scic_sds_port *sci_port = sci_dev->owning_port; |
461 | ||
462 | /* cleanup requests that failed after starting on the port */ | |
463 | if (status != SCI_SUCCESS) | |
464 | scic_sds_port_complete_io(sci_port, sci_dev, sci_req); | |
465 | else | |
466 | scic_sds_remote_device_increment_request_count(sci_dev); | |
467 | } | |
468 | ||
469 | enum sci_status scic_sds_remote_device_start_io(struct scic_sds_controller *scic, | |
470 | struct scic_sds_remote_device *sci_dev, | |
471 | struct scic_sds_request *sci_req) | |
472 | { | |
473 | struct sci_base_state_machine *sm = &sci_dev->state_machine; | |
474 | enum scic_sds_remote_device_states state = sm->current_state_id; | |
475 | struct scic_sds_port *sci_port = sci_dev->owning_port; | |
67ea838d | 476 | struct isci_request *ireq = sci_req_to_ireq(sci_req); |
18606557 DW |
477 | enum sci_status status; |
478 | ||
479 | switch (state) { | |
480 | case SCI_BASE_REMOTE_DEVICE_STATE_INITIAL: | |
481 | case SCI_BASE_REMOTE_DEVICE_STATE_STOPPED: | |
482 | case SCI_BASE_REMOTE_DEVICE_STATE_STARTING: | |
483 | case SCIC_SDS_STP_REMOTE_DEVICE_READY_SUBSTATE_NCQ_ERROR: | |
484 | case SCI_BASE_REMOTE_DEVICE_STATE_STOPPING: | |
485 | case SCI_BASE_REMOTE_DEVICE_STATE_FAILED: | |
486 | case SCI_BASE_REMOTE_DEVICE_STATE_RESETTING: | |
487 | case SCI_BASE_REMOTE_DEVICE_STATE_FINAL: | |
488 | default: | |
489 | dev_warn(scirdev_to_dev(sci_dev), "%s: in wrong state: %d\n", | |
490 | __func__, state); | |
491 | return SCI_FAILURE_INVALID_STATE; | |
492 | case SCI_BASE_REMOTE_DEVICE_STATE_READY: | |
493 | /* attempt to start an io request for this device object. The remote | |
494 | * device object will issue the start request for the io and if | |
495 | * successful it will start the request for the port object then | |
496 | * increment its own request count. | |
497 | */ | |
498 | status = scic_sds_port_start_io(sci_port, sci_dev, sci_req); | |
499 | if (status != SCI_SUCCESS) | |
500 | return status; | |
501 | ||
502 | status = scic_sds_remote_node_context_start_io(&sci_dev->rnc, sci_req); | |
503 | if (status != SCI_SUCCESS) | |
504 | break; | |
505 | ||
506 | status = scic_sds_request_start(sci_req); | |
507 | break; | |
508 | case SCIC_SDS_STP_REMOTE_DEVICE_READY_SUBSTATE_IDLE: { | |
509 | /* handle the start io operation for a sata device that is in | |
510 | * the command idle state. - Evalute the type of IO request to | |
511 | * be started - If its an NCQ request change to NCQ substate - | |
512 | * If its any other command change to the CMD substate | |
513 | * | |
514 | * If this is a softreset we may want to have a different | |
515 | * substate. | |
516 | */ | |
517 | enum scic_sds_remote_device_states new_state; | |
e76d6180 | 518 | struct sas_task *task = isci_request_access_task(ireq); |
18606557 DW |
519 | |
520 | status = scic_sds_port_start_io(sci_port, sci_dev, sci_req); | |
521 | if (status != SCI_SUCCESS) | |
522 | return status; | |
523 | ||
524 | status = scic_sds_remote_node_context_start_io(&sci_dev->rnc, sci_req); | |
525 | if (status != SCI_SUCCESS) | |
526 | break; | |
527 | ||
528 | status = sci_req->state_handlers->start_handler(sci_req); | |
529 | if (status != SCI_SUCCESS) | |
530 | break; | |
531 | ||
e76d6180 | 532 | if (task->ata_task.use_ncq) |
18606557 DW |
533 | new_state = SCIC_SDS_STP_REMOTE_DEVICE_READY_SUBSTATE_NCQ; |
534 | else { | |
535 | sci_dev->working_request = sci_req; | |
536 | new_state = SCIC_SDS_STP_REMOTE_DEVICE_READY_SUBSTATE_CMD; | |
537 | } | |
538 | sci_base_state_machine_change_state(sm, new_state); | |
539 | break; | |
540 | } | |
e76d6180 DJ |
541 | case SCIC_SDS_STP_REMOTE_DEVICE_READY_SUBSTATE_NCQ: { |
542 | struct sas_task *task = isci_request_access_task(ireq); | |
543 | ||
544 | if (task->ata_task.use_ncq) { | |
18606557 DW |
545 | status = scic_sds_port_start_io(sci_port, sci_dev, sci_req); |
546 | if (status != SCI_SUCCESS) | |
547 | return status; | |
548 | ||
549 | status = scic_sds_remote_node_context_start_io(&sci_dev->rnc, sci_req); | |
550 | if (status != SCI_SUCCESS) | |
551 | break; | |
552 | ||
553 | status = sci_req->state_handlers->start_handler(sci_req); | |
554 | } else | |
555 | return SCI_FAILURE_INVALID_STATE; | |
556 | break; | |
e76d6180 | 557 | } |
18606557 DW |
558 | case SCIC_SDS_STP_REMOTE_DEVICE_READY_SUBSTATE_AWAIT_RESET: |
559 | return SCI_FAILURE_REMOTE_DEVICE_RESET_REQUIRED; | |
560 | case SCIC_SDS_SMP_REMOTE_DEVICE_READY_SUBSTATE_IDLE: | |
561 | status = scic_sds_port_start_io(sci_port, sci_dev, sci_req); | |
562 | if (status != SCI_SUCCESS) | |
563 | return status; | |
564 | ||
565 | status = scic_sds_remote_node_context_start_io(&sci_dev->rnc, sci_req); | |
566 | if (status != SCI_SUCCESS) | |
567 | break; | |
568 | ||
569 | status = scic_sds_request_start(sci_req); | |
570 | if (status != SCI_SUCCESS) | |
571 | break; | |
572 | ||
573 | sci_dev->working_request = sci_req; | |
574 | sci_base_state_machine_change_state(&sci_dev->state_machine, | |
575 | SCIC_SDS_SMP_REMOTE_DEVICE_READY_SUBSTATE_CMD); | |
576 | break; | |
577 | case SCIC_SDS_STP_REMOTE_DEVICE_READY_SUBSTATE_CMD: | |
578 | case SCIC_SDS_SMP_REMOTE_DEVICE_READY_SUBSTATE_CMD: | |
579 | /* device is already handling a command it can not accept new commands | |
580 | * until this one is complete. | |
581 | */ | |
582 | return SCI_FAILURE_INVALID_STATE; | |
583 | } | |
584 | ||
585 | scic_sds_remote_device_start_request(sci_dev, sci_req, status); | |
586 | return status; | |
88f3b62a DW |
587 | } |
588 | ||
10a09e64 DW |
589 | static enum sci_status common_complete_io(struct scic_sds_port *sci_port, |
590 | struct scic_sds_remote_device *sci_dev, | |
591 | struct scic_sds_request *sci_req) | |
88f3b62a | 592 | { |
10a09e64 DW |
593 | enum sci_status status; |
594 | ||
595 | status = scic_sds_request_complete(sci_req); | |
596 | if (status != SCI_SUCCESS) | |
597 | return status; | |
598 | ||
599 | status = scic_sds_port_complete_io(sci_port, sci_dev, sci_req); | |
600 | if (status != SCI_SUCCESS) | |
601 | return status; | |
602 | ||
603 | scic_sds_remote_device_decrement_request_count(sci_dev); | |
604 | return status; | |
605 | } | |
606 | ||
607 | enum sci_status scic_sds_remote_device_complete_io(struct scic_sds_controller *scic, | |
608 | struct scic_sds_remote_device *sci_dev, | |
609 | struct scic_sds_request *sci_req) | |
610 | { | |
611 | struct sci_base_state_machine *sm = &sci_dev->state_machine; | |
612 | enum scic_sds_remote_device_states state = sm->current_state_id; | |
613 | struct scic_sds_port *sci_port = sci_dev->owning_port; | |
614 | enum sci_status status; | |
615 | ||
616 | switch (state) { | |
617 | case SCI_BASE_REMOTE_DEVICE_STATE_INITIAL: | |
618 | case SCI_BASE_REMOTE_DEVICE_STATE_STOPPED: | |
619 | case SCI_BASE_REMOTE_DEVICE_STATE_STARTING: | |
620 | case SCIC_SDS_STP_REMOTE_DEVICE_READY_SUBSTATE_IDLE: | |
621 | case SCIC_SDS_SMP_REMOTE_DEVICE_READY_SUBSTATE_IDLE: | |
622 | case SCI_BASE_REMOTE_DEVICE_STATE_FAILED: | |
623 | case SCI_BASE_REMOTE_DEVICE_STATE_FINAL: | |
624 | default: | |
625 | dev_warn(scirdev_to_dev(sci_dev), "%s: in wrong state: %d\n", | |
626 | __func__, state); | |
627 | return SCI_FAILURE_INVALID_STATE; | |
628 | case SCI_BASE_REMOTE_DEVICE_STATE_READY: | |
629 | case SCIC_SDS_STP_REMOTE_DEVICE_READY_SUBSTATE_AWAIT_RESET: | |
630 | case SCI_BASE_REMOTE_DEVICE_STATE_RESETTING: | |
631 | status = common_complete_io(sci_port, sci_dev, sci_req); | |
632 | break; | |
633 | case SCIC_SDS_STP_REMOTE_DEVICE_READY_SUBSTATE_CMD: | |
634 | case SCIC_SDS_STP_REMOTE_DEVICE_READY_SUBSTATE_NCQ: | |
635 | case SCIC_SDS_STP_REMOTE_DEVICE_READY_SUBSTATE_NCQ_ERROR: | |
636 | status = common_complete_io(sci_port, sci_dev, sci_req); | |
637 | if (status != SCI_SUCCESS) | |
638 | break; | |
639 | ||
640 | if (sci_req->sci_status == SCI_FAILURE_REMOTE_DEVICE_RESET_REQUIRED) { | |
641 | /* This request causes hardware error, device needs to be Lun Reset. | |
642 | * So here we force the state machine to IDLE state so the rest IOs | |
643 | * can reach RNC state handler, these IOs will be completed by RNC with | |
644 | * status of "DEVICE_RESET_REQUIRED", instead of "INVALID STATE". | |
645 | */ | |
646 | sci_base_state_machine_change_state(sm, SCIC_SDS_STP_REMOTE_DEVICE_READY_SUBSTATE_AWAIT_RESET); | |
647 | } else if (scic_sds_remote_device_get_request_count(sci_dev) == 0) | |
648 | sci_base_state_machine_change_state(sm, SCIC_SDS_STP_REMOTE_DEVICE_READY_SUBSTATE_IDLE); | |
649 | break; | |
650 | case SCIC_SDS_SMP_REMOTE_DEVICE_READY_SUBSTATE_CMD: | |
651 | status = common_complete_io(sci_port, sci_dev, sci_req); | |
652 | if (status != SCI_SUCCESS) | |
653 | break; | |
654 | sci_base_state_machine_change_state(sm, SCIC_SDS_SMP_REMOTE_DEVICE_READY_SUBSTATE_IDLE); | |
655 | break; | |
656 | case SCI_BASE_REMOTE_DEVICE_STATE_STOPPING: | |
657 | status = common_complete_io(sci_port, sci_dev, sci_req); | |
658 | if (status != SCI_SUCCESS) | |
659 | break; | |
660 | ||
661 | if (scic_sds_remote_device_get_request_count(sci_dev) == 0) | |
662 | scic_sds_remote_node_context_destruct(&sci_dev->rnc, | |
663 | rnc_destruct_done, | |
664 | sci_dev); | |
665 | break; | |
666 | } | |
667 | ||
668 | if (status != SCI_SUCCESS) | |
669 | dev_err(scirdev_to_dev(sci_dev), | |
670 | "%s: Port:0x%p Device:0x%p Request:0x%p Status:0x%x " | |
671 | "could not complete\n", __func__, sci_port, | |
672 | sci_dev, sci_req, status); | |
673 | ||
674 | return status; | |
88f3b62a DW |
675 | } |
676 | ||
84b9b029 | 677 | static void scic_sds_remote_device_continue_request(void *dev) |
88f3b62a | 678 | { |
84b9b029 DW |
679 | struct scic_sds_remote_device *sci_dev = dev; |
680 | ||
681 | /* we need to check if this request is still valid to continue. */ | |
682 | if (sci_dev->working_request) | |
683 | scic_controller_continue_io(sci_dev->working_request); | |
684 | } | |
685 | ||
686 | enum sci_status scic_sds_remote_device_start_task(struct scic_sds_controller *scic, | |
687 | struct scic_sds_remote_device *sci_dev, | |
688 | struct scic_sds_request *sci_req) | |
689 | { | |
690 | struct sci_base_state_machine *sm = &sci_dev->state_machine; | |
691 | enum scic_sds_remote_device_states state = sm->current_state_id; | |
692 | struct scic_sds_port *sci_port = sci_dev->owning_port; | |
693 | enum sci_status status; | |
694 | ||
695 | switch (state) { | |
696 | case SCI_BASE_REMOTE_DEVICE_STATE_INITIAL: | |
697 | case SCI_BASE_REMOTE_DEVICE_STATE_STOPPED: | |
698 | case SCI_BASE_REMOTE_DEVICE_STATE_STARTING: | |
699 | case SCIC_SDS_SMP_REMOTE_DEVICE_READY_SUBSTATE_IDLE: | |
700 | case SCIC_SDS_SMP_REMOTE_DEVICE_READY_SUBSTATE_CMD: | |
701 | case SCI_BASE_REMOTE_DEVICE_STATE_STOPPING: | |
702 | case SCI_BASE_REMOTE_DEVICE_STATE_FAILED: | |
703 | case SCI_BASE_REMOTE_DEVICE_STATE_RESETTING: | |
704 | case SCI_BASE_REMOTE_DEVICE_STATE_FINAL: | |
705 | default: | |
706 | dev_warn(scirdev_to_dev(sci_dev), "%s: in wrong state: %d\n", | |
707 | __func__, state); | |
708 | return SCI_FAILURE_INVALID_STATE; | |
709 | case SCIC_SDS_STP_REMOTE_DEVICE_READY_SUBSTATE_IDLE: | |
710 | case SCIC_SDS_STP_REMOTE_DEVICE_READY_SUBSTATE_CMD: | |
711 | case SCIC_SDS_STP_REMOTE_DEVICE_READY_SUBSTATE_NCQ: | |
712 | case SCIC_SDS_STP_REMOTE_DEVICE_READY_SUBSTATE_NCQ_ERROR: | |
713 | case SCIC_SDS_STP_REMOTE_DEVICE_READY_SUBSTATE_AWAIT_RESET: | |
714 | status = scic_sds_port_start_io(sci_port, sci_dev, sci_req); | |
715 | if (status != SCI_SUCCESS) | |
716 | return status; | |
717 | ||
718 | status = scic_sds_remote_node_context_start_task(&sci_dev->rnc, sci_req); | |
719 | if (status != SCI_SUCCESS) | |
720 | goto out; | |
721 | ||
722 | status = sci_req->state_handlers->start_handler(sci_req); | |
723 | if (status != SCI_SUCCESS) | |
724 | goto out; | |
725 | ||
726 | /* Note: If the remote device state is not IDLE this will | |
727 | * replace the request that probably resulted in the task | |
728 | * management request. | |
729 | */ | |
730 | sci_dev->working_request = sci_req; | |
731 | sci_base_state_machine_change_state(sm, SCIC_SDS_STP_REMOTE_DEVICE_READY_SUBSTATE_CMD); | |
732 | ||
733 | /* The remote node context must cleanup the TCi to NCQ mapping | |
734 | * table. The only way to do this correctly is to either write | |
735 | * to the TLCR register or to invalidate and repost the RNC. In | |
736 | * either case the remote node context state machine will take | |
737 | * the correct action when the remote node context is suspended | |
738 | * and later resumed. | |
739 | */ | |
740 | scic_sds_remote_node_context_suspend(&sci_dev->rnc, | |
741 | SCI_SOFTWARE_SUSPENSION, NULL, NULL); | |
742 | scic_sds_remote_node_context_resume(&sci_dev->rnc, | |
743 | scic_sds_remote_device_continue_request, | |
744 | sci_dev); | |
745 | ||
746 | out: | |
747 | scic_sds_remote_device_start_request(sci_dev, sci_req, status); | |
748 | /* We need to let the controller start request handler know that | |
749 | * it can't post TC yet. We will provide a callback function to | |
750 | * post TC when RNC gets resumed. | |
751 | */ | |
752 | return SCI_FAILURE_RESET_DEVICE_PARTIAL_SUCCESS; | |
753 | case SCI_BASE_REMOTE_DEVICE_STATE_READY: | |
754 | status = scic_sds_port_start_io(sci_port, sci_dev, sci_req); | |
755 | if (status != SCI_SUCCESS) | |
756 | return status; | |
757 | ||
758 | status = scic_sds_remote_node_context_start_task(&sci_dev->rnc, sci_req); | |
759 | if (status != SCI_SUCCESS) | |
760 | break; | |
761 | ||
762 | status = scic_sds_request_start(sci_req); | |
763 | break; | |
764 | } | |
765 | scic_sds_remote_device_start_request(sci_dev, sci_req, status); | |
766 | ||
767 | return status; | |
88f3b62a DW |
768 | } |
769 | ||
88f3b62a DW |
770 | /** |
771 | * | |
772 | * @sci_dev: | |
773 | * @request: | |
774 | * | |
775 | * This method takes the request and bulids an appropriate SCU context for the | |
776 | * request and then requests the controller to post the request. none | |
777 | */ | |
778 | void scic_sds_remote_device_post_request( | |
779 | struct scic_sds_remote_device *sci_dev, | |
780 | u32 request) | |
781 | { | |
782 | u32 context; | |
783 | ||
784 | context = scic_sds_remote_device_build_command_context(sci_dev, request); | |
785 | ||
786 | scic_sds_controller_post_request( | |
787 | scic_sds_remote_device_get_controller(sci_dev), | |
788 | context | |
789 | ); | |
790 | } | |
791 | ||
ab2e8f7d | 792 | /* called once the remote node context has transisitioned to a |
88f3b62a | 793 | * ready state. This is the indication that the remote device object can also |
ab2e8f7d | 794 | * transition to ready. |
88f3b62a | 795 | */ |
eb229671 | 796 | static void remote_device_resume_done(void *_dev) |
ab2e8f7d DW |
797 | { |
798 | struct scic_sds_remote_device *sci_dev = _dev; | |
ab2e8f7d | 799 | |
e622571f DW |
800 | if (is_remote_device_ready(sci_dev)) |
801 | return; | |
88f3b62a | 802 | |
e622571f DW |
803 | /* go 'ready' if we are not already in a ready state */ |
804 | sci_base_state_machine_change_state(&sci_dev->state_machine, | |
805 | SCI_BASE_REMOTE_DEVICE_STATE_READY); | |
88f3b62a DW |
806 | } |
807 | ||
ab2e8f7d DW |
808 | static void scic_sds_stp_remote_device_ready_idle_substate_resume_complete_handler(void *_dev) |
809 | { | |
810 | struct scic_sds_remote_device *sci_dev = _dev; | |
811 | struct isci_remote_device *idev = sci_dev_to_idev(sci_dev); | |
812 | struct scic_sds_controller *scic = sci_dev->owning_port->owning_controller; | |
813 | ||
814 | /* For NCQ operation we do not issue a isci_remote_device_not_ready(). | |
815 | * As a result, avoid sending the ready notification. | |
816 | */ | |
817 | if (sci_dev->state_machine.previous_state_id != SCIC_SDS_STP_REMOTE_DEVICE_READY_SUBSTATE_NCQ) | |
cc3dbd0a | 818 | isci_remote_device_ready(scic_to_ihost(scic), idev); |
ab2e8f7d DW |
819 | } |
820 | ||
ab2e8f7d | 821 | static void scic_sds_remote_device_initial_state_enter(void *object) |
88f3b62a | 822 | { |
ab2e8f7d | 823 | struct scic_sds_remote_device *sci_dev = object; |
88f3b62a | 824 | |
ab2e8f7d DW |
825 | /* Initial state is a transitional state to the stopped state */ |
826 | sci_base_state_machine_change_state(&sci_dev->state_machine, | |
827 | SCI_BASE_REMOTE_DEVICE_STATE_STOPPED); | |
88f3b62a | 828 | } |
6f231dda | 829 | |
88f3b62a DW |
830 | /** |
831 | * scic_remote_device_destruct() - free remote node context and destruct | |
832 | * @remote_device: This parameter specifies the remote device to be destructed. | |
833 | * | |
834 | * Remote device objects are a limited resource. As such, they must be | |
835 | * protected. Thus calls to construct and destruct are mutually exclusive and | |
836 | * non-reentrant. The return value shall indicate if the device was | |
837 | * successfully destructed or if some failure occurred. enum sci_status This value | |
838 | * is returned if the device is successfully destructed. | |
839 | * SCI_FAILURE_INVALID_REMOTE_DEVICE This value is returned if the supplied | |
840 | * device isn't valid (e.g. it's already been destoryed, the handle isn't | |
841 | * valid, etc.). | |
842 | */ | |
843 | static enum sci_status scic_remote_device_destruct(struct scic_sds_remote_device *sci_dev) | |
844 | { | |
b8d82f6c DW |
845 | struct sci_base_state_machine *sm = &sci_dev->state_machine; |
846 | enum scic_sds_remote_device_states state = sm->current_state_id; | |
847 | struct scic_sds_controller *scic; | |
848 | ||
849 | if (state != SCI_BASE_REMOTE_DEVICE_STATE_STOPPED) { | |
850 | dev_warn(scirdev_to_dev(sci_dev), "%s: in wrong state: %d\n", | |
851 | __func__, state); | |
852 | return SCI_FAILURE_INVALID_STATE; | |
853 | } | |
854 | ||
855 | scic = sci_dev->owning_port->owning_controller; | |
856 | scic_sds_controller_free_remote_node_context(scic, sci_dev, | |
857 | sci_dev->rnc.remote_node_index); | |
858 | sci_dev->rnc.remote_node_index = SCIC_SDS_REMOTE_NODE_CONTEXT_INVALID_INDEX; | |
859 | sci_base_state_machine_change_state(sm, SCI_BASE_REMOTE_DEVICE_STATE_FINAL); | |
860 | ||
861 | return SCI_SUCCESS; | |
88f3b62a | 862 | } |
6f231dda DW |
863 | |
864 | /** | |
865 | * isci_remote_device_deconstruct() - This function frees an isci_remote_device. | |
d9c37390 DW |
866 | * @ihost: This parameter specifies the isci host object. |
867 | * @idev: This parameter specifies the remote device to be freed. | |
6f231dda DW |
868 | * |
869 | */ | |
d9c37390 | 870 | static void isci_remote_device_deconstruct(struct isci_host *ihost, struct isci_remote_device *idev) |
6f231dda | 871 | { |
d9c37390 DW |
872 | dev_dbg(&ihost->pdev->dev, |
873 | "%s: isci_device = %p\n", __func__, idev); | |
6f231dda DW |
874 | |
875 | /* There should not be any outstanding io's. All paths to | |
876 | * here should go through isci_remote_device_nuke_requests. | |
877 | * If we hit this condition, we will need a way to complete | |
878 | * io requests in process */ | |
d9c37390 | 879 | while (!list_empty(&idev->reqs_in_process)) { |
6f231dda | 880 | |
d9c37390 | 881 | dev_err(&ihost->pdev->dev, |
6f231dda DW |
882 | "%s: ** request list not empty! **\n", __func__); |
883 | BUG(); | |
884 | } | |
885 | ||
57f20f4e | 886 | scic_remote_device_destruct(&idev->sci); |
d9c37390 DW |
887 | idev->domain_dev->lldd_dev = NULL; |
888 | idev->domain_dev = NULL; | |
889 | idev->isci_port = NULL; | |
890 | list_del_init(&idev->node); | |
891 | ||
892 | clear_bit(IDEV_START_PENDING, &idev->flags); | |
893 | clear_bit(IDEV_STOP_PENDING, &idev->flags); | |
d06b487b | 894 | clear_bit(IDEV_EH, &idev->flags); |
d9c37390 | 895 | wake_up(&ihost->eventq); |
6f231dda DW |
896 | } |
897 | ||
88f3b62a DW |
898 | /** |
899 | * isci_remote_device_stop_complete() - This function is called by the scic | |
900 | * when the remote device stop has completed. We mark the isci device as not | |
901 | * ready and remove the isci remote device. | |
902 | * @ihost: This parameter specifies the isci host object. | |
903 | * @idev: This parameter specifies the remote device. | |
904 | * @status: This parameter specifies status of the completion. | |
905 | * | |
906 | */ | |
907 | static void isci_remote_device_stop_complete(struct isci_host *ihost, | |
908 | struct isci_remote_device *idev) | |
909 | { | |
910 | dev_dbg(&ihost->pdev->dev, "%s: complete idev = %p\n", __func__, idev); | |
911 | ||
912 | isci_remote_device_change_state(idev, isci_stopped); | |
913 | ||
914 | /* after stop, we can tear down resources. */ | |
915 | isci_remote_device_deconstruct(ihost, idev); | |
916 | } | |
917 | ||
9a0fff7b | 918 | static void scic_sds_remote_device_stopped_state_enter(void *object) |
88f3b62a | 919 | { |
5d937e96 | 920 | struct scic_sds_remote_device *sci_dev = object; |
cc3dbd0a AW |
921 | struct scic_sds_controller *scic = sci_dev->owning_port->owning_controller; |
922 | struct isci_remote_device *idev = sci_dev_to_idev(sci_dev); | |
88f3b62a DW |
923 | u32 prev_state; |
924 | ||
88f3b62a DW |
925 | /* If we are entering from the stopping state let the SCI User know that |
926 | * the stop operation has completed. | |
927 | */ | |
928 | prev_state = sci_dev->state_machine.previous_state_id; | |
929 | if (prev_state == SCI_BASE_REMOTE_DEVICE_STATE_STOPPING) | |
cc3dbd0a | 930 | isci_remote_device_stop_complete(scic_to_ihost(scic), idev); |
88f3b62a DW |
931 | |
932 | scic_sds_controller_remote_device_stopped(scic, sci_dev); | |
933 | } | |
934 | ||
9a0fff7b | 935 | static void scic_sds_remote_device_starting_state_enter(void *object) |
88f3b62a | 936 | { |
5d937e96 | 937 | struct scic_sds_remote_device *sci_dev = object; |
88f3b62a | 938 | struct scic_sds_controller *scic = scic_sds_remote_device_get_controller(sci_dev); |
cc3dbd0a | 939 | struct isci_host *ihost = scic_to_ihost(scic); |
5d937e96 | 940 | struct isci_remote_device *idev = sci_dev_to_idev(sci_dev); |
88f3b62a | 941 | |
88f3b62a DW |
942 | isci_remote_device_not_ready(ihost, idev, |
943 | SCIC_REMOTE_DEVICE_NOT_READY_START_REQUESTED); | |
944 | } | |
945 | ||
9a0fff7b | 946 | static void scic_sds_remote_device_ready_state_enter(void *object) |
88f3b62a | 947 | { |
5d937e96 | 948 | struct scic_sds_remote_device *sci_dev = object; |
ab2e8f7d | 949 | struct scic_sds_controller *scic = sci_dev->owning_port->owning_controller; |
cc3dbd0a AW |
950 | struct isci_remote_device *idev = sci_dev_to_idev(sci_dev); |
951 | struct domain_device *dev = idev->domain_dev; | |
88f3b62a | 952 | |
88f3b62a DW |
953 | scic->remote_device_sequence[sci_dev->rnc.remote_node_index]++; |
954 | ||
ab2e8f7d DW |
955 | if (dev->dev_type == SATA_DEV || (dev->tproto & SAS_PROTOCOL_SATA)) { |
956 | sci_base_state_machine_change_state(&sci_dev->state_machine, | |
957 | SCIC_SDS_STP_REMOTE_DEVICE_READY_SUBSTATE_IDLE); | |
958 | } else if (dev_is_expander(dev)) { | |
959 | sci_base_state_machine_change_state(&sci_dev->state_machine, | |
960 | SCIC_SDS_SMP_REMOTE_DEVICE_READY_SUBSTATE_IDLE); | |
961 | } else | |
cc3dbd0a | 962 | isci_remote_device_ready(scic_to_ihost(scic), idev); |
88f3b62a DW |
963 | } |
964 | ||
9a0fff7b | 965 | static void scic_sds_remote_device_ready_state_exit(void *object) |
88f3b62a | 966 | { |
5d937e96 | 967 | struct scic_sds_remote_device *sci_dev = object; |
ab2e8f7d DW |
968 | struct domain_device *dev = sci_dev_to_domain(sci_dev); |
969 | ||
970 | if (dev->dev_type == SAS_END_DEV) { | |
971 | struct scic_sds_controller *scic = sci_dev->owning_port->owning_controller; | |
5d937e96 | 972 | struct isci_remote_device *idev = sci_dev_to_idev(sci_dev); |
88f3b62a | 973 | |
cc3dbd0a | 974 | isci_remote_device_not_ready(scic_to_ihost(scic), idev, |
88f3b62a DW |
975 | SCIC_REMOTE_DEVICE_NOT_READY_STOP_REQUESTED); |
976 | } | |
977 | } | |
978 | ||
9a0fff7b | 979 | static void scic_sds_remote_device_resetting_state_enter(void *object) |
88f3b62a | 980 | { |
5d937e96 | 981 | struct scic_sds_remote_device *sci_dev = object; |
88f3b62a | 982 | |
88f3b62a DW |
983 | scic_sds_remote_node_context_suspend( |
984 | &sci_dev->rnc, SCI_SOFTWARE_SUSPENSION, NULL, NULL); | |
985 | } | |
986 | ||
9a0fff7b | 987 | static void scic_sds_remote_device_resetting_state_exit(void *object) |
88f3b62a | 988 | { |
5d937e96 | 989 | struct scic_sds_remote_device *sci_dev = object; |
88f3b62a DW |
990 | |
991 | scic_sds_remote_node_context_resume(&sci_dev->rnc, NULL, NULL); | |
992 | } | |
993 | ||
ab2e8f7d DW |
994 | static void scic_sds_stp_remote_device_ready_idle_substate_enter(void *object) |
995 | { | |
996 | struct scic_sds_remote_device *sci_dev = object; | |
997 | ||
ab2e8f7d DW |
998 | sci_dev->working_request = NULL; |
999 | if (scic_sds_remote_node_context_is_ready(&sci_dev->rnc)) { | |
1000 | /* | |
1001 | * Since the RNC is ready, it's alright to finish completion | |
1002 | * processing (e.g. signal the remote device is ready). */ | |
1003 | scic_sds_stp_remote_device_ready_idle_substate_resume_complete_handler(sci_dev); | |
1004 | } else { | |
1005 | scic_sds_remote_node_context_resume(&sci_dev->rnc, | |
1006 | scic_sds_stp_remote_device_ready_idle_substate_resume_complete_handler, | |
1007 | sci_dev); | |
1008 | } | |
1009 | } | |
1010 | ||
1011 | static void scic_sds_stp_remote_device_ready_cmd_substate_enter(void *object) | |
1012 | { | |
1013 | struct scic_sds_remote_device *sci_dev = object; | |
1014 | struct scic_sds_controller *scic = scic_sds_remote_device_get_controller(sci_dev); | |
1015 | ||
1016 | BUG_ON(sci_dev->working_request == NULL); | |
1017 | ||
cc3dbd0a | 1018 | isci_remote_device_not_ready(scic_to_ihost(scic), sci_dev_to_idev(sci_dev), |
ab2e8f7d DW |
1019 | SCIC_REMOTE_DEVICE_NOT_READY_SATA_REQUEST_STARTED); |
1020 | } | |
1021 | ||
ab2e8f7d DW |
1022 | static void scic_sds_stp_remote_device_ready_ncq_error_substate_enter(void *object) |
1023 | { | |
1024 | struct scic_sds_remote_device *sci_dev = object; | |
1025 | struct scic_sds_controller *scic = scic_sds_remote_device_get_controller(sci_dev); | |
1026 | struct isci_remote_device *idev = sci_dev_to_idev(sci_dev); | |
1027 | ||
ab2e8f7d | 1028 | if (sci_dev->not_ready_reason == SCIC_REMOTE_DEVICE_NOT_READY_SATA_SDB_ERROR_FIS_RECEIVED) |
cc3dbd0a | 1029 | isci_remote_device_not_ready(scic_to_ihost(scic), idev, |
ab2e8f7d DW |
1030 | sci_dev->not_ready_reason); |
1031 | } | |
1032 | ||
ab2e8f7d DW |
1033 | static void scic_sds_smp_remote_device_ready_idle_substate_enter(void *object) |
1034 | { | |
1035 | struct scic_sds_remote_device *sci_dev = object; | |
1036 | struct scic_sds_controller *scic = scic_sds_remote_device_get_controller(sci_dev); | |
1037 | ||
cc3dbd0a | 1038 | isci_remote_device_ready(scic_to_ihost(scic), sci_dev_to_idev(sci_dev)); |
ab2e8f7d DW |
1039 | } |
1040 | ||
1041 | static void scic_sds_smp_remote_device_ready_cmd_substate_enter(void *object) | |
1042 | { | |
1043 | struct scic_sds_remote_device *sci_dev = object; | |
1044 | struct scic_sds_controller *scic = scic_sds_remote_device_get_controller(sci_dev); | |
1045 | ||
1046 | BUG_ON(sci_dev->working_request == NULL); | |
1047 | ||
cc3dbd0a | 1048 | isci_remote_device_not_ready(scic_to_ihost(scic), sci_dev_to_idev(sci_dev), |
ab2e8f7d DW |
1049 | SCIC_REMOTE_DEVICE_NOT_READY_SMP_REQUEST_STARTED); |
1050 | } | |
1051 | ||
1052 | static void scic_sds_smp_remote_device_ready_cmd_substate_exit(void *object) | |
1053 | { | |
1054 | struct scic_sds_remote_device *sci_dev = object; | |
1055 | ||
1056 | sci_dev->working_request = NULL; | |
1057 | } | |
88f3b62a DW |
1058 | |
1059 | static const struct sci_base_state scic_sds_remote_device_state_table[] = { | |
1060 | [SCI_BASE_REMOTE_DEVICE_STATE_INITIAL] = { | |
1061 | .enter_state = scic_sds_remote_device_initial_state_enter, | |
1062 | }, | |
1063 | [SCI_BASE_REMOTE_DEVICE_STATE_STOPPED] = { | |
1064 | .enter_state = scic_sds_remote_device_stopped_state_enter, | |
1065 | }, | |
1066 | [SCI_BASE_REMOTE_DEVICE_STATE_STARTING] = { | |
1067 | .enter_state = scic_sds_remote_device_starting_state_enter, | |
1068 | }, | |
1069 | [SCI_BASE_REMOTE_DEVICE_STATE_READY] = { | |
1070 | .enter_state = scic_sds_remote_device_ready_state_enter, | |
1071 | .exit_state = scic_sds_remote_device_ready_state_exit | |
1072 | }, | |
ab2e8f7d DW |
1073 | [SCIC_SDS_STP_REMOTE_DEVICE_READY_SUBSTATE_IDLE] = { |
1074 | .enter_state = scic_sds_stp_remote_device_ready_idle_substate_enter, | |
1075 | }, | |
1076 | [SCIC_SDS_STP_REMOTE_DEVICE_READY_SUBSTATE_CMD] = { | |
1077 | .enter_state = scic_sds_stp_remote_device_ready_cmd_substate_enter, | |
1078 | }, | |
971cc2ff | 1079 | [SCIC_SDS_STP_REMOTE_DEVICE_READY_SUBSTATE_NCQ] = { }, |
ab2e8f7d DW |
1080 | [SCIC_SDS_STP_REMOTE_DEVICE_READY_SUBSTATE_NCQ_ERROR] = { |
1081 | .enter_state = scic_sds_stp_remote_device_ready_ncq_error_substate_enter, | |
1082 | }, | |
971cc2ff | 1083 | [SCIC_SDS_STP_REMOTE_DEVICE_READY_SUBSTATE_AWAIT_RESET] = { }, |
ab2e8f7d DW |
1084 | [SCIC_SDS_SMP_REMOTE_DEVICE_READY_SUBSTATE_IDLE] = { |
1085 | .enter_state = scic_sds_smp_remote_device_ready_idle_substate_enter, | |
1086 | }, | |
1087 | [SCIC_SDS_SMP_REMOTE_DEVICE_READY_SUBSTATE_CMD] = { | |
1088 | .enter_state = scic_sds_smp_remote_device_ready_cmd_substate_enter, | |
1089 | .exit_state = scic_sds_smp_remote_device_ready_cmd_substate_exit, | |
1090 | }, | |
971cc2ff DW |
1091 | [SCI_BASE_REMOTE_DEVICE_STATE_STOPPING] = { }, |
1092 | [SCI_BASE_REMOTE_DEVICE_STATE_FAILED] = { }, | |
88f3b62a DW |
1093 | [SCI_BASE_REMOTE_DEVICE_STATE_RESETTING] = { |
1094 | .enter_state = scic_sds_remote_device_resetting_state_enter, | |
1095 | .exit_state = scic_sds_remote_device_resetting_state_exit | |
1096 | }, | |
971cc2ff | 1097 | [SCI_BASE_REMOTE_DEVICE_STATE_FINAL] = { }, |
88f3b62a DW |
1098 | }; |
1099 | ||
1100 | /** | |
b87ee307 | 1101 | * scic_remote_device_construct() - common construction |
88f3b62a DW |
1102 | * @sci_port: SAS/SATA port through which this device is accessed. |
1103 | * @sci_dev: remote device to construct | |
1104 | * | |
b87ee307 DW |
1105 | * This routine just performs benign initialization and does not |
1106 | * allocate the remote_node_context which is left to | |
1107 | * scic_remote_device_[de]a_construct(). scic_remote_device_destruct() | |
1108 | * frees the remote_node_context(s) for the device. | |
88f3b62a DW |
1109 | */ |
1110 | static void scic_remote_device_construct(struct scic_sds_port *sci_port, | |
1111 | struct scic_sds_remote_device *sci_dev) | |
1112 | { | |
1113 | sci_dev->owning_port = sci_port; | |
1114 | sci_dev->started_request_count = 0; | |
88f3b62a DW |
1115 | |
1116 | sci_base_state_machine_construct( | |
1117 | &sci_dev->state_machine, | |
5d937e96 | 1118 | sci_dev, |
88f3b62a DW |
1119 | scic_sds_remote_device_state_table, |
1120 | SCI_BASE_REMOTE_DEVICE_STATE_INITIAL | |
1121 | ); | |
1122 | ||
1123 | sci_base_state_machine_start( | |
1124 | &sci_dev->state_machine | |
1125 | ); | |
1126 | ||
1127 | scic_sds_remote_node_context_construct(&sci_dev->rnc, | |
1128 | SCIC_SDS_REMOTE_NODE_CONTEXT_INVALID_INDEX); | |
88f3b62a DW |
1129 | } |
1130 | ||
1131 | /** | |
b87ee307 DW |
1132 | * scic_remote_device_da_construct() - construct direct attached device. |
1133 | * | |
1134 | * The information (e.g. IAF, Signature FIS, etc.) necessary to build | |
1135 | * the device is known to the SCI Core since it is contained in the | |
1136 | * scic_phy object. Remote node context(s) is/are a global resource | |
1137 | * allocated by this routine, freed by scic_remote_device_destruct(). | |
1138 | * | |
1139 | * Returns: | |
1140 | * SCI_FAILURE_DEVICE_EXISTS - device has already been constructed. | |
1141 | * SCI_FAILURE_UNSUPPORTED_PROTOCOL - e.g. sas device attached to | |
1142 | * sata-only controller instance. | |
1143 | * SCI_FAILURE_INSUFFICIENT_RESOURCES - remote node contexts exhausted. | |
88f3b62a | 1144 | */ |
b87ee307 DW |
1145 | static enum sci_status scic_remote_device_da_construct(struct scic_sds_port *sci_port, |
1146 | struct scic_sds_remote_device *sci_dev) | |
88f3b62a DW |
1147 | { |
1148 | enum sci_status status; | |
a1a113b0 | 1149 | struct domain_device *dev = sci_dev_to_domain(sci_dev); |
88f3b62a | 1150 | |
b87ee307 DW |
1151 | scic_remote_device_construct(sci_port, sci_dev); |
1152 | ||
88f3b62a DW |
1153 | /* |
1154 | * This information is request to determine how many remote node context | |
1155 | * entries will be needed to store the remote node. | |
1156 | */ | |
88f3b62a | 1157 | sci_dev->is_direct_attached = true; |
a1a113b0 DW |
1158 | status = scic_sds_controller_allocate_remote_node_context(sci_port->owning_controller, |
1159 | sci_dev, | |
ab2e8f7d | 1160 | &sci_dev->rnc.remote_node_index); |
88f3b62a | 1161 | |
a1a113b0 DW |
1162 | if (status != SCI_SUCCESS) |
1163 | return status; | |
88f3b62a | 1164 | |
ab2e8f7d DW |
1165 | if (dev->dev_type == SAS_END_DEV || dev->dev_type == SATA_DEV || |
1166 | (dev->tproto & SAS_PROTOCOL_STP) || dev_is_expander(dev)) | |
1167 | /* pass */; | |
1168 | else | |
a1a113b0 | 1169 | return SCI_FAILURE_UNSUPPORTED_PROTOCOL; |
88f3b62a | 1170 | |
a1a113b0 | 1171 | sci_dev->connection_rate = scic_sds_port_get_max_allowed_speed(sci_port); |
88f3b62a | 1172 | |
a1a113b0 DW |
1173 | /* / @todo Should I assign the port width by reading all of the phys on the port? */ |
1174 | sci_dev->device_port_width = 1; | |
88f3b62a | 1175 | |
a1a113b0 | 1176 | return SCI_SUCCESS; |
88f3b62a DW |
1177 | } |
1178 | ||
88f3b62a | 1179 | /** |
b87ee307 | 1180 | * scic_remote_device_ea_construct() - construct expander attached device |
b87ee307 DW |
1181 | * |
1182 | * Remote node context(s) is/are a global resource allocated by this | |
1183 | * routine, freed by scic_remote_device_destruct(). | |
1184 | * | |
1185 | * Returns: | |
1186 | * SCI_FAILURE_DEVICE_EXISTS - device has already been constructed. | |
1187 | * SCI_FAILURE_UNSUPPORTED_PROTOCOL - e.g. sas device attached to | |
1188 | * sata-only controller instance. | |
1189 | * SCI_FAILURE_INSUFFICIENT_RESOURCES - remote node contexts exhausted. | |
88f3b62a | 1190 | */ |
b87ee307 | 1191 | static enum sci_status scic_remote_device_ea_construct(struct scic_sds_port *sci_port, |
00d680ef | 1192 | struct scic_sds_remote_device *sci_dev) |
88f3b62a | 1193 | { |
a1a113b0 | 1194 | struct domain_device *dev = sci_dev_to_domain(sci_dev); |
88f3b62a | 1195 | enum sci_status status; |
88f3b62a | 1196 | |
b87ee307 | 1197 | scic_remote_device_construct(sci_port, sci_dev); |
88f3b62a | 1198 | |
ab2e8f7d DW |
1199 | status = scic_sds_controller_allocate_remote_node_context(sci_port->owning_controller, |
1200 | sci_dev, | |
1201 | &sci_dev->rnc.remote_node_index); | |
a1a113b0 DW |
1202 | if (status != SCI_SUCCESS) |
1203 | return status; | |
88f3b62a | 1204 | |
ab2e8f7d DW |
1205 | if (dev->dev_type == SAS_END_DEV || dev->dev_type == SATA_DEV || |
1206 | (dev->tproto & SAS_PROTOCOL_STP) || dev_is_expander(dev)) | |
1207 | /* pass */; | |
1208 | else | |
1209 | return SCI_FAILURE_UNSUPPORTED_PROTOCOL; | |
88f3b62a | 1210 | |
a1a113b0 DW |
1211 | /* |
1212 | * For SAS-2 the physical link rate is actually a logical link | |
1213 | * rate that incorporates multiplexing. The SCU doesn't | |
1214 | * incorporate multiplexing and for the purposes of the | |
1215 | * connection the logical link rate is that same as the | |
1216 | * physical. Furthermore, the SAS-2 and SAS-1.1 fields overlay | |
1217 | * one another, so this code works for both situations. */ | |
1218 | sci_dev->connection_rate = min_t(u16, scic_sds_port_get_max_allowed_speed(sci_port), | |
00d680ef | 1219 | dev->linkrate); |
88f3b62a | 1220 | |
a1a113b0 DW |
1221 | /* / @todo Should I assign the port width by reading all of the phys on the port? */ |
1222 | sci_dev->device_port_width = 1; | |
88f3b62a | 1223 | |
ab2e8f7d | 1224 | return SCI_SUCCESS; |
88f3b62a DW |
1225 | } |
1226 | ||
1227 | /** | |
1228 | * scic_remote_device_start() - This method will start the supplied remote | |
1229 | * device. This method enables normal IO requests to flow through to the | |
1230 | * remote device. | |
1231 | * @remote_device: This parameter specifies the device to be started. | |
1232 | * @timeout: This parameter specifies the number of milliseconds in which the | |
1233 | * start operation should complete. | |
1234 | * | |
1235 | * An indication of whether the device was successfully started. SCI_SUCCESS | |
1236 | * This value is returned if the device was successfully started. | |
1237 | * SCI_FAILURE_INVALID_PHY This value is returned if the user attempts to start | |
1238 | * the device when there have been no phys added to it. | |
1239 | */ | |
1240 | static enum sci_status scic_remote_device_start(struct scic_sds_remote_device *sci_dev, | |
eb229671 | 1241 | u32 timeout) |
88f3b62a | 1242 | { |
eb229671 DW |
1243 | struct sci_base_state_machine *sm = &sci_dev->state_machine; |
1244 | enum scic_sds_remote_device_states state = sm->current_state_id; | |
1245 | enum sci_status status; | |
1246 | ||
1247 | if (state != SCI_BASE_REMOTE_DEVICE_STATE_STOPPED) { | |
1248 | dev_warn(scirdev_to_dev(sci_dev), "%s: in wrong state: %d\n", | |
1249 | __func__, state); | |
1250 | return SCI_FAILURE_INVALID_STATE; | |
1251 | } | |
1252 | ||
1253 | status = scic_sds_remote_node_context_resume(&sci_dev->rnc, | |
1254 | remote_device_resume_done, | |
1255 | sci_dev); | |
1256 | if (status != SCI_SUCCESS) | |
1257 | return status; | |
1258 | ||
1259 | sci_base_state_machine_change_state(sm, SCI_BASE_REMOTE_DEVICE_STATE_STARTING); | |
1260 | ||
1261 | return SCI_SUCCESS; | |
88f3b62a | 1262 | } |
6f231dda | 1263 | |
00d680ef DW |
1264 | static enum sci_status isci_remote_device_construct(struct isci_port *iport, |
1265 | struct isci_remote_device *idev) | |
6f231dda | 1266 | { |
e531381e | 1267 | struct scic_sds_port *sci_port = &iport->sci; |
00d680ef DW |
1268 | struct isci_host *ihost = iport->isci_host; |
1269 | struct domain_device *dev = idev->domain_dev; | |
1270 | enum sci_status status; | |
6f231dda | 1271 | |
00d680ef DW |
1272 | if (dev->parent && dev_is_expander(dev->parent)) |
1273 | status = scic_remote_device_ea_construct(sci_port, &idev->sci); | |
1274 | else | |
1275 | status = scic_remote_device_da_construct(sci_port, &idev->sci); | |
6f231dda DW |
1276 | |
1277 | if (status != SCI_SUCCESS) { | |
00d680ef DW |
1278 | dev_dbg(&ihost->pdev->dev, "%s: construct failed: %d\n", |
1279 | __func__, status); | |
6f231dda DW |
1280 | |
1281 | return status; | |
1282 | } | |
1283 | ||
6f231dda | 1284 | /* start the device. */ |
00d680ef | 1285 | status = scic_remote_device_start(&idev->sci, ISCI_REMOTE_DEVICE_START_TIMEOUT); |
6f231dda | 1286 | |
00d680ef DW |
1287 | if (status != SCI_SUCCESS) |
1288 | dev_warn(&ihost->pdev->dev, "remote device start failed: %d\n", | |
1289 | status); | |
6f231dda DW |
1290 | |
1291 | return status; | |
1292 | } | |
1293 | ||
4393aa4e | 1294 | void isci_remote_device_nuke_requests(struct isci_host *ihost, struct isci_remote_device *idev) |
6f231dda DW |
1295 | { |
1296 | DECLARE_COMPLETION_ONSTACK(aborted_task_completion); | |
6f231dda | 1297 | |
4393aa4e DW |
1298 | dev_dbg(&ihost->pdev->dev, |
1299 | "%s: idev = %p\n", __func__, idev); | |
6f231dda DW |
1300 | |
1301 | /* Cleanup all requests pending for this device. */ | |
4393aa4e | 1302 | isci_terminate_pending_requests(ihost, idev, terminating); |
6f231dda | 1303 | |
4393aa4e DW |
1304 | dev_dbg(&ihost->pdev->dev, |
1305 | "%s: idev = %p, done\n", __func__, idev); | |
6f231dda DW |
1306 | } |
1307 | ||
6f231dda DW |
1308 | /** |
1309 | * This function builds the isci_remote_device when a libsas dev_found message | |
1310 | * is received. | |
1311 | * @isci_host: This parameter specifies the isci host object. | |
1312 | * @port: This parameter specifies the isci_port conected to this device. | |
1313 | * | |
1314 | * pointer to new isci_remote_device. | |
1315 | */ | |
1316 | static struct isci_remote_device * | |
d9c37390 | 1317 | isci_remote_device_alloc(struct isci_host *ihost, struct isci_port *iport) |
6f231dda | 1318 | { |
d9c37390 DW |
1319 | struct isci_remote_device *idev; |
1320 | int i; | |
6f231dda | 1321 | |
d9c37390 | 1322 | for (i = 0; i < SCI_MAX_REMOTE_DEVICES; i++) { |
57f20f4e | 1323 | idev = &ihost->devices[i]; |
d9c37390 DW |
1324 | if (!test_and_set_bit(IDEV_ALLOCATED, &idev->flags)) |
1325 | break; | |
1326 | } | |
6f231dda | 1327 | |
d9c37390 DW |
1328 | if (i >= SCI_MAX_REMOTE_DEVICES) { |
1329 | dev_warn(&ihost->pdev->dev, "%s: failed\n", __func__); | |
6f231dda DW |
1330 | return NULL; |
1331 | } | |
1332 | ||
6cb4d6b3 BB |
1333 | if (WARN_ONCE(!list_empty(&idev->reqs_in_process), "found requests in process\n")) |
1334 | return NULL; | |
1335 | ||
1336 | if (WARN_ONCE(!list_empty(&idev->node), "found non-idle remote device\n")) | |
1337 | return NULL; | |
1338 | ||
d9c37390 | 1339 | isci_remote_device_change_state(idev, isci_freed); |
6f231dda | 1340 | |
d9c37390 | 1341 | return idev; |
6f231dda | 1342 | } |
6f231dda | 1343 | |
6f231dda DW |
1344 | /** |
1345 | * isci_remote_device_stop() - This function is called internally to stop the | |
1346 | * remote device. | |
1347 | * @isci_host: This parameter specifies the isci host object. | |
1348 | * @isci_device: This parameter specifies the remote device. | |
1349 | * | |
1350 | * The status of the scic request to stop. | |
1351 | */ | |
6ad31fec | 1352 | enum sci_status isci_remote_device_stop(struct isci_host *ihost, struct isci_remote_device *idev) |
6f231dda DW |
1353 | { |
1354 | enum sci_status status; | |
1355 | unsigned long flags; | |
6f231dda | 1356 | |
6ad31fec DW |
1357 | dev_dbg(&ihost->pdev->dev, |
1358 | "%s: isci_device = %p\n", __func__, idev); | |
6f231dda | 1359 | |
6ad31fec | 1360 | isci_remote_device_change_state(idev, isci_stopping); |
6e2802a7 JS |
1361 | |
1362 | /* Kill all outstanding requests. */ | |
4393aa4e | 1363 | isci_remote_device_nuke_requests(ihost, idev); |
6e2802a7 | 1364 | |
6ad31fec | 1365 | set_bit(IDEV_STOP_PENDING, &idev->flags); |
6f231dda | 1366 | |
6ad31fec | 1367 | spin_lock_irqsave(&ihost->scic_lock, flags); |
57f20f4e | 1368 | status = scic_remote_device_stop(&idev->sci, 50); |
6ad31fec | 1369 | spin_unlock_irqrestore(&ihost->scic_lock, flags); |
6f231dda DW |
1370 | |
1371 | /* Wait for the stop complete callback. */ | |
d9c37390 | 1372 | if (status == SCI_SUCCESS) { |
6ad31fec | 1373 | wait_for_device_stop(ihost, idev); |
d9c37390 DW |
1374 | clear_bit(IDEV_ALLOCATED, &idev->flags); |
1375 | } | |
6f231dda | 1376 | |
6ad31fec DW |
1377 | dev_dbg(&ihost->pdev->dev, |
1378 | "%s: idev = %p - after completion wait\n", | |
1379 | __func__, idev); | |
6f231dda | 1380 | |
6f231dda DW |
1381 | return status; |
1382 | } | |
1383 | ||
1384 | /** | |
1385 | * isci_remote_device_gone() - This function is called by libsas when a domain | |
1386 | * device is removed. | |
1387 | * @domain_device: This parameter specifies the libsas domain device. | |
1388 | * | |
1389 | */ | |
6ad31fec | 1390 | void isci_remote_device_gone(struct domain_device *dev) |
6f231dda | 1391 | { |
4393aa4e | 1392 | struct isci_host *ihost = dev_to_ihost(dev); |
6ad31fec | 1393 | struct isci_remote_device *idev = dev->lldd_dev; |
6f231dda | 1394 | |
6ad31fec | 1395 | dev_dbg(&ihost->pdev->dev, |
6f231dda | 1396 | "%s: domain_device = %p, isci_device = %p, isci_port = %p\n", |
6ad31fec | 1397 | __func__, dev, idev, idev->isci_port); |
6f231dda | 1398 | |
6ad31fec | 1399 | isci_remote_device_stop(ihost, idev); |
6f231dda DW |
1400 | } |
1401 | ||
1402 | ||
1403 | /** | |
1404 | * isci_remote_device_found() - This function is called by libsas when a remote | |
1405 | * device is discovered. A remote device object is created and started. the | |
1406 | * function then sleeps until the sci core device started message is | |
1407 | * received. | |
1408 | * @domain_device: This parameter specifies the libsas domain device. | |
1409 | * | |
1410 | * status, zero indicates success. | |
1411 | */ | |
1412 | int isci_remote_device_found(struct domain_device *domain_dev) | |
1413 | { | |
4393aa4e | 1414 | struct isci_host *isci_host = dev_to_ihost(domain_dev); |
6f231dda DW |
1415 | struct isci_port *isci_port; |
1416 | struct isci_phy *isci_phy; | |
1417 | struct asd_sas_port *sas_port; | |
1418 | struct asd_sas_phy *sas_phy; | |
1419 | struct isci_remote_device *isci_device; | |
1420 | enum sci_status status; | |
6f231dda | 1421 | |
6f231dda DW |
1422 | dev_dbg(&isci_host->pdev->dev, |
1423 | "%s: domain_device = %p\n", __func__, domain_dev); | |
1424 | ||
0cf89d1d DW |
1425 | wait_for_start(isci_host); |
1426 | ||
6f231dda DW |
1427 | sas_port = domain_dev->port; |
1428 | sas_phy = list_first_entry(&sas_port->phy_list, struct asd_sas_phy, | |
1429 | port_phy_el); | |
1430 | isci_phy = to_isci_phy(sas_phy); | |
1431 | isci_port = isci_phy->isci_port; | |
1432 | ||
1433 | /* we are being called for a device on this port, | |
1434 | * so it has to come up eventually | |
1435 | */ | |
1436 | wait_for_completion(&isci_port->start_complete); | |
1437 | ||
1438 | if ((isci_stopping == isci_port_get_state(isci_port)) || | |
1439 | (isci_stopped == isci_port_get_state(isci_port))) | |
1440 | return -ENODEV; | |
1441 | ||
1442 | isci_device = isci_remote_device_alloc(isci_host, isci_port); | |
d9c37390 DW |
1443 | if (!isci_device) |
1444 | return -ENODEV; | |
6f231dda DW |
1445 | |
1446 | INIT_LIST_HEAD(&isci_device->node); | |
1447 | domain_dev->lldd_dev = isci_device; | |
1448 | isci_device->domain_dev = domain_dev; | |
1449 | isci_device->isci_port = isci_port; | |
1450 | isci_remote_device_change_state(isci_device, isci_starting); | |
1451 | ||
1452 | ||
1a38045b | 1453 | spin_lock_irq(&isci_host->scic_lock); |
6f231dda DW |
1454 | list_add_tail(&isci_device->node, &isci_port->remote_dev_list); |
1455 | ||
6ad31fec | 1456 | set_bit(IDEV_START_PENDING, &isci_device->flags); |
6f231dda | 1457 | status = isci_remote_device_construct(isci_port, isci_device); |
1a38045b | 1458 | spin_unlock_irq(&isci_host->scic_lock); |
6f231dda | 1459 | |
6f231dda DW |
1460 | dev_dbg(&isci_host->pdev->dev, |
1461 | "%s: isci_device = %p\n", | |
1462 | __func__, isci_device); | |
1463 | ||
1464 | if (status != SCI_SUCCESS) { | |
1465 | ||
1a38045b | 1466 | spin_lock_irq(&isci_host->scic_lock); |
6f231dda DW |
1467 | isci_remote_device_deconstruct( |
1468 | isci_host, | |
1469 | isci_device | |
1470 | ); | |
1a38045b | 1471 | spin_unlock_irq(&isci_host->scic_lock); |
6f231dda DW |
1472 | return -ENODEV; |
1473 | } | |
1474 | ||
6ad31fec DW |
1475 | /* wait for the device ready callback. */ |
1476 | wait_for_device_start(isci_host, isci_device); | |
1477 | ||
6f231dda DW |
1478 | return 0; |
1479 | } | |
1480 | /** | |
1481 | * isci_device_is_reset_pending() - This function will check if there is any | |
1482 | * pending reset condition on the device. | |
1483 | * @request: This parameter is the isci_device object. | |
1484 | * | |
1485 | * true if there is a reset pending for the device. | |
1486 | */ | |
1487 | bool isci_device_is_reset_pending( | |
1488 | struct isci_host *isci_host, | |
1489 | struct isci_remote_device *isci_device) | |
1490 | { | |
1491 | struct isci_request *isci_request; | |
1492 | struct isci_request *tmp_req; | |
1493 | bool reset_is_pending = false; | |
1494 | unsigned long flags; | |
1495 | ||
1496 | dev_dbg(&isci_host->pdev->dev, | |
1497 | "%s: isci_device = %p\n", __func__, isci_device); | |
1498 | ||
1499 | spin_lock_irqsave(&isci_host->scic_lock, flags); | |
1500 | ||
1501 | /* Check for reset on all pending requests. */ | |
1502 | list_for_each_entry_safe(isci_request, tmp_req, | |
1503 | &isci_device->reqs_in_process, dev_node) { | |
1504 | dev_dbg(&isci_host->pdev->dev, | |
1505 | "%s: isci_device = %p request = %p\n", | |
1506 | __func__, isci_device, isci_request); | |
1507 | ||
1508 | if (isci_request->ttype == io_task) { | |
6f231dda DW |
1509 | struct sas_task *task = isci_request_access_task( |
1510 | isci_request); | |
1511 | ||
467e855a | 1512 | spin_lock(&task->task_state_lock); |
6f231dda DW |
1513 | if (task->task_state_flags & SAS_TASK_NEED_DEV_RESET) |
1514 | reset_is_pending = true; | |
467e855a | 1515 | spin_unlock(&task->task_state_lock); |
6f231dda DW |
1516 | } |
1517 | } | |
1518 | ||
1519 | spin_unlock_irqrestore(&isci_host->scic_lock, flags); | |
1520 | ||
1521 | dev_dbg(&isci_host->pdev->dev, | |
1522 | "%s: isci_device = %p reset_is_pending = %d\n", | |
1523 | __func__, isci_device, reset_is_pending); | |
1524 | ||
1525 | return reset_is_pending; | |
1526 | } | |
1527 | ||
1528 | /** | |
1529 | * isci_device_clear_reset_pending() - This function will clear if any pending | |
1530 | * reset condition flags on the device. | |
1531 | * @request: This parameter is the isci_device object. | |
1532 | * | |
1533 | * true if there is a reset pending for the device. | |
1534 | */ | |
4393aa4e | 1535 | void isci_device_clear_reset_pending(struct isci_host *ihost, struct isci_remote_device *idev) |
6f231dda DW |
1536 | { |
1537 | struct isci_request *isci_request; | |
1538 | struct isci_request *tmp_req; | |
6f231dda DW |
1539 | unsigned long flags = 0; |
1540 | ||
4393aa4e DW |
1541 | dev_dbg(&ihost->pdev->dev, "%s: idev=%p, ihost=%p\n", |
1542 | __func__, idev, ihost); | |
6f231dda | 1543 | |
4393aa4e | 1544 | spin_lock_irqsave(&ihost->scic_lock, flags); |
6f231dda DW |
1545 | |
1546 | /* Clear reset pending on all pending requests. */ | |
1547 | list_for_each_entry_safe(isci_request, tmp_req, | |
4393aa4e DW |
1548 | &idev->reqs_in_process, dev_node) { |
1549 | dev_dbg(&ihost->pdev->dev, "%s: idev = %p request = %p\n", | |
1550 | __func__, idev, isci_request); | |
6f231dda DW |
1551 | |
1552 | if (isci_request->ttype == io_task) { | |
1553 | ||
1554 | unsigned long flags2; | |
1555 | struct sas_task *task = isci_request_access_task( | |
1556 | isci_request); | |
1557 | ||
1558 | spin_lock_irqsave(&task->task_state_lock, flags2); | |
1559 | task->task_state_flags &= ~SAS_TASK_NEED_DEV_RESET; | |
1560 | spin_unlock_irqrestore(&task->task_state_lock, flags2); | |
1561 | } | |
1562 | } | |
4393aa4e | 1563 | spin_unlock_irqrestore(&ihost->scic_lock, flags); |
6f231dda | 1564 | } |