1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause OR GPL-2.0 3 * 4 * This file is provided under a dual BSD/GPLv2 license. When using or 5 * redistributing this file, you may do so under either license. 6 * 7 * GPL LICENSE SUMMARY 8 * 9 * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. 10 * 11 * This program is free software; you can redistribute it and/or modify 12 * it under the terms of version 2 of the GNU General Public License as 13 * published by the Free Software Foundation. 14 * 15 * This program is distributed in the hope that it will be useful, but 16 * WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 18 * General Public License for more details. 19 * 20 * You should have received a copy of the GNU General Public License 21 * along with this program; if not, write to the Free Software 22 * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. 23 * The full GNU General Public License is included in this distribution 24 * in the file called LICENSE.GPL. 25 * 26 * BSD LICENSE 27 * 28 * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. 29 * All rights reserved. 30 * 31 * Redistribution and use in source and binary forms, with or without 32 * modification, are permitted provided that the following conditions 33 * are met: 34 * 35 * * Redistributions of source code must retain the above copyright 36 * notice, this list of conditions and the following disclaimer. 37 * * Redistributions in binary form must reproduce the above copyright 38 * notice, this list of conditions and the following disclaimer in 39 * the documentation and/or other materials provided with the 40 * distribution. 41 * 42 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 43 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 44 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 45 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 46 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 47 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 48 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 49 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 50 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 51 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 52 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 53 */ 54 55 #include <sys/cdefs.h> 56 __FBSDID("$FreeBSD$"); 57 58 #include <dev/isci/scil/scic_sds_smp_request.h> 59 #include <dev/isci/scil/scic_sds_logger.h> 60 #include <dev/isci/scil/scic_sds_controller.h> 61 #include <dev/isci/scil/scic_sds_remote_device.h> 62 #include <dev/isci/scil/scic_remote_device.h> 63 #include <dev/isci/scil/sci_util.h> 64 #include <dev/isci/sci_environment.h> 65 #include <dev/isci/scil/intel_sas.h> 66 #include <dev/isci/scil/scic_sds_request.h> 67 #include <dev/isci/scil/scic_controller.h> 68 #include <dev/isci/scil/scu_completion_codes.h> 69 #include <dev/isci/scil/scu_task_context.h> 70 #include <dev/isci/scil/sci_base_state_machine.h> 71 72 /** 73 * This method return the memory space required for STP PIO requests. 74 * 75 * @return U32 76 */ 77 U32 scic_sds_smp_request_get_object_size(void) 78 { 79 return sizeof(SCIC_SDS_REQUEST_T) 80 + sizeof(SMP_REQUEST_T) 81 + sizeof(U32) 82 + sizeof(SMP_RESPONSE_T) 83 + sizeof(U32) 84 + sizeof(SCU_TASK_CONTEXT_T) 85 + CACHE_LINE_SIZE; 86 } 87 88 /** 89 * This macro returns the address of the smp command buffer in the smp request 90 * memory. No need to cast to SMP request type. 91 */ 92 #define scic_sds_smp_request_get_command_buffer_unaligned(memory) \ 93 ( ((char *)(memory)) + sizeof(SCIC_SDS_REQUEST_T) ) 94 95 /** 96 * This macro aligns the smp command buffer in DWORD alignment 97 */ 98 #define scic_sds_smp_request_align_command_buffer(address) \ 99 ((char *)( \ 100 (((POINTER_UINT)(address)) + (sizeof(U32) - 1)) \ 101 & ~(sizeof(U32)- 1) \ 102 )) 103 104 /** 105 * This macro returns the DWORD-aligned smp command buffer 106 */ 107 #define scic_sds_smp_request_get_command_buffer(memory) \ 108 ((char *) \ 109 ((char *)scic_sds_smp_request_align_command_buffer( \ 110 (char *) scic_sds_smp_request_get_command_buffer_unaligned(memory) \ 111 ))) 112 113 /** 114 * This macro returns the address of the smp response buffer in the smp request 115 * memory. 116 */ 117 #define scic_sds_smp_request_get_response_buffer_unaligned(memory) \ 118 ( ((char *)(scic_sds_smp_request_get_command_buffer(memory))) \ 119 + sizeof(SMP_REQUEST_T) ) 120 121 /** 122 * This macro aligns the smp command buffer in DWORD alignment 123 */ 124 #define scic_sds_smp_request_align_response_buffer(address) \ 125 ((char *)( \ 126 (((POINTER_UINT)(address)) + (sizeof(U32) - 1)) \ 127 & ~(sizeof(U32)- 1) \ 128 )) 129 130 /** 131 * This macro returns the DWORD-aligned smp resposne buffer 132 */ 133 #define scic_sds_smp_request_get_response_buffer(memory) \ 134 ((char *) \ 135 ((char *)scic_sds_smp_request_align_response_buffer( \ 136 (char *) scic_sds_smp_request_get_response_buffer_unaligned(memory) \ 137 ))) 138 139 /** 140 * This macro returs the task context buffer for the SMP request. 141 */ 142 #define scic_sds_smp_request_get_task_context_buffer_unaligned(memory) \ 143 ((SCU_TASK_CONTEXT_T *)( \ 144 ((char *)(scic_sds_smp_request_get_response_buffer(memory))) \ 145 + sizeof(SMP_RESPONSE_T) \ 146 )) 147 148 /** 149 * This macro returns the dword-aligned smp task context buffer 150 */ 151 #define scic_sds_smp_request_get_task_context_buffer(memory) \ 152 ((SCU_TASK_CONTEXT_T *)( \ 153 ((char *)scic_sds_request_align_task_context_buffer( \ 154 (char *)scic_sds_smp_request_get_task_context_buffer_unaligned(memory)) \ 155 ))) 156 157 /** 158 * @brief This method build the remainder of the IO request object. 159 * 160 * @pre The scic_sds_general_request_construct() must be called before this 161 * call is valid. 162 * 163 * @param[in] this_request This parameter specifies the request object being 164 * constructed. 165 * 166 * @return none 167 */ 168 169 void scic_sds_smp_request_assign_buffers( 170 SCIC_SDS_REQUEST_T *this_request 171 ) 172 { 173 // Assign all of the buffer pointers 174 this_request->command_buffer = 175 scic_sds_smp_request_get_command_buffer(this_request); 176 this_request->response_buffer = 177 scic_sds_smp_request_get_response_buffer(this_request); 178 this_request->sgl_element_pair_buffer = NULL; 179 180 if (this_request->was_tag_assigned_by_user == FALSE) 181 { 182 this_request->task_context_buffer = 183 scic_sds_smp_request_get_task_context_buffer(this_request); 184 } 185 186 } 187 /** 188 * @brief This method is called by the SCI user to build an SMP 189 * IO request. 190 * 191 * @pre 192 * - The user must have previously called scic_io_request_construct() 193 * on the supplied IO request. 194 * 195 * @param[in] scic_io_request This parameter specifies the handle to the 196 * io request object to be built. 197 * 198 * @return Indicate if the controller successfully built the IO request. 199 * @retval SCI_SUCCESS This value is returned if the IO request was 200 * successfully built. 201 * @retval SCI_FAILURE_UNSUPPORTED_PROTOCOL This value is returned if the 202 * remote_device does not support the SMP protocol. 203 * @retval SCI_FAILURE_INVALID_ASSOCIATION This value is returned if the 204 * user did not properly set the association between the SCIC IO 205 * request and the user's IO request. Please refer to the 206 * sci_object_set_association() routine for more 207 * information. 208 */ 209 SCI_STATUS scic_io_request_construct_smp( 210 SCI_IO_REQUEST_HANDLE_T scic_smp_request 211 ) 212 { 213 SMP_REQUEST_T smp_request; 214 215 SCIC_SDS_REQUEST_T *this_request = (SCIC_SDS_REQUEST_T *) scic_smp_request; 216 SCIC_LOG_TRACE(( 217 sci_base_object_get_logger(this_request), 218 SCIC_LOG_OBJECT_SMP_IO_REQUEST, 219 "scic_io_request_construct_smp(0x%x) enter\n", 220 this_request 221 )); 222 223 this_request->protocol = SCIC_SMP_PROTOCOL; 224 this_request->has_started_substate_machine = TRUE; 225 226 // Construct the started sub-state machine. 227 sci_base_state_machine_construct( 228 &this_request->started_substate_machine, 229 &this_request->parent.parent, 230 scic_sds_smp_request_started_substate_table, 231 SCIC_SDS_SMP_REQUEST_STARTED_SUBSTATE_AWAIT_RESPONSE 232 ); 233 234 // Construct the SMP SCU Task Context 235 memcpy((char *)&smp_request, 236 this_request->command_buffer, 237 sizeof(SMP_REQUEST_T)); 238 239 // Look at the SMP requests' header fields; for certain SAS 1.x SMP 240 // functions under SAS 2.0, a zero request length really indicates 241 // a non-zero default length. 242 if( smp_request.header.request_length == 0 ) 243 { 244 switch( smp_request.header.function ) 245 { 246 case SMP_FUNCTION_DISCOVER: 247 case SMP_FUNCTION_REPORT_PHY_ERROR_LOG: 248 case SMP_FUNCTION_REPORT_PHY_SATA: 249 case SMP_FUNCTION_REPORT_ROUTE_INFORMATION: 250 smp_request.header.request_length = 2; 251 break; 252 case SMP_FUNCTION_CONFIGURE_ROUTE_INFORMATION: 253 case SMP_FUNCTION_PHY_CONTROL: 254 case SMP_FUNCTION_PHY_TEST: 255 smp_request.header.request_length = 9; 256 break; 257 // Default - zero is a valid default for 2.0. 258 } 259 } 260 261 scu_smp_request_construct_task_context( 262 this_request, 263 &smp_request 264 ); 265 266 sci_base_state_machine_change_state( 267 &this_request->parent.state_machine, 268 SCI_BASE_REQUEST_STATE_CONSTRUCTED 269 ); 270 271 return SCI_SUCCESS; 272 } 273 274 /** 275 * @brief This method is called by the SCI user to build an SMP pass-through 276 * IO request. 277 * 278 * @pre 279 * - The user must have previously called scic_io_request_construct() 280 * on the supplied IO request. 281 * 282 * @param[in] scic_smp_request This parameter specifies the handle to the 283 * io request object to be built. 284 * 285 * @param[in] passthru_cb This parameter specifies the pointer to the callback 286 * structure that contains the function pointers 287 * 288 * @return Indicate if the controller successfully built the IO request. 289 */ 290 SCI_STATUS scic_io_request_construct_smp_pass_through( 291 SCI_IO_REQUEST_HANDLE_T scic_smp_request, 292 SCIC_SMP_PASSTHRU_REQUEST_CALLBACKS_T *passthru_cb 293 ) 294 { 295 SMP_REQUEST_T smp_request; 296 U8 * request_buffer; 297 U32 request_buffer_length_in_bytes; 298 299 SCIC_SDS_REQUEST_T *this_request = (SCIC_SDS_REQUEST_T *) scic_smp_request; 300 SCIC_LOG_TRACE(( 301 sci_base_object_get_logger(this_request), 302 SCIC_LOG_OBJECT_SMP_IO_REQUEST, 303 "scic_io_request_construct_smp_pass_through(0x%x) enter\n", 304 this_request 305 )); 306 307 this_request->protocol = SCIC_SMP_PROTOCOL; 308 this_request->has_started_substate_machine = TRUE; 309 310 // Call the callback function to retrieve the SMP passthrough request 311 request_buffer_length_in_bytes = passthru_cb->scic_cb_smp_passthru_get_request ( 312 (void *)this_request, 313 &request_buffer 314 ); 315 316 //copy the request to smp request 317 memcpy((char *)&smp_request.request.vendor_specific_request, 318 request_buffer, 319 request_buffer_length_in_bytes); 320 321 //the header length in smp_request is in dwords - the sas spec has similar way, 322 //but the csmi header contains the number of bytes, so we need to convert the 323 //number of bytes to number of dwords 324 smp_request.header.request_length = (U8) (request_buffer_length_in_bytes / sizeof (U32)); 325 326 //Grab the other needed fields from the smp request using callbacks 327 smp_request.header.smp_frame_type = passthru_cb->scic_cb_smp_passthru_get_frame_type ((void *)this_request); 328 smp_request.header.function = passthru_cb->scic_cb_smp_passthru_get_function ((void *)this_request); 329 smp_request.header.allocated_response_length = passthru_cb->scic_cb_smp_passthru_get_allocated_response_length((void *)this_request); 330 331 // Construct the started sub-state machine. 332 sci_base_state_machine_construct( 333 &this_request->started_substate_machine, 334 &this_request->parent.parent, 335 scic_sds_smp_request_started_substate_table, 336 SCIC_SDS_SMP_REQUEST_STARTED_SUBSTATE_AWAIT_RESPONSE 337 ); 338 339 // Construct the SMP SCU Task Context 340 scu_smp_request_construct_task_context (this_request, &smp_request); 341 342 sci_base_state_machine_change_state( 343 &this_request->parent.state_machine, 344 SCI_BASE_REQUEST_STATE_CONSTRUCTED 345 ); 346 347 return SCI_SUCCESS; 348 } 349 350 /** 351 * @brief This method will fill in the SCU Task Context for a SMP request. The 352 * following important settings are utilized: 353 * 354 * -# task_type == SCU_TASK_TYPE_SMP. This simply indicates 355 * that a normal request type (i.e. non-raw frame) is being 356 * utilized to perform task management. 357 * -# control_frame == 1. This ensures that the proper endianness 358 * is set so that the bytes are transmitted in the right order 359 * for a smp request frame. 360 * 361 * @param[in] this_request This parameter specifies the smp request object 362 * being constructed. 363 * 364 * @return none 365 */ 366 void scu_smp_request_construct_task_context( 367 SCIC_SDS_REQUEST_T *this_request, 368 SMP_REQUEST_T *smp_request 369 ) 370 { 371 SCI_PHYSICAL_ADDRESS physical_address; 372 SCIC_SDS_CONTROLLER_T *owning_controller; 373 SCIC_SDS_REMOTE_DEVICE_T *target_device; 374 SCIC_SDS_PORT_T *target_port; 375 SCU_TASK_CONTEXT_T *task_context; 376 377 //byte swap the smp request. 378 scic_word_copy_with_swap( 379 this_request->command_buffer, 380 (U32*) smp_request, 381 sizeof(SMP_REQUEST_T)/sizeof(U32) 382 ); 383 384 task_context = scic_sds_request_get_task_context(this_request); 385 386 owning_controller = scic_sds_request_get_controller(this_request); 387 target_device = scic_sds_request_get_device(this_request); 388 target_port = scic_sds_request_get_port(this_request); 389 390 SCIC_LOG_TRACE(( 391 sci_base_object_get_logger(this_request), 392 SCIC_LOG_OBJECT_SMP_IO_REQUEST, 393 "scu_smp_request_construct_task_context(0x%x) contents\n" 394 " reqlen=%x; function=%x;\n", 395 this_request, 396 smp_request->header.request_length, 397 smp_request->header.function 398 )); 399 400 // Fill in the TC with the its required data 401 // 00h 402 task_context->priority = 0; 403 task_context->initiator_request = 1; 404 task_context->connection_rate = 405 scic_remote_device_get_connection_rate(target_device); 406 task_context->protocol_engine_index = 407 scic_sds_controller_get_protocol_engine_group(owning_controller); 408 task_context->logical_port_index = 409 scic_sds_port_get_index(target_port); 410 task_context->protocol_type = SCU_TASK_CONTEXT_PROTOCOL_SMP; 411 task_context->abort = 0; 412 task_context->valid = SCU_TASK_CONTEXT_VALID; 413 task_context->context_type = SCU_TASK_CONTEXT_TYPE; 414 415 //04h 416 task_context->remote_node_index = this_request->target_device->rnc->remote_node_index; 417 task_context->command_code = 0; 418 task_context->task_type = SCU_TASK_TYPE_SMP_REQUEST; 419 420 //08h 421 task_context->link_layer_control = 0; 422 task_context->do_not_dma_ssp_good_response = 1; 423 task_context->strict_ordering = 0; 424 task_context->control_frame = 1; 425 task_context->timeout_enable = 0; 426 task_context->block_guard_enable = 0; 427 428 //0ch 429 task_context->address_modifier = 0; 430 431 //10h 432 task_context->ssp_command_iu_length = smp_request->header.request_length; 433 434 //14h 435 task_context->transfer_length_bytes = 0; 436 437 //18h ~ 30h, protocol specific 438 // since commandIU has been build by framework at this point, we just 439 // copy the frist DWord from command IU to this location. 440 memcpy((void *)(&task_context->type.smp), this_request->command_buffer, sizeof(U32) ); 441 442 //40h 443 // "For SMP you could program it to zero. We would prefer that way so that 444 // done code will be consistent." - Venki 445 task_context->task_phase = 0; 446 447 if (this_request->was_tag_assigned_by_user) 448 { 449 // Build the task context now since we have already read the data 450 this_request->post_context = ( 451 SCU_CONTEXT_COMMAND_REQUEST_TYPE_POST_TC 452 | ( 453 scic_sds_controller_get_protocol_engine_group(owning_controller) 454 << SCU_CONTEXT_COMMAND_PROTOCOL_ENGINE_GROUP_SHIFT 455 ) 456 | ( 457 scic_sds_port_get_index(target_port) 458 << SCU_CONTEXT_COMMAND_LOGICAL_PORT_SHIFT 459 ) 460 | scic_sds_io_tag_get_index(this_request->io_tag) 461 ); 462 } 463 else 464 { 465 // Build the task context now since we have already read the data 466 this_request->post_context = ( 467 SCU_CONTEXT_COMMAND_REQUEST_TYPE_POST_TC 468 | ( 469 scic_sds_controller_get_protocol_engine_group(owning_controller) 470 << SCU_CONTEXT_COMMAND_PROTOCOL_ENGINE_GROUP_SHIFT 471 ) 472 | ( 473 scic_sds_port_get_index(target_port) 474 << SCU_CONTEXT_COMMAND_LOGICAL_PORT_SHIFT 475 ) 476 // This is not assigned because we have to wait until we get a TCi 477 ); 478 } 479 480 // Copy the physical address for the command buffer to the SCU Task Context 481 // command buffer should not contain command header. 482 scic_cb_io_request_get_physical_address( 483 scic_sds_request_get_controller(this_request), 484 this_request, 485 ((char *)(this_request->command_buffer) + sizeof(U32)), 486 &physical_address 487 ); 488 489 task_context->command_iu_upper = 490 sci_cb_physical_address_upper(physical_address); 491 task_context->command_iu_lower = 492 sci_cb_physical_address_lower(physical_address); 493 494 495 //SMP response comes as UF, so no need to set response IU address. 496 task_context->response_iu_upper = 0; 497 task_context->response_iu_lower = 0; 498 } 499 500 //****************************************************************************** 501 //* SMP REQUEST STATE MACHINE 502 //****************************************************************************** 503 504 /** 505 * @brief This method processes an unsolicited frame while the SMP request is 506 * waiting for a response frame. It will copy the response data, release 507 * the unsolicited frame, and transition the request to the 508 * SCI_BASE_REQUEST_STATE_COMPLETED state. 509 * 510 * @param[in] this_request This parameter specifies the request for which 511 * the unsolicited frame was received. 512 * @param[in] frame_index This parameter indicates the unsolicited frame 513 * index that should contain the response. 514 * 515 * @return This method returns an indication of whether the response 516 * frame was handled successfully or not. 517 * @retval SCI_SUCCESS Currently this value is always returned and indicates 518 * successful processing of the TC response. 519 */ 520 static 521 SCI_STATUS scic_sds_smp_request_await_response_frame_handler( 522 SCIC_SDS_REQUEST_T * this_request, 523 U32 frame_index 524 ) 525 { 526 SCI_STATUS status; 527 void * frame_header; 528 SMP_RESPONSE_HEADER_T * this_frame_header; 529 U8 * user_smp_buffer = this_request->response_buffer; 530 531 // Save off the controller, so that we do not touch the request after it 532 // is completed. 533 SCIC_SDS_CONTROLLER_T * controller = scic_sds_request_get_controller(this_request); 534 535 SCIC_LOG_TRACE(( 536 sci_base_object_get_logger(this_request), 537 SCIC_LOG_OBJECT_SMP_IO_REQUEST, 538 "scic_sds_smp_request_await_response_frame_handler(0x%x, 0x%x) enter\n", 539 this_request, frame_index 540 )); 541 542 status = scic_sds_unsolicited_frame_control_get_header( 543 &(controller->uf_control), 544 frame_index, 545 &frame_header 546 ); 547 548 //byte swap the header. 549 scic_word_copy_with_swap( 550 (U32*) user_smp_buffer, 551 frame_header, 552 sizeof(SMP_RESPONSE_HEADER_T)/sizeof(U32) 553 ); 554 this_frame_header = (SMP_RESPONSE_HEADER_T*) user_smp_buffer; 555 556 if (this_frame_header->smp_frame_type == SMP_FRAME_TYPE_RESPONSE) 557 { 558 void * smp_response_buffer; 559 560 status = scic_sds_unsolicited_frame_control_get_buffer( 561 &(controller->uf_control), 562 frame_index, 563 &smp_response_buffer 564 ); 565 566 scic_word_copy_with_swap( 567 (U32*) (user_smp_buffer + sizeof(SMP_RESPONSE_HEADER_T)), 568 smp_response_buffer, 569 sizeof(SMP_RESPONSE_BODY_T)/sizeof(U32) 570 ); 571 if (this_frame_header->function == SMP_FUNCTION_DISCOVER) 572 { 573 SMP_RESPONSE_T * this_smp_response; 574 575 this_smp_response = (SMP_RESPONSE_T *)user_smp_buffer; 576 577 // Some expanders only report an attached SATA device, and 578 // not an STP target. Since the core depends on the STP 579 // target attribute to correctly build I/O, set the bit now 580 // if necessary. 581 if (this_smp_response->response.discover.protocols.u.bits.attached_sata_device 582 && !this_smp_response->response.discover.protocols.u.bits.attached_stp_target) 583 { 584 this_smp_response->response.discover.protocols.u.bits.attached_stp_target = 1; 585 586 SCIC_LOG_TRACE(( 587 sci_base_object_get_logger(this_request), 588 SCIC_LOG_OBJECT_SMP_IO_REQUEST, 589 "scic_sds_smp_request_await_response_frame_handler(0x%x) Found SATA dev, setting STP bit.\n", 590 this_request 591 )); 592 } 593 } 594 595 //Don't need to copy to user space. User instead will refer to 596 //core request's response buffer. 597 598 //copy the smp response to framework smp request's response buffer. 599 //scic_sds_smp_request_copy_response(this_request); 600 601 scic_sds_request_set_status( 602 this_request, SCU_TASK_DONE_GOOD, SCI_SUCCESS 603 ); 604 605 sci_base_state_machine_change_state( 606 &this_request->started_substate_machine, 607 SCIC_SDS_SMP_REQUEST_STARTED_SUBSTATE_AWAIT_TC_COMPLETION 608 ); 609 } 610 else 611 { 612 // This was not a response frame why did it get forwarded? 613 SCIC_LOG_ERROR(( 614 sci_base_object_get_logger(this_request), 615 SCIC_LOG_OBJECT_SMP_IO_REQUEST, 616 "SCIC SMP Request 0x%08x received unexpected frame %d type 0x%02x\n", 617 this_request, frame_index, this_frame_header->smp_frame_type 618 )); 619 620 scic_sds_request_set_status( 621 this_request, 622 SCU_TASK_DONE_SMP_FRM_TYPE_ERR, 623 SCI_FAILURE_CONTROLLER_SPECIFIC_IO_ERR 624 ); 625 626 sci_base_state_machine_change_state( 627 &this_request->parent.state_machine, 628 SCI_BASE_REQUEST_STATE_COMPLETED 629 ); 630 } 631 632 scic_sds_controller_release_frame( 633 controller, frame_index 634 ); 635 636 return SCI_SUCCESS; 637 } 638 639 640 /** 641 * @brief This method processes an abnormal TC completion while the SMP 642 * request is waiting for a response frame. It decides what 643 * happened to the IO based on TC completion status. 644 * 645 * @param[in] this_request This parameter specifies the request for which 646 * the TC completion was received. 647 * @param[in] completion_code This parameter indicates the completion status 648 * information for the TC. 649 * 650 * @return Indicate if the tc completion handler was successful. 651 * @retval SCI_SUCCESS currently this method always returns success. 652 */ 653 static 654 SCI_STATUS scic_sds_smp_request_await_response_tc_completion_handler( 655 SCIC_SDS_REQUEST_T * this_request, 656 U32 completion_code 657 ) 658 { 659 SCIC_LOG_TRACE(( 660 sci_base_object_get_logger(this_request), 661 SCIC_LOG_OBJECT_SMP_IO_REQUEST, 662 "scic_sds_smp_request_await_response_tc_completion_handler(0x%x, 0x%x) enter\n", 663 this_request, completion_code 664 )); 665 666 switch (SCU_GET_COMPLETION_TL_STATUS(completion_code)) 667 { 668 case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_GOOD): 669 //In the AWAIT RESPONSE state, any TC completion is unexpected. 670 //but if the TC has success status, we complete the IO anyway. 671 scic_sds_request_set_status( 672 this_request, SCU_TASK_DONE_GOOD, SCI_SUCCESS 673 ); 674 675 sci_base_state_machine_change_state( 676 &this_request->parent.state_machine, 677 SCI_BASE_REQUEST_STATE_COMPLETED 678 ); 679 break; 680 681 case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_SMP_RESP_TO_ERR): 682 case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_SMP_UFI_ERR): 683 case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_SMP_FRM_TYPE_ERR): 684 case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_SMP_LL_RX_ERR): 685 //These status has been seen in a specific LSI expander, which sometimes 686 //is not able to send smp response within 2 ms. This causes our hardware 687 //break the connection and set TC completion with one of these SMP_XXX_XX_ERR 688 //status. For these type of error, we ask scic user to retry the request. 689 scic_sds_request_set_status( 690 this_request, SCU_TASK_DONE_SMP_RESP_TO_ERR, SCI_FAILURE_RETRY_REQUIRED 691 ); 692 693 sci_base_state_machine_change_state( 694 &this_request->parent.state_machine, 695 SCI_BASE_REQUEST_STATE_COMPLETED 696 ); 697 break; 698 699 default: 700 // All other completion status cause the IO to be complete. If a NAK 701 // was received, then it is up to the user to retry the request. 702 scic_sds_request_set_status( 703 this_request, 704 SCU_NORMALIZE_COMPLETION_STATUS(completion_code), 705 SCI_FAILURE_CONTROLLER_SPECIFIC_IO_ERR 706 ); 707 708 sci_base_state_machine_change_state( 709 &this_request->parent.state_machine, 710 SCI_BASE_REQUEST_STATE_COMPLETED 711 ); 712 break; 713 } 714 715 return SCI_SUCCESS; 716 } 717 718 719 /** 720 * @brief This method processes the completions transport layer (TL) status 721 * to determine if the SMP request was sent successfully. If the SMP 722 * request was sent successfully, then the state for the SMP request 723 * transits to waiting for a response frame. 724 * 725 * @param[in] this_request This parameter specifies the request for which 726 * the TC completion was received. 727 * @param[in] completion_code This parameter indicates the completion status 728 * information for the TC. 729 * 730 * @return Indicate if the tc completion handler was successful. 731 * @retval SCI_SUCCESS currently this method always returns success. 732 */ 733 static 734 SCI_STATUS scic_sds_smp_request_await_tc_completion_tc_completion_handler( 735 SCIC_SDS_REQUEST_T * this_request, 736 U32 completion_code 737 ) 738 { 739 SCIC_LOG_TRACE(( 740 sci_base_object_get_logger(this_request), 741 SCIC_LOG_OBJECT_SMP_IO_REQUEST, 742 "scic_sds_smp_request_await_tc_completion_tc_completion_handler(0x%x, 0x%x) enter\n", 743 this_request, completion_code 744 )); 745 746 switch (SCU_GET_COMPLETION_TL_STATUS(completion_code)) 747 { 748 case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_GOOD): 749 scic_sds_request_set_status( 750 this_request, SCU_TASK_DONE_GOOD, SCI_SUCCESS 751 ); 752 753 sci_base_state_machine_change_state( 754 &this_request->parent.state_machine, 755 SCI_BASE_REQUEST_STATE_COMPLETED 756 ); 757 break; 758 759 default: 760 // All other completion status cause the IO to be complete. If a NAK 761 // was received, then it is up to the user to retry the request. 762 scic_sds_request_set_status( 763 this_request, 764 SCU_NORMALIZE_COMPLETION_STATUS(completion_code), 765 SCI_FAILURE_CONTROLLER_SPECIFIC_IO_ERR 766 ); 767 768 sci_base_state_machine_change_state( 769 &this_request->parent.state_machine, 770 SCI_BASE_REQUEST_STATE_COMPLETED 771 ); 772 break; 773 } 774 775 return SCI_SUCCESS; 776 } 777 778 779 SCIC_SDS_IO_REQUEST_STATE_HANDLER_T 780 scic_sds_smp_request_started_substate_handler_table 781 [SCIC_SDS_SMP_REQUEST_STARTED_MAX_SUBSTATES] = 782 { 783 // SCIC_SDS_SMP_REQUEST_STARTED_SUBSTATE_AWAIT_RESPONSE 784 { 785 { 786 scic_sds_request_default_start_handler, 787 scic_sds_request_started_state_abort_handler, 788 scic_sds_request_default_complete_handler, 789 scic_sds_request_default_destruct_handler 790 }, 791 scic_sds_smp_request_await_response_tc_completion_handler, 792 scic_sds_request_default_event_handler, 793 scic_sds_smp_request_await_response_frame_handler 794 }, 795 // SCIC_SDS_SMP_REQUEST_STARTED_SUBSTATE_AWAIT_TC_COMPLETION 796 { 797 { 798 scic_sds_request_default_start_handler, 799 scic_sds_request_started_state_abort_handler, 800 scic_sds_request_default_complete_handler, 801 scic_sds_request_default_destruct_handler 802 }, 803 scic_sds_smp_request_await_tc_completion_tc_completion_handler, 804 scic_sds_request_default_event_handler, 805 scic_sds_request_default_frame_handler 806 } 807 }; 808 809 /** 810 * @brief This method performs the actions required when entering the 811 * SCIC_SDS_SMP_REQUEST_STARTED_SUBSTATE_AWAIT_TC_RESPONSE sub-state. 812 * This includes setting the IO request state handlers for this 813 * sub-state. 814 * 815 * @param[in] object This parameter specifies the request object for which 816 * the sub-state change is occurring. 817 * 818 * @return none. 819 */ 820 static 821 void scic_sds_smp_request_started_await_response_substate_enter( 822 SCI_BASE_OBJECT_T *object 823 ) 824 { 825 SCIC_SDS_REQUEST_T *this_request = (SCIC_SDS_REQUEST_T *)object; 826 827 SET_STATE_HANDLER( 828 this_request, 829 scic_sds_smp_request_started_substate_handler_table, 830 SCIC_SDS_SMP_REQUEST_STARTED_SUBSTATE_AWAIT_RESPONSE 831 ); 832 } 833 834 /** 835 * @brief This method performs the actions required when entering the 836 * SCIC_SDS_SMP_REQUEST_STARTED_SUBSTATE_AWAIT_TC_COMPLETION 837 * sub-state. This includes setting the SMP request state handlers for 838 * this sub-state. 839 * 840 * @param[in] object This parameter specifies the request object for which 841 * the sub-state change is occurring. 842 * 843 * @return none. 844 */ 845 static 846 void scic_sds_smp_request_started_await_tc_completion_substate_enter( 847 SCI_BASE_OBJECT_T *object 848 ) 849 { 850 SCIC_SDS_REQUEST_T *this_request = (SCIC_SDS_REQUEST_T *)object; 851 852 SET_STATE_HANDLER( 853 this_request, 854 scic_sds_smp_request_started_substate_handler_table, 855 SCIC_SDS_SMP_REQUEST_STARTED_SUBSTATE_AWAIT_TC_COMPLETION 856 ); 857 } 858 859 SCI_BASE_STATE_T scic_sds_smp_request_started_substate_table 860 [SCIC_SDS_SMP_REQUEST_STARTED_MAX_SUBSTATES] = 861 { 862 { 863 SCIC_SDS_SMP_REQUEST_STARTED_SUBSTATE_AWAIT_RESPONSE, 864 scic_sds_smp_request_started_await_response_substate_enter, 865 NULL 866 }, 867 { 868 SCIC_SDS_SMP_REQUEST_STARTED_SUBSTATE_AWAIT_TC_COMPLETION, 869 scic_sds_smp_request_started_await_tc_completion_substate_enter, 870 NULL 871 } 872 }; 873 874 875