Commit | Line | Data |
---|---|---|
6f231dda DW |
1 | /* |
2 | * This file is provided under a dual BSD/GPLv2 license. When using or | |
3 | * redistributing this file, you may do so under either license. | |
4 | * | |
5 | * GPL LICENSE SUMMARY | |
6 | * | |
7 | * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. | |
8 | * | |
9 | * This program is free software; you can redistribute it and/or modify | |
10 | * it under the terms of version 2 of the GNU General Public License as | |
11 | * published by the Free Software Foundation. | |
12 | * | |
13 | * This program is distributed in the hope that it will be useful, but | |
14 | * WITHOUT ANY WARRANTY; without even the implied warranty of | |
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
16 | * General Public License for more details. | |
17 | * | |
18 | * You should have received a copy of the GNU General Public License | |
19 | * along with this program; if not, write to the Free Software | |
20 | * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. | |
21 | * The full GNU General Public License is included in this distribution | |
22 | * in the file called LICENSE.GPL. | |
23 | * | |
24 | * BSD LICENSE | |
25 | * | |
26 | * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. | |
27 | * All rights reserved. | |
28 | * | |
29 | * Redistribution and use in source and binary forms, with or without | |
30 | * modification, are permitted provided that the following conditions | |
31 | * are met: | |
32 | * | |
33 | * * Redistributions of source code must retain the above copyright | |
34 | * notice, this list of conditions and the following disclaimer. | |
35 | * * Redistributions in binary form must reproduce the above copyright | |
36 | * notice, this list of conditions and the following disclaimer in | |
37 | * the documentation and/or other materials provided with the | |
38 | * distribution. | |
39 | * * Neither the name of Intel Corporation nor the names of its | |
40 | * contributors may be used to endorse or promote products derived | |
41 | * from this software without specific prior written permission. | |
42 | * | |
43 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
44 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
45 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | |
46 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | |
47 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
48 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |
49 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |
50 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |
51 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
52 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |
53 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
54 | */ | |
55 | ||
f2f30080 | 56 | #include <scsi/sas.h> |
6f231dda DW |
57 | #include "intel_sas.h" |
58 | #include "intel_sata.h" | |
59 | #include "intel_sat.h" | |
6f231dda DW |
60 | #include "scic_controller.h" |
61 | #include "scic_io_request.h" | |
6f231dda | 62 | #include "scic_sds_controller.h" |
bc99aa47 | 63 | #include "scu_registers.h" |
6f231dda | 64 | #include "scic_sds_port.h" |
88f3b62a | 65 | #include "remote_device.h" |
6f231dda DW |
66 | #include "scic_sds_request.h" |
67 | #include "scic_sds_smp_request.h" | |
68 | #include "scic_sds_stp_request.h" | |
69 | #include "scic_sds_unsolicited_frame_control.h" | |
6f231dda | 70 | #include "sci_environment.h" |
6f231dda DW |
71 | #include "sci_util.h" |
72 | #include "scu_completion_codes.h" | |
73 | #include "scu_constants.h" | |
74 | #include "scu_task_context.h" | |
75 | ||
6f231dda DW |
76 | /* |
77 | * **************************************************************************** | |
78 | * * SCIC SDS IO REQUEST CONSTANTS | |
79 | * **************************************************************************** */ | |
80 | ||
81 | /** | |
82 | * | |
83 | * | |
84 | * We have no timer requirements for IO requests right now | |
85 | */ | |
86 | #define SCIC_SDS_IO_REQUEST_MINIMUM_TIMER_COUNT (0) | |
87 | #define SCIC_SDS_IO_REQUEST_MAXIMUM_TIMER_COUNT (0) | |
88 | ||
89 | /* | |
90 | * **************************************************************************** | |
91 | * * SCIC SDS IO REQUEST MACROS | |
92 | * **************************************************************************** */ | |
93 | ||
6f231dda DW |
94 | /** |
95 | * scic_ssp_io_request_get_object_size() - | |
96 | * | |
97 | * This macro returns the sizeof memory required to store the an SSP IO | |
98 | * request. This does not include the size of the SGL or SCU Task Context | |
99 | * memory. | |
100 | */ | |
101 | #define scic_ssp_io_request_get_object_size() \ | |
102 | (\ | |
103 | sizeof(struct sci_ssp_command_iu) \ | |
104 | + sizeof(struct sci_ssp_response_iu) \ | |
105 | ) | |
106 | ||
107 | /** | |
108 | * scic_sds_ssp_request_get_command_buffer() - | |
109 | * | |
110 | * This macro returns the address of the ssp command buffer in the io request | |
111 | * memory | |
112 | */ | |
113 | #define scic_sds_ssp_request_get_command_buffer(memory) \ | |
114 | ((struct sci_ssp_command_iu *)(\ | |
115 | ((char *)(memory)) + sizeof(struct scic_sds_request) \ | |
116 | )) | |
117 | ||
118 | /** | |
119 | * scic_sds_ssp_request_get_response_buffer() - | |
120 | * | |
121 | * This macro returns the address of the ssp response buffer in the io request | |
122 | * memory | |
123 | */ | |
124 | #define scic_sds_ssp_request_get_response_buffer(memory) \ | |
125 | ((struct sci_ssp_response_iu *)(\ | |
126 | ((char *)(scic_sds_ssp_request_get_command_buffer(memory))) \ | |
127 | + sizeof(struct sci_ssp_command_iu) \ | |
128 | )) | |
129 | ||
130 | /** | |
131 | * scic_sds_ssp_request_get_task_context_buffer() - | |
132 | * | |
133 | * This macro returns the address of the task context buffer in the io request | |
134 | * memory | |
135 | */ | |
136 | #define scic_sds_ssp_request_get_task_context_buffer(memory) \ | |
137 | ((struct scu_task_context *)(\ | |
138 | ((char *)(scic_sds_ssp_request_get_response_buffer(memory))) \ | |
139 | + sizeof(struct sci_ssp_response_iu) \ | |
140 | )) | |
141 | ||
142 | /** | |
143 | * scic_sds_ssp_request_get_sgl_element_buffer() - | |
144 | * | |
145 | * This macro returns the address of the sgl elment pairs in the io request | |
146 | * memory buffer | |
147 | */ | |
148 | #define scic_sds_ssp_request_get_sgl_element_buffer(memory) \ | |
149 | ((struct scu_sgl_element_pair *)(\ | |
150 | ((char *)(scic_sds_ssp_request_get_task_context_buffer(memory))) \ | |
151 | + sizeof(struct scu_task_context) \ | |
152 | )) | |
153 | ||
154 | ||
155 | /** | |
156 | * scic_ssp_task_request_get_object_size() - | |
157 | * | |
158 | * This macro returns the sizeof of memory required to store an SSP Task | |
159 | * request. This does not include the size of the SCU Task Context memory. | |
160 | */ | |
161 | #define scic_ssp_task_request_get_object_size() \ | |
162 | (\ | |
163 | sizeof(struct sci_ssp_task_iu) \ | |
164 | + sizeof(struct sci_ssp_response_iu) \ | |
165 | ) | |
166 | ||
167 | /** | |
168 | * scic_sds_ssp_task_request_get_command_buffer() - | |
169 | * | |
170 | * This macro returns the address of the ssp command buffer in the task request | |
171 | * memory. Yes its the same as the above macro except for the name. | |
172 | */ | |
173 | #define scic_sds_ssp_task_request_get_command_buffer(memory) \ | |
174 | ((struct sci_ssp_task_iu *)(\ | |
175 | ((char *)(memory)) + sizeof(struct scic_sds_request) \ | |
176 | )) | |
177 | ||
178 | /** | |
179 | * scic_sds_ssp_task_request_get_response_buffer() - | |
180 | * | |
181 | * This macro returns the address of the ssp response buffer in the task | |
182 | * request memory. | |
183 | */ | |
184 | #define scic_sds_ssp_task_request_get_response_buffer(memory) \ | |
185 | ((struct sci_ssp_response_iu *)(\ | |
186 | ((char *)(scic_sds_ssp_task_request_get_command_buffer(memory))) \ | |
187 | + sizeof(struct sci_ssp_task_iu) \ | |
188 | )) | |
189 | ||
190 | /** | |
191 | * scic_sds_ssp_task_request_get_task_context_buffer() - | |
192 | * | |
193 | * This macro returs the task context buffer for the SSP task request. | |
194 | */ | |
195 | #define scic_sds_ssp_task_request_get_task_context_buffer(memory) \ | |
196 | ((struct scu_task_context *)(\ | |
197 | ((char *)(scic_sds_ssp_task_request_get_response_buffer(memory))) \ | |
198 | + sizeof(struct sci_ssp_response_iu) \ | |
199 | )) | |
200 | ||
201 | ||
202 | ||
203 | /* | |
204 | * **************************************************************************** | |
205 | * * SCIC SDS IO REQUEST PRIVATE METHODS | |
206 | * **************************************************************************** */ | |
207 | ||
208 | /** | |
209 | * | |
210 | * | |
211 | * This method returns the size required to store an SSP IO request object. u32 | |
212 | */ | |
213 | static u32 scic_sds_ssp_request_get_object_size(void) | |
214 | { | |
215 | return sizeof(struct scic_sds_request) | |
216 | + scic_ssp_io_request_get_object_size() | |
217 | + sizeof(struct scu_task_context) | |
fe9a6431 | 218 | + SMP_CACHE_BYTES |
6f231dda DW |
219 | + sizeof(struct scu_sgl_element_pair) * SCU_MAX_SGL_ELEMENT_PAIRS; |
220 | } | |
221 | ||
222 | /** | |
223 | * This method returns the sgl element pair for the specificed sgl_pair index. | |
e2023b87 | 224 | * @sci_req: This parameter specifies the IO request for which to retrieve |
6f231dda DW |
225 | * the Scatter-Gather List element pair. |
226 | * @sgl_pair_index: This parameter specifies the index into the SGL element | |
227 | * pair to be retrieved. | |
228 | * | |
229 | * This method returns a pointer to an struct scu_sgl_element_pair. | |
230 | */ | |
231 | static struct scu_sgl_element_pair *scic_sds_request_get_sgl_element_pair( | |
e2023b87 | 232 | struct scic_sds_request *sci_req, |
6f231dda DW |
233 | u32 sgl_pair_index |
234 | ) { | |
235 | struct scu_task_context *task_context; | |
236 | ||
e2023b87 | 237 | task_context = (struct scu_task_context *)sci_req->task_context_buffer; |
6f231dda DW |
238 | |
239 | if (sgl_pair_index == 0) { | |
240 | return &task_context->sgl_pair_ab; | |
241 | } else if (sgl_pair_index == 1) { | |
242 | return &task_context->sgl_pair_cd; | |
243 | } | |
244 | ||
e2023b87 | 245 | return &sci_req->sgl_element_pair_buffer[sgl_pair_index - 2]; |
6f231dda DW |
246 | } |
247 | ||
248 | /** | |
249 | * This function will build the SGL list for an IO request. | |
e2023b87 | 250 | * @sci_req: This parameter specifies the IO request for which to build |
6f231dda DW |
251 | * the Scatter-Gather List. |
252 | * | |
253 | */ | |
6389a775 | 254 | void scic_sds_request_build_sgl(struct scic_sds_request *sds_request) |
6f231dda | 255 | { |
890cae9b | 256 | struct isci_request *isci_request = sds_request->ireq; |
6389a775 DJ |
257 | struct isci_host *isci_host = isci_request->isci_host; |
258 | struct sas_task *task = isci_request_access_task(isci_request); | |
259 | struct scatterlist *sg = NULL; | |
260 | dma_addr_t dma_addr; | |
261 | u32 sg_idx = 0; | |
262 | struct scu_sgl_element_pair *scu_sg = NULL; | |
263 | struct scu_sgl_element_pair *prev_sg = NULL; | |
264 | ||
265 | if (task->num_scatter > 0) { | |
266 | sg = task->scatter; | |
267 | ||
268 | while (sg) { | |
269 | scu_sg = scic_sds_request_get_sgl_element_pair( | |
270 | sds_request, | |
271 | sg_idx); | |
272 | ||
273 | SCU_SGL_COPY(scu_sg->A, sg); | |
274 | ||
275 | sg = sg_next(sg); | |
276 | ||
277 | if (sg) { | |
278 | SCU_SGL_COPY(scu_sg->B, sg); | |
279 | sg = sg_next(sg); | |
280 | } else | |
281 | SCU_SGL_ZERO(scu_sg->B); | |
282 | ||
283 | if (prev_sg) { | |
284 | dma_addr = | |
285 | scic_io_request_get_dma_addr( | |
286 | sds_request, | |
287 | scu_sg); | |
288 | ||
289 | prev_sg->next_pair_upper = | |
290 | upper_32_bits(dma_addr); | |
291 | prev_sg->next_pair_lower = | |
292 | lower_32_bits(dma_addr); | |
293 | } | |
294 | ||
295 | prev_sg = scu_sg; | |
296 | sg_idx++; | |
6f231dda | 297 | } |
6389a775 DJ |
298 | } else { /* handle when no sg */ |
299 | scu_sg = scic_sds_request_get_sgl_element_pair(sds_request, | |
300 | sg_idx); | |
6f231dda | 301 | |
6389a775 DJ |
302 | dma_addr = dma_map_single(&isci_host->pdev->dev, |
303 | task->scatter, | |
304 | task->total_xfer_len, | |
305 | task->data_dir); | |
6f231dda | 306 | |
6389a775 DJ |
307 | isci_request->zero_scatter_daddr = dma_addr; |
308 | ||
309 | scu_sg->A.length = task->total_xfer_len; | |
310 | scu_sg->A.address_upper = upper_32_bits(dma_addr); | |
311 | scu_sg->A.address_lower = lower_32_bits(dma_addr); | |
6f231dda DW |
312 | } |
313 | ||
6389a775 DJ |
314 | if (scu_sg) { |
315 | scu_sg->next_pair_upper = 0; | |
316 | scu_sg->next_pair_lower = 0; | |
6f231dda DW |
317 | } |
318 | } | |
319 | ||
6f231dda DW |
320 | /** |
321 | * This method build the remainder of the IO request object. | |
e2023b87 | 322 | * @sci_req: This parameter specifies the request object being constructed. |
6f231dda DW |
323 | * |
324 | * The scic_sds_general_request_construct() must be called before this call is | |
325 | * valid. none | |
326 | */ | |
327 | static void scic_sds_ssp_io_request_assign_buffers( | |
e2023b87 | 328 | struct scic_sds_request *sci_req) |
6f231dda | 329 | { |
e2023b87 DJ |
330 | sci_req->command_buffer = |
331 | scic_sds_ssp_request_get_command_buffer(sci_req); | |
332 | sci_req->response_buffer = | |
333 | scic_sds_ssp_request_get_response_buffer(sci_req); | |
334 | sci_req->sgl_element_pair_buffer = | |
335 | scic_sds_ssp_request_get_sgl_element_buffer(sci_req); | |
336 | sci_req->sgl_element_pair_buffer = | |
337 | PTR_ALIGN(sci_req->sgl_element_pair_buffer, | |
fe9a6431 | 338 | sizeof(struct scu_sgl_element_pair)); |
6f231dda | 339 | |
e2023b87 DJ |
340 | if (sci_req->was_tag_assigned_by_user == false) { |
341 | sci_req->task_context_buffer = | |
342 | scic_sds_ssp_request_get_task_context_buffer(sci_req); | |
343 | sci_req->task_context_buffer = | |
344 | PTR_ALIGN(sci_req->task_context_buffer, | |
fe9a6431 | 345 | SMP_CACHE_BYTES); |
6f231dda DW |
346 | } |
347 | } | |
348 | ||
349 | /** | |
350 | * This method constructs the SSP Command IU data for this io request object. | |
e2023b87 | 351 | * @sci_req: This parameter specifies the request object for which the SSP |
6f231dda DW |
352 | * command information unit is being built. |
353 | * | |
354 | */ | |
355 | static void scic_sds_io_request_build_ssp_command_iu( | |
7392d275 | 356 | struct scic_sds_request *sds_request) |
6f231dda DW |
357 | { |
358 | struct sci_ssp_command_iu *command_frame; | |
6f231dda DW |
359 | u32 cdb_length; |
360 | u32 *cdb_buffer; | |
890cae9b | 361 | struct isci_request *isci_request = sds_request->ireq; |
6f231dda DW |
362 | |
363 | command_frame = | |
7392d275 | 364 | (struct sci_ssp_command_iu *)sds_request->command_buffer; |
6f231dda DW |
365 | |
366 | command_frame->lun_upper = 0; | |
7392d275 DJ |
367 | command_frame->lun_lower = |
368 | isci_request_ssp_io_request_get_lun(isci_request); | |
6f231dda DW |
369 | |
370 | ((u32 *)command_frame)[2] = 0; | |
371 | ||
7392d275 DJ |
372 | cdb_length = isci_request_ssp_io_request_get_cdb_length(isci_request); |
373 | cdb_buffer = (u32 *)isci_request_ssp_io_request_get_cdb_address( | |
374 | isci_request); | |
6f231dda DW |
375 | |
376 | if (cdb_length > 16) { | |
377 | command_frame->additional_cdb_length = cdb_length - 16; | |
378 | } | |
379 | ||
380 | /* / @todo Is it ok to leave junk at the end of the cdb buffer? */ | |
381 | scic_word_copy_with_swap( | |
382 | (u32 *)(&command_frame->cdb), | |
383 | (u32 *)(cdb_buffer), | |
384 | (cdb_length + 3) / sizeof(u32) | |
385 | ); | |
386 | ||
387 | command_frame->enable_first_burst = 0; | |
388 | command_frame->task_priority = | |
7392d275 | 389 | isci_request_ssp_io_request_get_command_priority(isci_request); |
6f231dda | 390 | command_frame->task_attribute = |
7392d275 | 391 | isci_request_ssp_io_request_get_task_attribute(isci_request); |
6f231dda DW |
392 | } |
393 | ||
394 | ||
395 | /** | |
396 | * This method constructs the SSP Task IU data for this io request object. | |
e2023b87 | 397 | * @sci_req: |
6f231dda DW |
398 | * |
399 | */ | |
400 | static void scic_sds_task_request_build_ssp_task_iu( | |
7392d275 | 401 | struct scic_sds_request *sds_request) |
6f231dda DW |
402 | { |
403 | struct sci_ssp_task_iu *command_frame; | |
890cae9b | 404 | struct isci_request *isci_request = sds_request->ireq; |
6f231dda DW |
405 | |
406 | command_frame = | |
7392d275 | 407 | (struct sci_ssp_task_iu *)sds_request->command_buffer; |
6f231dda DW |
408 | |
409 | command_frame->lun_upper = 0; | |
7392d275 DJ |
410 | command_frame->lun_lower = isci_request_ssp_io_request_get_lun( |
411 | isci_request); | |
6f231dda DW |
412 | |
413 | ((u32 *)command_frame)[2] = 0; | |
414 | ||
415 | command_frame->task_function = | |
7392d275 | 416 | isci_task_ssp_request_get_function(isci_request); |
6f231dda | 417 | command_frame->task_tag = |
7392d275 DJ |
418 | isci_task_ssp_request_get_io_tag_to_manage( |
419 | isci_request); | |
6f231dda DW |
420 | } |
421 | ||
422 | ||
423 | /** | |
424 | * This method is will fill in the SCU Task Context for any type of SSP request. | |
e2023b87 | 425 | * @sci_req: |
6f231dda DW |
426 | * @task_context: |
427 | * | |
428 | */ | |
429 | static void scu_ssp_reqeust_construct_task_context( | |
6389a775 | 430 | struct scic_sds_request *sds_request, |
6f231dda DW |
431 | struct scu_task_context *task_context) |
432 | { | |
6389a775 DJ |
433 | dma_addr_t dma_addr; |
434 | struct scic_sds_controller *controller; | |
6f231dda DW |
435 | struct scic_sds_remote_device *target_device; |
436 | struct scic_sds_port *target_port; | |
437 | ||
6389a775 DJ |
438 | controller = scic_sds_request_get_controller(sds_request); |
439 | target_device = scic_sds_request_get_device(sds_request); | |
440 | target_port = scic_sds_request_get_port(sds_request); | |
6f231dda DW |
441 | |
442 | /* Fill in the TC with the its required data */ | |
443 | task_context->abort = 0; | |
444 | task_context->priority = 0; | |
445 | task_context->initiator_request = 1; | |
8f304c36 | 446 | task_context->connection_rate = target_device->connection_rate; |
6f231dda | 447 | task_context->protocol_engine_index = |
6389a775 | 448 | scic_sds_controller_get_protocol_engine_group(controller); |
6f231dda DW |
449 | task_context->logical_port_index = |
450 | scic_sds_port_get_index(target_port); | |
451 | task_context->protocol_type = SCU_TASK_CONTEXT_PROTOCOL_SSP; | |
452 | task_context->valid = SCU_TASK_CONTEXT_VALID; | |
453 | task_context->context_type = SCU_TASK_CONTEXT_TYPE; | |
454 | ||
455 | task_context->remote_node_index = | |
6389a775 | 456 | scic_sds_remote_device_get_index(sds_request->target_device); |
6f231dda DW |
457 | task_context->command_code = 0; |
458 | ||
459 | task_context->link_layer_control = 0; | |
460 | task_context->do_not_dma_ssp_good_response = 1; | |
461 | task_context->strict_ordering = 0; | |
462 | task_context->control_frame = 0; | |
463 | task_context->timeout_enable = 0; | |
464 | task_context->block_guard_enable = 0; | |
465 | ||
466 | task_context->address_modifier = 0; | |
467 | ||
e2023b87 | 468 | /* task_context->type.ssp.tag = sci_req->io_tag; */ |
6f231dda DW |
469 | task_context->task_phase = 0x01; |
470 | ||
6389a775 DJ |
471 | if (sds_request->was_tag_assigned_by_user) { |
472 | /* | |
473 | * Build the task context now since we have already read | |
474 | * the data | |
475 | */ | |
476 | sds_request->post_context = | |
477 | (SCU_CONTEXT_COMMAND_REQUEST_TYPE_POST_TC | | |
478 | (scic_sds_controller_get_protocol_engine_group( | |
479 | controller) << | |
480 | SCU_CONTEXT_COMMAND_PROTOCOL_ENGINE_GROUP_SHIFT) | | |
481 | (scic_sds_port_get_index(target_port) << | |
482 | SCU_CONTEXT_COMMAND_LOGICAL_PORT_SHIFT) | | |
483 | scic_sds_io_tag_get_index(sds_request->io_tag)); | |
6f231dda | 484 | } else { |
6389a775 DJ |
485 | /* |
486 | * Build the task context now since we have already read | |
487 | * the data | |
488 | * | |
489 | * I/O tag index is not assigned because we have to wait | |
490 | * until we get a TCi | |
491 | */ | |
492 | sds_request->post_context = | |
493 | (SCU_CONTEXT_COMMAND_REQUEST_TYPE_POST_TC | | |
494 | (scic_sds_controller_get_protocol_engine_group( | |
495 | owning_controller) << | |
496 | SCU_CONTEXT_COMMAND_PROTOCOL_ENGINE_GROUP_SHIFT) | | |
497 | (scic_sds_port_get_index(target_port) << | |
498 | SCU_CONTEXT_COMMAND_LOGICAL_PORT_SHIFT)); | |
6f231dda DW |
499 | } |
500 | ||
6389a775 DJ |
501 | /* |
502 | * Copy the physical address for the command buffer to the | |
503 | * SCU Task Context | |
504 | */ | |
505 | dma_addr = scic_io_request_get_dma_addr(sds_request, | |
506 | sds_request->command_buffer); | |
507 | ||
508 | task_context->command_iu_upper = upper_32_bits(dma_addr); | |
509 | task_context->command_iu_lower = lower_32_bits(dma_addr); | |
510 | ||
511 | /* | |
512 | * Copy the physical address for the response buffer to the | |
513 | * SCU Task Context | |
514 | */ | |
515 | dma_addr = scic_io_request_get_dma_addr(sds_request, | |
516 | sds_request->response_buffer); | |
517 | ||
518 | task_context->response_iu_upper = upper_32_bits(dma_addr); | |
519 | task_context->response_iu_lower = lower_32_bits(dma_addr); | |
6f231dda DW |
520 | } |
521 | ||
522 | /** | |
523 | * This method is will fill in the SCU Task Context for a SSP IO request. | |
e2023b87 | 524 | * @sci_req: |
6f231dda DW |
525 | * |
526 | */ | |
527 | static void scu_ssp_io_request_construct_task_context( | |
82d29928 DW |
528 | struct scic_sds_request *sci_req, |
529 | enum dma_data_direction dir, | |
530 | u32 len) | |
6f231dda DW |
531 | { |
532 | struct scu_task_context *task_context; | |
533 | ||
82d29928 | 534 | task_context = scic_sds_request_get_task_context(sci_req); |
6f231dda | 535 | |
82d29928 | 536 | scu_ssp_reqeust_construct_task_context(sci_req, task_context); |
6f231dda DW |
537 | |
538 | task_context->ssp_command_iu_length = sizeof(struct sci_ssp_command_iu) / sizeof(u32); | |
539 | task_context->type.ssp.frame_type = SCI_SAS_COMMAND_FRAME; | |
540 | ||
82d29928 DW |
541 | switch (dir) { |
542 | case DMA_FROM_DEVICE: | |
543 | case DMA_NONE: | |
544 | default: | |
6f231dda DW |
545 | task_context->task_type = SCU_TASK_TYPE_IOREAD; |
546 | break; | |
82d29928 | 547 | case DMA_TO_DEVICE: |
6f231dda DW |
548 | task_context->task_type = SCU_TASK_TYPE_IOWRITE; |
549 | break; | |
550 | } | |
551 | ||
82d29928 | 552 | task_context->transfer_length_bytes = len; |
6f231dda | 553 | |
82d29928 DW |
554 | if (task_context->transfer_length_bytes > 0) |
555 | scic_sds_request_build_sgl(sci_req); | |
6f231dda DW |
556 | } |
557 | ||
558 | ||
559 | /** | |
560 | * This method will fill in the remainder of the io request object for SSP Task | |
561 | * requests. | |
e2023b87 | 562 | * @sci_req: |
6f231dda DW |
563 | * |
564 | */ | |
565 | static void scic_sds_ssp_task_request_assign_buffers( | |
e2023b87 | 566 | struct scic_sds_request *sci_req) |
6f231dda DW |
567 | { |
568 | /* Assign all of the buffer pointers */ | |
e2023b87 DJ |
569 | sci_req->command_buffer = |
570 | scic_sds_ssp_task_request_get_command_buffer(sci_req); | |
571 | sci_req->response_buffer = | |
572 | scic_sds_ssp_task_request_get_response_buffer(sci_req); | |
573 | sci_req->sgl_element_pair_buffer = NULL; | |
574 | ||
575 | if (sci_req->was_tag_assigned_by_user == false) { | |
576 | sci_req->task_context_buffer = | |
577 | scic_sds_ssp_task_request_get_task_context_buffer(sci_req); | |
578 | sci_req->task_context_buffer = | |
579 | PTR_ALIGN(sci_req->task_context_buffer, SMP_CACHE_BYTES); | |
6f231dda DW |
580 | } |
581 | } | |
582 | ||
583 | /** | |
584 | * This method will fill in the SCU Task Context for a SSP Task request. The | |
585 | * following important settings are utilized: -# priority == | |
586 | * SCU_TASK_PRIORITY_HIGH. This ensures that the task request is issued | |
587 | * ahead of other task destined for the same Remote Node. -# task_type == | |
588 | * SCU_TASK_TYPE_IOREAD. This simply indicates that a normal request type | |
589 | * (i.e. non-raw frame) is being utilized to perform task management. -# | |
590 | * control_frame == 1. This ensures that the proper endianess is set so | |
591 | * that the bytes are transmitted in the right order for a task frame. | |
e2023b87 | 592 | * @sci_req: This parameter specifies the task request object being |
6f231dda DW |
593 | * constructed. |
594 | * | |
595 | */ | |
596 | static void scu_ssp_task_request_construct_task_context( | |
e2023b87 | 597 | struct scic_sds_request *sci_req) |
6f231dda DW |
598 | { |
599 | struct scu_task_context *task_context; | |
600 | ||
e2023b87 | 601 | task_context = scic_sds_request_get_task_context(sci_req); |
6f231dda | 602 | |
e2023b87 | 603 | scu_ssp_reqeust_construct_task_context(sci_req, task_context); |
6f231dda DW |
604 | |
605 | task_context->control_frame = 1; | |
606 | task_context->priority = SCU_TASK_PRIORITY_HIGH; | |
607 | task_context->task_type = SCU_TASK_TYPE_RAW_FRAME; | |
608 | task_context->transfer_length_bytes = 0; | |
609 | task_context->type.ssp.frame_type = SCI_SAS_TASK_FRAME; | |
610 | task_context->ssp_command_iu_length = sizeof(struct sci_ssp_task_iu) / sizeof(u32); | |
611 | } | |
612 | ||
613 | ||
614 | /** | |
615 | * This method constructs the SSP Command IU data for this ssp passthrough | |
616 | * comand request object. | |
e2023b87 | 617 | * @sci_req: This parameter specifies the request object for which the SSP |
6f231dda DW |
618 | * command information unit is being built. |
619 | * | |
620 | * enum sci_status, returns invalid parameter is cdb > 16 | |
621 | */ | |
622 | ||
623 | ||
624 | /** | |
625 | * This method constructs the SATA request object. | |
e2023b87 | 626 | * @sci_req: |
6f231dda DW |
627 | * @sat_protocol: |
628 | * @transfer_length: | |
629 | * @data_direction: | |
630 | * @copy_rx_frame: | |
631 | * | |
632 | * enum sci_status | |
633 | */ | |
82d29928 DW |
634 | static enum sci_status scic_io_request_construct_sata(struct scic_sds_request *sci_req, |
635 | u8 proto, u32 len, | |
636 | enum dma_data_direction dir, | |
637 | bool copy) | |
6f231dda DW |
638 | { |
639 | enum sci_status status = SCI_SUCCESS; | |
640 | ||
82d29928 | 641 | switch (proto) { |
6f231dda DW |
642 | case SAT_PROTOCOL_PIO_DATA_IN: |
643 | case SAT_PROTOCOL_PIO_DATA_OUT: | |
82d29928 | 644 | status = scic_sds_stp_pio_request_construct(sci_req, proto, copy); |
6f231dda DW |
645 | break; |
646 | ||
647 | case SAT_PROTOCOL_UDMA_DATA_IN: | |
648 | case SAT_PROTOCOL_UDMA_DATA_OUT: | |
82d29928 | 649 | status = scic_sds_stp_udma_request_construct(sci_req, len, dir); |
6f231dda DW |
650 | break; |
651 | ||
652 | case SAT_PROTOCOL_ATA_HARD_RESET: | |
653 | case SAT_PROTOCOL_SOFT_RESET: | |
82d29928 | 654 | status = scic_sds_stp_soft_reset_request_construct(sci_req); |
6f231dda DW |
655 | break; |
656 | ||
657 | case SAT_PROTOCOL_NON_DATA: | |
82d29928 | 658 | status = scic_sds_stp_non_data_request_construct(sci_req); |
6f231dda DW |
659 | break; |
660 | ||
661 | case SAT_PROTOCOL_FPDMA: | |
82d29928 | 662 | status = scic_sds_stp_ncq_request_construct(sci_req, len, dir); |
6f231dda DW |
663 | break; |
664 | ||
6f231dda DW |
665 | case SAT_PROTOCOL_DMA_QUEUED: |
666 | case SAT_PROTOCOL_DMA: | |
667 | case SAT_PROTOCOL_DEVICE_DIAGNOSTIC: | |
668 | case SAT_PROTOCOL_DEVICE_RESET: | |
669 | case SAT_PROTOCOL_RETURN_RESPONSE_INFO: | |
670 | default: | |
82d29928 | 671 | dev_err(scic_to_dev(sci_req->owning_controller), |
6f231dda DW |
672 | "%s: SCIC IO Request 0x%p received un-handled " |
673 | "SAT Protocl %d.\n", | |
82d29928 | 674 | __func__, sci_req, proto); |
6f231dda DW |
675 | |
676 | status = SCI_FAILURE; | |
677 | break; | |
678 | } | |
679 | ||
680 | return status; | |
681 | } | |
682 | ||
6f231dda DW |
683 | u32 scic_io_request_get_object_size(void) |
684 | { | |
685 | u32 ssp_request_size; | |
686 | u32 stp_request_size; | |
687 | u32 smp_request_size; | |
688 | ||
689 | ssp_request_size = scic_sds_ssp_request_get_object_size(); | |
690 | stp_request_size = scic_sds_stp_request_get_object_size(); | |
691 | smp_request_size = scic_sds_smp_request_get_object_size(); | |
692 | ||
693 | return max(ssp_request_size, max(stp_request_size, smp_request_size)); | |
694 | } | |
695 | ||
6f231dda DW |
696 | enum sci_status scic_io_request_construct_basic_ssp( |
697 | struct scic_sds_request *sci_req) | |
698 | { | |
890cae9b | 699 | struct isci_request *isci_request = sci_req->ireq; |
6f231dda DW |
700 | |
701 | sci_req->protocol = SCIC_SSP_PROTOCOL; | |
702 | ||
6f231dda DW |
703 | scu_ssp_io_request_construct_task_context( |
704 | sci_req, | |
7392d275 DJ |
705 | isci_request_io_request_get_data_direction(isci_request), |
706 | isci_request_io_request_get_transfer_length(isci_request)); | |
6f231dda DW |
707 | |
708 | scic_sds_io_request_build_ssp_command_iu(sci_req); | |
709 | ||
38aa74eb CH |
710 | sci_base_state_machine_change_state(&sci_req->state_machine, |
711 | SCI_BASE_REQUEST_STATE_CONSTRUCTED); | |
6f231dda DW |
712 | |
713 | return SCI_SUCCESS; | |
714 | } | |
715 | ||
716 | ||
717 | enum sci_status scic_task_request_construct_ssp( | |
718 | struct scic_sds_request *sci_req) | |
719 | { | |
720 | /* Construct the SSP Task SCU Task Context */ | |
721 | scu_ssp_task_request_construct_task_context(sci_req); | |
722 | ||
723 | /* Fill in the SSP Task IU */ | |
724 | scic_sds_task_request_build_ssp_task_iu(sci_req); | |
725 | ||
38aa74eb CH |
726 | sci_base_state_machine_change_state(&sci_req->state_machine, |
727 | SCI_BASE_REQUEST_STATE_CONSTRUCTED); | |
6f231dda DW |
728 | |
729 | return SCI_SUCCESS; | |
730 | } | |
731 | ||
732 | ||
7392d275 DJ |
733 | enum sci_status scic_io_request_construct_basic_sata( |
734 | struct scic_sds_request *sci_req) | |
6f231dda DW |
735 | { |
736 | enum sci_status status; | |
82d29928 DW |
737 | struct scic_sds_stp_request *stp_req; |
738 | u8 proto; | |
739 | u32 len; | |
740 | enum dma_data_direction dir; | |
741 | bool copy = false; | |
890cae9b | 742 | struct isci_request *isci_request = sci_req->ireq; |
7392d275 | 743 | struct sas_task *task = isci_request_access_task(isci_request); |
6f231dda | 744 | |
82d29928 | 745 | stp_req = container_of(sci_req, typeof(*stp_req), parent); |
6f231dda DW |
746 | |
747 | sci_req->protocol = SCIC_STP_PROTOCOL; | |
748 | ||
7392d275 DJ |
749 | len = isci_request_io_request_get_transfer_length(isci_request); |
750 | dir = isci_request_io_request_get_data_direction(isci_request); | |
751 | proto = isci_sata_get_sat_protocol(isci_request); | |
752 | copy = (task->data_dir == DMA_NONE) ? false : true; | |
6f231dda | 753 | |
82d29928 | 754 | status = scic_io_request_construct_sata(sci_req, proto, len, dir, copy); |
6f231dda DW |
755 | |
756 | if (status == SCI_SUCCESS) | |
38aa74eb CH |
757 | sci_base_state_machine_change_state(&sci_req->state_machine, |
758 | SCI_BASE_REQUEST_STATE_CONSTRUCTED); | |
6f231dda DW |
759 | |
760 | return status; | |
761 | } | |
762 | ||
763 | ||
764 | enum sci_status scic_task_request_construct_sata( | |
765 | struct scic_sds_request *sci_req) | |
766 | { | |
767 | enum sci_status status; | |
7392d275 | 768 | u8 sat_protocol; |
890cae9b | 769 | struct isci_request *isci_request = sci_req->ireq; |
7392d275 DJ |
770 | |
771 | sat_protocol = isci_sata_get_sat_protocol(isci_request); | |
6f231dda DW |
772 | |
773 | switch (sat_protocol) { | |
774 | case SAT_PROTOCOL_ATA_HARD_RESET: | |
775 | case SAT_PROTOCOL_SOFT_RESET: | |
776 | status = scic_sds_stp_soft_reset_request_construct(sci_req); | |
777 | break; | |
778 | ||
779 | default: | |
780 | dev_err(scic_to_dev(sci_req->owning_controller), | |
781 | "%s: SCIC IO Request 0x%p received un-handled SAT " | |
782 | "Protocl %d.\n", | |
783 | __func__, | |
784 | sci_req, | |
785 | sat_protocol); | |
786 | ||
787 | status = SCI_FAILURE; | |
788 | break; | |
789 | } | |
790 | ||
791 | if (status == SCI_SUCCESS) | |
38aa74eb CH |
792 | sci_base_state_machine_change_state(&sci_req->state_machine, |
793 | SCI_BASE_REQUEST_STATE_CONSTRUCTED); | |
6f231dda DW |
794 | |
795 | return status; | |
796 | } | |
797 | ||
798 | ||
799 | u16 scic_io_request_get_io_tag( | |
800 | struct scic_sds_request *sci_req) | |
801 | { | |
802 | return sci_req->io_tag; | |
803 | } | |
804 | ||
805 | ||
806 | u32 scic_request_get_controller_status( | |
807 | struct scic_sds_request *sci_req) | |
808 | { | |
809 | return sci_req->scu_status; | |
810 | } | |
811 | ||
812 | ||
813 | void *scic_io_request_get_command_iu_address( | |
814 | struct scic_sds_request *sci_req) | |
815 | { | |
816 | return sci_req->command_buffer; | |
817 | } | |
818 | ||
819 | ||
820 | void *scic_io_request_get_response_iu_address( | |
821 | struct scic_sds_request *sci_req) | |
822 | { | |
823 | return sci_req->response_buffer; | |
824 | } | |
825 | ||
826 | ||
827 | #define SCU_TASK_CONTEXT_SRAM 0x200000 | |
828 | u32 scic_io_request_get_number_of_bytes_transferred( | |
829 | struct scic_sds_request *scic_sds_request) | |
830 | { | |
467e855a | 831 | struct scic_sds_controller *scic = scic_sds_request->owning_controller; |
6f231dda DW |
832 | u32 ret_val = 0; |
833 | ||
467e855a BB |
834 | if (readl(&scic->smu_registers->address_modifier) == 0) { |
835 | void __iomem *scu_reg_base = scic->scu_registers; | |
6f231dda DW |
836 | /* |
837 | * get the bytes of data from the Address == BAR1 + 20002Ch + (256*TCi) where | |
838 | * BAR1 is the scu_registers | |
839 | * 0x20002C = 0x200000 + 0x2c | |
840 | * = start of task context SRAM + offset of (type.ssp.data_offset) | |
841 | * TCi is the io_tag of struct scic_sds_request */ | |
467e855a BB |
842 | ret_val = readl(scu_reg_base + |
843 | (SCU_TASK_CONTEXT_SRAM + offsetof(struct scu_task_context, type.ssp.data_offset)) + | |
844 | ((sizeof(struct scu_task_context)) * scic_sds_io_tag_get_index(scic_sds_request->io_tag))); | |
6f231dda DW |
845 | } |
846 | ||
847 | return ret_val; | |
848 | } | |
849 | ||
850 | ||
851 | /* | |
852 | * **************************************************************************** | |
853 | * * SCIC SDS Interface Implementation | |
854 | * **************************************************************************** */ | |
855 | ||
38aa74eb CH |
856 | enum sci_status |
857 | scic_sds_request_start(struct scic_sds_request *request) | |
6f231dda | 858 | { |
524b5f72 | 859 | if (request->device_sequence != |
38aa74eb | 860 | scic_sds_remote_device_get_sequence(request->target_device)) |
524b5f72 CH |
861 | return SCI_FAILURE; |
862 | ||
863 | if (request->state_handlers->start_handler) | |
38aa74eb | 864 | return request->state_handlers->start_handler(request); |
524b5f72 CH |
865 | |
866 | dev_warn(scic_to_dev(request->owning_controller), | |
867 | "%s: SCIC IO Request requested to start while in wrong " | |
868 | "state %d\n", | |
869 | __func__, | |
870 | sci_base_state_machine_get_state(&request->state_machine)); | |
871 | ||
872 | return SCI_FAILURE_INVALID_STATE; | |
6f231dda DW |
873 | } |
874 | ||
38aa74eb CH |
875 | enum sci_status |
876 | scic_sds_io_request_terminate(struct scic_sds_request *request) | |
6f231dda | 877 | { |
524b5f72 CH |
878 | if (request->state_handlers->abort_handler) |
879 | return request->state_handlers->abort_handler(request); | |
880 | ||
881 | dev_warn(scic_to_dev(request->owning_controller), | |
882 | "%s: SCIC IO Request requested to abort while in wrong " | |
883 | "state %d\n", | |
884 | __func__, | |
885 | sci_base_state_machine_get_state(&request->state_machine)); | |
886 | ||
887 | return SCI_FAILURE_INVALID_STATE; | |
6f231dda DW |
888 | } |
889 | ||
38aa74eb CH |
890 | enum sci_status |
891 | scic_sds_io_request_complete(struct scic_sds_request *request) | |
6f231dda | 892 | { |
524b5f72 CH |
893 | if (request->state_handlers->complete_handler) |
894 | return request->state_handlers->complete_handler(request); | |
895 | ||
896 | dev_warn(scic_to_dev(request->owning_controller), | |
897 | "%s: SCIC IO Request requested to complete while in wrong " | |
898 | "state %d\n", | |
899 | __func__, | |
900 | sci_base_state_machine_get_state(&request->state_machine)); | |
901 | ||
902 | return SCI_FAILURE_INVALID_STATE; | |
6f231dda DW |
903 | } |
904 | ||
6f231dda | 905 | enum sci_status scic_sds_io_request_event_handler( |
524b5f72 | 906 | struct scic_sds_request *request, |
6f231dda DW |
907 | u32 event_code) |
908 | { | |
524b5f72 CH |
909 | if (request->state_handlers->event_handler) |
910 | return request->state_handlers->event_handler(request, event_code); | |
911 | ||
912 | dev_warn(scic_to_dev(request->owning_controller), | |
913 | "%s: SCIC IO Request given event code notification %x while " | |
914 | "in wrong state %d\n", | |
915 | __func__, | |
916 | event_code, | |
917 | sci_base_state_machine_get_state(&request->state_machine)); | |
918 | ||
919 | return SCI_FAILURE_INVALID_STATE; | |
6f231dda DW |
920 | } |
921 | ||
524b5f72 CH |
922 | enum sci_status |
923 | scic_sds_io_request_tc_completion(struct scic_sds_request *request, u32 completion_code) | |
924 | { | |
925 | if (request->state_machine.current_state_id == SCI_BASE_REQUEST_STATE_STARTED && | |
926 | request->has_started_substate_machine == false) | |
927 | return scic_sds_request_started_state_tc_completion_handler(request, completion_code); | |
928 | else if (request->state_handlers->tc_completion_handler) | |
929 | return request->state_handlers->tc_completion_handler(request, completion_code); | |
930 | ||
931 | dev_warn(scic_to_dev(request->owning_controller), | |
932 | "%s: SCIC IO Request given task completion notification %x " | |
933 | "while in wrong state %d\n", | |
934 | __func__, | |
935 | completion_code, | |
936 | sci_base_state_machine_get_state(&request->state_machine)); | |
937 | ||
938 | return SCI_FAILURE_INVALID_STATE; | |
939 | ||
940 | } | |
941 | ||
942 | ||
6f231dda DW |
943 | /** |
944 | * | |
e2023b87 | 945 | * @sci_req: The SCIC_SDS_IO_REQUEST_T object for which the start |
6f231dda DW |
946 | * operation is to be executed. |
947 | * @frame_index: The frame index returned by the hardware for the reqeust | |
948 | * object. | |
949 | * | |
950 | * This method invokes the core state frame handler for the | |
951 | * SCIC_SDS_IO_REQUEST_T object. enum sci_status | |
952 | */ | |
953 | enum sci_status scic_sds_io_request_frame_handler( | |
524b5f72 | 954 | struct scic_sds_request *request, |
6f231dda DW |
955 | u32 frame_index) |
956 | { | |
524b5f72 CH |
957 | if (request->state_handlers->frame_handler) |
958 | return request->state_handlers->frame_handler(request, frame_index); | |
959 | ||
960 | dev_warn(scic_to_dev(request->owning_controller), | |
961 | "%s: SCIC IO Request given unexpected frame %x while in " | |
962 | "state %d\n", | |
963 | __func__, | |
964 | frame_index, | |
965 | sci_base_state_machine_get_state(&request->state_machine)); | |
966 | ||
967 | scic_sds_controller_release_frame(request->owning_controller, frame_index); | |
968 | return SCI_FAILURE_INVALID_STATE; | |
6f231dda DW |
969 | } |
970 | ||
971 | /** | |
972 | * | |
e2023b87 | 973 | * @sci_req: The SCIC_SDS_IO_REQUEST_T object for which the task start |
6f231dda DW |
974 | * operation is to be executed. |
975 | * | |
976 | * This method invokes the core state task complete handler for the | |
977 | * SCIC_SDS_IO_REQUEST_T object. enum sci_status | |
978 | */ | |
979 | ||
980 | /* | |
981 | * **************************************************************************** | |
982 | * * SCIC SDS PROTECTED METHODS | |
983 | * **************************************************************************** */ | |
984 | ||
985 | /** | |
986 | * This method copies response data for requests returning response data | |
987 | * instead of sense data. | |
e2023b87 | 988 | * @sci_req: This parameter specifies the request object for which to copy |
6f231dda DW |
989 | * the response data. |
990 | * | |
991 | */ | |
7392d275 | 992 | void scic_sds_io_request_copy_response(struct scic_sds_request *sds_request) |
6f231dda DW |
993 | { |
994 | void *response_buffer; | |
995 | u32 user_response_length; | |
996 | u32 core_response_length; | |
997 | struct sci_ssp_response_iu *ssp_response; | |
890cae9b | 998 | struct isci_request *isci_request = sds_request->ireq; |
6f231dda | 999 | |
7392d275 DJ |
1000 | ssp_response = |
1001 | (struct sci_ssp_response_iu *)sds_request->response_buffer; | |
6f231dda | 1002 | |
7392d275 DJ |
1003 | response_buffer = |
1004 | isci_task_ssp_request_get_response_data_address( | |
1005 | isci_request); | |
6f231dda | 1006 | |
7392d275 DJ |
1007 | user_response_length = |
1008 | isci_task_ssp_request_get_response_data_length( | |
1009 | isci_request); | |
6f231dda DW |
1010 | |
1011 | core_response_length = sci_ssp_get_response_data_length( | |
7392d275 | 1012 | ssp_response->response_data_length); |
6f231dda DW |
1013 | |
1014 | user_response_length = min(user_response_length, core_response_length); | |
1015 | ||
1016 | memcpy(response_buffer, ssp_response->data, user_response_length); | |
1017 | } | |
1018 | ||
6f231dda DW |
1019 | /* |
1020 | * ***************************************************************************** | |
1021 | * * CONSTRUCTED STATE HANDLERS | |
1022 | * ***************************************************************************** */ | |
1023 | ||
38aa74eb | 1024 | /* |
6f231dda DW |
1025 | * This method implements the action taken when a constructed |
1026 | * SCIC_SDS_IO_REQUEST_T object receives a scic_sds_request_start() request. | |
1027 | * This method will, if necessary, allocate a TCi for the io request object and | |
1028 | * then will, if necessary, copy the constructed TC data into the actual TC | |
1029 | * buffer. If everything is successful the post context field is updated with | |
1030 | * the TCi so the controller can post the request to the hardware. enum sci_status | |
1031 | * SCI_SUCCESS SCI_FAILURE_INSUFFICIENT_RESOURCES | |
1032 | */ | |
1033 | static enum sci_status scic_sds_request_constructed_state_start_handler( | |
38aa74eb | 1034 | struct scic_sds_request *request) |
6f231dda DW |
1035 | { |
1036 | struct scu_task_context *task_context; | |
6f231dda | 1037 | |
38aa74eb CH |
1038 | if (request->io_tag == SCI_CONTROLLER_INVALID_IO_TAG) { |
1039 | request->io_tag = | |
1040 | scic_controller_allocate_io_tag(request->owning_controller); | |
6f231dda DW |
1041 | } |
1042 | ||
1043 | /* Record the IO Tag in the request */ | |
38aa74eb CH |
1044 | if (request->io_tag != SCI_CONTROLLER_INVALID_IO_TAG) { |
1045 | task_context = request->task_context_buffer; | |
6f231dda | 1046 | |
38aa74eb | 1047 | task_context->task_index = scic_sds_io_tag_get_index(request->io_tag); |
6f231dda DW |
1048 | |
1049 | switch (task_context->protocol_type) { | |
1050 | case SCU_TASK_CONTEXT_PROTOCOL_SMP: | |
1051 | case SCU_TASK_CONTEXT_PROTOCOL_SSP: | |
1052 | /* SSP/SMP Frame */ | |
38aa74eb | 1053 | task_context->type.ssp.tag = request->io_tag; |
6f231dda DW |
1054 | task_context->type.ssp.target_port_transfer_tag = 0xFFFF; |
1055 | break; | |
1056 | ||
1057 | case SCU_TASK_CONTEXT_PROTOCOL_STP: | |
1058 | /* | |
1059 | * STP/SATA Frame | |
38aa74eb | 1060 | * task_context->type.stp.ncq_tag = request->ncq_tag; */ |
6f231dda DW |
1061 | break; |
1062 | ||
1063 | case SCU_TASK_CONTEXT_PROTOCOL_NONE: | |
1064 | /* / @todo When do we set no protocol type? */ | |
1065 | break; | |
1066 | ||
1067 | default: | |
1068 | /* This should never happen since we build the IO requests */ | |
1069 | break; | |
1070 | } | |
1071 | ||
1072 | /* | |
1073 | * Check to see if we need to copy the task context buffer | |
1074 | * or have been building into the task context buffer */ | |
38aa74eb | 1075 | if (request->was_tag_assigned_by_user == false) { |
6f231dda | 1076 | scic_sds_controller_copy_task_context( |
38aa74eb | 1077 | request->owning_controller, request); |
6f231dda DW |
1078 | } |
1079 | ||
1080 | /* Add to the post_context the io tag value */ | |
38aa74eb | 1081 | request->post_context |= scic_sds_io_tag_get_index(request->io_tag); |
6f231dda DW |
1082 | |
1083 | /* Everything is good go ahead and change state */ | |
38aa74eb CH |
1084 | sci_base_state_machine_change_state(&request->state_machine, |
1085 | SCI_BASE_REQUEST_STATE_STARTED); | |
6f231dda DW |
1086 | |
1087 | return SCI_SUCCESS; | |
1088 | } | |
1089 | ||
1090 | return SCI_FAILURE_INSUFFICIENT_RESOURCES; | |
1091 | } | |
1092 | ||
38aa74eb | 1093 | /* |
6f231dda DW |
1094 | * This method implements the action to be taken when an SCIC_SDS_IO_REQUEST_T |
1095 | * object receives a scic_sds_request_terminate() request. Since the request | |
1096 | * has not yet been posted to the hardware the request transitions to the | |
1097 | * completed state. enum sci_status SCI_SUCCESS | |
1098 | */ | |
1099 | static enum sci_status scic_sds_request_constructed_state_abort_handler( | |
38aa74eb | 1100 | struct scic_sds_request *request) |
6f231dda | 1101 | { |
6f231dda DW |
1102 | /* |
1103 | * This request has been terminated by the user make sure that the correct | |
1104 | * status code is returned */ | |
38aa74eb | 1105 | scic_sds_request_set_status(request, |
6f231dda | 1106 | SCU_TASK_DONE_TASK_ABORT, |
38aa74eb | 1107 | SCI_FAILURE_IO_TERMINATED); |
6f231dda | 1108 | |
38aa74eb CH |
1109 | sci_base_state_machine_change_state(&request->state_machine, |
1110 | SCI_BASE_REQUEST_STATE_COMPLETED); | |
6f231dda DW |
1111 | return SCI_SUCCESS; |
1112 | } | |
1113 | ||
1114 | /* | |
1115 | * ***************************************************************************** | |
1116 | * * STARTED STATE HANDLERS | |
1117 | * ***************************************************************************** */ | |
1118 | ||
38aa74eb | 1119 | /* |
6f231dda DW |
1120 | * This method implements the action to be taken when an SCIC_SDS_IO_REQUEST_T |
1121 | * object receives a scic_sds_request_terminate() request. Since the request | |
1122 | * has been posted to the hardware the io request state is changed to the | |
1123 | * aborting state. enum sci_status SCI_SUCCESS | |
1124 | */ | |
1125 | enum sci_status scic_sds_request_started_state_abort_handler( | |
38aa74eb | 1126 | struct scic_sds_request *request) |
6f231dda | 1127 | { |
38aa74eb CH |
1128 | if (request->has_started_substate_machine) |
1129 | sci_base_state_machine_stop(&request->started_substate_machine); | |
6f231dda | 1130 | |
38aa74eb CH |
1131 | sci_base_state_machine_change_state(&request->state_machine, |
1132 | SCI_BASE_REQUEST_STATE_ABORTING); | |
6f231dda DW |
1133 | return SCI_SUCCESS; |
1134 | } | |
1135 | ||
1136 | /** | |
1137 | * scic_sds_request_started_state_tc_completion_handler() - This method process | |
1138 | * TC (task context) completions for normal IO request (i.e. Task/Abort | |
1139 | * Completions of type 0). This method will update the | |
1140 | * SCIC_SDS_IO_REQUEST_T::status field. | |
e2023b87 | 1141 | * @sci_req: This parameter specifies the request for which a completion |
6f231dda DW |
1142 | * occurred. |
1143 | * @completion_code: This parameter specifies the completion code received from | |
1144 | * the SCU. | |
1145 | * | |
1146 | */ | |
1147 | enum sci_status scic_sds_request_started_state_tc_completion_handler( | |
e2023b87 | 1148 | struct scic_sds_request *sci_req, |
6f231dda DW |
1149 | u32 completion_code) |
1150 | { | |
1151 | u8 data_present; | |
1152 | struct sci_ssp_response_iu *response_buffer; | |
1153 | ||
1154 | /** | |
1155 | * @todo Any SDMA return code of other than 0 is bad | |
1156 | * decode 0x003C0000 to determine SDMA status | |
1157 | */ | |
1158 | switch (SCU_GET_COMPLETION_TL_STATUS(completion_code)) { | |
1159 | case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_GOOD): | |
1160 | scic_sds_request_set_status( | |
e2023b87 | 1161 | sci_req, SCU_TASK_DONE_GOOD, SCI_SUCCESS |
6f231dda DW |
1162 | ); |
1163 | break; | |
1164 | ||
1165 | case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_EARLY_RESP): | |
1166 | { | |
1167 | /* | |
1168 | * There are times when the SCU hardware will return an early response | |
1169 | * because the io request specified more data than is returned by the | |
1170 | * target device (mode pages, inquiry data, etc.). We must check the | |
1171 | * response stats to see if this is truly a failed request or a good | |
1172 | * request that just got completed early. */ | |
1173 | struct sci_ssp_response_iu *response = (struct sci_ssp_response_iu *) | |
e2023b87 | 1174 | sci_req->response_buffer; |
6f231dda | 1175 | scic_word_copy_with_swap( |
e2023b87 DJ |
1176 | sci_req->response_buffer, |
1177 | sci_req->response_buffer, | |
6f231dda DW |
1178 | sizeof(struct sci_ssp_response_iu) / sizeof(u32) |
1179 | ); | |
1180 | ||
1181 | if (response->status == 0) { | |
1182 | scic_sds_request_set_status( | |
e2023b87 | 1183 | sci_req, SCU_TASK_DONE_GOOD, SCI_SUCCESS_IO_DONE_EARLY |
6f231dda DW |
1184 | ); |
1185 | } else { | |
1186 | scic_sds_request_set_status( | |
e2023b87 | 1187 | sci_req, |
6f231dda DW |
1188 | SCU_TASK_DONE_CHECK_RESPONSE, |
1189 | SCI_FAILURE_IO_RESPONSE_VALID | |
1190 | ); | |
1191 | } | |
1192 | } | |
1193 | break; | |
1194 | ||
1195 | case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_CHECK_RESPONSE): | |
1196 | scic_word_copy_with_swap( | |
e2023b87 DJ |
1197 | sci_req->response_buffer, |
1198 | sci_req->response_buffer, | |
6f231dda DW |
1199 | sizeof(struct sci_ssp_response_iu) / sizeof(u32) |
1200 | ); | |
1201 | ||
1202 | scic_sds_request_set_status( | |
e2023b87 | 1203 | sci_req, |
6f231dda DW |
1204 | SCU_TASK_DONE_CHECK_RESPONSE, |
1205 | SCI_FAILURE_IO_RESPONSE_VALID | |
1206 | ); | |
1207 | break; | |
1208 | ||
1209 | case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_RESP_LEN_ERR): | |
1210 | /* | |
1211 | * / @todo With TASK_DONE_RESP_LEN_ERR is the response frame guaranteed | |
1212 | * / to be received before this completion status is posted? */ | |
1213 | response_buffer = | |
e2023b87 | 1214 | (struct sci_ssp_response_iu *)sci_req->response_buffer; |
6f231dda DW |
1215 | data_present = |
1216 | response_buffer->data_present & SCI_SSP_RESPONSE_IU_DATA_PRESENT_MASK; | |
1217 | ||
1218 | if ((data_present == 0x01) || (data_present == 0x02)) { | |
1219 | scic_sds_request_set_status( | |
e2023b87 | 1220 | sci_req, |
6f231dda DW |
1221 | SCU_TASK_DONE_CHECK_RESPONSE, |
1222 | SCI_FAILURE_IO_RESPONSE_VALID | |
1223 | ); | |
1224 | } else { | |
1225 | scic_sds_request_set_status( | |
e2023b87 | 1226 | sci_req, SCU_TASK_DONE_GOOD, SCI_SUCCESS |
6f231dda DW |
1227 | ); |
1228 | } | |
1229 | break; | |
1230 | ||
1231 | /* only stp device gets suspended. */ | |
1232 | case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_ACK_NAK_TO): | |
1233 | case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_LL_PERR): | |
1234 | case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_NAK_ERR): | |
1235 | case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_DATA_LEN_ERR): | |
1236 | case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_LL_ABORT_ERR): | |
1237 | case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_XR_WD_LEN): | |
1238 | case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_MAX_PLD_ERR): | |
1239 | case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_UNEXP_RESP): | |
1240 | case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_UNEXP_SDBFIS): | |
1241 | case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_REG_ERR): | |
1242 | case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_SDB_ERR): | |
e2023b87 | 1243 | if (sci_req->protocol == SCIC_STP_PROTOCOL) { |
6f231dda | 1244 | scic_sds_request_set_status( |
e2023b87 | 1245 | sci_req, |
6f231dda DW |
1246 | SCU_GET_COMPLETION_TL_STATUS(completion_code) >> SCU_COMPLETION_TL_STATUS_SHIFT, |
1247 | SCI_FAILURE_REMOTE_DEVICE_RESET_REQUIRED | |
1248 | ); | |
1249 | } else { | |
1250 | scic_sds_request_set_status( | |
e2023b87 | 1251 | sci_req, |
6f231dda DW |
1252 | SCU_GET_COMPLETION_TL_STATUS(completion_code) >> SCU_COMPLETION_TL_STATUS_SHIFT, |
1253 | SCI_FAILURE_CONTROLLER_SPECIFIC_IO_ERR | |
1254 | ); | |
1255 | } | |
1256 | break; | |
1257 | ||
1258 | /* both stp/ssp device gets suspended */ | |
1259 | case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_LF_ERR): | |
1260 | case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_OPEN_REJECT_WRONG_DESTINATION): | |
1261 | case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_OPEN_REJECT_RESERVED_ABANDON_1): | |
1262 | case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_OPEN_REJECT_RESERVED_ABANDON_2): | |
1263 | case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_OPEN_REJECT_RESERVED_ABANDON_3): | |
1264 | case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_OPEN_REJECT_BAD_DESTINATION): | |
1265 | case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_OPEN_REJECT_ZONE_VIOLATION): | |
1266 | case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_OPEN_REJECT_STP_RESOURCES_BUSY): | |
1267 | case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_OPEN_REJECT_PROTOCOL_NOT_SUPPORTED): | |
1268 | case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_OPEN_REJECT_CONNECTION_RATE_NOT_SUPPORTED): | |
1269 | scic_sds_request_set_status( | |
e2023b87 | 1270 | sci_req, |
6f231dda DW |
1271 | SCU_GET_COMPLETION_TL_STATUS(completion_code) >> SCU_COMPLETION_TL_STATUS_SHIFT, |
1272 | SCI_FAILURE_REMOTE_DEVICE_RESET_REQUIRED | |
1273 | ); | |
1274 | break; | |
1275 | ||
1276 | /* neither ssp nor stp gets suspended. */ | |
1277 | case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_NAK_CMD_ERR): | |
1278 | case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_UNEXP_XR): | |
1279 | case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_XR_IU_LEN_ERR): | |
1280 | case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_SDMA_ERR): | |
1281 | case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_OFFSET_ERR): | |
1282 | case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_EXCESS_DATA): | |
1283 | case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_SMP_RESP_TO_ERR): | |
1284 | case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_SMP_UFI_ERR): | |
1285 | case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_SMP_FRM_TYPE_ERR): | |
1286 | case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_SMP_LL_RX_ERR): | |
1287 | case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_UNEXP_DATA): | |
1288 | case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_OPEN_FAIL): | |
1289 | case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_VIIT_ENTRY_NV): | |
1290 | case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_IIT_ENTRY_NV): | |
1291 | case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_RNCNV_OUTBOUND): | |
1292 | default: | |
1293 | scic_sds_request_set_status( | |
e2023b87 | 1294 | sci_req, |
6f231dda DW |
1295 | SCU_GET_COMPLETION_TL_STATUS(completion_code) >> SCU_COMPLETION_TL_STATUS_SHIFT, |
1296 | SCI_FAILURE_CONTROLLER_SPECIFIC_IO_ERR | |
1297 | ); | |
1298 | break; | |
1299 | } | |
1300 | ||
1301 | /** | |
1302 | * @todo This is probably wrong for ACK/NAK timeout conditions | |
1303 | */ | |
1304 | ||
1305 | /* In all cases we will treat this as the completion of the IO request. */ | |
e2023b87 | 1306 | sci_base_state_machine_change_state(&sci_req->state_machine, |
38aa74eb | 1307 | SCI_BASE_REQUEST_STATE_COMPLETED); |
6f231dda DW |
1308 | return SCI_SUCCESS; |
1309 | } | |
1310 | ||
38aa74eb | 1311 | /* |
6f231dda DW |
1312 | * This method implements the action to be taken when an SCIC_SDS_IO_REQUEST_T |
1313 | * object receives a scic_sds_request_frame_handler() request. This method | |
1314 | * first determines the frame type received. If this is a response frame then | |
1315 | * the response data is copied to the io request response buffer for processing | |
1316 | * at completion time. If the frame type is not a response buffer an error is | |
1317 | * logged. enum sci_status SCI_SUCCESS SCI_FAILURE_INVALID_PARAMETER_VALUE | |
1318 | */ | |
1319 | static enum sci_status scic_sds_request_started_state_frame_handler( | |
e2023b87 | 1320 | struct scic_sds_request *sci_req, |
6f231dda DW |
1321 | u32 frame_index) |
1322 | { | |
1323 | enum sci_status status; | |
1324 | struct sci_ssp_frame_header *frame_header; | |
1325 | ||
1326 | /* / @todo If this is a response frame we must record that we received it */ | |
1327 | status = scic_sds_unsolicited_frame_control_get_header( | |
e2023b87 | 1328 | &(scic_sds_request_get_controller(sci_req)->uf_control), |
6f231dda DW |
1329 | frame_index, |
1330 | (void **)&frame_header | |
1331 | ); | |
1332 | ||
1333 | if (frame_header->frame_type == SCI_SAS_RESPONSE_FRAME) { | |
1334 | struct sci_ssp_response_iu *response_buffer; | |
1335 | ||
1336 | status = scic_sds_unsolicited_frame_control_get_buffer( | |
e2023b87 | 1337 | &(scic_sds_request_get_controller(sci_req)->uf_control), |
6f231dda DW |
1338 | frame_index, |
1339 | (void **)&response_buffer | |
1340 | ); | |
1341 | ||
1342 | scic_word_copy_with_swap( | |
e2023b87 | 1343 | sci_req->response_buffer, |
6f231dda DW |
1344 | (u32 *)response_buffer, |
1345 | sizeof(struct sci_ssp_response_iu) | |
1346 | ); | |
1347 | ||
e2023b87 | 1348 | response_buffer = (struct sci_ssp_response_iu *)sci_req->response_buffer; |
6f231dda DW |
1349 | |
1350 | if ((response_buffer->data_present == 0x01) || | |
1351 | (response_buffer->data_present == 0x02)) { | |
1352 | scic_sds_request_set_status( | |
e2023b87 | 1353 | sci_req, |
6f231dda DW |
1354 | SCU_TASK_DONE_CHECK_RESPONSE, |
1355 | SCI_FAILURE_CONTROLLER_SPECIFIC_IO_ERR | |
1356 | ); | |
1357 | } else | |
1358 | scic_sds_request_set_status( | |
e2023b87 | 1359 | sci_req, SCU_TASK_DONE_GOOD, SCI_SUCCESS |
6f231dda DW |
1360 | ); |
1361 | } else | |
1362 | /* This was not a response frame why did it get forwarded? */ | |
e2023b87 | 1363 | dev_err(scic_to_dev(sci_req->owning_controller), |
6f231dda DW |
1364 | "%s: SCIC IO Request 0x%p received unexpected " |
1365 | "frame %d type 0x%02x\n", | |
1366 | __func__, | |
e2023b87 | 1367 | sci_req, |
6f231dda DW |
1368 | frame_index, |
1369 | frame_header->frame_type); | |
1370 | ||
1371 | /* | |
1372 | * In any case we are done with this frame buffer return it to the | |
1373 | * controller */ | |
1374 | scic_sds_controller_release_frame( | |
e2023b87 | 1375 | sci_req->owning_controller, frame_index |
6f231dda DW |
1376 | ); |
1377 | ||
1378 | return SCI_SUCCESS; | |
1379 | } | |
1380 | ||
1381 | /* | |
1382 | * ***************************************************************************** | |
1383 | * * COMPLETED STATE HANDLERS | |
1384 | * ***************************************************************************** */ | |
1385 | ||
1386 | ||
38aa74eb | 1387 | /* |
6f231dda DW |
1388 | * This method implements the action to be taken when an SCIC_SDS_IO_REQUEST_T |
1389 | * object receives a scic_sds_request_complete() request. This method frees up | |
1390 | * any io request resources that have been allocated and transitions the | |
1391 | * request to its final state. Consider stopping the state machine instead of | |
1392 | * transitioning to the final state? enum sci_status SCI_SUCCESS | |
1393 | */ | |
1394 | static enum sci_status scic_sds_request_completed_state_complete_handler( | |
38aa74eb | 1395 | struct scic_sds_request *request) |
6f231dda | 1396 | { |
38aa74eb | 1397 | if (request->was_tag_assigned_by_user != true) { |
6f231dda | 1398 | scic_controller_free_io_tag( |
38aa74eb | 1399 | request->owning_controller, request->io_tag); |
6f231dda DW |
1400 | } |
1401 | ||
38aa74eb | 1402 | if (request->saved_rx_frame_index != SCU_INVALID_FRAME_INDEX) { |
6f231dda | 1403 | scic_sds_controller_release_frame( |
38aa74eb | 1404 | request->owning_controller, request->saved_rx_frame_index); |
6f231dda DW |
1405 | } |
1406 | ||
38aa74eb CH |
1407 | sci_base_state_machine_change_state(&request->state_machine, |
1408 | SCI_BASE_REQUEST_STATE_FINAL); | |
6f231dda DW |
1409 | return SCI_SUCCESS; |
1410 | } | |
1411 | ||
1412 | /* | |
1413 | * ***************************************************************************** | |
1414 | * * ABORTING STATE HANDLERS | |
1415 | * ***************************************************************************** */ | |
1416 | ||
38aa74eb | 1417 | /* |
6f231dda DW |
1418 | * This method implements the action to be taken when an SCIC_SDS_IO_REQUEST_T |
1419 | * object receives a scic_sds_request_terminate() request. This method is the | |
1420 | * io request aborting state abort handlers. On receipt of a multiple | |
1421 | * terminate requests the io request will transition to the completed state. | |
1422 | * This should not happen in normal operation. enum sci_status SCI_SUCCESS | |
1423 | */ | |
1424 | static enum sci_status scic_sds_request_aborting_state_abort_handler( | |
38aa74eb | 1425 | struct scic_sds_request *request) |
6f231dda | 1426 | { |
38aa74eb CH |
1427 | sci_base_state_machine_change_state(&request->state_machine, |
1428 | SCI_BASE_REQUEST_STATE_COMPLETED); | |
6f231dda DW |
1429 | return SCI_SUCCESS; |
1430 | } | |
1431 | ||
38aa74eb | 1432 | /* |
6f231dda DW |
1433 | * This method implements the action to be taken when an SCIC_SDS_IO_REQUEST_T |
1434 | * object receives a scic_sds_request_task_completion() request. This method | |
1435 | * decodes the completion type waiting for the abort task complete | |
1436 | * notification. When the abort task complete is received the io request | |
1437 | * transitions to the completed state. enum sci_status SCI_SUCCESS | |
1438 | */ | |
1439 | static enum sci_status scic_sds_request_aborting_state_tc_completion_handler( | |
e2023b87 | 1440 | struct scic_sds_request *sci_req, |
6f231dda DW |
1441 | u32 completion_code) |
1442 | { | |
1443 | switch (SCU_GET_COMPLETION_TL_STATUS(completion_code)) { | |
1444 | case (SCU_TASK_DONE_GOOD << SCU_COMPLETION_TL_STATUS_SHIFT): | |
1445 | case (SCU_TASK_DONE_TASK_ABORT << SCU_COMPLETION_TL_STATUS_SHIFT): | |
1446 | scic_sds_request_set_status( | |
e2023b87 | 1447 | sci_req, SCU_TASK_DONE_TASK_ABORT, SCI_FAILURE_IO_TERMINATED |
6f231dda DW |
1448 | ); |
1449 | ||
e2023b87 | 1450 | sci_base_state_machine_change_state(&sci_req->state_machine, |
38aa74eb | 1451 | SCI_BASE_REQUEST_STATE_COMPLETED); |
6f231dda DW |
1452 | break; |
1453 | ||
1454 | default: | |
1455 | /* | |
1456 | * Unless we get some strange error wait for the task abort to complete | |
1457 | * TODO: Should there be a state change for this completion? */ | |
1458 | break; | |
1459 | } | |
1460 | ||
1461 | return SCI_SUCCESS; | |
1462 | } | |
1463 | ||
38aa74eb | 1464 | /* |
6f231dda DW |
1465 | * This method implements the action to be taken when an SCIC_SDS_IO_REQUEST_T |
1466 | * object receives a scic_sds_request_frame_handler() request. This method | |
1467 | * discards the unsolicited frame since we are waiting for the abort task | |
1468 | * completion. enum sci_status SCI_SUCCESS | |
1469 | */ | |
1470 | static enum sci_status scic_sds_request_aborting_state_frame_handler( | |
e2023b87 | 1471 | struct scic_sds_request *sci_req, |
6f231dda DW |
1472 | u32 frame_index) |
1473 | { | |
1474 | /* TODO: Is it even possible to get an unsolicited frame in the aborting state? */ | |
1475 | ||
1476 | scic_sds_controller_release_frame( | |
e2023b87 | 1477 | sci_req->owning_controller, frame_index); |
6f231dda DW |
1478 | |
1479 | return SCI_SUCCESS; | |
1480 | } | |
1481 | ||
35173d57 | 1482 | static const struct scic_sds_io_request_state_handler scic_sds_request_state_handler_table[] = { |
6f231dda | 1483 | [SCI_BASE_REQUEST_STATE_INITIAL] = { |
6f231dda DW |
1484 | }, |
1485 | [SCI_BASE_REQUEST_STATE_CONSTRUCTED] = { | |
38aa74eb CH |
1486 | .start_handler = scic_sds_request_constructed_state_start_handler, |
1487 | .abort_handler = scic_sds_request_constructed_state_abort_handler, | |
6f231dda DW |
1488 | }, |
1489 | [SCI_BASE_REQUEST_STATE_STARTED] = { | |
38aa74eb | 1490 | .abort_handler = scic_sds_request_started_state_abort_handler, |
38aa74eb | 1491 | .tc_completion_handler = scic_sds_request_started_state_tc_completion_handler, |
38aa74eb | 1492 | .frame_handler = scic_sds_request_started_state_frame_handler, |
6f231dda DW |
1493 | }, |
1494 | [SCI_BASE_REQUEST_STATE_COMPLETED] = { | |
38aa74eb | 1495 | .complete_handler = scic_sds_request_completed_state_complete_handler, |
6f231dda DW |
1496 | }, |
1497 | [SCI_BASE_REQUEST_STATE_ABORTING] = { | |
38aa74eb | 1498 | .abort_handler = scic_sds_request_aborting_state_abort_handler, |
38aa74eb | 1499 | .tc_completion_handler = scic_sds_request_aborting_state_tc_completion_handler, |
38aa74eb | 1500 | .frame_handler = scic_sds_request_aborting_state_frame_handler, |
6f231dda DW |
1501 | }, |
1502 | [SCI_BASE_REQUEST_STATE_FINAL] = { | |
6f231dda DW |
1503 | }, |
1504 | }; | |
1505 | ||
1506 | /** | |
1507 | * scic_sds_request_initial_state_enter() - | |
1508 | * @object: This parameter specifies the base object for which the state | |
1509 | * transition is occurring. | |
1510 | * | |
1511 | * This method implements the actions taken when entering the | |
1512 | * SCI_BASE_REQUEST_STATE_INITIAL state. This state is entered when the initial | |
1513 | * base request is constructed. Entry into the initial state sets all handlers | |
1514 | * for the io request object to their default handlers. none | |
1515 | */ | |
9a0fff7b | 1516 | static void scic_sds_request_initial_state_enter(void *object) |
6f231dda | 1517 | { |
890cae9b | 1518 | struct scic_sds_request *sci_req = object; |
6f231dda DW |
1519 | |
1520 | SET_STATE_HANDLER( | |
e2023b87 | 1521 | sci_req, |
6f231dda DW |
1522 | scic_sds_request_state_handler_table, |
1523 | SCI_BASE_REQUEST_STATE_INITIAL | |
1524 | ); | |
1525 | } | |
1526 | ||
1527 | /** | |
1528 | * scic_sds_request_constructed_state_enter() - | |
1529 | * @object: The io request object that is to enter the constructed state. | |
1530 | * | |
1531 | * This method implements the actions taken when entering the | |
1532 | * SCI_BASE_REQUEST_STATE_CONSTRUCTED state. The method sets the state handlers | |
1533 | * for the the constructed state. none | |
1534 | */ | |
9a0fff7b | 1535 | static void scic_sds_request_constructed_state_enter(void *object) |
6f231dda | 1536 | { |
890cae9b | 1537 | struct scic_sds_request *sci_req = object; |
6f231dda DW |
1538 | |
1539 | SET_STATE_HANDLER( | |
e2023b87 | 1540 | sci_req, |
6f231dda DW |
1541 | scic_sds_request_state_handler_table, |
1542 | SCI_BASE_REQUEST_STATE_CONSTRUCTED | |
1543 | ); | |
1544 | } | |
1545 | ||
1546 | /** | |
1547 | * scic_sds_request_started_state_enter() - | |
1548 | * @object: This parameter specifies the base object for which the state | |
9a0fff7b | 1549 | * transition is occurring. This is cast into a SCIC_SDS_IO_REQUEST object. |
6f231dda DW |
1550 | * |
1551 | * This method implements the actions taken when entering the | |
1552 | * SCI_BASE_REQUEST_STATE_STARTED state. If the io request object type is a | |
1553 | * SCSI Task request we must enter the started substate machine. none | |
1554 | */ | |
9a0fff7b | 1555 | static void scic_sds_request_started_state_enter(void *object) |
6f231dda | 1556 | { |
890cae9b | 1557 | struct scic_sds_request *sci_req = object; |
6f231dda DW |
1558 | |
1559 | SET_STATE_HANDLER( | |
e2023b87 | 1560 | sci_req, |
6f231dda DW |
1561 | scic_sds_request_state_handler_table, |
1562 | SCI_BASE_REQUEST_STATE_STARTED | |
1563 | ); | |
1564 | ||
1565 | /* | |
1566 | * Most of the request state machines have a started substate machine so | |
1567 | * start its execution on the entry to the started state. */ | |
e2023b87 DJ |
1568 | if (sci_req->has_started_substate_machine == true) |
1569 | sci_base_state_machine_start(&sci_req->started_substate_machine); | |
6f231dda DW |
1570 | } |
1571 | ||
1572 | /** | |
1573 | * scic_sds_request_started_state_exit() - | |
1574 | * @object: This parameter specifies the base object for which the state | |
9a0fff7b | 1575 | * transition is occurring. This object is cast into a SCIC_SDS_IO_REQUEST |
6f231dda DW |
1576 | * object. |
1577 | * | |
1578 | * This method implements the actions taken when exiting the | |
1579 | * SCI_BASE_REQUEST_STATE_STARTED state. For task requests the action will be | |
1580 | * to stop the started substate machine. none | |
1581 | */ | |
9a0fff7b | 1582 | static void scic_sds_request_started_state_exit(void *object) |
6f231dda | 1583 | { |
890cae9b | 1584 | struct scic_sds_request *sci_req = object; |
6f231dda | 1585 | |
e2023b87 DJ |
1586 | if (sci_req->has_started_substate_machine == true) |
1587 | sci_base_state_machine_stop(&sci_req->started_substate_machine); | |
6f231dda DW |
1588 | } |
1589 | ||
1590 | /** | |
1591 | * scic_sds_request_completed_state_enter() - | |
1592 | * @object: This parameter specifies the base object for which the state | |
9a0fff7b | 1593 | * transition is occurring. This object is cast into a SCIC_SDS_IO_REQUEST |
6f231dda DW |
1594 | * object. |
1595 | * | |
1596 | * This method implements the actions taken when entering the | |
1597 | * SCI_BASE_REQUEST_STATE_COMPLETED state. This state is entered when the | |
1598 | * SCIC_SDS_IO_REQUEST has completed. The method will decode the request | |
1599 | * completion status and convert it to an enum sci_status to return in the | |
1600 | * completion callback function. none | |
1601 | */ | |
9a0fff7b | 1602 | static void scic_sds_request_completed_state_enter(void *object) |
6f231dda | 1603 | { |
890cae9b | 1604 | struct scic_sds_request *sci_req = object; |
09d7da13 DJ |
1605 | struct scic_sds_controller *scic = |
1606 | scic_sds_request_get_controller(sci_req); | |
d3757c3a | 1607 | struct isci_host *ihost = scic->ihost; |
890cae9b | 1608 | struct isci_request *ireq = sci_req->ireq; |
6f231dda | 1609 | |
09d7da13 DJ |
1610 | SET_STATE_HANDLER(sci_req, |
1611 | scic_sds_request_state_handler_table, | |
1612 | SCI_BASE_REQUEST_STATE_COMPLETED); | |
6f231dda DW |
1613 | |
1614 | /* Tell the SCI_USER that the IO request is complete */ | |
09d7da13 DJ |
1615 | if (sci_req->is_task_management_request == false) |
1616 | isci_request_io_request_complete(ihost, | |
1617 | ireq, | |
1618 | sci_req->sci_status); | |
1619 | else | |
1620 | isci_task_request_complete(ihost, ireq, sci_req->sci_status); | |
6f231dda DW |
1621 | } |
1622 | ||
1623 | /** | |
1624 | * scic_sds_request_aborting_state_enter() - | |
1625 | * @object: This parameter specifies the base object for which the state | |
9a0fff7b | 1626 | * transition is occurring. This object is cast into a SCIC_SDS_IO_REQUEST |
6f231dda DW |
1627 | * object. |
1628 | * | |
1629 | * This method implements the actions taken when entering the | |
1630 | * SCI_BASE_REQUEST_STATE_ABORTING state. none | |
1631 | */ | |
9a0fff7b | 1632 | static void scic_sds_request_aborting_state_enter(void *object) |
6f231dda | 1633 | { |
890cae9b | 1634 | struct scic_sds_request *sci_req = object; |
6f231dda DW |
1635 | |
1636 | /* Setting the abort bit in the Task Context is required by the silicon. */ | |
e2023b87 | 1637 | sci_req->task_context_buffer->abort = 1; |
6f231dda DW |
1638 | |
1639 | SET_STATE_HANDLER( | |
e2023b87 | 1640 | sci_req, |
6f231dda DW |
1641 | scic_sds_request_state_handler_table, |
1642 | SCI_BASE_REQUEST_STATE_ABORTING | |
1643 | ); | |
1644 | } | |
1645 | ||
1646 | /** | |
1647 | * scic_sds_request_final_state_enter() - | |
1648 | * @object: This parameter specifies the base object for which the state | |
9a0fff7b | 1649 | * transition is occurring. This is cast into a SCIC_SDS_IO_REQUEST object. |
6f231dda DW |
1650 | * |
1651 | * This method implements the actions taken when entering the | |
1652 | * SCI_BASE_REQUEST_STATE_FINAL state. The only action required is to put the | |
1653 | * state handlers in place. none | |
1654 | */ | |
9a0fff7b | 1655 | static void scic_sds_request_final_state_enter(void *object) |
6f231dda | 1656 | { |
890cae9b | 1657 | struct scic_sds_request *sci_req = object; |
6f231dda DW |
1658 | |
1659 | SET_STATE_HANDLER( | |
e2023b87 | 1660 | sci_req, |
6f231dda DW |
1661 | scic_sds_request_state_handler_table, |
1662 | SCI_BASE_REQUEST_STATE_FINAL | |
1663 | ); | |
1664 | } | |
1665 | ||
35173d57 | 1666 | static const struct sci_base_state scic_sds_request_state_table[] = { |
6f231dda DW |
1667 | [SCI_BASE_REQUEST_STATE_INITIAL] = { |
1668 | .enter_state = scic_sds_request_initial_state_enter, | |
1669 | }, | |
1670 | [SCI_BASE_REQUEST_STATE_CONSTRUCTED] = { | |
1671 | .enter_state = scic_sds_request_constructed_state_enter, | |
1672 | }, | |
1673 | [SCI_BASE_REQUEST_STATE_STARTED] = { | |
1674 | .enter_state = scic_sds_request_started_state_enter, | |
1675 | .exit_state = scic_sds_request_started_state_exit | |
1676 | }, | |
1677 | [SCI_BASE_REQUEST_STATE_COMPLETED] = { | |
1678 | .enter_state = scic_sds_request_completed_state_enter, | |
1679 | }, | |
1680 | [SCI_BASE_REQUEST_STATE_ABORTING] = { | |
1681 | .enter_state = scic_sds_request_aborting_state_enter, | |
1682 | }, | |
1683 | [SCI_BASE_REQUEST_STATE_FINAL] = { | |
1684 | .enter_state = scic_sds_request_final_state_enter, | |
1685 | }, | |
1686 | }; | |
1687 | ||
35173d57 DW |
1688 | static void scic_sds_general_request_construct(struct scic_sds_controller *scic, |
1689 | struct scic_sds_remote_device *sci_dev, | |
1690 | u16 io_tag, | |
1691 | void *user_io_request_object, | |
1692 | struct scic_sds_request *sci_req) | |
1693 | { | |
890cae9b | 1694 | sci_base_state_machine_construct(&sci_req->state_machine, sci_req, |
38aa74eb CH |
1695 | scic_sds_request_state_table, SCI_BASE_REQUEST_STATE_INITIAL); |
1696 | sci_base_state_machine_start(&sci_req->state_machine); | |
1697 | ||
35173d57 DW |
1698 | sci_req->io_tag = io_tag; |
1699 | sci_req->user_request = user_io_request_object; | |
1700 | sci_req->owning_controller = scic; | |
1701 | sci_req->target_device = sci_dev; | |
1702 | sci_req->has_started_substate_machine = false; | |
1703 | sci_req->protocol = SCIC_NO_PROTOCOL; | |
1704 | sci_req->saved_rx_frame_index = SCU_INVALID_FRAME_INDEX; | |
1705 | sci_req->device_sequence = scic_sds_remote_device_get_sequence(sci_dev); | |
1706 | ||
1707 | sci_req->sci_status = SCI_SUCCESS; | |
1708 | sci_req->scu_status = 0; | |
1709 | sci_req->post_context = 0xFFFFFFFF; | |
1710 | ||
1711 | sci_req->is_task_management_request = false; | |
1712 | ||
1713 | if (io_tag == SCI_CONTROLLER_INVALID_IO_TAG) { | |
1714 | sci_req->was_tag_assigned_by_user = false; | |
1715 | sci_req->task_context_buffer = NULL; | |
1716 | } else { | |
1717 | sci_req->was_tag_assigned_by_user = true; | |
1718 | ||
1719 | sci_req->task_context_buffer = | |
1720 | scic_sds_controller_get_task_context_buffer(scic, io_tag); | |
1721 | } | |
1722 | } | |
1723 | ||
1724 | enum sci_status scic_io_request_construct(struct scic_sds_controller *scic, | |
1725 | struct scic_sds_remote_device *sci_dev, | |
1726 | u16 io_tag, | |
1727 | void *user_io_request_object, | |
1728 | struct scic_sds_request *sci_req, | |
1729 | struct scic_sds_request **new_scic_io_request_handle) | |
1730 | { | |
a1a113b0 | 1731 | struct domain_device *dev = sci_dev_to_domain(sci_dev); |
35173d57 | 1732 | enum sci_status status = SCI_SUCCESS; |
35173d57 DW |
1733 | |
1734 | /* Build the common part of the request */ | |
1735 | scic_sds_general_request_construct(scic, sci_dev, io_tag, | |
1736 | user_io_request_object, sci_req); | |
1737 | ||
7ab92c9e | 1738 | if (sci_dev->rnc.remote_node_index == SCIC_SDS_REMOTE_NODE_CONTEXT_INVALID_INDEX) |
35173d57 DW |
1739 | return SCI_FAILURE_INVALID_REMOTE_DEVICE; |
1740 | ||
a1a113b0 | 1741 | if (dev->dev_type == SAS_END_DEV) { |
35173d57 | 1742 | scic_sds_ssp_io_request_assign_buffers(sci_req); |
a1a113b0 | 1743 | } else if (dev->dev_type == SATA_DEV || (dev->tproto & SAS_PROTOCOL_STP)) { |
35173d57 | 1744 | scic_sds_stp_request_assign_buffers(sci_req); |
f2f30080 | 1745 | memset(sci_req->command_buffer, 0, sizeof(struct host_to_dev_fis)); |
a1a113b0 | 1746 | } else if (dev_is_expander(dev)) { |
35173d57 DW |
1747 | scic_sds_smp_request_assign_buffers(sci_req); |
1748 | memset(sci_req->command_buffer, 0, sizeof(struct smp_request)); | |
a1a113b0 | 1749 | } else |
35173d57 | 1750 | status = SCI_FAILURE_UNSUPPORTED_PROTOCOL; |
35173d57 DW |
1751 | |
1752 | if (status == SCI_SUCCESS) { | |
1753 | memset(sci_req->task_context_buffer, 0, | |
1754 | SCI_FIELD_OFFSET(struct scu_task_context, sgl_pair_ab)); | |
1755 | *new_scic_io_request_handle = sci_req; | |
1756 | } | |
1757 | ||
1758 | return status; | |
1759 | } | |
1760 | ||
1761 | enum sci_status scic_task_request_construct(struct scic_sds_controller *scic, | |
1762 | struct scic_sds_remote_device *sci_dev, | |
1763 | u16 io_tag, | |
1764 | void *user_io_request_object, | |
1765 | struct scic_sds_request *sci_req, | |
1766 | struct scic_sds_request **new_sci_req) | |
1767 | { | |
a1a113b0 | 1768 | struct domain_device *dev = sci_dev_to_domain(sci_dev); |
35173d57 | 1769 | enum sci_status status = SCI_SUCCESS; |
35173d57 DW |
1770 | |
1771 | /* Build the common part of the request */ | |
1772 | scic_sds_general_request_construct(scic, sci_dev, io_tag, | |
1773 | user_io_request_object, | |
1774 | sci_req); | |
1775 | ||
a1a113b0 | 1776 | if (dev->dev_type == SAS_END_DEV) { |
35173d57 DW |
1777 | scic_sds_ssp_task_request_assign_buffers(sci_req); |
1778 | ||
1779 | sci_req->has_started_substate_machine = true; | |
1780 | ||
1781 | /* Construct the started sub-state machine. */ | |
1782 | sci_base_state_machine_construct( | |
1783 | &sci_req->started_substate_machine, | |
890cae9b | 1784 | sci_req, |
35173d57 DW |
1785 | scic_sds_io_request_started_task_mgmt_substate_table, |
1786 | SCIC_SDS_IO_REQUEST_STARTED_TASK_MGMT_SUBSTATE_AWAIT_TC_COMPLETION | |
1787 | ); | |
a1a113b0 | 1788 | } else if (dev->dev_type == SATA_DEV || (dev->tproto & SAS_PROTOCOL_STP)) |
35173d57 | 1789 | scic_sds_stp_request_assign_buffers(sci_req); |
a1a113b0 | 1790 | else |
35173d57 | 1791 | status = SCI_FAILURE_UNSUPPORTED_PROTOCOL; |
35173d57 DW |
1792 | |
1793 | if (status == SCI_SUCCESS) { | |
1794 | sci_req->is_task_management_request = true; | |
1795 | memset(sci_req->task_context_buffer, 0, sizeof(struct scu_task_context)); | |
1796 | *new_sci_req = sci_req; | |
1797 | } | |
1798 | ||
1799 | return status; | |
1800 | } |