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 "scic_controller.h" |
58 | #include "scic_io_request.h" | |
6f231dda | 59 | #include "scic_sds_controller.h" |
bc99aa47 | 60 | #include "scu_registers.h" |
6f231dda | 61 | #include "scic_sds_port.h" |
88f3b62a | 62 | #include "remote_device.h" |
6f231dda DW |
63 | #include "scic_sds_request.h" |
64 | #include "scic_sds_smp_request.h" | |
65 | #include "scic_sds_stp_request.h" | |
66 | #include "scic_sds_unsolicited_frame_control.h" | |
6f231dda | 67 | #include "sci_environment.h" |
6f231dda DW |
68 | #include "sci_util.h" |
69 | #include "scu_completion_codes.h" | |
6f231dda | 70 | #include "scu_task_context.h" |
ce2b3261 DW |
71 | #include "request.h" |
72 | #include "task.h" | |
6f231dda | 73 | |
6f231dda DW |
74 | /* |
75 | * **************************************************************************** | |
76 | * * SCIC SDS IO REQUEST CONSTANTS | |
77 | * **************************************************************************** */ | |
78 | ||
79 | /** | |
80 | * | |
81 | * | |
82 | * We have no timer requirements for IO requests right now | |
83 | */ | |
84 | #define SCIC_SDS_IO_REQUEST_MINIMUM_TIMER_COUNT (0) | |
85 | #define SCIC_SDS_IO_REQUEST_MAXIMUM_TIMER_COUNT (0) | |
86 | ||
6f231dda DW |
87 | /** |
88 | * This method returns the sgl element pair for the specificed sgl_pair index. | |
e2023b87 | 89 | * @sci_req: This parameter specifies the IO request for which to retrieve |
6f231dda DW |
90 | * the Scatter-Gather List element pair. |
91 | * @sgl_pair_index: This parameter specifies the index into the SGL element | |
92 | * pair to be retrieved. | |
93 | * | |
94 | * This method returns a pointer to an struct scu_sgl_element_pair. | |
95 | */ | |
96 | static struct scu_sgl_element_pair *scic_sds_request_get_sgl_element_pair( | |
e2023b87 | 97 | struct scic_sds_request *sci_req, |
6f231dda DW |
98 | u32 sgl_pair_index |
99 | ) { | |
100 | struct scu_task_context *task_context; | |
101 | ||
e2023b87 | 102 | task_context = (struct scu_task_context *)sci_req->task_context_buffer; |
6f231dda DW |
103 | |
104 | if (sgl_pair_index == 0) { | |
105 | return &task_context->sgl_pair_ab; | |
106 | } else if (sgl_pair_index == 1) { | |
107 | return &task_context->sgl_pair_cd; | |
108 | } | |
109 | ||
0d84366f | 110 | return &sci_req->sg_table[sgl_pair_index - 2]; |
6f231dda DW |
111 | } |
112 | ||
113 | /** | |
114 | * This function will build the SGL list for an IO request. | |
e2023b87 | 115 | * @sci_req: This parameter specifies the IO request for which to build |
6f231dda DW |
116 | * the Scatter-Gather List. |
117 | * | |
118 | */ | |
6389a775 | 119 | void scic_sds_request_build_sgl(struct scic_sds_request *sds_request) |
6f231dda | 120 | { |
67ea838d | 121 | struct isci_request *isci_request = sci_req_to_ireq(sds_request); |
6389a775 DJ |
122 | struct isci_host *isci_host = isci_request->isci_host; |
123 | struct sas_task *task = isci_request_access_task(isci_request); | |
124 | struct scatterlist *sg = NULL; | |
125 | dma_addr_t dma_addr; | |
126 | u32 sg_idx = 0; | |
127 | struct scu_sgl_element_pair *scu_sg = NULL; | |
128 | struct scu_sgl_element_pair *prev_sg = NULL; | |
129 | ||
130 | if (task->num_scatter > 0) { | |
131 | sg = task->scatter; | |
132 | ||
133 | while (sg) { | |
134 | scu_sg = scic_sds_request_get_sgl_element_pair( | |
135 | sds_request, | |
136 | sg_idx); | |
137 | ||
138 | SCU_SGL_COPY(scu_sg->A, sg); | |
139 | ||
140 | sg = sg_next(sg); | |
141 | ||
142 | if (sg) { | |
143 | SCU_SGL_COPY(scu_sg->B, sg); | |
144 | sg = sg_next(sg); | |
145 | } else | |
146 | SCU_SGL_ZERO(scu_sg->B); | |
147 | ||
148 | if (prev_sg) { | |
149 | dma_addr = | |
150 | scic_io_request_get_dma_addr( | |
151 | sds_request, | |
152 | scu_sg); | |
153 | ||
154 | prev_sg->next_pair_upper = | |
155 | upper_32_bits(dma_addr); | |
156 | prev_sg->next_pair_lower = | |
157 | lower_32_bits(dma_addr); | |
158 | } | |
159 | ||
160 | prev_sg = scu_sg; | |
161 | sg_idx++; | |
6f231dda | 162 | } |
6389a775 DJ |
163 | } else { /* handle when no sg */ |
164 | scu_sg = scic_sds_request_get_sgl_element_pair(sds_request, | |
165 | sg_idx); | |
6f231dda | 166 | |
6389a775 DJ |
167 | dma_addr = dma_map_single(&isci_host->pdev->dev, |
168 | task->scatter, | |
169 | task->total_xfer_len, | |
170 | task->data_dir); | |
6f231dda | 171 | |
6389a775 DJ |
172 | isci_request->zero_scatter_daddr = dma_addr; |
173 | ||
174 | scu_sg->A.length = task->total_xfer_len; | |
175 | scu_sg->A.address_upper = upper_32_bits(dma_addr); | |
176 | scu_sg->A.address_lower = lower_32_bits(dma_addr); | |
6f231dda DW |
177 | } |
178 | ||
6389a775 DJ |
179 | if (scu_sg) { |
180 | scu_sg->next_pair_upper = 0; | |
181 | scu_sg->next_pair_lower = 0; | |
6f231dda DW |
182 | } |
183 | } | |
184 | ||
b7645818 | 185 | static void scic_sds_ssp_io_request_assign_buffers(struct scic_sds_request *sci_req) |
6f231dda | 186 | { |
26298264 DW |
187 | if (sci_req->was_tag_assigned_by_user == false) |
188 | sci_req->task_context_buffer = &sci_req->tc; | |
6f231dda DW |
189 | } |
190 | ||
0cfa890e | 191 | static void scic_sds_io_request_build_ssp_command_iu(struct scic_sds_request *sci_req) |
6f231dda | 192 | { |
0cfa890e | 193 | struct ssp_cmd_iu *cmd_iu; |
67ea838d | 194 | struct isci_request *ireq = sci_req_to_ireq(sci_req); |
0cfa890e | 195 | struct sas_task *task = isci_request_access_task(ireq); |
6f231dda | 196 | |
b7645818 | 197 | cmd_iu = &sci_req->ssp.cmd; |
6f231dda | 198 | |
0cfa890e DJ |
199 | memcpy(cmd_iu->LUN, task->ssp_task.LUN, 8); |
200 | cmd_iu->add_cdb_len = 0; | |
201 | cmd_iu->_r_a = 0; | |
202 | cmd_iu->_r_b = 0; | |
203 | cmd_iu->en_fburst = 0; /* unsupported */ | |
204 | cmd_iu->task_prio = task->ssp_task.task_prio; | |
205 | cmd_iu->task_attr = task->ssp_task.task_attr; | |
206 | cmd_iu->_r_c = 0; | |
6f231dda | 207 | |
51a57cff DJ |
208 | sci_swab32_cpy(&cmd_iu->cdb, task->ssp_task.cdb, |
209 | sizeof(task->ssp_task.cdb) / sizeof(u32)); | |
6f231dda DW |
210 | } |
211 | ||
0cfa890e | 212 | static void scic_sds_task_request_build_ssp_task_iu(struct scic_sds_request *sci_req) |
6f231dda | 213 | { |
0cfa890e | 214 | struct ssp_task_iu *task_iu; |
67ea838d | 215 | struct isci_request *ireq = sci_req_to_ireq(sci_req); |
0cfa890e DJ |
216 | struct sas_task *task = isci_request_access_task(ireq); |
217 | struct isci_tmf *isci_tmf = isci_request_access_tmf(ireq); | |
6f231dda | 218 | |
b7645818 | 219 | task_iu = &sci_req->ssp.tmf; |
6f231dda | 220 | |
0cfa890e | 221 | memset(task_iu, 0, sizeof(struct ssp_task_iu)); |
6f231dda | 222 | |
0cfa890e | 223 | memcpy(task_iu->LUN, task->ssp_task.LUN, 8); |
6f231dda | 224 | |
0cfa890e DJ |
225 | task_iu->task_func = isci_tmf->tmf_code; |
226 | task_iu->task_tag = | |
227 | (ireq->ttype == tmf_task) ? | |
228 | isci_tmf->io_tag : | |
229 | SCI_CONTROLLER_INVALID_IO_TAG; | |
6f231dda DW |
230 | } |
231 | ||
6f231dda DW |
232 | /** |
233 | * This method is will fill in the SCU Task Context for any type of SSP request. | |
e2023b87 | 234 | * @sci_req: |
6f231dda DW |
235 | * @task_context: |
236 | * | |
237 | */ | |
238 | static void scu_ssp_reqeust_construct_task_context( | |
6389a775 | 239 | struct scic_sds_request *sds_request, |
6f231dda DW |
240 | struct scu_task_context *task_context) |
241 | { | |
6389a775 DJ |
242 | dma_addr_t dma_addr; |
243 | struct scic_sds_controller *controller; | |
6f231dda DW |
244 | struct scic_sds_remote_device *target_device; |
245 | struct scic_sds_port *target_port; | |
246 | ||
6389a775 DJ |
247 | controller = scic_sds_request_get_controller(sds_request); |
248 | target_device = scic_sds_request_get_device(sds_request); | |
249 | target_port = scic_sds_request_get_port(sds_request); | |
6f231dda DW |
250 | |
251 | /* Fill in the TC with the its required data */ | |
252 | task_context->abort = 0; | |
253 | task_context->priority = 0; | |
254 | task_context->initiator_request = 1; | |
8f304c36 | 255 | task_context->connection_rate = target_device->connection_rate; |
6f231dda | 256 | task_context->protocol_engine_index = |
6389a775 | 257 | scic_sds_controller_get_protocol_engine_group(controller); |
6f231dda DW |
258 | task_context->logical_port_index = |
259 | scic_sds_port_get_index(target_port); | |
260 | task_context->protocol_type = SCU_TASK_CONTEXT_PROTOCOL_SSP; | |
261 | task_context->valid = SCU_TASK_CONTEXT_VALID; | |
262 | task_context->context_type = SCU_TASK_CONTEXT_TYPE; | |
263 | ||
264 | task_context->remote_node_index = | |
6389a775 | 265 | scic_sds_remote_device_get_index(sds_request->target_device); |
6f231dda DW |
266 | task_context->command_code = 0; |
267 | ||
268 | task_context->link_layer_control = 0; | |
269 | task_context->do_not_dma_ssp_good_response = 1; | |
270 | task_context->strict_ordering = 0; | |
271 | task_context->control_frame = 0; | |
272 | task_context->timeout_enable = 0; | |
273 | task_context->block_guard_enable = 0; | |
274 | ||
275 | task_context->address_modifier = 0; | |
276 | ||
e2023b87 | 277 | /* task_context->type.ssp.tag = sci_req->io_tag; */ |
6f231dda DW |
278 | task_context->task_phase = 0x01; |
279 | ||
6389a775 DJ |
280 | if (sds_request->was_tag_assigned_by_user) { |
281 | /* | |
282 | * Build the task context now since we have already read | |
283 | * the data | |
284 | */ | |
285 | sds_request->post_context = | |
286 | (SCU_CONTEXT_COMMAND_REQUEST_TYPE_POST_TC | | |
287 | (scic_sds_controller_get_protocol_engine_group( | |
288 | controller) << | |
289 | SCU_CONTEXT_COMMAND_PROTOCOL_ENGINE_GROUP_SHIFT) | | |
290 | (scic_sds_port_get_index(target_port) << | |
291 | SCU_CONTEXT_COMMAND_LOGICAL_PORT_SHIFT) | | |
292 | scic_sds_io_tag_get_index(sds_request->io_tag)); | |
6f231dda | 293 | } else { |
6389a775 DJ |
294 | /* |
295 | * Build the task context now since we have already read | |
296 | * the data | |
297 | * | |
298 | * I/O tag index is not assigned because we have to wait | |
299 | * until we get a TCi | |
300 | */ | |
301 | sds_request->post_context = | |
302 | (SCU_CONTEXT_COMMAND_REQUEST_TYPE_POST_TC | | |
303 | (scic_sds_controller_get_protocol_engine_group( | |
304 | owning_controller) << | |
305 | SCU_CONTEXT_COMMAND_PROTOCOL_ENGINE_GROUP_SHIFT) | | |
306 | (scic_sds_port_get_index(target_port) << | |
307 | SCU_CONTEXT_COMMAND_LOGICAL_PORT_SHIFT)); | |
6f231dda DW |
308 | } |
309 | ||
6389a775 DJ |
310 | /* |
311 | * Copy the physical address for the command buffer to the | |
312 | * SCU Task Context | |
313 | */ | |
314 | dma_addr = scic_io_request_get_dma_addr(sds_request, | |
b7645818 | 315 | &sds_request->ssp.cmd); |
6389a775 DJ |
316 | |
317 | task_context->command_iu_upper = upper_32_bits(dma_addr); | |
318 | task_context->command_iu_lower = lower_32_bits(dma_addr); | |
319 | ||
320 | /* | |
321 | * Copy the physical address for the response buffer to the | |
322 | * SCU Task Context | |
323 | */ | |
324 | dma_addr = scic_io_request_get_dma_addr(sds_request, | |
b7645818 | 325 | &sds_request->ssp.rsp); |
6389a775 DJ |
326 | |
327 | task_context->response_iu_upper = upper_32_bits(dma_addr); | |
328 | task_context->response_iu_lower = lower_32_bits(dma_addr); | |
6f231dda DW |
329 | } |
330 | ||
331 | /** | |
332 | * This method is will fill in the SCU Task Context for a SSP IO request. | |
e2023b87 | 333 | * @sci_req: |
6f231dda DW |
334 | * |
335 | */ | |
336 | static void scu_ssp_io_request_construct_task_context( | |
82d29928 DW |
337 | struct scic_sds_request *sci_req, |
338 | enum dma_data_direction dir, | |
339 | u32 len) | |
6f231dda DW |
340 | { |
341 | struct scu_task_context *task_context; | |
342 | ||
82d29928 | 343 | task_context = scic_sds_request_get_task_context(sci_req); |
6f231dda | 344 | |
82d29928 | 345 | scu_ssp_reqeust_construct_task_context(sci_req, task_context); |
6f231dda | 346 | |
0cfa890e DJ |
347 | task_context->ssp_command_iu_length = |
348 | sizeof(struct ssp_cmd_iu) / sizeof(u32); | |
8694e792 | 349 | task_context->type.ssp.frame_type = SSP_COMMAND; |
6f231dda | 350 | |
82d29928 DW |
351 | switch (dir) { |
352 | case DMA_FROM_DEVICE: | |
353 | case DMA_NONE: | |
354 | default: | |
6f231dda DW |
355 | task_context->task_type = SCU_TASK_TYPE_IOREAD; |
356 | break; | |
82d29928 | 357 | case DMA_TO_DEVICE: |
6f231dda DW |
358 | task_context->task_type = SCU_TASK_TYPE_IOWRITE; |
359 | break; | |
360 | } | |
361 | ||
82d29928 | 362 | task_context->transfer_length_bytes = len; |
6f231dda | 363 | |
82d29928 DW |
364 | if (task_context->transfer_length_bytes > 0) |
365 | scic_sds_request_build_sgl(sci_req); | |
6f231dda DW |
366 | } |
367 | ||
b7645818 | 368 | static void scic_sds_ssp_task_request_assign_buffers(struct scic_sds_request *sci_req) |
6f231dda | 369 | { |
26298264 DW |
370 | if (sci_req->was_tag_assigned_by_user == false) |
371 | sci_req->task_context_buffer = &sci_req->tc; | |
6f231dda DW |
372 | } |
373 | ||
374 | /** | |
375 | * This method will fill in the SCU Task Context for a SSP Task request. The | |
376 | * following important settings are utilized: -# priority == | |
377 | * SCU_TASK_PRIORITY_HIGH. This ensures that the task request is issued | |
378 | * ahead of other task destined for the same Remote Node. -# task_type == | |
379 | * SCU_TASK_TYPE_IOREAD. This simply indicates that a normal request type | |
380 | * (i.e. non-raw frame) is being utilized to perform task management. -# | |
381 | * control_frame == 1. This ensures that the proper endianess is set so | |
382 | * that the bytes are transmitted in the right order for a task frame. | |
e2023b87 | 383 | * @sci_req: This parameter specifies the task request object being |
6f231dda DW |
384 | * constructed. |
385 | * | |
386 | */ | |
387 | static void scu_ssp_task_request_construct_task_context( | |
e2023b87 | 388 | struct scic_sds_request *sci_req) |
6f231dda DW |
389 | { |
390 | struct scu_task_context *task_context; | |
391 | ||
e2023b87 | 392 | task_context = scic_sds_request_get_task_context(sci_req); |
6f231dda | 393 | |
e2023b87 | 394 | scu_ssp_reqeust_construct_task_context(sci_req, task_context); |
6f231dda DW |
395 | |
396 | task_context->control_frame = 1; | |
397 | task_context->priority = SCU_TASK_PRIORITY_HIGH; | |
398 | task_context->task_type = SCU_TASK_TYPE_RAW_FRAME; | |
399 | task_context->transfer_length_bytes = 0; | |
8694e792 | 400 | task_context->type.ssp.frame_type = SSP_TASK; |
0cfa890e DJ |
401 | task_context->ssp_command_iu_length = |
402 | sizeof(struct ssp_task_iu) / sizeof(u32); | |
6f231dda DW |
403 | } |
404 | ||
405 | ||
406 | /** | |
407 | * This method constructs the SSP Command IU data for this ssp passthrough | |
408 | * comand request object. | |
e2023b87 | 409 | * @sci_req: This parameter specifies the request object for which the SSP |
6f231dda DW |
410 | * command information unit is being built. |
411 | * | |
412 | * enum sci_status, returns invalid parameter is cdb > 16 | |
413 | */ | |
414 | ||
415 | ||
416 | /** | |
417 | * This method constructs the SATA request object. | |
e2023b87 | 418 | * @sci_req: |
6f231dda DW |
419 | * @sat_protocol: |
420 | * @transfer_length: | |
421 | * @data_direction: | |
422 | * @copy_rx_frame: | |
423 | * | |
424 | * enum sci_status | |
425 | */ | |
e76d6180 DJ |
426 | static enum sci_status |
427 | scic_io_request_construct_sata(struct scic_sds_request *sci_req, | |
428 | u32 len, | |
429 | enum dma_data_direction dir, | |
430 | bool copy) | |
6f231dda DW |
431 | { |
432 | enum sci_status status = SCI_SUCCESS; | |
67ea838d | 433 | struct isci_request *ireq = sci_req_to_ireq(sci_req); |
e76d6180 DJ |
434 | struct sas_task *task = isci_request_access_task(ireq); |
435 | ||
436 | /* check for management protocols */ | |
437 | if (ireq->ttype == tmf_task) { | |
438 | struct isci_tmf *tmf = isci_request_access_tmf(ireq); | |
439 | ||
440 | if (tmf->tmf_code == isci_tmf_sata_srst_high || | |
441 | tmf->tmf_code == isci_tmf_sata_srst_low) | |
442 | return scic_sds_stp_soft_reset_request_construct(sci_req); | |
443 | else { | |
444 | dev_err(scic_to_dev(sci_req->owning_controller), | |
445 | "%s: Request 0x%p received un-handled SAT " | |
446 | "management protocol 0x%x.\n", | |
447 | __func__, sci_req, tmf->tmf_code); | |
448 | ||
449 | return SCI_FAILURE; | |
450 | } | |
451 | } | |
6f231dda | 452 | |
e76d6180 DJ |
453 | if (!sas_protocol_ata(task->task_proto)) { |
454 | dev_err(scic_to_dev(sci_req->owning_controller), | |
455 | "%s: Non-ATA protocol in SATA path: 0x%x\n", | |
456 | __func__, | |
457 | task->task_proto); | |
458 | return SCI_FAILURE; | |
6f231dda | 459 | |
e76d6180 | 460 | } |
6f231dda | 461 | |
e76d6180 DJ |
462 | /* non data */ |
463 | if (task->data_dir == DMA_NONE) | |
464 | return scic_sds_stp_non_data_request_construct(sci_req); | |
6f231dda | 465 | |
e76d6180 DJ |
466 | /* NCQ */ |
467 | if (task->ata_task.use_ncq) | |
468 | return scic_sds_stp_ncq_request_construct(sci_req, len, dir); | |
6f231dda | 469 | |
e76d6180 DJ |
470 | /* DMA */ |
471 | if (task->ata_task.dma_xfer) | |
472 | return scic_sds_stp_udma_request_construct(sci_req, len, dir); | |
473 | else /* PIO */ | |
474 | return scic_sds_stp_pio_request_construct(sci_req, copy); | |
6f231dda DW |
475 | |
476 | return status; | |
477 | } | |
478 | ||
6f231dda DW |
479 | enum sci_status scic_io_request_construct_basic_ssp( |
480 | struct scic_sds_request *sci_req) | |
481 | { | |
67ea838d | 482 | struct isci_request *ireq = sci_req_to_ireq(sci_req); |
9286a195 | 483 | struct sas_task *task = isci_request_access_task(ireq); |
6f231dda DW |
484 | |
485 | sci_req->protocol = SCIC_SSP_PROTOCOL; | |
486 | ||
9286a195 DJ |
487 | scu_ssp_io_request_construct_task_context(sci_req, |
488 | task->data_dir, | |
489 | task->total_xfer_len); | |
6f231dda DW |
490 | |
491 | scic_sds_io_request_build_ssp_command_iu(sci_req); | |
492 | ||
9286a195 DJ |
493 | sci_base_state_machine_change_state( |
494 | &sci_req->state_machine, | |
495 | SCI_BASE_REQUEST_STATE_CONSTRUCTED); | |
6f231dda DW |
496 | |
497 | return SCI_SUCCESS; | |
498 | } | |
499 | ||
500 | ||
501 | enum sci_status scic_task_request_construct_ssp( | |
502 | struct scic_sds_request *sci_req) | |
503 | { | |
504 | /* Construct the SSP Task SCU Task Context */ | |
505 | scu_ssp_task_request_construct_task_context(sci_req); | |
506 | ||
507 | /* Fill in the SSP Task IU */ | |
508 | scic_sds_task_request_build_ssp_task_iu(sci_req); | |
509 | ||
38aa74eb CH |
510 | sci_base_state_machine_change_state(&sci_req->state_machine, |
511 | SCI_BASE_REQUEST_STATE_CONSTRUCTED); | |
6f231dda DW |
512 | |
513 | return SCI_SUCCESS; | |
514 | } | |
515 | ||
516 | ||
7392d275 DJ |
517 | enum sci_status scic_io_request_construct_basic_sata( |
518 | struct scic_sds_request *sci_req) | |
6f231dda DW |
519 | { |
520 | enum sci_status status; | |
82d29928 | 521 | struct scic_sds_stp_request *stp_req; |
82d29928 | 522 | bool copy = false; |
67ea838d | 523 | struct isci_request *isci_request = sci_req_to_ireq(sci_req); |
7392d275 | 524 | struct sas_task *task = isci_request_access_task(isci_request); |
6f231dda | 525 | |
827a84d4 | 526 | stp_req = &sci_req->stp.req; |
6f231dda DW |
527 | sci_req->protocol = SCIC_STP_PROTOCOL; |
528 | ||
7392d275 | 529 | copy = (task->data_dir == DMA_NONE) ? false : true; |
6f231dda | 530 | |
9286a195 DJ |
531 | status = scic_io_request_construct_sata(sci_req, |
532 | task->total_xfer_len, | |
533 | task->data_dir, | |
534 | copy); | |
6f231dda DW |
535 | |
536 | if (status == SCI_SUCCESS) | |
38aa74eb CH |
537 | sci_base_state_machine_change_state(&sci_req->state_machine, |
538 | SCI_BASE_REQUEST_STATE_CONSTRUCTED); | |
6f231dda DW |
539 | |
540 | return status; | |
541 | } | |
542 | ||
543 | ||
67ea838d | 544 | enum sci_status scic_task_request_construct_sata(struct scic_sds_request *sci_req) |
6f231dda | 545 | { |
e76d6180 | 546 | enum sci_status status = SCI_SUCCESS; |
67ea838d | 547 | struct isci_request *ireq = sci_req_to_ireq(sci_req); |
e76d6180 DJ |
548 | |
549 | /* check for management protocols */ | |
550 | if (ireq->ttype == tmf_task) { | |
551 | struct isci_tmf *tmf = isci_request_access_tmf(ireq); | |
552 | ||
553 | if (tmf->tmf_code == isci_tmf_sata_srst_high || | |
554 | tmf->tmf_code == isci_tmf_sata_srst_low) { | |
555 | status = scic_sds_stp_soft_reset_request_construct(sci_req); | |
556 | } else { | |
557 | dev_err(scic_to_dev(sci_req->owning_controller), | |
558 | "%s: Request 0x%p received un-handled SAT " | |
559 | "Protocol 0x%x.\n", | |
560 | __func__, sci_req, tmf->tmf_code); | |
561 | ||
562 | return SCI_FAILURE; | |
563 | } | |
6f231dda DW |
564 | } |
565 | ||
566 | if (status == SCI_SUCCESS) | |
e76d6180 DJ |
567 | sci_base_state_machine_change_state( |
568 | &sci_req->state_machine, | |
569 | SCI_BASE_REQUEST_STATE_CONSTRUCTED); | |
6f231dda DW |
570 | |
571 | return status; | |
572 | } | |
573 | ||
574 | ||
575 | u16 scic_io_request_get_io_tag( | |
576 | struct scic_sds_request *sci_req) | |
577 | { | |
578 | return sci_req->io_tag; | |
579 | } | |
580 | ||
581 | ||
582 | u32 scic_request_get_controller_status( | |
583 | struct scic_sds_request *sci_req) | |
584 | { | |
585 | return sci_req->scu_status; | |
586 | } | |
587 | ||
6f231dda DW |
588 | #define SCU_TASK_CONTEXT_SRAM 0x200000 |
589 | u32 scic_io_request_get_number_of_bytes_transferred( | |
590 | struct scic_sds_request *scic_sds_request) | |
591 | { | |
467e855a | 592 | struct scic_sds_controller *scic = scic_sds_request->owning_controller; |
6f231dda DW |
593 | u32 ret_val = 0; |
594 | ||
467e855a BB |
595 | if (readl(&scic->smu_registers->address_modifier) == 0) { |
596 | void __iomem *scu_reg_base = scic->scu_registers; | |
6f231dda DW |
597 | /* |
598 | * get the bytes of data from the Address == BAR1 + 20002Ch + (256*TCi) where | |
599 | * BAR1 is the scu_registers | |
600 | * 0x20002C = 0x200000 + 0x2c | |
601 | * = start of task context SRAM + offset of (type.ssp.data_offset) | |
602 | * TCi is the io_tag of struct scic_sds_request */ | |
467e855a BB |
603 | ret_val = readl(scu_reg_base + |
604 | (SCU_TASK_CONTEXT_SRAM + offsetof(struct scu_task_context, type.ssp.data_offset)) + | |
605 | ((sizeof(struct scu_task_context)) * scic_sds_io_tag_get_index(scic_sds_request->io_tag))); | |
6f231dda DW |
606 | } |
607 | ||
608 | return ret_val; | |
609 | } | |
610 | ||
611 | ||
612 | /* | |
613 | * **************************************************************************** | |
614 | * * SCIC SDS Interface Implementation | |
615 | * **************************************************************************** */ | |
616 | ||
38aa74eb CH |
617 | enum sci_status |
618 | scic_sds_request_start(struct scic_sds_request *request) | |
6f231dda | 619 | { |
524b5f72 | 620 | if (request->device_sequence != |
38aa74eb | 621 | scic_sds_remote_device_get_sequence(request->target_device)) |
524b5f72 CH |
622 | return SCI_FAILURE; |
623 | ||
624 | if (request->state_handlers->start_handler) | |
38aa74eb | 625 | return request->state_handlers->start_handler(request); |
524b5f72 CH |
626 | |
627 | dev_warn(scic_to_dev(request->owning_controller), | |
628 | "%s: SCIC IO Request requested to start while in wrong " | |
629 | "state %d\n", | |
630 | __func__, | |
631 | sci_base_state_machine_get_state(&request->state_machine)); | |
632 | ||
633 | return SCI_FAILURE_INVALID_STATE; | |
6f231dda DW |
634 | } |
635 | ||
38aa74eb CH |
636 | enum sci_status |
637 | scic_sds_io_request_terminate(struct scic_sds_request *request) | |
6f231dda | 638 | { |
524b5f72 CH |
639 | if (request->state_handlers->abort_handler) |
640 | return request->state_handlers->abort_handler(request); | |
641 | ||
642 | dev_warn(scic_to_dev(request->owning_controller), | |
643 | "%s: SCIC IO Request requested to abort while in wrong " | |
644 | "state %d\n", | |
645 | __func__, | |
646 | sci_base_state_machine_get_state(&request->state_machine)); | |
647 | ||
648 | return SCI_FAILURE_INVALID_STATE; | |
6f231dda DW |
649 | } |
650 | ||
38aa74eb CH |
651 | enum sci_status |
652 | scic_sds_io_request_complete(struct scic_sds_request *request) | |
6f231dda | 653 | { |
524b5f72 CH |
654 | if (request->state_handlers->complete_handler) |
655 | return request->state_handlers->complete_handler(request); | |
656 | ||
657 | dev_warn(scic_to_dev(request->owning_controller), | |
658 | "%s: SCIC IO Request requested to complete while in wrong " | |
659 | "state %d\n", | |
660 | __func__, | |
661 | sci_base_state_machine_get_state(&request->state_machine)); | |
662 | ||
663 | return SCI_FAILURE_INVALID_STATE; | |
6f231dda DW |
664 | } |
665 | ||
6f231dda | 666 | enum sci_status scic_sds_io_request_event_handler( |
524b5f72 | 667 | struct scic_sds_request *request, |
6f231dda DW |
668 | u32 event_code) |
669 | { | |
524b5f72 CH |
670 | if (request->state_handlers->event_handler) |
671 | return request->state_handlers->event_handler(request, event_code); | |
672 | ||
673 | dev_warn(scic_to_dev(request->owning_controller), | |
674 | "%s: SCIC IO Request given event code notification %x while " | |
675 | "in wrong state %d\n", | |
676 | __func__, | |
677 | event_code, | |
678 | sci_base_state_machine_get_state(&request->state_machine)); | |
679 | ||
680 | return SCI_FAILURE_INVALID_STATE; | |
6f231dda DW |
681 | } |
682 | ||
524b5f72 CH |
683 | enum sci_status |
684 | scic_sds_io_request_tc_completion(struct scic_sds_request *request, u32 completion_code) | |
685 | { | |
686 | if (request->state_machine.current_state_id == SCI_BASE_REQUEST_STATE_STARTED && | |
687 | request->has_started_substate_machine == false) | |
688 | return scic_sds_request_started_state_tc_completion_handler(request, completion_code); | |
689 | else if (request->state_handlers->tc_completion_handler) | |
690 | return request->state_handlers->tc_completion_handler(request, completion_code); | |
691 | ||
692 | dev_warn(scic_to_dev(request->owning_controller), | |
693 | "%s: SCIC IO Request given task completion notification %x " | |
694 | "while in wrong state %d\n", | |
695 | __func__, | |
696 | completion_code, | |
697 | sci_base_state_machine_get_state(&request->state_machine)); | |
698 | ||
699 | return SCI_FAILURE_INVALID_STATE; | |
700 | ||
701 | } | |
702 | ||
703 | ||
6f231dda DW |
704 | /** |
705 | * | |
e2023b87 | 706 | * @sci_req: The SCIC_SDS_IO_REQUEST_T object for which the start |
6f231dda DW |
707 | * operation is to be executed. |
708 | * @frame_index: The frame index returned by the hardware for the reqeust | |
709 | * object. | |
710 | * | |
711 | * This method invokes the core state frame handler for the | |
712 | * SCIC_SDS_IO_REQUEST_T object. enum sci_status | |
713 | */ | |
714 | enum sci_status scic_sds_io_request_frame_handler( | |
524b5f72 | 715 | struct scic_sds_request *request, |
6f231dda DW |
716 | u32 frame_index) |
717 | { | |
524b5f72 CH |
718 | if (request->state_handlers->frame_handler) |
719 | return request->state_handlers->frame_handler(request, frame_index); | |
720 | ||
721 | dev_warn(scic_to_dev(request->owning_controller), | |
722 | "%s: SCIC IO Request given unexpected frame %x while in " | |
723 | "state %d\n", | |
724 | __func__, | |
725 | frame_index, | |
726 | sci_base_state_machine_get_state(&request->state_machine)); | |
727 | ||
728 | scic_sds_controller_release_frame(request->owning_controller, frame_index); | |
729 | return SCI_FAILURE_INVALID_STATE; | |
6f231dda DW |
730 | } |
731 | ||
6f231dda | 732 | /* |
af5ae893 | 733 | * This function copies response data for requests returning response data |
6f231dda | 734 | * instead of sense data. |
e2023b87 | 735 | * @sci_req: This parameter specifies the request object for which to copy |
6f231dda | 736 | * the response data. |
6f231dda | 737 | */ |
af5ae893 | 738 | void scic_sds_io_request_copy_response(struct scic_sds_request *sci_req) |
6f231dda | 739 | { |
af5ae893 DJ |
740 | void *resp_buf; |
741 | u32 len; | |
742 | struct ssp_response_iu *ssp_response; | |
67ea838d | 743 | struct isci_request *ireq = sci_req_to_ireq(sci_req); |
af5ae893 | 744 | struct isci_tmf *isci_tmf = isci_request_access_tmf(ireq); |
6f231dda | 745 | |
b7645818 | 746 | ssp_response = &sci_req->ssp.rsp; |
6f231dda | 747 | |
af5ae893 | 748 | resp_buf = &isci_tmf->resp.resp_iu; |
6f231dda | 749 | |
af5ae893 DJ |
750 | len = min_t(u32, |
751 | SSP_RESP_IU_MAX_SIZE, | |
752 | be32_to_cpu(ssp_response->response_data_len)); | |
6f231dda | 753 | |
af5ae893 | 754 | memcpy(resp_buf, ssp_response->resp_data, len); |
6f231dda DW |
755 | } |
756 | ||
6f231dda DW |
757 | /* |
758 | * ***************************************************************************** | |
759 | * * CONSTRUCTED STATE HANDLERS | |
760 | * ***************************************************************************** */ | |
761 | ||
38aa74eb | 762 | /* |
6f231dda DW |
763 | * This method implements the action taken when a constructed |
764 | * SCIC_SDS_IO_REQUEST_T object receives a scic_sds_request_start() request. | |
765 | * This method will, if necessary, allocate a TCi for the io request object and | |
766 | * then will, if necessary, copy the constructed TC data into the actual TC | |
767 | * buffer. If everything is successful the post context field is updated with | |
768 | * the TCi so the controller can post the request to the hardware. enum sci_status | |
769 | * SCI_SUCCESS SCI_FAILURE_INSUFFICIENT_RESOURCES | |
770 | */ | |
771 | static enum sci_status scic_sds_request_constructed_state_start_handler( | |
38aa74eb | 772 | struct scic_sds_request *request) |
6f231dda DW |
773 | { |
774 | struct scu_task_context *task_context; | |
6f231dda | 775 | |
38aa74eb CH |
776 | if (request->io_tag == SCI_CONTROLLER_INVALID_IO_TAG) { |
777 | request->io_tag = | |
778 | scic_controller_allocate_io_tag(request->owning_controller); | |
6f231dda DW |
779 | } |
780 | ||
781 | /* Record the IO Tag in the request */ | |
38aa74eb CH |
782 | if (request->io_tag != SCI_CONTROLLER_INVALID_IO_TAG) { |
783 | task_context = request->task_context_buffer; | |
6f231dda | 784 | |
38aa74eb | 785 | task_context->task_index = scic_sds_io_tag_get_index(request->io_tag); |
6f231dda DW |
786 | |
787 | switch (task_context->protocol_type) { | |
788 | case SCU_TASK_CONTEXT_PROTOCOL_SMP: | |
789 | case SCU_TASK_CONTEXT_PROTOCOL_SSP: | |
790 | /* SSP/SMP Frame */ | |
38aa74eb | 791 | task_context->type.ssp.tag = request->io_tag; |
6f231dda DW |
792 | task_context->type.ssp.target_port_transfer_tag = 0xFFFF; |
793 | break; | |
794 | ||
795 | case SCU_TASK_CONTEXT_PROTOCOL_STP: | |
796 | /* | |
797 | * STP/SATA Frame | |
38aa74eb | 798 | * task_context->type.stp.ncq_tag = request->ncq_tag; */ |
6f231dda DW |
799 | break; |
800 | ||
801 | case SCU_TASK_CONTEXT_PROTOCOL_NONE: | |
802 | /* / @todo When do we set no protocol type? */ | |
803 | break; | |
804 | ||
805 | default: | |
806 | /* This should never happen since we build the IO requests */ | |
807 | break; | |
808 | } | |
809 | ||
810 | /* | |
811 | * Check to see if we need to copy the task context buffer | |
812 | * or have been building into the task context buffer */ | |
38aa74eb | 813 | if (request->was_tag_assigned_by_user == false) { |
6f231dda | 814 | scic_sds_controller_copy_task_context( |
38aa74eb | 815 | request->owning_controller, request); |
6f231dda DW |
816 | } |
817 | ||
818 | /* Add to the post_context the io tag value */ | |
38aa74eb | 819 | request->post_context |= scic_sds_io_tag_get_index(request->io_tag); |
6f231dda DW |
820 | |
821 | /* Everything is good go ahead and change state */ | |
38aa74eb CH |
822 | sci_base_state_machine_change_state(&request->state_machine, |
823 | SCI_BASE_REQUEST_STATE_STARTED); | |
6f231dda DW |
824 | |
825 | return SCI_SUCCESS; | |
826 | } | |
827 | ||
828 | return SCI_FAILURE_INSUFFICIENT_RESOURCES; | |
829 | } | |
830 | ||
38aa74eb | 831 | /* |
6f231dda DW |
832 | * This method implements the action to be taken when an SCIC_SDS_IO_REQUEST_T |
833 | * object receives a scic_sds_request_terminate() request. Since the request | |
834 | * has not yet been posted to the hardware the request transitions to the | |
835 | * completed state. enum sci_status SCI_SUCCESS | |
836 | */ | |
837 | static enum sci_status scic_sds_request_constructed_state_abort_handler( | |
38aa74eb | 838 | struct scic_sds_request *request) |
6f231dda | 839 | { |
6f231dda DW |
840 | /* |
841 | * This request has been terminated by the user make sure that the correct | |
842 | * status code is returned */ | |
38aa74eb | 843 | scic_sds_request_set_status(request, |
6f231dda | 844 | SCU_TASK_DONE_TASK_ABORT, |
38aa74eb | 845 | SCI_FAILURE_IO_TERMINATED); |
6f231dda | 846 | |
38aa74eb CH |
847 | sci_base_state_machine_change_state(&request->state_machine, |
848 | SCI_BASE_REQUEST_STATE_COMPLETED); | |
6f231dda DW |
849 | return SCI_SUCCESS; |
850 | } | |
851 | ||
852 | /* | |
853 | * ***************************************************************************** | |
854 | * * STARTED STATE HANDLERS | |
855 | * ***************************************************************************** */ | |
856 | ||
38aa74eb | 857 | /* |
6f231dda DW |
858 | * This method implements the action to be taken when an SCIC_SDS_IO_REQUEST_T |
859 | * object receives a scic_sds_request_terminate() request. Since the request | |
860 | * has been posted to the hardware the io request state is changed to the | |
861 | * aborting state. enum sci_status SCI_SUCCESS | |
862 | */ | |
863 | enum sci_status scic_sds_request_started_state_abort_handler( | |
38aa74eb | 864 | struct scic_sds_request *request) |
6f231dda | 865 | { |
38aa74eb CH |
866 | if (request->has_started_substate_machine) |
867 | sci_base_state_machine_stop(&request->started_substate_machine); | |
6f231dda | 868 | |
38aa74eb CH |
869 | sci_base_state_machine_change_state(&request->state_machine, |
870 | SCI_BASE_REQUEST_STATE_ABORTING); | |
6f231dda DW |
871 | return SCI_SUCCESS; |
872 | } | |
873 | ||
af5ae893 | 874 | /* |
6f231dda DW |
875 | * scic_sds_request_started_state_tc_completion_handler() - This method process |
876 | * TC (task context) completions for normal IO request (i.e. Task/Abort | |
877 | * Completions of type 0). This method will update the | |
878 | * SCIC_SDS_IO_REQUEST_T::status field. | |
e2023b87 | 879 | * @sci_req: This parameter specifies the request for which a completion |
6f231dda DW |
880 | * occurred. |
881 | * @completion_code: This parameter specifies the completion code received from | |
882 | * the SCU. | |
883 | * | |
884 | */ | |
af5ae893 DJ |
885 | enum sci_status |
886 | scic_sds_request_started_state_tc_completion_handler( | |
887 | struct scic_sds_request *sci_req, | |
888 | u32 completion_code) | |
6f231dda | 889 | { |
af5ae893 DJ |
890 | u8 datapres; |
891 | struct ssp_response_iu *resp_iu; | |
6f231dda | 892 | |
af5ae893 DJ |
893 | /* |
894 | * TODO: Any SDMA return code of other than 0 is bad | |
6f231dda DW |
895 | * decode 0x003C0000 to determine SDMA status |
896 | */ | |
897 | switch (SCU_GET_COMPLETION_TL_STATUS(completion_code)) { | |
898 | case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_GOOD): | |
af5ae893 DJ |
899 | scic_sds_request_set_status(sci_req, |
900 | SCU_TASK_DONE_GOOD, | |
901 | SCI_SUCCESS); | |
6f231dda DW |
902 | break; |
903 | ||
904 | case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_EARLY_RESP): | |
905 | { | |
906 | /* | |
af5ae893 DJ |
907 | * There are times when the SCU hardware will return an early |
908 | * response because the io request specified more data than is | |
909 | * returned by the target device (mode pages, inquiry data, | |
910 | * etc.). We must check the response stats to see if this is | |
911 | * truly a failed request or a good request that just got | |
912 | * completed early. | |
913 | */ | |
b7645818 | 914 | struct ssp_response_iu *resp = &sci_req->ssp.rsp; |
51a57cff DJ |
915 | ssize_t word_cnt = SSP_RESP_IU_MAX_SIZE / sizeof(u32); |
916 | ||
b7645818 DW |
917 | sci_swab32_cpy(&sci_req->ssp.rsp, |
918 | &sci_req->ssp.rsp, | |
51a57cff | 919 | word_cnt); |
6f231dda | 920 | |
af5ae893 | 921 | if (resp->status == 0) { |
6f231dda | 922 | scic_sds_request_set_status( |
af5ae893 DJ |
923 | sci_req, |
924 | SCU_TASK_DONE_GOOD, | |
925 | SCI_SUCCESS_IO_DONE_EARLY); | |
6f231dda DW |
926 | } else { |
927 | scic_sds_request_set_status( | |
e2023b87 | 928 | sci_req, |
6f231dda | 929 | SCU_TASK_DONE_CHECK_RESPONSE, |
af5ae893 | 930 | SCI_FAILURE_IO_RESPONSE_VALID); |
6f231dda DW |
931 | } |
932 | } | |
933 | break; | |
934 | ||
935 | case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_CHECK_RESPONSE): | |
51a57cff DJ |
936 | { |
937 | ssize_t word_cnt = SSP_RESP_IU_MAX_SIZE / sizeof(u32); | |
6f231dda | 938 | |
b7645818 DW |
939 | sci_swab32_cpy(&sci_req->ssp.rsp, |
940 | &sci_req->ssp.rsp, | |
51a57cff DJ |
941 | word_cnt); |
942 | ||
943 | scic_sds_request_set_status(sci_req, | |
944 | SCU_TASK_DONE_CHECK_RESPONSE, | |
945 | SCI_FAILURE_IO_RESPONSE_VALID); | |
6f231dda | 946 | break; |
51a57cff | 947 | } |
6f231dda DW |
948 | |
949 | case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_RESP_LEN_ERR): | |
950 | /* | |
af5ae893 DJ |
951 | * / @todo With TASK_DONE_RESP_LEN_ERR is the response frame |
952 | * guaranteed to be received before this completion status is | |
953 | * posted? | |
954 | */ | |
b7645818 | 955 | resp_iu = &sci_req->ssp.rsp; |
af5ae893 DJ |
956 | datapres = resp_iu->datapres; |
957 | ||
958 | if ((datapres == 0x01) || (datapres == 0x02)) { | |
6f231dda | 959 | scic_sds_request_set_status( |
e2023b87 | 960 | sci_req, |
6f231dda | 961 | SCU_TASK_DONE_CHECK_RESPONSE, |
af5ae893 DJ |
962 | SCI_FAILURE_IO_RESPONSE_VALID); |
963 | } else | |
6f231dda | 964 | scic_sds_request_set_status( |
af5ae893 | 965 | sci_req, SCU_TASK_DONE_GOOD, SCI_SUCCESS); |
6f231dda DW |
966 | break; |
967 | ||
968 | /* only stp device gets suspended. */ | |
969 | case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_ACK_NAK_TO): | |
970 | case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_LL_PERR): | |
971 | case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_NAK_ERR): | |
972 | case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_DATA_LEN_ERR): | |
973 | case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_LL_ABORT_ERR): | |
974 | case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_XR_WD_LEN): | |
975 | case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_MAX_PLD_ERR): | |
976 | case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_UNEXP_RESP): | |
977 | case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_UNEXP_SDBFIS): | |
978 | case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_REG_ERR): | |
979 | case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_SDB_ERR): | |
e2023b87 | 980 | if (sci_req->protocol == SCIC_STP_PROTOCOL) { |
6f231dda | 981 | scic_sds_request_set_status( |
e2023b87 | 982 | sci_req, |
af5ae893 DJ |
983 | SCU_GET_COMPLETION_TL_STATUS(completion_code) >> |
984 | SCU_COMPLETION_TL_STATUS_SHIFT, | |
985 | SCI_FAILURE_REMOTE_DEVICE_RESET_REQUIRED); | |
6f231dda DW |
986 | } else { |
987 | scic_sds_request_set_status( | |
e2023b87 | 988 | sci_req, |
af5ae893 DJ |
989 | SCU_GET_COMPLETION_TL_STATUS(completion_code) >> |
990 | SCU_COMPLETION_TL_STATUS_SHIFT, | |
991 | SCI_FAILURE_CONTROLLER_SPECIFIC_IO_ERR); | |
6f231dda DW |
992 | } |
993 | break; | |
994 | ||
995 | /* both stp/ssp device gets suspended */ | |
996 | case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_LF_ERR): | |
997 | case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_OPEN_REJECT_WRONG_DESTINATION): | |
998 | case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_OPEN_REJECT_RESERVED_ABANDON_1): | |
999 | case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_OPEN_REJECT_RESERVED_ABANDON_2): | |
1000 | case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_OPEN_REJECT_RESERVED_ABANDON_3): | |
1001 | case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_OPEN_REJECT_BAD_DESTINATION): | |
1002 | case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_OPEN_REJECT_ZONE_VIOLATION): | |
1003 | case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_OPEN_REJECT_STP_RESOURCES_BUSY): | |
1004 | case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_OPEN_REJECT_PROTOCOL_NOT_SUPPORTED): | |
1005 | case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_OPEN_REJECT_CONNECTION_RATE_NOT_SUPPORTED): | |
1006 | scic_sds_request_set_status( | |
e2023b87 | 1007 | sci_req, |
af5ae893 DJ |
1008 | SCU_GET_COMPLETION_TL_STATUS(completion_code) >> |
1009 | SCU_COMPLETION_TL_STATUS_SHIFT, | |
1010 | SCI_FAILURE_REMOTE_DEVICE_RESET_REQUIRED); | |
6f231dda DW |
1011 | break; |
1012 | ||
1013 | /* neither ssp nor stp gets suspended. */ | |
1014 | case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_NAK_CMD_ERR): | |
1015 | case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_UNEXP_XR): | |
1016 | case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_XR_IU_LEN_ERR): | |
1017 | case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_SDMA_ERR): | |
1018 | case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_OFFSET_ERR): | |
1019 | case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_EXCESS_DATA): | |
1020 | case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_SMP_RESP_TO_ERR): | |
1021 | case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_SMP_UFI_ERR): | |
1022 | case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_SMP_FRM_TYPE_ERR): | |
1023 | case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_SMP_LL_RX_ERR): | |
1024 | case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_UNEXP_DATA): | |
1025 | case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_OPEN_FAIL): | |
1026 | case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_VIIT_ENTRY_NV): | |
1027 | case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_IIT_ENTRY_NV): | |
1028 | case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_RNCNV_OUTBOUND): | |
1029 | default: | |
1030 | scic_sds_request_set_status( | |
e2023b87 | 1031 | sci_req, |
af5ae893 DJ |
1032 | SCU_GET_COMPLETION_TL_STATUS(completion_code) >> |
1033 | SCU_COMPLETION_TL_STATUS_SHIFT, | |
1034 | SCI_FAILURE_CONTROLLER_SPECIFIC_IO_ERR); | |
6f231dda DW |
1035 | break; |
1036 | } | |
1037 | ||
af5ae893 DJ |
1038 | /* |
1039 | * TODO: This is probably wrong for ACK/NAK timeout conditions | |
6f231dda DW |
1040 | */ |
1041 | ||
af5ae893 DJ |
1042 | /* In all cases we will treat this as the completion of the IO req. */ |
1043 | sci_base_state_machine_change_state( | |
1044 | &sci_req->state_machine, | |
1045 | SCI_BASE_REQUEST_STATE_COMPLETED); | |
6f231dda DW |
1046 | return SCI_SUCCESS; |
1047 | } | |
1048 | ||
38aa74eb | 1049 | /* |
6f231dda DW |
1050 | * This method implements the action to be taken when an SCIC_SDS_IO_REQUEST_T |
1051 | * object receives a scic_sds_request_frame_handler() request. This method | |
1052 | * first determines the frame type received. If this is a response frame then | |
1053 | * the response data is copied to the io request response buffer for processing | |
1054 | * at completion time. If the frame type is not a response buffer an error is | |
1055 | * logged. enum sci_status SCI_SUCCESS SCI_FAILURE_INVALID_PARAMETER_VALUE | |
1056 | */ | |
af5ae893 DJ |
1057 | static enum sci_status |
1058 | scic_sds_request_started_state_frame_handler(struct scic_sds_request *sci_req, | |
1059 | u32 frame_index) | |
6f231dda DW |
1060 | { |
1061 | enum sci_status status; | |
2d9c2240 DJ |
1062 | u32 *frame_header; |
1063 | struct ssp_frame_hdr ssp_hdr; | |
1064 | ssize_t word_cnt; | |
6f231dda | 1065 | |
6f231dda | 1066 | status = scic_sds_unsolicited_frame_control_get_header( |
e2023b87 | 1067 | &(scic_sds_request_get_controller(sci_req)->uf_control), |
6f231dda | 1068 | frame_index, |
af5ae893 | 1069 | (void **)&frame_header); |
6f231dda | 1070 | |
2d9c2240 DJ |
1071 | word_cnt = sizeof(struct ssp_frame_hdr) / sizeof(u32); |
1072 | sci_swab32_cpy(&ssp_hdr, frame_header, word_cnt); | |
1073 | ||
1074 | if (ssp_hdr.frame_type == SSP_RESPONSE) { | |
af5ae893 | 1075 | struct ssp_response_iu *resp_iu; |
51a57cff | 1076 | ssize_t word_cnt = SSP_RESP_IU_MAX_SIZE / sizeof(u32); |
6f231dda DW |
1077 | |
1078 | status = scic_sds_unsolicited_frame_control_get_buffer( | |
e2023b87 | 1079 | &(scic_sds_request_get_controller(sci_req)->uf_control), |
6f231dda | 1080 | frame_index, |
af5ae893 | 1081 | (void **)&resp_iu); |
6f231dda | 1082 | |
b7645818 | 1083 | sci_swab32_cpy(&sci_req->ssp.rsp, |
51a57cff | 1084 | resp_iu, word_cnt); |
6f231dda | 1085 | |
b7645818 | 1086 | resp_iu = &sci_req->ssp.rsp; |
6f231dda | 1087 | |
af5ae893 DJ |
1088 | if ((resp_iu->datapres == 0x01) || |
1089 | (resp_iu->datapres == 0x02)) { | |
6f231dda | 1090 | scic_sds_request_set_status( |
e2023b87 | 1091 | sci_req, |
6f231dda | 1092 | SCU_TASK_DONE_CHECK_RESPONSE, |
af5ae893 | 1093 | SCI_FAILURE_CONTROLLER_SPECIFIC_IO_ERR); |
6f231dda DW |
1094 | } else |
1095 | scic_sds_request_set_status( | |
af5ae893 DJ |
1096 | sci_req, SCU_TASK_DONE_GOOD, SCI_SUCCESS); |
1097 | } else { | |
6f231dda | 1098 | /* This was not a response frame why did it get forwarded? */ |
e2023b87 | 1099 | dev_err(scic_to_dev(sci_req->owning_controller), |
6f231dda DW |
1100 | "%s: SCIC IO Request 0x%p received unexpected " |
1101 | "frame %d type 0x%02x\n", | |
1102 | __func__, | |
e2023b87 | 1103 | sci_req, |
6f231dda | 1104 | frame_index, |
2d9c2240 | 1105 | ssp_hdr.frame_type); |
af5ae893 | 1106 | } |
6f231dda DW |
1107 | |
1108 | /* | |
1109 | * In any case we are done with this frame buffer return it to the | |
af5ae893 DJ |
1110 | * controller |
1111 | */ | |
6f231dda | 1112 | scic_sds_controller_release_frame( |
af5ae893 | 1113 | sci_req->owning_controller, frame_index); |
6f231dda DW |
1114 | |
1115 | return SCI_SUCCESS; | |
1116 | } | |
1117 | ||
1118 | /* | |
1119 | * ***************************************************************************** | |
1120 | * * COMPLETED STATE HANDLERS | |
1121 | * ***************************************************************************** */ | |
1122 | ||
1123 | ||
38aa74eb | 1124 | /* |
6f231dda DW |
1125 | * This method implements the action to be taken when an SCIC_SDS_IO_REQUEST_T |
1126 | * object receives a scic_sds_request_complete() request. This method frees up | |
1127 | * any io request resources that have been allocated and transitions the | |
1128 | * request to its final state. Consider stopping the state machine instead of | |
1129 | * transitioning to the final state? enum sci_status SCI_SUCCESS | |
1130 | */ | |
1131 | static enum sci_status scic_sds_request_completed_state_complete_handler( | |
38aa74eb | 1132 | struct scic_sds_request *request) |
6f231dda | 1133 | { |
38aa74eb | 1134 | if (request->was_tag_assigned_by_user != true) { |
6f231dda | 1135 | scic_controller_free_io_tag( |
38aa74eb | 1136 | request->owning_controller, request->io_tag); |
6f231dda DW |
1137 | } |
1138 | ||
38aa74eb | 1139 | if (request->saved_rx_frame_index != SCU_INVALID_FRAME_INDEX) { |
6f231dda | 1140 | scic_sds_controller_release_frame( |
38aa74eb | 1141 | request->owning_controller, request->saved_rx_frame_index); |
6f231dda DW |
1142 | } |
1143 | ||
38aa74eb CH |
1144 | sci_base_state_machine_change_state(&request->state_machine, |
1145 | SCI_BASE_REQUEST_STATE_FINAL); | |
6f231dda DW |
1146 | return SCI_SUCCESS; |
1147 | } | |
1148 | ||
1149 | /* | |
1150 | * ***************************************************************************** | |
1151 | * * ABORTING STATE HANDLERS | |
1152 | * ***************************************************************************** */ | |
1153 | ||
38aa74eb | 1154 | /* |
6f231dda DW |
1155 | * This method implements the action to be taken when an SCIC_SDS_IO_REQUEST_T |
1156 | * object receives a scic_sds_request_terminate() request. This method is the | |
1157 | * io request aborting state abort handlers. On receipt of a multiple | |
1158 | * terminate requests the io request will transition to the completed state. | |
1159 | * This should not happen in normal operation. enum sci_status SCI_SUCCESS | |
1160 | */ | |
1161 | static enum sci_status scic_sds_request_aborting_state_abort_handler( | |
38aa74eb | 1162 | struct scic_sds_request *request) |
6f231dda | 1163 | { |
38aa74eb CH |
1164 | sci_base_state_machine_change_state(&request->state_machine, |
1165 | SCI_BASE_REQUEST_STATE_COMPLETED); | |
6f231dda DW |
1166 | return SCI_SUCCESS; |
1167 | } | |
1168 | ||
38aa74eb | 1169 | /* |
6f231dda DW |
1170 | * This method implements the action to be taken when an SCIC_SDS_IO_REQUEST_T |
1171 | * object receives a scic_sds_request_task_completion() request. This method | |
1172 | * decodes the completion type waiting for the abort task complete | |
1173 | * notification. When the abort task complete is received the io request | |
1174 | * transitions to the completed state. enum sci_status SCI_SUCCESS | |
1175 | */ | |
1176 | static enum sci_status scic_sds_request_aborting_state_tc_completion_handler( | |
e2023b87 | 1177 | struct scic_sds_request *sci_req, |
6f231dda DW |
1178 | u32 completion_code) |
1179 | { | |
1180 | switch (SCU_GET_COMPLETION_TL_STATUS(completion_code)) { | |
1181 | case (SCU_TASK_DONE_GOOD << SCU_COMPLETION_TL_STATUS_SHIFT): | |
1182 | case (SCU_TASK_DONE_TASK_ABORT << SCU_COMPLETION_TL_STATUS_SHIFT): | |
1183 | scic_sds_request_set_status( | |
e2023b87 | 1184 | sci_req, SCU_TASK_DONE_TASK_ABORT, SCI_FAILURE_IO_TERMINATED |
6f231dda DW |
1185 | ); |
1186 | ||
e2023b87 | 1187 | sci_base_state_machine_change_state(&sci_req->state_machine, |
38aa74eb | 1188 | SCI_BASE_REQUEST_STATE_COMPLETED); |
6f231dda DW |
1189 | break; |
1190 | ||
1191 | default: | |
1192 | /* | |
1193 | * Unless we get some strange error wait for the task abort to complete | |
1194 | * TODO: Should there be a state change for this completion? */ | |
1195 | break; | |
1196 | } | |
1197 | ||
1198 | return SCI_SUCCESS; | |
1199 | } | |
1200 | ||
38aa74eb | 1201 | /* |
6f231dda DW |
1202 | * This method implements the action to be taken when an SCIC_SDS_IO_REQUEST_T |
1203 | * object receives a scic_sds_request_frame_handler() request. This method | |
1204 | * discards the unsolicited frame since we are waiting for the abort task | |
1205 | * completion. enum sci_status SCI_SUCCESS | |
1206 | */ | |
1207 | static enum sci_status scic_sds_request_aborting_state_frame_handler( | |
e2023b87 | 1208 | struct scic_sds_request *sci_req, |
6f231dda DW |
1209 | u32 frame_index) |
1210 | { | |
1211 | /* TODO: Is it even possible to get an unsolicited frame in the aborting state? */ | |
1212 | ||
1213 | scic_sds_controller_release_frame( | |
e2023b87 | 1214 | sci_req->owning_controller, frame_index); |
6f231dda DW |
1215 | |
1216 | return SCI_SUCCESS; | |
1217 | } | |
1218 | ||
35173d57 | 1219 | static const struct scic_sds_io_request_state_handler scic_sds_request_state_handler_table[] = { |
6f231dda | 1220 | [SCI_BASE_REQUEST_STATE_INITIAL] = { |
6f231dda DW |
1221 | }, |
1222 | [SCI_BASE_REQUEST_STATE_CONSTRUCTED] = { | |
38aa74eb CH |
1223 | .start_handler = scic_sds_request_constructed_state_start_handler, |
1224 | .abort_handler = scic_sds_request_constructed_state_abort_handler, | |
6f231dda DW |
1225 | }, |
1226 | [SCI_BASE_REQUEST_STATE_STARTED] = { | |
38aa74eb | 1227 | .abort_handler = scic_sds_request_started_state_abort_handler, |
38aa74eb | 1228 | .tc_completion_handler = scic_sds_request_started_state_tc_completion_handler, |
38aa74eb | 1229 | .frame_handler = scic_sds_request_started_state_frame_handler, |
6f231dda DW |
1230 | }, |
1231 | [SCI_BASE_REQUEST_STATE_COMPLETED] = { | |
38aa74eb | 1232 | .complete_handler = scic_sds_request_completed_state_complete_handler, |
6f231dda DW |
1233 | }, |
1234 | [SCI_BASE_REQUEST_STATE_ABORTING] = { | |
38aa74eb | 1235 | .abort_handler = scic_sds_request_aborting_state_abort_handler, |
38aa74eb | 1236 | .tc_completion_handler = scic_sds_request_aborting_state_tc_completion_handler, |
38aa74eb | 1237 | .frame_handler = scic_sds_request_aborting_state_frame_handler, |
6f231dda DW |
1238 | }, |
1239 | [SCI_BASE_REQUEST_STATE_FINAL] = { | |
6f231dda DW |
1240 | }, |
1241 | }; | |
1242 | ||
1243 | /** | |
1244 | * scic_sds_request_initial_state_enter() - | |
1245 | * @object: This parameter specifies the base object for which the state | |
1246 | * transition is occurring. | |
1247 | * | |
1248 | * This method implements the actions taken when entering the | |
1249 | * SCI_BASE_REQUEST_STATE_INITIAL state. This state is entered when the initial | |
1250 | * base request is constructed. Entry into the initial state sets all handlers | |
1251 | * for the io request object to their default handlers. none | |
1252 | */ | |
9a0fff7b | 1253 | static void scic_sds_request_initial_state_enter(void *object) |
6f231dda | 1254 | { |
890cae9b | 1255 | struct scic_sds_request *sci_req = object; |
6f231dda DW |
1256 | |
1257 | SET_STATE_HANDLER( | |
e2023b87 | 1258 | sci_req, |
6f231dda DW |
1259 | scic_sds_request_state_handler_table, |
1260 | SCI_BASE_REQUEST_STATE_INITIAL | |
1261 | ); | |
1262 | } | |
1263 | ||
1264 | /** | |
1265 | * scic_sds_request_constructed_state_enter() - | |
1266 | * @object: The io request object that is to enter the constructed state. | |
1267 | * | |
1268 | * This method implements the actions taken when entering the | |
1269 | * SCI_BASE_REQUEST_STATE_CONSTRUCTED state. The method sets the state handlers | |
1270 | * for the the constructed state. none | |
1271 | */ | |
9a0fff7b | 1272 | static void scic_sds_request_constructed_state_enter(void *object) |
6f231dda | 1273 | { |
890cae9b | 1274 | struct scic_sds_request *sci_req = object; |
6f231dda DW |
1275 | |
1276 | SET_STATE_HANDLER( | |
e2023b87 | 1277 | sci_req, |
6f231dda DW |
1278 | scic_sds_request_state_handler_table, |
1279 | SCI_BASE_REQUEST_STATE_CONSTRUCTED | |
1280 | ); | |
1281 | } | |
1282 | ||
1283 | /** | |
1284 | * scic_sds_request_started_state_enter() - | |
1285 | * @object: This parameter specifies the base object for which the state | |
9a0fff7b | 1286 | * transition is occurring. This is cast into a SCIC_SDS_IO_REQUEST object. |
6f231dda DW |
1287 | * |
1288 | * This method implements the actions taken when entering the | |
1289 | * SCI_BASE_REQUEST_STATE_STARTED state. If the io request object type is a | |
1290 | * SCSI Task request we must enter the started substate machine. none | |
1291 | */ | |
9a0fff7b | 1292 | static void scic_sds_request_started_state_enter(void *object) |
6f231dda | 1293 | { |
890cae9b | 1294 | struct scic_sds_request *sci_req = object; |
6f231dda DW |
1295 | |
1296 | SET_STATE_HANDLER( | |
e2023b87 | 1297 | sci_req, |
6f231dda DW |
1298 | scic_sds_request_state_handler_table, |
1299 | SCI_BASE_REQUEST_STATE_STARTED | |
1300 | ); | |
1301 | ||
1302 | /* | |
1303 | * Most of the request state machines have a started substate machine so | |
1304 | * start its execution on the entry to the started state. */ | |
e2023b87 DJ |
1305 | if (sci_req->has_started_substate_machine == true) |
1306 | sci_base_state_machine_start(&sci_req->started_substate_machine); | |
6f231dda DW |
1307 | } |
1308 | ||
1309 | /** | |
1310 | * scic_sds_request_started_state_exit() - | |
1311 | * @object: This parameter specifies the base object for which the state | |
9a0fff7b | 1312 | * transition is occurring. This object is cast into a SCIC_SDS_IO_REQUEST |
6f231dda DW |
1313 | * object. |
1314 | * | |
1315 | * This method implements the actions taken when exiting the | |
1316 | * SCI_BASE_REQUEST_STATE_STARTED state. For task requests the action will be | |
1317 | * to stop the started substate machine. none | |
1318 | */ | |
9a0fff7b | 1319 | static void scic_sds_request_started_state_exit(void *object) |
6f231dda | 1320 | { |
890cae9b | 1321 | struct scic_sds_request *sci_req = object; |
6f231dda | 1322 | |
e2023b87 DJ |
1323 | if (sci_req->has_started_substate_machine == true) |
1324 | sci_base_state_machine_stop(&sci_req->started_substate_machine); | |
6f231dda DW |
1325 | } |
1326 | ||
1327 | /** | |
1328 | * scic_sds_request_completed_state_enter() - | |
1329 | * @object: This parameter specifies the base object for which the state | |
9a0fff7b | 1330 | * transition is occurring. This object is cast into a SCIC_SDS_IO_REQUEST |
6f231dda DW |
1331 | * object. |
1332 | * | |
1333 | * This method implements the actions taken when entering the | |
1334 | * SCI_BASE_REQUEST_STATE_COMPLETED state. This state is entered when the | |
1335 | * SCIC_SDS_IO_REQUEST has completed. The method will decode the request | |
1336 | * completion status and convert it to an enum sci_status to return in the | |
1337 | * completion callback function. none | |
1338 | */ | |
9a0fff7b | 1339 | static void scic_sds_request_completed_state_enter(void *object) |
6f231dda | 1340 | { |
890cae9b | 1341 | struct scic_sds_request *sci_req = object; |
09d7da13 DJ |
1342 | struct scic_sds_controller *scic = |
1343 | scic_sds_request_get_controller(sci_req); | |
cc3dbd0a | 1344 | struct isci_host *ihost = scic_to_ihost(scic); |
67ea838d | 1345 | struct isci_request *ireq = sci_req_to_ireq(sci_req); |
6f231dda | 1346 | |
09d7da13 DJ |
1347 | SET_STATE_HANDLER(sci_req, |
1348 | scic_sds_request_state_handler_table, | |
1349 | SCI_BASE_REQUEST_STATE_COMPLETED); | |
6f231dda DW |
1350 | |
1351 | /* Tell the SCI_USER that the IO request is complete */ | |
09d7da13 DJ |
1352 | if (sci_req->is_task_management_request == false) |
1353 | isci_request_io_request_complete(ihost, | |
1354 | ireq, | |
1355 | sci_req->sci_status); | |
1356 | else | |
1357 | isci_task_request_complete(ihost, ireq, sci_req->sci_status); | |
6f231dda DW |
1358 | } |
1359 | ||
1360 | /** | |
1361 | * scic_sds_request_aborting_state_enter() - | |
1362 | * @object: This parameter specifies the base object for which the state | |
9a0fff7b | 1363 | * transition is occurring. This object is cast into a SCIC_SDS_IO_REQUEST |
6f231dda DW |
1364 | * object. |
1365 | * | |
1366 | * This method implements the actions taken when entering the | |
1367 | * SCI_BASE_REQUEST_STATE_ABORTING state. none | |
1368 | */ | |
9a0fff7b | 1369 | static void scic_sds_request_aborting_state_enter(void *object) |
6f231dda | 1370 | { |
890cae9b | 1371 | struct scic_sds_request *sci_req = object; |
6f231dda DW |
1372 | |
1373 | /* Setting the abort bit in the Task Context is required by the silicon. */ | |
e2023b87 | 1374 | sci_req->task_context_buffer->abort = 1; |
6f231dda DW |
1375 | |
1376 | SET_STATE_HANDLER( | |
e2023b87 | 1377 | sci_req, |
6f231dda DW |
1378 | scic_sds_request_state_handler_table, |
1379 | SCI_BASE_REQUEST_STATE_ABORTING | |
1380 | ); | |
1381 | } | |
1382 | ||
1383 | /** | |
1384 | * scic_sds_request_final_state_enter() - | |
1385 | * @object: This parameter specifies the base object for which the state | |
9a0fff7b | 1386 | * transition is occurring. This is cast into a SCIC_SDS_IO_REQUEST object. |
6f231dda DW |
1387 | * |
1388 | * This method implements the actions taken when entering the | |
1389 | * SCI_BASE_REQUEST_STATE_FINAL state. The only action required is to put the | |
1390 | * state handlers in place. none | |
1391 | */ | |
9a0fff7b | 1392 | static void scic_sds_request_final_state_enter(void *object) |
6f231dda | 1393 | { |
890cae9b | 1394 | struct scic_sds_request *sci_req = object; |
6f231dda DW |
1395 | |
1396 | SET_STATE_HANDLER( | |
e2023b87 | 1397 | sci_req, |
6f231dda DW |
1398 | scic_sds_request_state_handler_table, |
1399 | SCI_BASE_REQUEST_STATE_FINAL | |
1400 | ); | |
1401 | } | |
1402 | ||
35173d57 | 1403 | static const struct sci_base_state scic_sds_request_state_table[] = { |
6f231dda DW |
1404 | [SCI_BASE_REQUEST_STATE_INITIAL] = { |
1405 | .enter_state = scic_sds_request_initial_state_enter, | |
1406 | }, | |
1407 | [SCI_BASE_REQUEST_STATE_CONSTRUCTED] = { | |
1408 | .enter_state = scic_sds_request_constructed_state_enter, | |
1409 | }, | |
1410 | [SCI_BASE_REQUEST_STATE_STARTED] = { | |
1411 | .enter_state = scic_sds_request_started_state_enter, | |
1412 | .exit_state = scic_sds_request_started_state_exit | |
1413 | }, | |
1414 | [SCI_BASE_REQUEST_STATE_COMPLETED] = { | |
1415 | .enter_state = scic_sds_request_completed_state_enter, | |
1416 | }, | |
1417 | [SCI_BASE_REQUEST_STATE_ABORTING] = { | |
1418 | .enter_state = scic_sds_request_aborting_state_enter, | |
1419 | }, | |
1420 | [SCI_BASE_REQUEST_STATE_FINAL] = { | |
1421 | .enter_state = scic_sds_request_final_state_enter, | |
1422 | }, | |
1423 | }; | |
1424 | ||
35173d57 DW |
1425 | static void scic_sds_general_request_construct(struct scic_sds_controller *scic, |
1426 | struct scic_sds_remote_device *sci_dev, | |
67ea838d | 1427 | u16 io_tag, struct scic_sds_request *sci_req) |
35173d57 | 1428 | { |
890cae9b | 1429 | sci_base_state_machine_construct(&sci_req->state_machine, sci_req, |
38aa74eb CH |
1430 | scic_sds_request_state_table, SCI_BASE_REQUEST_STATE_INITIAL); |
1431 | sci_base_state_machine_start(&sci_req->state_machine); | |
1432 | ||
35173d57 | 1433 | sci_req->io_tag = io_tag; |
35173d57 DW |
1434 | sci_req->owning_controller = scic; |
1435 | sci_req->target_device = sci_dev; | |
1436 | sci_req->has_started_substate_machine = false; | |
1437 | sci_req->protocol = SCIC_NO_PROTOCOL; | |
1438 | sci_req->saved_rx_frame_index = SCU_INVALID_FRAME_INDEX; | |
1439 | sci_req->device_sequence = scic_sds_remote_device_get_sequence(sci_dev); | |
1440 | ||
1441 | sci_req->sci_status = SCI_SUCCESS; | |
1442 | sci_req->scu_status = 0; | |
1443 | sci_req->post_context = 0xFFFFFFFF; | |
1444 | ||
1445 | sci_req->is_task_management_request = false; | |
1446 | ||
1447 | if (io_tag == SCI_CONTROLLER_INVALID_IO_TAG) { | |
1448 | sci_req->was_tag_assigned_by_user = false; | |
1449 | sci_req->task_context_buffer = NULL; | |
1450 | } else { | |
1451 | sci_req->was_tag_assigned_by_user = true; | |
1452 | ||
1453 | sci_req->task_context_buffer = | |
1454 | scic_sds_controller_get_task_context_buffer(scic, io_tag); | |
1455 | } | |
1456 | } | |
1457 | ||
2ec53eb4 DJ |
1458 | enum sci_status |
1459 | scic_io_request_construct(struct scic_sds_controller *scic, | |
1460 | struct scic_sds_remote_device *sci_dev, | |
67ea838d | 1461 | u16 io_tag, struct scic_sds_request *sci_req) |
35173d57 | 1462 | { |
a1a113b0 | 1463 | struct domain_device *dev = sci_dev_to_domain(sci_dev); |
35173d57 | 1464 | enum sci_status status = SCI_SUCCESS; |
35173d57 DW |
1465 | |
1466 | /* Build the common part of the request */ | |
67ea838d | 1467 | scic_sds_general_request_construct(scic, sci_dev, io_tag, sci_req); |
2ec53eb4 DJ |
1468 | |
1469 | if (sci_dev->rnc.remote_node_index == | |
1470 | SCIC_SDS_REMOTE_NODE_CONTEXT_INVALID_INDEX) | |
35173d57 DW |
1471 | return SCI_FAILURE_INVALID_REMOTE_DEVICE; |
1472 | ||
2ec53eb4 | 1473 | if (dev->dev_type == SAS_END_DEV) |
35173d57 | 1474 | scic_sds_ssp_io_request_assign_buffers(sci_req); |
2ec53eb4 DJ |
1475 | else if ((dev->dev_type == SATA_DEV) || |
1476 | (dev->tproto & SAS_PROTOCOL_STP)) { | |
35173d57 | 1477 | scic_sds_stp_request_assign_buffers(sci_req); |
b7645818 | 1478 | memset(&sci_req->stp.cmd, 0, sizeof(sci_req->stp.cmd)); |
a1a113b0 | 1479 | } else if (dev_is_expander(dev)) { |
35173d57 | 1480 | scic_sds_smp_request_assign_buffers(sci_req); |
b7645818 | 1481 | memset(&sci_req->smp.cmd, 0, sizeof(sci_req->smp.cmd)); |
a1a113b0 | 1482 | } else |
35173d57 | 1483 | status = SCI_FAILURE_UNSUPPORTED_PROTOCOL; |
35173d57 DW |
1484 | |
1485 | if (status == SCI_SUCCESS) { | |
67ea838d DW |
1486 | memset(sci_req->task_context_buffer, 0, |
1487 | offsetof(struct scu_task_context, sgl_pair_ab)); | |
35173d57 DW |
1488 | } |
1489 | ||
1490 | return status; | |
1491 | } | |
1492 | ||
1493 | enum sci_status scic_task_request_construct(struct scic_sds_controller *scic, | |
1494 | struct scic_sds_remote_device *sci_dev, | |
67ea838d | 1495 | u16 io_tag, struct scic_sds_request *sci_req) |
35173d57 | 1496 | { |
a1a113b0 | 1497 | struct domain_device *dev = sci_dev_to_domain(sci_dev); |
35173d57 | 1498 | enum sci_status status = SCI_SUCCESS; |
35173d57 DW |
1499 | |
1500 | /* Build the common part of the request */ | |
67ea838d | 1501 | scic_sds_general_request_construct(scic, sci_dev, io_tag, sci_req); |
35173d57 | 1502 | |
a1a113b0 | 1503 | if (dev->dev_type == SAS_END_DEV) { |
35173d57 DW |
1504 | scic_sds_ssp_task_request_assign_buffers(sci_req); |
1505 | ||
1506 | sci_req->has_started_substate_machine = true; | |
1507 | ||
1508 | /* Construct the started sub-state machine. */ | |
1509 | sci_base_state_machine_construct( | |
1510 | &sci_req->started_substate_machine, | |
890cae9b | 1511 | sci_req, |
35173d57 DW |
1512 | scic_sds_io_request_started_task_mgmt_substate_table, |
1513 | SCIC_SDS_IO_REQUEST_STARTED_TASK_MGMT_SUBSTATE_AWAIT_TC_COMPLETION | |
1514 | ); | |
a1a113b0 | 1515 | } else if (dev->dev_type == SATA_DEV || (dev->tproto & SAS_PROTOCOL_STP)) |
35173d57 | 1516 | scic_sds_stp_request_assign_buffers(sci_req); |
a1a113b0 | 1517 | else |
35173d57 | 1518 | status = SCI_FAILURE_UNSUPPORTED_PROTOCOL; |
35173d57 DW |
1519 | |
1520 | if (status == SCI_SUCCESS) { | |
1521 | sci_req->is_task_management_request = true; | |
1522 | memset(sci_req->task_context_buffer, 0, sizeof(struct scu_task_context)); | |
35173d57 DW |
1523 | } |
1524 | ||
1525 | return status; | |
1526 | } |