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