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