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 | ||
d20930a2 | 56 | #include <scsi/sas.h> |
2ec53eb4 | 57 | #include "sas.h" |
6f231dda DW |
58 | #include "intel_sas.h" |
59 | #include "sci_base_state_machine.h" | |
60 | #include "scic_controller.h" | |
6f231dda | 61 | #include "scic_sds_controller.h" |
88f3b62a | 62 | #include "remote_device.h" |
6f231dda DW |
63 | #include "scic_sds_request.h" |
64 | #include "scic_sds_smp_request.h" | |
65 | #include "sci_environment.h" | |
66 | #include "sci_util.h" | |
67 | #include "scu_completion_codes.h" | |
68 | #include "scu_task_context.h" | |
69 | ||
70 | static void scu_smp_request_construct_task_context( | |
e2023b87 | 71 | struct scic_sds_request *sci_req, |
2ec53eb4 | 72 | struct smp_req *smp_req); |
6f231dda DW |
73 | |
74 | /** | |
75 | * | |
76 | * | |
77 | * This method return the memory space required for STP PIO requests. u32 | |
78 | */ | |
79 | u32 scic_sds_smp_request_get_object_size(void) | |
80 | { | |
81 | return sizeof(struct scic_sds_request) | |
2ec53eb4 | 82 | + sizeof(struct smp_req) |
d20930a2 | 83 | + sizeof(struct smp_resp) |
fe9a6431 DW |
84 | + sizeof(struct scu_task_context) |
85 | + SMP_CACHE_BYTES; | |
6f231dda DW |
86 | } |
87 | ||
88 | /** | |
89 | * scic_sds_smp_request_get_command_buffer() - | |
90 | * | |
91 | * This macro returns the address of the smp command buffer in the smp request | |
92 | * memory. No need to cast to SMP request type. | |
93 | */ | |
94 | #define scic_sds_smp_request_get_command_buffer(memory) \ | |
95 | (((char *)(memory)) + sizeof(struct scic_sds_request)) | |
96 | ||
97 | /** | |
98 | * scic_sds_smp_request_get_response_buffer() - | |
99 | * | |
100 | * This macro returns the address of the smp response buffer in the smp request | |
101 | * memory. | |
102 | */ | |
103 | #define scic_sds_smp_request_get_response_buffer(memory) \ | |
104 | (((char *)(scic_sds_smp_request_get_command_buffer(memory))) \ | |
2ec53eb4 | 105 | + sizeof(struct smp_req)) |
6f231dda DW |
106 | |
107 | /** | |
108 | * scic_sds_smp_request_get_task_context_buffer() - | |
109 | * | |
110 | * This macro returs the task context buffer for the SMP request. | |
111 | */ | |
112 | #define scic_sds_smp_request_get_task_context_buffer(memory) \ | |
113 | ((struct scu_task_context *)(\ | |
114 | ((char *)(scic_sds_smp_request_get_response_buffer(memory))) \ | |
d20930a2 | 115 | + sizeof(struct smp_resp) \ |
6f231dda DW |
116 | )) |
117 | ||
118 | ||
119 | ||
120 | /** | |
121 | * This method build the remainder of the IO request object. | |
e2023b87 | 122 | * @sci_req: This parameter specifies the request object being constructed. |
6f231dda DW |
123 | * |
124 | * The scic_sds_general_request_construct() must be called before this call is | |
125 | * valid. none | |
126 | */ | |
127 | ||
128 | void scic_sds_smp_request_assign_buffers( | |
e2023b87 | 129 | struct scic_sds_request *sci_req) |
6f231dda DW |
130 | { |
131 | /* Assign all of the buffer pointers */ | |
e2023b87 DJ |
132 | sci_req->command_buffer = |
133 | scic_sds_smp_request_get_command_buffer(sci_req); | |
134 | sci_req->response_buffer = | |
135 | scic_sds_smp_request_get_response_buffer(sci_req); | |
136 | sci_req->sgl_element_pair_buffer = NULL; | |
137 | ||
138 | if (sci_req->was_tag_assigned_by_user == false) { | |
139 | sci_req->task_context_buffer = | |
140 | scic_sds_smp_request_get_task_context_buffer(sci_req); | |
141 | sci_req->task_context_buffer = | |
142 | PTR_ALIGN(sci_req->task_context_buffer, SMP_CACHE_BYTES); | |
6f231dda DW |
143 | } |
144 | ||
145 | } | |
6f231dda | 146 | |
2ec53eb4 DJ |
147 | /* |
148 | * This function will fill in the SCU Task Context for a SMP request. The | |
6f231dda DW |
149 | * following important settings are utilized: -# task_type == |
150 | * SCU_TASK_TYPE_SMP. This simply indicates that a normal request type | |
151 | * (i.e. non-raw frame) is being utilized to perform task management. -# | |
152 | * control_frame == 1. This ensures that the proper endianess is set so | |
153 | * that the bytes are transmitted in the right order for a smp request frame. | |
e2023b87 | 154 | * @sci_req: This parameter specifies the smp request object being |
6f231dda DW |
155 | * constructed. |
156 | * | |
157 | */ | |
2ec53eb4 DJ |
158 | static void |
159 | scu_smp_request_construct_task_context(struct scic_sds_request *sci_req, | |
160 | struct smp_req *smp_req) | |
6f231dda | 161 | { |
6389a775 | 162 | dma_addr_t dma_addr; |
2ec53eb4 | 163 | struct scic_sds_controller *scic; |
7ab92c9e | 164 | struct scic_sds_remote_device *sci_dev; |
2ec53eb4 | 165 | struct scic_sds_port *sci_port; |
6f231dda | 166 | struct scu_task_context *task_context; |
51a57cff | 167 | ssize_t word_cnt = sizeof(struct smp_req) / sizeof(u32); |
6f231dda DW |
168 | |
169 | /* byte swap the smp request. */ | |
51a57cff DJ |
170 | sci_swab32_cpy(sci_req->command_buffer, smp_req, |
171 | word_cnt); | |
6f231dda | 172 | |
2ec53eb4 | 173 | task_context = scic_sds_request_get_task_context(sci_req); |
6f231dda | 174 | |
2ec53eb4 DJ |
175 | scic = scic_sds_request_get_controller(sci_req); |
176 | sci_dev = scic_sds_request_get_device(sci_req); | |
177 | sci_port = scic_sds_request_get_port(sci_req); | |
6f231dda DW |
178 | |
179 | /* | |
180 | * Fill in the TC with the its required data | |
6389a775 DJ |
181 | * 00h |
182 | */ | |
6f231dda DW |
183 | task_context->priority = 0; |
184 | task_context->initiator_request = 1; | |
8f304c36 | 185 | task_context->connection_rate = sci_dev->connection_rate; |
6f231dda | 186 | task_context->protocol_engine_index = |
2ec53eb4 DJ |
187 | scic_sds_controller_get_protocol_engine_group(scic); |
188 | task_context->logical_port_index = scic_sds_port_get_index(sci_port); | |
6f231dda DW |
189 | task_context->protocol_type = SCU_TASK_CONTEXT_PROTOCOL_SMP; |
190 | task_context->abort = 0; | |
191 | task_context->valid = SCU_TASK_CONTEXT_VALID; | |
192 | task_context->context_type = SCU_TASK_CONTEXT_TYPE; | |
193 | ||
194 | /* 04h */ | |
7ab92c9e | 195 | task_context->remote_node_index = sci_dev->rnc.remote_node_index; |
6f231dda DW |
196 | task_context->command_code = 0; |
197 | task_context->task_type = SCU_TASK_TYPE_SMP_REQUEST; | |
198 | ||
199 | /* 08h */ | |
200 | task_context->link_layer_control = 0; | |
201 | task_context->do_not_dma_ssp_good_response = 1; | |
202 | task_context->strict_ordering = 0; | |
203 | task_context->control_frame = 1; | |
204 | task_context->timeout_enable = 0; | |
205 | task_context->block_guard_enable = 0; | |
206 | ||
207 | /* 0ch */ | |
208 | task_context->address_modifier = 0; | |
209 | ||
210 | /* 10h */ | |
2ec53eb4 | 211 | task_context->ssp_command_iu_length = smp_req->req_len; |
6f231dda DW |
212 | |
213 | /* 14h */ | |
214 | task_context->transfer_length_bytes = 0; | |
215 | ||
216 | /* | |
217 | * 18h ~ 30h, protocol specific | |
218 | * since commandIU has been build by framework at this point, we just | |
219 | * copy the frist DWord from command IU to this location. */ | |
6389a775 | 220 | memcpy((void *)(&task_context->type.smp), |
2ec53eb4 | 221 | sci_req->command_buffer, |
6389a775 | 222 | sizeof(u32)); |
6f231dda DW |
223 | |
224 | /* | |
225 | * 40h | |
6389a775 DJ |
226 | * "For SMP you could program it to zero. We would prefer that way |
227 | * so that done code will be consistent." - Venki | |
228 | */ | |
6f231dda DW |
229 | task_context->task_phase = 0; |
230 | ||
2ec53eb4 | 231 | if (sci_req->was_tag_assigned_by_user) { |
6389a775 DJ |
232 | /* |
233 | * Build the task context now since we have already read | |
234 | * the data | |
235 | */ | |
2ec53eb4 | 236 | sci_req->post_context = |
6389a775 | 237 | (SCU_CONTEXT_COMMAND_REQUEST_TYPE_POST_TC | |
2ec53eb4 | 238 | (scic_sds_controller_get_protocol_engine_group(scic) << |
6389a775 | 239 | SCU_CONTEXT_COMMAND_PROTOCOL_ENGINE_GROUP_SHIFT) | |
2ec53eb4 | 240 | (scic_sds_port_get_index(sci_port) << |
6389a775 | 241 | SCU_CONTEXT_COMMAND_LOGICAL_PORT_SHIFT) | |
2ec53eb4 | 242 | scic_sds_io_tag_get_index(sci_req->io_tag)); |
6f231dda | 243 | } else { |
6389a775 DJ |
244 | /* |
245 | * Build the task context now since we have already read | |
246 | * the data. | |
247 | * I/O tag index is not assigned because we have to wait | |
248 | * until we get a TCi. | |
249 | */ | |
2ec53eb4 | 250 | sci_req->post_context = |
6389a775 | 251 | (SCU_CONTEXT_COMMAND_REQUEST_TYPE_POST_TC | |
2ec53eb4 | 252 | (scic_sds_controller_get_protocol_engine_group(scic) << |
6389a775 | 253 | SCU_CONTEXT_COMMAND_PROTOCOL_ENGINE_GROUP_SHIFT) | |
2ec53eb4 | 254 | (scic_sds_port_get_index(sci_port) << |
6389a775 | 255 | SCU_CONTEXT_COMMAND_LOGICAL_PORT_SHIFT)); |
6f231dda DW |
256 | } |
257 | ||
258 | /* | |
6389a775 DJ |
259 | * Copy the physical address for the command buffer to the SCU Task |
260 | * Context command buffer should not contain command header. | |
261 | */ | |
2ec53eb4 | 262 | dma_addr = scic_io_request_get_dma_addr(sci_req, |
6389a775 | 263 | (char *) |
2ec53eb4 | 264 | (sci_req->command_buffer) + |
6389a775 DJ |
265 | sizeof(u32)); |
266 | ||
267 | task_context->command_iu_upper = upper_32_bits(dma_addr); | |
268 | task_context->command_iu_lower = lower_32_bits(dma_addr); | |
6f231dda DW |
269 | |
270 | /* SMP response comes as UF, so no need to set response IU address. */ | |
271 | task_context->response_iu_upper = 0; | |
272 | task_context->response_iu_lower = 0; | |
273 | } | |
274 | ||
d20930a2 DJ |
275 | /* |
276 | * This function processes an unsolicited frame while the SMP request is waiting | |
6f231dda DW |
277 | * for a response frame. It will copy the response data, release the |
278 | * unsolicited frame, and transition the request to the | |
279 | * SCI_BASE_REQUEST_STATE_COMPLETED state. | |
e2023b87 | 280 | * @sci_req: This parameter specifies the request for which the |
6f231dda DW |
281 | * unsolicited frame was received. |
282 | * @frame_index: This parameter indicates the unsolicited frame index that | |
283 | * should contain the response. | |
284 | * | |
d20930a2 | 285 | * This function returns an indication of whether the response frame was handled |
6f231dda DW |
286 | * successfully or not. SCI_SUCCESS Currently this value is always returned and |
287 | * indicates successful processing of the TC response. | |
288 | */ | |
d20930a2 DJ |
289 | static enum sci_status |
290 | scic_sds_smp_request_await_response_frame_handler( | |
291 | struct scic_sds_request *sci_req, | |
292 | u32 frame_index) | |
6f231dda DW |
293 | { |
294 | enum sci_status status; | |
295 | void *frame_header; | |
d20930a2 DJ |
296 | struct smp_resp *rsp_hdr; |
297 | u8 *usr_smp_buf = sci_req->response_buffer; | |
51a57cff | 298 | ssize_t word_cnt = SMP_RESP_HDR_SZ / sizeof(u32); |
6f231dda DW |
299 | |
300 | status = scic_sds_unsolicited_frame_control_get_header( | |
e2023b87 | 301 | &(scic_sds_request_get_controller(sci_req)->uf_control), |
6f231dda | 302 | frame_index, |
d20930a2 | 303 | &frame_header); |
6f231dda DW |
304 | |
305 | /* byte swap the header. */ | |
51a57cff | 306 | sci_swab32_cpy(usr_smp_buf, frame_header, word_cnt); |
d20930a2 DJ |
307 | |
308 | rsp_hdr = (struct smp_resp *)usr_smp_buf; | |
6f231dda | 309 | |
d20930a2 DJ |
310 | if (rsp_hdr->frame_type == SMP_RESPONSE) { |
311 | void *smp_resp; | |
6f231dda DW |
312 | |
313 | status = scic_sds_unsolicited_frame_control_get_buffer( | |
e2023b87 | 314 | &(scic_sds_request_get_controller(sci_req)->uf_control), |
6f231dda | 315 | frame_index, |
d20930a2 | 316 | &smp_resp); |
6f231dda | 317 | |
51a57cff DJ |
318 | word_cnt = (sizeof(struct smp_req) - SMP_RESP_HDR_SZ) / |
319 | sizeof(u32); | |
320 | ||
321 | sci_swab32_cpy(usr_smp_buf + SMP_RESP_HDR_SZ, | |
322 | smp_resp, word_cnt); | |
6f231dda DW |
323 | |
324 | scic_sds_request_set_status( | |
d20930a2 | 325 | sci_req, SCU_TASK_DONE_GOOD, SCI_SUCCESS); |
6f231dda DW |
326 | |
327 | sci_base_state_machine_change_state( | |
e2023b87 | 328 | &sci_req->started_substate_machine, |
d20930a2 | 329 | SCIC_SDS_SMP_REQUEST_STARTED_SUBSTATE_AWAIT_TC_COMPLETION); |
6f231dda DW |
330 | } else { |
331 | /* This was not a response frame why did it get forwarded? */ | |
e2023b87 | 332 | dev_err(scic_to_dev(sci_req->owning_controller), |
6f231dda DW |
333 | "%s: SCIC SMP Request 0x%p received unexpected frame " |
334 | "%d type 0x%02x\n", | |
335 | __func__, | |
e2023b87 | 336 | sci_req, |
6f231dda | 337 | frame_index, |
d20930a2 | 338 | rsp_hdr->frame_type); |
6f231dda DW |
339 | |
340 | scic_sds_request_set_status( | |
e2023b87 | 341 | sci_req, |
6f231dda | 342 | SCU_TASK_DONE_SMP_FRM_TYPE_ERR, |
d20930a2 | 343 | SCI_FAILURE_CONTROLLER_SPECIFIC_IO_ERR); |
6f231dda DW |
344 | |
345 | sci_base_state_machine_change_state( | |
e2023b87 | 346 | &sci_req->state_machine, |
d20930a2 | 347 | SCI_BASE_REQUEST_STATE_COMPLETED); |
6f231dda DW |
348 | } |
349 | ||
d20930a2 DJ |
350 | scic_sds_controller_release_frame(sci_req->owning_controller, |
351 | frame_index); | |
6f231dda DW |
352 | |
353 | return SCI_SUCCESS; | |
354 | } | |
355 | ||
356 | ||
357 | /** | |
358 | * This method processes an abnormal TC completion while the SMP request is | |
359 | * waiting for a response frame. It decides what happened to the IO based | |
360 | * on TC completion status. | |
e2023b87 | 361 | * @sci_req: This parameter specifies the request for which the TC |
6f231dda DW |
362 | * completion was received. |
363 | * @completion_code: This parameter indicates the completion status information | |
364 | * for the TC. | |
365 | * | |
366 | * Indicate if the tc completion handler was successful. SCI_SUCCESS currently | |
367 | * this method always returns success. | |
368 | */ | |
369 | static enum sci_status scic_sds_smp_request_await_response_tc_completion_handler( | |
e2023b87 | 370 | struct scic_sds_request *sci_req, |
6f231dda DW |
371 | u32 completion_code) |
372 | { | |
373 | switch (SCU_GET_COMPLETION_TL_STATUS(completion_code)) { | |
374 | case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_GOOD): | |
375 | /* | |
376 | * In the AWAIT RESPONSE state, any TC completion is unexpected. | |
377 | * but if the TC has success status, we complete the IO anyway. */ | |
378 | scic_sds_request_set_status( | |
e2023b87 | 379 | sci_req, SCU_TASK_DONE_GOOD, SCI_SUCCESS |
6f231dda DW |
380 | ); |
381 | ||
382 | sci_base_state_machine_change_state( | |
e2023b87 | 383 | &sci_req->state_machine, |
38aa74eb | 384 | SCI_BASE_REQUEST_STATE_COMPLETED); |
6f231dda DW |
385 | break; |
386 | ||
387 | case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_SMP_RESP_TO_ERR): | |
388 | case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_SMP_UFI_ERR): | |
389 | case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_SMP_FRM_TYPE_ERR): | |
390 | case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_SMP_LL_RX_ERR): | |
391 | /* | |
392 | * These status has been seen in a specific LSI expander, which sometimes | |
393 | * is not able to send smp response within 2 ms. This causes our hardware | |
394 | * break the connection and set TC completion with one of these SMP_XXX_XX_ERR | |
395 | * status. For these type of error, we ask scic user to retry the request. */ | |
396 | scic_sds_request_set_status( | |
e2023b87 | 397 | sci_req, SCU_TASK_DONE_SMP_RESP_TO_ERR, SCI_FAILURE_RETRY_REQUIRED |
6f231dda DW |
398 | ); |
399 | ||
400 | sci_base_state_machine_change_state( | |
e2023b87 | 401 | &sci_req->state_machine, |
38aa74eb | 402 | SCI_BASE_REQUEST_STATE_COMPLETED); |
6f231dda DW |
403 | break; |
404 | ||
405 | default: | |
406 | /* | |
407 | * All other completion status cause the IO to be complete. If a NAK | |
408 | * was received, then it is up to the user to retry the request. */ | |
409 | scic_sds_request_set_status( | |
e2023b87 | 410 | sci_req, |
6f231dda DW |
411 | SCU_NORMALIZE_COMPLETION_STATUS(completion_code), |
412 | SCI_FAILURE_CONTROLLER_SPECIFIC_IO_ERR | |
413 | ); | |
414 | ||
415 | sci_base_state_machine_change_state( | |
e2023b87 | 416 | &sci_req->state_machine, |
38aa74eb | 417 | SCI_BASE_REQUEST_STATE_COMPLETED); |
6f231dda DW |
418 | break; |
419 | } | |
420 | ||
421 | return SCI_SUCCESS; | |
422 | } | |
423 | ||
424 | ||
425 | /** | |
426 | * This method processes the completions transport layer (TL) status to | |
427 | * determine if the SMP request was sent successfully. If the SMP request | |
428 | * was sent successfully, then the state for the SMP request transits to | |
429 | * waiting for a response frame. | |
e2023b87 | 430 | * @sci_req: This parameter specifies the request for which the TC |
6f231dda DW |
431 | * completion was received. |
432 | * @completion_code: This parameter indicates the completion status information | |
433 | * for the TC. | |
434 | * | |
435 | * Indicate if the tc completion handler was successful. SCI_SUCCESS currently | |
436 | * this method always returns success. | |
437 | */ | |
438 | static enum sci_status scic_sds_smp_request_await_tc_completion_tc_completion_handler( | |
e2023b87 | 439 | struct scic_sds_request *sci_req, |
6f231dda DW |
440 | u32 completion_code) |
441 | { | |
442 | switch (SCU_GET_COMPLETION_TL_STATUS(completion_code)) { | |
443 | case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_GOOD): | |
444 | scic_sds_request_set_status( | |
e2023b87 | 445 | sci_req, SCU_TASK_DONE_GOOD, SCI_SUCCESS |
6f231dda DW |
446 | ); |
447 | ||
448 | sci_base_state_machine_change_state( | |
e2023b87 | 449 | &sci_req->state_machine, |
38aa74eb | 450 | SCI_BASE_REQUEST_STATE_COMPLETED); |
6f231dda DW |
451 | break; |
452 | ||
453 | default: | |
454 | /* | |
455 | * All other completion status cause the IO to be complete. If a NAK | |
456 | * was received, then it is up to the user to retry the request. */ | |
457 | scic_sds_request_set_status( | |
e2023b87 | 458 | sci_req, |
6f231dda DW |
459 | SCU_NORMALIZE_COMPLETION_STATUS(completion_code), |
460 | SCI_FAILURE_CONTROLLER_SPECIFIC_IO_ERR | |
461 | ); | |
462 | ||
463 | sci_base_state_machine_change_state( | |
e2023b87 | 464 | &sci_req->state_machine, |
38aa74eb | 465 | SCI_BASE_REQUEST_STATE_COMPLETED); |
6f231dda DW |
466 | break; |
467 | } | |
468 | ||
469 | return SCI_SUCCESS; | |
470 | } | |
471 | ||
472 | ||
35173d57 | 473 | static const struct scic_sds_io_request_state_handler scic_sds_smp_request_started_substate_handler_table[] = { |
6f231dda | 474 | [SCIC_SDS_SMP_REQUEST_STARTED_SUBSTATE_AWAIT_RESPONSE] = { |
38aa74eb | 475 | .abort_handler = scic_sds_request_started_state_abort_handler, |
38aa74eb | 476 | .tc_completion_handler = scic_sds_smp_request_await_response_tc_completion_handler, |
38aa74eb | 477 | .frame_handler = scic_sds_smp_request_await_response_frame_handler, |
6f231dda DW |
478 | }, |
479 | [SCIC_SDS_SMP_REQUEST_STARTED_SUBSTATE_AWAIT_TC_COMPLETION] = { | |
38aa74eb | 480 | .abort_handler = scic_sds_request_started_state_abort_handler, |
38aa74eb | 481 | .tc_completion_handler = scic_sds_smp_request_await_tc_completion_tc_completion_handler, |
6f231dda DW |
482 | } |
483 | }; | |
484 | ||
485 | /** | |
486 | * This method performs the actions required when entering the | |
487 | * SCIC_SDS_SMP_REQUEST_STARTED_SUBSTATE_AWAIT_TC_RESPONSE sub-state. This | |
488 | * includes setting the IO request state handlers for this sub-state. | |
489 | * @object: This parameter specifies the request object for which the sub-state | |
9a0fff7b | 490 | * change is occurring. |
6f231dda DW |
491 | * |
492 | * none. | |
493 | */ | |
494 | static void scic_sds_smp_request_started_await_response_substate_enter( | |
9a0fff7b | 495 | void *object) |
6f231dda | 496 | { |
890cae9b | 497 | struct scic_sds_request *sci_req = object; |
6f231dda DW |
498 | |
499 | SET_STATE_HANDLER( | |
e2023b87 | 500 | sci_req, |
6f231dda DW |
501 | scic_sds_smp_request_started_substate_handler_table, |
502 | SCIC_SDS_SMP_REQUEST_STARTED_SUBSTATE_AWAIT_RESPONSE | |
503 | ); | |
504 | } | |
505 | ||
506 | /** | |
507 | * This method performs the actions required when entering the | |
508 | * SCIC_SDS_SMP_REQUEST_STARTED_SUBSTATE_AWAIT_TC_COMPLETION sub-state. | |
509 | * This includes setting the SMP request state handlers for this sub-state. | |
510 | * @object: This parameter specifies the request object for which the sub-state | |
9a0fff7b | 511 | * change is occurring. |
6f231dda DW |
512 | * |
513 | * none. | |
514 | */ | |
515 | static void scic_sds_smp_request_started_await_tc_completion_substate_enter( | |
9a0fff7b | 516 | void *object) |
6f231dda | 517 | { |
890cae9b | 518 | struct scic_sds_request *sci_req = object; |
6f231dda DW |
519 | |
520 | SET_STATE_HANDLER( | |
e2023b87 | 521 | sci_req, |
6f231dda DW |
522 | scic_sds_smp_request_started_substate_handler_table, |
523 | SCIC_SDS_SMP_REQUEST_STARTED_SUBSTATE_AWAIT_TC_COMPLETION | |
524 | ); | |
525 | } | |
526 | ||
35173d57 | 527 | static const struct sci_base_state scic_sds_smp_request_started_substate_table[] = { |
6f231dda DW |
528 | [SCIC_SDS_SMP_REQUEST_STARTED_SUBSTATE_AWAIT_RESPONSE] = { |
529 | .enter_state = scic_sds_smp_request_started_await_response_substate_enter, | |
530 | }, | |
531 | [SCIC_SDS_SMP_REQUEST_STARTED_SUBSTATE_AWAIT_TC_COMPLETION] = { | |
532 | .enter_state = scic_sds_smp_request_started_await_tc_completion_substate_enter, | |
533 | }, | |
534 | }; | |
535 | ||
35173d57 DW |
536 | /** |
537 | * This method is called by the SCI user to build an SMP IO request. | |
538 | * | |
539 | * - The user must have previously called scic_io_request_construct() on the | |
540 | * supplied IO request. Indicate if the controller successfully built the IO | |
541 | * request. SCI_SUCCESS This value is returned if the IO request was | |
542 | * successfully built. SCI_FAILURE_UNSUPPORTED_PROTOCOL This value is returned | |
543 | * if the remote_device does not support the SMP protocol. | |
544 | * SCI_FAILURE_INVALID_ASSOCIATION This value is returned if the user did not | |
545 | * properly set the association between the SCIC IO request and the user's IO | |
be2f41c6 | 546 | * request. |
35173d57 DW |
547 | */ |
548 | enum sci_status scic_io_request_construct_smp(struct scic_sds_request *sci_req) | |
549 | { | |
2ec53eb4 | 550 | struct smp_req *smp_req = kmalloc(sizeof(*smp_req), GFP_KERNEL); |
35173d57 DW |
551 | |
552 | if (!smp_req) | |
553 | return SCI_FAILURE_INSUFFICIENT_RESOURCES; | |
554 | ||
555 | sci_req->protocol = SCIC_SMP_PROTOCOL; | |
556 | sci_req->has_started_substate_machine = true; | |
557 | ||
558 | /* Construct the started sub-state machine. */ | |
559 | sci_base_state_machine_construct( | |
560 | &sci_req->started_substate_machine, | |
890cae9b | 561 | sci_req, |
35173d57 DW |
562 | scic_sds_smp_request_started_substate_table, |
563 | SCIC_SDS_SMP_REQUEST_STARTED_SUBSTATE_AWAIT_RESPONSE | |
564 | ); | |
565 | ||
566 | /* Construct the SMP SCU Task Context */ | |
567 | memcpy(smp_req, sci_req->command_buffer, sizeof(*smp_req)); | |
568 | ||
569 | /* | |
570 | * Look at the SMP requests' header fields; for certain SAS 1.x SMP | |
571 | * functions under SAS 2.0, a zero request length really indicates | |
572 | * a non-zero default length. */ | |
2ec53eb4 DJ |
573 | if (smp_req->req_len == 0) { |
574 | switch (smp_req->func) { | |
575 | case SMP_DISCOVER: | |
576 | case SMP_REPORT_PHY_ERR_LOG: | |
577 | case SMP_REPORT_PHY_SATA: | |
578 | case SMP_REPORT_ROUTE_INFO: | |
579 | smp_req->req_len = 2; | |
35173d57 | 580 | break; |
2ec53eb4 DJ |
581 | case SMP_CONF_ROUTE_INFO: |
582 | case SMP_PHY_CONTROL: | |
583 | case SMP_PHY_TEST_FUNCTION: | |
584 | smp_req->req_len = 9; | |
35173d57 DW |
585 | break; |
586 | /* Default - zero is a valid default for 2.0. */ | |
587 | } | |
588 | } | |
589 | ||
590 | scu_smp_request_construct_task_context(sci_req, smp_req); | |
591 | ||
38aa74eb CH |
592 | sci_base_state_machine_change_state(&sci_req->state_machine, |
593 | SCI_BASE_REQUEST_STATE_CONSTRUCTED); | |
35173d57 DW |
594 | |
595 | kfree(smp_req); | |
596 | ||
597 | return SCI_SUCCESS; | |
598 | } |