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 /** 57 * @file 58 * 59 * @brief This file contains the method implementations for the 60 * SCIF_SAS_SMP_IO_REQUEST object. The contents will implement SMP 61 * specific functionality. 62 */ 63 64 #include <dev/isci/scil/scif_sas_smp_io_request.h> 65 #include <dev/isci/scil/scif_sas_logger.h> 66 #include <dev/isci/scil/scif_sas_controller.h> 67 #include <dev/isci/scil/sci_controller.h> 68 69 #include <dev/isci/scil/sci_status.h> 70 #include <dev/isci/scil/scic_io_request.h> 71 #include <dev/isci/scil/scic_user_callback.h> 72 73 #include <dev/isci/scil/intel_sas.h> 74 75 /** 76 * @brief This routine is to fill in the space given by core the SMP command 77 * frame. Then it calls core's construction. 78 * 79 * @param[in] fw_io The smp io request to be constructed. 80 * @param[in] smp_command The SMP request filled according to SAS spec. 81 * 82 * @return none 83 */ 84 void scif_sas_smp_request_construct( 85 SCIF_SAS_REQUEST_T * fw_request, 86 SMP_REQUEST_T * smp_command 87 ) 88 { 89 void * command_iu_address = 90 scic_io_request_get_command_iu_address(fw_request->core_object); 91 92 //copy the smp_command to the address; 93 memcpy( (char*) command_iu_address, 94 smp_command, 95 sizeof(SMP_REQUEST_T) 96 ); 97 98 scic_io_request_construct_smp(fw_request->core_object); 99 100 fw_request->protocol_complete_handler 101 = NULL; 102 } 103 104 /** 105 * @brief This method will perform all of the construction common to all 106 * SMP requests (e.g. filling in the frame type, zero-out memory, 107 * etc.). 108 * 109 * @param[out] smp_request This parameter specifies the SMP request 110 * structure containing the SMP request to be sent to the 111 * SMP target. 112 * @param[in] smp_function This parameter specifies the SMP function to 113 * sent. 114 * @param[in] smp_response_length This parameter specifies the length of 115 * the response (in DWORDs) that will be returned for this 116 * SMP request. 117 * @param[in] smp_request_length This parameter specifies the length of 118 * the request (in DWORDs) that will be sent. 119 */ 120 static 121 void scif_sas_smp_protocol_request_construct( 122 SMP_REQUEST_T * smp_request, 123 U8 smp_function, 124 U8 smp_response_length, 125 U8 smp_request_length 126 ) 127 { 128 memset((char*)smp_request, 0, sizeof(SMP_REQUEST_T)); 129 130 smp_request->header.smp_frame_type = SMP_FRAME_TYPE_REQUEST; 131 smp_request->header.function = smp_function; 132 smp_request->header.allocated_response_length = smp_response_length; 133 smp_request->header.request_length = smp_request_length; 134 } 135 136 137 /** 138 * @brief This method will allocate the internal IO request object and 139 * construct its contents based upon the supplied SMP request. 140 * 141 * @param[in] fw_controller This parameter specifies the controller object 142 * from which to allocate the internal IO request. 143 * @param[in] fw_device This parameter specifies the remote device for 144 * which the internal IO request is destined. 145 * @param[in] smp_request This parameter specifies the SMP request contents 146 * to be sent to the SMP target. 147 * 148 * @return void * The address of built scif sas smp request. 149 */ 150 static 151 void * scif_sas_smp_request_build( 152 SCIF_SAS_CONTROLLER_T * fw_controller, 153 SCIF_SAS_REMOTE_DEVICE_T * fw_device, 154 SMP_REQUEST_T * smp_request, 155 void * external_request_object, 156 void * external_memory 157 ) 158 { 159 if (external_memory != NULL && external_request_object != NULL) 160 { 161 scif_sas_io_request_construct_smp( 162 fw_controller, 163 fw_device, 164 external_memory, 165 (char *)external_memory + sizeof(SCIF_SAS_IO_REQUEST_T), 166 SCI_CONTROLLER_INVALID_IO_TAG, 167 smp_request, 168 external_request_object 169 ); 170 171 return external_memory; 172 } 173 else 174 { 175 void * internal_io_memory; 176 internal_io_memory = scif_sas_controller_allocate_internal_request(fw_controller); 177 ASSERT(internal_io_memory != NULL); 178 179 if (internal_io_memory != NULL) 180 { 181 //construct, only when we got valid io memory. 182 scif_sas_internal_io_request_construct_smp( 183 fw_controller, 184 fw_device, 185 internal_io_memory, 186 SCI_CONTROLLER_INVALID_IO_TAG, 187 smp_request 188 ); 189 } 190 else 191 { 192 SCIF_LOG_ERROR(( 193 sci_base_object_get_logger(fw_controller), 194 SCIF_LOG_OBJECT_IO_REQUEST, 195 "scif_sas_smp_request_build, no memory available!\n" 196 )); 197 } 198 199 return internal_io_memory; 200 } 201 } 202 203 /** 204 * @brief construct a smp Report Genernal command to the fw_device. 205 * 206 * @param[in] fw_controller The framework controller object. 207 * @param[in] fw_device the framework device that the REPORT GENERAL command 208 * targets to. 209 * 210 * @return void * address to the built scif sas smp request. 211 */ 212 void * scif_sas_smp_request_construct_report_general( 213 SCIF_SAS_CONTROLLER_T * fw_controller, 214 SCIF_SAS_REMOTE_DEVICE_T * fw_device 215 ) 216 { 217 SMP_REQUEST_T smp_report_general; 218 219 // Build the REPORT GENERAL request. 220 scif_sas_smp_protocol_request_construct( 221 &smp_report_general, 222 SMP_FUNCTION_REPORT_GENERAL, 223 sizeof(SMP_RESPONSE_REPORT_GENERAL_T) / sizeof(U32), 224 0 225 ); 226 227 smp_report_general.request.report_general.crc = 0; 228 229 SCIF_LOG_INFO(( 230 sci_base_object_get_logger(fw_device), 231 SCIF_LOG_OBJECT_IO_REQUEST | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY, 232 "SMP REPORT GENERAL - Device:0x%x\n", 233 fw_device 234 )); 235 236 return scif_sas_smp_request_build( 237 fw_controller, fw_device, &smp_report_general, NULL, NULL); 238 } 239 240 /** 241 * @brief construct a SMP Report Manufacturer Info request to the fw_device. 242 * 243 * @param[in] fw_controller The framework controller object. 244 * @param[in] fw_device the framework device that the REPORT MANUFACTURER 245 * INFO targets to. 246 * 247 * @return void * address to the built scif sas smp request. 248 */ 249 void * scif_sas_smp_request_construct_report_manufacturer_info( 250 SCIF_SAS_CONTROLLER_T * fw_controller, 251 SCIF_SAS_REMOTE_DEVICE_T * fw_device 252 ) 253 { 254 SMP_REQUEST_T smp_report_manufacturer_info; 255 256 scif_sas_smp_protocol_request_construct( 257 &smp_report_manufacturer_info, 258 SMP_FUNCTION_REPORT_MANUFACTURER_INFORMATION, 259 sizeof(SMP_RESPONSE_REPORT_MANUFACTURER_INFORMATION_T) / sizeof(U32), 260 0 261 ); 262 263 smp_report_manufacturer_info.request.report_general.crc = 0; 264 265 SCIF_LOG_INFO(( 266 sci_base_object_get_logger(fw_device), 267 SCIF_LOG_OBJECT_IO_REQUEST | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY, 268 "SMP REPORT MANUFACTURER_INFO - Device:0x%x\n", 269 fw_device 270 )); 271 272 return scif_sas_smp_request_build( 273 fw_controller, fw_device, &smp_report_manufacturer_info, NULL, NULL 274 ); 275 } 276 277 /** 278 * @brief construct a smp Discover command to the fw_device. 279 * @param[in] fw_controller The framework controller object. 280 * @param[in] fw_device the framework smp device that DISCOVER command targets 281 * to. 282 * @param[in] phy_identifier The phy index the DISCOVER command targets to. 283 * 284 * @return void * address to the built scif sas smp request. 285 */ 286 void * scif_sas_smp_request_construct_discover( 287 SCIF_SAS_CONTROLLER_T * fw_controller, 288 SCIF_SAS_REMOTE_DEVICE_T * fw_device, 289 U8 phy_identifier, 290 void * external_request_object, 291 void * external_memory 292 ) 293 { 294 SMP_REQUEST_T smp_discover; 295 296 scif_sas_smp_protocol_request_construct( 297 &smp_discover, 298 SMP_FUNCTION_DISCOVER, 299 sizeof(SMP_RESPONSE_DISCOVER_T) / sizeof(U32), 300 sizeof(SMP_REQUEST_PHY_IDENTIFIER_T) / sizeof(U32) 301 ); 302 303 smp_discover.request.discover.phy_identifier = phy_identifier; 304 305 SCIF_LOG_INFO(( 306 sci_base_object_get_logger(fw_device), 307 SCIF_LOG_OBJECT_IO_REQUEST | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY, 308 "SMP DISCOVER - Device:0x%x PhyId:0x%x\n", 309 fw_device, phy_identifier 310 )); 311 312 return scif_sas_smp_request_build( 313 fw_controller, fw_device, &smp_discover, 314 external_request_object, external_memory 315 ); 316 } 317 318 319 /** 320 * @brief construct a smp REPORT PHY SATA command to the fw_device. 321 * @param[in] fw_controller The framework controller object. 322 * @param[in] fw_device the framework smp device that DISCOVER command targets 323 * to. 324 * @param[in] phy_identifier The phy index the DISCOVER command targets to. 325 * 326 * @return void * address to the built scif sas smp request. 327 */ 328 void * scif_sas_smp_request_construct_report_phy_sata( 329 SCIF_SAS_CONTROLLER_T * fw_controller, 330 SCIF_SAS_REMOTE_DEVICE_T * fw_device, 331 U8 phy_identifier 332 ) 333 { 334 SMP_REQUEST_T report_phy_sata; 335 336 scif_sas_smp_protocol_request_construct( 337 &report_phy_sata, 338 SMP_FUNCTION_REPORT_PHY_SATA, 339 sizeof(SMP_RESPONSE_REPORT_PHY_SATA_T) / sizeof(U32), 340 sizeof(SMP_REQUEST_PHY_IDENTIFIER_T) / sizeof(U32) 341 ); 342 343 report_phy_sata.request.report_phy_sata.phy_identifier = phy_identifier; 344 345 SCIF_LOG_INFO(( 346 sci_base_object_get_logger(fw_device), 347 SCIF_LOG_OBJECT_IO_REQUEST | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY, 348 "SMP REPORT PHY SATA - Device:0x%x PhyId:0x%x\n", 349 fw_device, phy_identifier 350 )); 351 352 return scif_sas_smp_request_build( 353 fw_controller, fw_device, &report_phy_sata, NULL, NULL); 354 } 355 356 357 /** 358 * @brief construct a smp REPORT PHY SATA command to the fw_device. 359 * @param[in] fw_controller The framework controller object. 360 * @param[in] fw_device the framework smp device that PHY CONTROL command 361 * targets to. 362 * @param[in] phy_identifier The phy index the DISCOVER command targets to. 363 * 364 * @return void * address to the built scif sas smp request. 365 */ 366 void * scif_sas_smp_request_construct_phy_control( 367 SCIF_SAS_CONTROLLER_T * fw_controller, 368 SCIF_SAS_REMOTE_DEVICE_T * fw_device, 369 U8 phy_operation, 370 U8 phy_identifier, 371 void * external_request_object, 372 void * external_memory 373 ) 374 { 375 SMP_REQUEST_T phy_control; 376 377 scif_sas_smp_protocol_request_construct( 378 &phy_control, 379 SMP_FUNCTION_PHY_CONTROL, 380 0, 381 sizeof(SMP_REQUEST_PHY_CONTROL_T) / sizeof(U32) 382 ); 383 384 phy_control.request.phy_control.phy_operation = phy_operation; 385 phy_control.request.phy_control.phy_identifier = phy_identifier; 386 387 return scif_sas_smp_request_build( 388 fw_controller, fw_device, &phy_control, 389 external_request_object, external_memory 390 ); 391 } 392 393 394 /** 395 * @brief construct a smp CONFIG ROUTE INFO command to the fw_device. 396 * 397 * @param[in] fw_controller The framework controller object. 398 * @param[in] fw_device the framework smp device that PHY CONTROL command 399 * targets to. 400 * @param[in] phy_id The phy, whose route entry at route_index is to be configured. 401 * @param[in] route_index The index of a phy's route entry that is to be configured. 402 * @param[in] destination_sas_address A sas address for an route table entry 403 * 404 * @return void * address to the built scif sas smp request. 405 */ 406 void * scif_sas_smp_request_construct_config_route_info( 407 struct SCIF_SAS_CONTROLLER * fw_controller, 408 struct SCIF_SAS_REMOTE_DEVICE * fw_device, 409 U8 phy_id, 410 U16 route_index, 411 SCI_SAS_ADDRESS_T destination_sas_address, 412 BOOL disable_expander_route_entry 413 ) 414 { 415 SMP_REQUEST_T config_route_info; 416 417 scif_sas_smp_protocol_request_construct( 418 &config_route_info, 419 SMP_FUNCTION_CONFIGURE_ROUTE_INFORMATION, 420 0, 421 sizeof(SMP_REQUEST_CONFIGURE_ROUTE_INFORMATION_T) / sizeof(U32) 422 ); 423 424 config_route_info.request.configure_route_information.phy_identifier = phy_id; 425 config_route_info.request.configure_route_information.expander_route_index_high = 426 ((route_index & 0xff00) >> 8); 427 config_route_info.request.configure_route_information.expander_route_index = 428 route_index & 0xff; 429 config_route_info.request.configure_route_information.routed_sas_address[0] = 430 destination_sas_address.high; 431 config_route_info.request.configure_route_information.routed_sas_address[1] = 432 destination_sas_address.low; 433 434 if (disable_expander_route_entry == TRUE) 435 config_route_info.request.configure_route_information.disable_route_entry = 1; 436 437 return scif_sas_smp_request_build( 438 fw_controller, fw_device, &config_route_info, 439 NULL, NULL 440 ); 441 } 442 443 /** 444 * @brief This method retry the internal smp request. 445 * 446 * @param[in] fw_device This parameter specifies the remote device for 447 * which the internal IO request is destined. 448 * @param[in] retry_count This parameter specifies how many times the 449 * old smp request has been retried. 450 * 451 * @return none. 452 */ 453 SCI_STATUS scif_sas_smp_internal_request_retry( 454 SCIF_SAS_REMOTE_DEVICE_T * fw_device 455 ) 456 { 457 SCIF_SAS_CONTROLLER_T * fw_controller; 458 SCIF_SAS_IO_REQUEST_T * new_io; 459 void * new_request_memory = NULL; 460 U8 retry_count = fw_device->protocol_device.smp_device.io_retry_count; 461 462 SCIF_LOG_TRACE(( 463 sci_base_object_get_logger(fw_device), 464 SCIF_LOG_OBJECT_IO_REQUEST | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY, 465 "scif_sas_smp_internal_request_retry(0x%x, 0x%x) time %d!\n", 466 fw_device, retry_count 467 )); 468 469 fw_controller = fw_device->domain->controller; 470 471 switch (fw_device->protocol_device.smp_device.current_smp_request) 472 { 473 case SMP_FUNCTION_REPORT_GENERAL: 474 new_request_memory = scif_sas_smp_request_construct_report_general( 475 fw_controller, fw_device 476 ); 477 break; 478 479 case SMP_FUNCTION_DISCOVER: 480 //We are retrying an internal io. So we are going to allocate 481 //a new memory from internal io memory pool. 482 new_request_memory = scif_sas_smp_request_construct_discover( 483 fw_controller, fw_device, 484 fw_device->protocol_device.smp_device.current_activity_phy_index, 485 NULL, NULL 486 ); 487 488 break; 489 490 case SMP_FUNCTION_REPORT_PHY_SATA: 491 new_request_memory = scif_sas_smp_request_construct_report_phy_sata( 492 fw_controller, fw_device, 493 fw_device->protocol_device.smp_device.current_activity_phy_index 494 ); 495 break; 496 497 default: 498 //unsupported case, TBD 499 break; 500 } //end of switch 501 502 if (new_request_memory != NULL) 503 { 504 //set the retry count to new built smp request. 505 new_io = (SCIF_SAS_IO_REQUEST_T *) new_request_memory; 506 new_io->retry_count = ++retry_count; 507 508 //need to schedule the DPC here. 509 scif_cb_start_internal_io_task_schedule( 510 fw_controller, 511 scif_sas_controller_start_high_priority_io, 512 fw_controller 513 ); 514 515 return SCI_SUCCESS; 516 } 517 else 518 return SCI_FAILURE_INSUFFICIENT_RESOURCES; 519 520 } 521 522 /** 523 * @brief This method retry the external smp request. 524 * 525 * @param[in] fw_device This parameter specifies the remote device for 526 * which the internal IO request is destined. 527 * @param[in] old_internal_io This parameter specifies the old smp request to be 528 * retried. 529 * 530 * @return none. 531 */ 532 SCI_STATUS scif_sas_smp_external_request_retry( 533 SCIF_SAS_IO_REQUEST_T * old_io 534 ) 535 { 536 SCIF_SAS_REMOTE_DEVICE_T * fw_device = old_io->parent.device; 537 SCIF_SAS_CONTROLLER_T * fw_controller; 538 SCIF_SAS_IO_REQUEST_T * new_io; 539 void * new_request_memory = NULL; 540 U8 retry_count = old_io->retry_count; 541 542 SCIF_LOG_TRACE(( 543 sci_base_object_get_logger(fw_device), 544 SCIF_LOG_OBJECT_IO_REQUEST | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY, 545 "scif_sas_smp_external_request_retry(0x%x) time %d!\n", 546 old_io 547 )); 548 549 fw_controller = fw_device->domain->controller; 550 551 // Before we construct new io using the same memory, we need to 552 // remove the IO from the list of outstanding requests on the domain 553 // so that we don't damage the domain's fast list of request. 554 sci_fast_list_remove_element(&old_io->parent.list_element); 555 556 switch (fw_device->protocol_device.smp_device.current_smp_request) 557 { 558 case SMP_FUNCTION_DISCOVER: 559 //we are retrying an external io, we are going to reuse the 560 //old io's memory. new_request_memory is same as old_io. 561 new_request_memory = scif_sas_smp_request_construct_discover( 562 fw_controller, fw_device, 563 fw_device->protocol_device.smp_device.current_activity_phy_index, 564 (void *)sci_object_get_association(old_io), 565 (void *)old_io 566 ); 567 568 break; 569 570 case SMP_FUNCTION_PHY_CONTROL: 571 //Phy Control command always uses external io memory. 572 new_request_memory = scif_sas_smp_request_construct_phy_control( 573 fw_controller, fw_device, PHY_OPERATION_HARD_RESET, 574 fw_device->protocol_device.smp_device.current_activity_phy_index, 575 (void *)sci_object_get_association(old_io), 576 (void *)old_io 577 ); 578 579 break; 580 581 default: 582 //unsupported case, TBD 583 return SCI_FAILURE; 584 } //end of switch 585 586 //set the retry count to new built smp request. 587 new_io = (SCIF_SAS_IO_REQUEST_T *) new_request_memory; 588 new_io->retry_count = ++retry_count; 589 590 //put into the high priority queue. 591 sci_pool_put(fw_controller->hprq.pool, (POINTER_UINT) new_request_memory); 592 593 //schedule the DPC to start new io. 594 scif_cb_start_internal_io_task_schedule( 595 fw_controller, scif_sas_controller_start_high_priority_io, fw_controller 596 ); 597 598 return SCI_SUCCESS; 599 } 600 601