diff options
-rw-r--r-- | drivers/scsi/isci/core/scic_port.h | 17 | ||||
-rw-r--r-- | drivers/scsi/isci/core/scic_sds_controller.c | 22 | ||||
-rw-r--r-- | drivers/scsi/isci/core/scic_sds_port.c | 334 | ||||
-rw-r--r-- | drivers/scsi/isci/core/scic_sds_port.h | 9 | ||||
-rw-r--r-- | drivers/scsi/isci/host.c | 7 |
5 files changed, 298 insertions, 91 deletions
diff --git a/drivers/scsi/isci/core/scic_port.h b/drivers/scsi/isci/core/scic_port.h index e55abb68ff9a..8222443c9fd7 100644 --- a/drivers/scsi/isci/core/scic_port.h +++ b/drivers/scsi/isci/core/scic_port.h | |||
@@ -147,23 +147,6 @@ enum sci_status scic_port_get_properties( | |||
147 | struct scic_sds_port *port, | 147 | struct scic_sds_port *port, |
148 | struct scic_port_properties *properties); | 148 | struct scic_port_properties *properties); |
149 | 149 | ||
150 | |||
151 | |||
152 | /** | ||
153 | * scic_port_start() - This method will make the port ready for operation. | ||
154 | * Prior to calling the start method IO operation is not possible. | ||
155 | * @port: This parameter specifies the port to be started. | ||
156 | * | ||
157 | * Indicate if the port was successfully started. SCI_SUCCESS This value is | ||
158 | * returned if the port was successfully started. SCI_WARNING_ALREADY_IN_STATE | ||
159 | * This value is returned if the port is in the process of starting. | ||
160 | * SCI_FAILURE_INVALID_PORT This value is returned if the supplied port is not | ||
161 | * valid. SCI_FAILURE_INVALID_STATE This value is returned if a start operation | ||
162 | * can't be completed due to the state of port. | ||
163 | */ | ||
164 | enum sci_status scic_port_start( | ||
165 | struct scic_sds_port *port); | ||
166 | |||
167 | /** | 150 | /** |
168 | * scic_port_stop() - This method will make the port no longer ready for | 151 | * scic_port_stop() - This method will make the port no longer ready for |
169 | * operation. After invoking this method IO operation is not possible. | 152 | * operation. After invoking this method IO operation is not possible. |
diff --git a/drivers/scsi/isci/core/scic_sds_controller.c b/drivers/scsi/isci/core/scic_sds_controller.c index d642ff7be6db..5e26df7fcb3a 100644 --- a/drivers/scsi/isci/core/scic_sds_controller.c +++ b/drivers/scsi/isci/core/scic_sds_controller.c | |||
@@ -796,7 +796,11 @@ enum sci_status scic_sds_controller_stop_ports(struct scic_sds_controller *scic) | |||
796 | enum sci_status status = SCI_SUCCESS; | 796 | enum sci_status status = SCI_SUCCESS; |
797 | 797 | ||
798 | for (index = 0; index < scic->logical_port_entries; index++) { | 798 | for (index = 0; index < scic->logical_port_entries; index++) { |
799 | port_status = scic_port_stop(&scic->port_table[index]); | 799 | struct scic_sds_port *sci_port = &scic->port_table[index]; |
800 | SCI_BASE_PORT_HANDLER_T stop; | ||
801 | |||
802 | stop = sci_port->state_handlers->parent.stop_handler; | ||
803 | port_status = stop(&sci_port->parent); | ||
800 | 804 | ||
801 | if ((port_status != SCI_SUCCESS) && | 805 | if ((port_status != SCI_SUCCESS) && |
802 | (port_status != SCI_FAILURE_INVALID_STATE)) { | 806 | (port_status != SCI_FAILURE_INVALID_STATE)) { |
@@ -806,7 +810,7 @@ enum sci_status scic_sds_controller_stop_ports(struct scic_sds_controller *scic) | |||
806 | "%s: Controller stop operation failed to " | 810 | "%s: Controller stop operation failed to " |
807 | "stop port %d because of status %d.\n", | 811 | "stop port %d because of status %d.\n", |
808 | __func__, | 812 | __func__, |
809 | scic->port_table[index].logical_port_index, | 813 | sci_port->logical_port_index, |
810 | port_status); | 814 | port_status); |
811 | } | 815 | } |
812 | } | 816 | } |
@@ -3003,7 +3007,7 @@ static enum sci_status scic_sds_controller_initialized_state_start_handler( | |||
3003 | scic_sds_controller_ram_initialization(this_controller); | 3007 | scic_sds_controller_ram_initialization(this_controller); |
3004 | } | 3008 | } |
3005 | 3009 | ||
3006 | if (SCI_SUCCESS == result) { | 3010 | if (result == SCI_SUCCESS) { |
3007 | /* Build the TCi free pool */ | 3011 | /* Build the TCi free pool */ |
3008 | sci_pool_initialize(this_controller->tci_pool); | 3012 | sci_pool_initialize(this_controller->tci_pool); |
3009 | for (index = 0; index < this_controller->task_context_entries; index++) { | 3013 | for (index = 0; index < this_controller->task_context_entries; index++) { |
@@ -3017,7 +3021,7 @@ static enum sci_status scic_sds_controller_initialized_state_start_handler( | |||
3017 | ); | 3021 | ); |
3018 | } | 3022 | } |
3019 | 3023 | ||
3020 | if (SCI_SUCCESS == result) { | 3024 | if (result == SCI_SUCCESS) { |
3021 | /* | 3025 | /* |
3022 | * Before anything else lets make sure we will not be interrupted | 3026 | * Before anything else lets make sure we will not be interrupted |
3023 | * by the hardware. */ | 3027 | * by the hardware. */ |
@@ -3036,7 +3040,15 @@ static enum sci_status scic_sds_controller_initialized_state_start_handler( | |||
3036 | scic_sds_controller_initialize_unsolicited_frame_queue(this_controller); | 3040 | scic_sds_controller_initialize_unsolicited_frame_queue(this_controller); |
3037 | } | 3041 | } |
3038 | 3042 | ||
3039 | if (SCI_SUCCESS == result) { | 3043 | /* Start all of the ports on this controller */ |
3044 | for (index = 0; index < this_controller->logical_port_entries && | ||
3045 | result == SCI_SUCCESS; index++) { | ||
3046 | struct scic_sds_port *sci_port = &this_controller->port_table[index]; | ||
3047 | |||
3048 | result = sci_port->state_handlers->parent.start_handler(&sci_port->parent); | ||
3049 | } | ||
3050 | |||
3051 | if (result == SCI_SUCCESS) { | ||
3040 | scic_sds_controller_start_next_phy(this_controller); | 3052 | scic_sds_controller_start_next_phy(this_controller); |
3041 | 3053 | ||
3042 | isci_event_timer_start(this_controller, | 3054 | isci_event_timer_start(this_controller, |
diff --git a/drivers/scsi/isci/core/scic_sds_port.c b/drivers/scsi/isci/core/scic_sds_port.c index d374c7ac0b71..2a193d30c55d 100644 --- a/drivers/scsi/isci/core/scic_sds_port.c +++ b/drivers/scsi/isci/core/scic_sds_port.c | |||
@@ -67,6 +67,7 @@ | |||
67 | #include "scic_sds_remote_node_context.h" | 67 | #include "scic_sds_remote_node_context.h" |
68 | #include "scic_sds_request.h" | 68 | #include "scic_sds_request.h" |
69 | #include "sci_environment.h" | 69 | #include "sci_environment.h" |
70 | #include "scic_sds_controller_registers.h" | ||
70 | 71 | ||
71 | 72 | ||
72 | static void scic_sds_port_invalid_link_up( | 73 | static void scic_sds_port_invalid_link_up( |
@@ -78,6 +79,7 @@ static void scic_sds_port_timeout_handler( | |||
78 | #define SCIC_SDS_PORT_MAX_TIMER_COUNT (SCI_MAX_PORTS) | 79 | #define SCIC_SDS_PORT_MAX_TIMER_COUNT (SCI_MAX_PORTS) |
79 | 80 | ||
80 | #define SCIC_SDS_PORT_HARD_RESET_TIMEOUT (1000) | 81 | #define SCIC_SDS_PORT_HARD_RESET_TIMEOUT (1000) |
82 | #define SCU_DUMMY_INDEX (0xFFFF) | ||
81 | 83 | ||
82 | void sci_base_port_construct( | 84 | void sci_base_port_construct( |
83 | struct sci_base_port *base_port, | 85 | struct sci_base_port *base_port, |
@@ -474,67 +476,131 @@ void scic_sds_port_get_attached_protocols( | |||
474 | } | 476 | } |
475 | 477 | ||
476 | /** | 478 | /** |
477 | * This method returns the amount of memory requred for a port object. | 479 | * scic_sds_port_construct_dummy_rnc() - create dummy rnc for si workaround |
478 | * | 480 | * |
479 | * u32 | 481 | * @sci_port: logical port on which we need to create the remote node context |
480 | */ | 482 | * @rni: remote node index for this remote node context. |
481 | |||
482 | /** | ||
483 | * This method returns the minimum number of timers required for all port | ||
484 | * objects. | ||
485 | * | 483 | * |
486 | * u32 | 484 | * This routine will construct a dummy remote node context data structure |
485 | * This structure will be posted to the hardware to work around a scheduler | ||
486 | * error in the hardware. | ||
487 | */ | 487 | */ |
488 | void scic_sds_port_construct_dummy_rnc(struct scic_sds_port *sci_port, u16 rni) | ||
489 | { | ||
490 | union scu_remote_node_context *rnc; | ||
488 | 491 | ||
489 | /** | 492 | rnc = &sci_port->owning_controller->remote_node_context_table[rni]; |
490 | * This method returns the maximum number of timers required for all port | 493 | |
491 | * objects. | 494 | memset(rnc, 0, sizeof(union scu_remote_node_context)); |
492 | * | 495 | |
493 | * u32 | 496 | rnc->ssp.remote_sas_address_hi = 0; |
494 | */ | 497 | rnc->ssp.remote_sas_address_lo = 0; |
498 | |||
499 | rnc->ssp.remote_node_index = rni; | ||
500 | rnc->ssp.remote_node_port_width = 1; | ||
501 | rnc->ssp.logical_port_index = sci_port->physical_port_index; | ||
502 | |||
503 | rnc->ssp.nexus_loss_timer_enable = false; | ||
504 | rnc->ssp.check_bit = false; | ||
505 | rnc->ssp.is_valid = true; | ||
506 | rnc->ssp.is_remote_node_context = true; | ||
507 | rnc->ssp.function_number = 0; | ||
508 | rnc->ssp.arbitration_wait_time = 0; | ||
509 | } | ||
495 | 510 | ||
496 | /** | 511 | /** |
512 | * scic_sds_port_construct_dummy_task() - create dummy task for si workaround | ||
513 | * @sci_port The logical port on which we need to create the | ||
514 | * remote node context. | ||
515 | * context. | ||
516 | * @tci The remote node index for this remote node context. | ||
497 | * | 517 | * |
498 | * @this_port: | 518 | * This routine will construct a dummy task context data structure. This |
499 | * @port_index: | 519 | * structure will be posted to the hardwre to work around a scheduler error |
500 | * | 520 | * in the hardware. |
501 | * | 521 | * |
502 | */ | 522 | */ |
503 | void scic_sds_port_construct( | 523 | void scic_sds_port_construct_dummy_task(struct scic_sds_port *sci_port, u16 tci) |
504 | struct scic_sds_port *this_port, | 524 | { |
505 | u8 port_index, | 525 | struct scu_task_context *task_context; |
506 | struct scic_sds_controller *owning_controller) | 526 | |
527 | task_context = scic_sds_controller_get_task_context_buffer(sci_port->owning_controller, tci); | ||
528 | |||
529 | memset(task_context, 0, sizeof(struct scu_task_context)); | ||
530 | |||
531 | task_context->abort = 0; | ||
532 | task_context->priority = 0; | ||
533 | task_context->initiator_request = 1; | ||
534 | task_context->connection_rate = 1; | ||
535 | task_context->protocol_engine_index = 0; | ||
536 | task_context->logical_port_index = sci_port->physical_port_index; | ||
537 | task_context->protocol_type = SCU_TASK_CONTEXT_PROTOCOL_SSP; | ||
538 | task_context->task_index = scic_sds_io_tag_get_index(tci); | ||
539 | task_context->valid = SCU_TASK_CONTEXT_VALID; | ||
540 | task_context->context_type = SCU_TASK_CONTEXT_TYPE; | ||
541 | |||
542 | task_context->remote_node_index = sci_port->reserved_rni; | ||
543 | task_context->command_code = 0; | ||
544 | |||
545 | task_context->link_layer_control = 0; | ||
546 | task_context->do_not_dma_ssp_good_response = 1; | ||
547 | task_context->strict_ordering = 0; | ||
548 | task_context->control_frame = 0; | ||
549 | task_context->timeout_enable = 0; | ||
550 | task_context->block_guard_enable = 0; | ||
551 | |||
552 | task_context->address_modifier = 0; | ||
553 | |||
554 | task_context->task_phase = 0x01; | ||
555 | } | ||
556 | |||
557 | void scic_sds_port_destroy_dummy_resources(struct scic_sds_port *sci_port) | ||
558 | { | ||
559 | struct scic_sds_controller *scic = sci_port->owning_controller; | ||
560 | |||
561 | if (sci_port->reserved_tci != SCU_DUMMY_INDEX) | ||
562 | scic_controller_free_io_tag(scic, sci_port->reserved_tci); | ||
563 | |||
564 | if (sci_port->reserved_rni != SCU_DUMMY_INDEX) | ||
565 | scic_sds_remote_node_table_release_remote_node_index(&scic->available_remote_nodes, | ||
566 | 1, sci_port->reserved_rni); | ||
567 | |||
568 | sci_port->reserved_rni = SCU_DUMMY_INDEX; | ||
569 | sci_port->reserved_tci = SCU_DUMMY_INDEX; | ||
570 | } | ||
571 | |||
572 | void scic_sds_port_construct(struct scic_sds_port *sci_port, u8 port_index, | ||
573 | struct scic_sds_controller *scic) | ||
507 | { | 574 | { |
508 | u32 index; | 575 | u32 index; |
509 | 576 | ||
510 | sci_base_port_construct( | 577 | sci_base_port_construct(&sci_port->parent, scic_sds_port_state_table); |
511 | &this_port->parent, | ||
512 | scic_sds_port_state_table | ||
513 | ); | ||
514 | 578 | ||
515 | sci_base_state_machine_construct( | 579 | sci_base_state_machine_construct( |
516 | scic_sds_port_get_ready_substate_machine(this_port), | 580 | scic_sds_port_get_ready_substate_machine(sci_port), |
517 | &this_port->parent.parent, | 581 | &sci_port->parent.parent, |
518 | scic_sds_port_ready_substate_table, | 582 | scic_sds_port_ready_substate_table, |
519 | SCIC_SDS_PORT_READY_SUBSTATE_WAITING | 583 | SCIC_SDS_PORT_READY_SUBSTATE_WAITING |
520 | ); | 584 | ); |
521 | 585 | ||
522 | this_port->logical_port_index = SCIC_SDS_DUMMY_PORT; | 586 | sci_port->logical_port_index = SCIC_SDS_DUMMY_PORT; |
523 | this_port->physical_port_index = port_index; | 587 | sci_port->physical_port_index = port_index; |
524 | this_port->active_phy_mask = 0; | 588 | sci_port->active_phy_mask = 0; |
525 | 589 | ||
526 | this_port->owning_controller = owning_controller; | 590 | sci_port->owning_controller = scic; |
527 | 591 | ||
528 | this_port->started_request_count = 0; | 592 | sci_port->started_request_count = 0; |
529 | this_port->assigned_device_count = 0; | 593 | sci_port->assigned_device_count = 0; |
530 | 594 | ||
531 | this_port->timer_handle = NULL; | 595 | sci_port->reserved_rni = SCU_DUMMY_INDEX; |
596 | sci_port->reserved_tci = SCU_DUMMY_INDEX; | ||
532 | 597 | ||
533 | this_port->port_task_scheduler_registers = NULL; | 598 | sci_port->timer_handle = NULL; |
534 | 599 | ||
535 | for (index = 0; index < SCI_MAX_PHYS; index++) { | 600 | sci_port->port_task_scheduler_registers = NULL; |
536 | this_port->phy_table[index] = NULL; | 601 | |
537 | } | 602 | for (index = 0; index < SCI_MAX_PHYS; index++) |
603 | sci_port->phy_table[index] = NULL; | ||
538 | } | 604 | } |
539 | 605 | ||
540 | /** | 606 | /** |
@@ -634,19 +700,11 @@ void scic_sds_port_general_link_up_handler( | |||
634 | } | 700 | } |
635 | } | 701 | } |
636 | 702 | ||
637 | |||
638 | enum sci_status scic_port_start(struct scic_sds_port *port) | ||
639 | { | ||
640 | return port->state_handlers->parent.start_handler(&port->parent); | ||
641 | } | ||
642 | |||
643 | |||
644 | enum sci_status scic_port_stop(struct scic_sds_port *port) | 703 | enum sci_status scic_port_stop(struct scic_sds_port *port) |
645 | { | 704 | { |
646 | return port->state_handlers->parent.stop_handler(&port->parent); | 705 | return port->state_handlers->parent.stop_handler(&port->parent); |
647 | } | 706 | } |
648 | 707 | ||
649 | |||
650 | enum sci_status scic_port_get_properties( | 708 | enum sci_status scic_port_get_properties( |
651 | struct scic_sds_port *port, | 709 | struct scic_sds_port *port, |
652 | struct scic_port_properties *prop) | 710 | struct scic_port_properties *prop) |
@@ -1542,6 +1600,58 @@ static void scic_sds_port_suspend_port_task_scheduler( | |||
1542 | } | 1600 | } |
1543 | 1601 | ||
1544 | /** | 1602 | /** |
1603 | * scic_sds_port_post_dummy_request() - post dummy/workaround request | ||
1604 | * @sci_port: port to post task | ||
1605 | * | ||
1606 | * Prevent the hardware scheduler from posting new requests to the front | ||
1607 | * of the scheduler queue causing a starvation problem for currently | ||
1608 | * ongoing requests. | ||
1609 | * | ||
1610 | */ | ||
1611 | void scic_sds_port_post_dummy_request(struct scic_sds_port *sci_port) | ||
1612 | { | ||
1613 | u32 command; | ||
1614 | struct scu_task_context *task_context; | ||
1615 | struct scic_sds_controller *scic = sci_port->owning_controller; | ||
1616 | u16 tci = sci_port->reserved_tci; | ||
1617 | |||
1618 | task_context = scic_sds_controller_get_task_context_buffer(scic, tci); | ||
1619 | |||
1620 | task_context->abort = 0; | ||
1621 | |||
1622 | command = SCU_CONTEXT_COMMAND_REQUEST_TYPE_POST_TC | | ||
1623 | sci_port->physical_port_index << SCU_CONTEXT_COMMAND_LOGICAL_PORT_SHIFT | | ||
1624 | tci; | ||
1625 | |||
1626 | scic_sds_controller_post_request(scic, command); | ||
1627 | } | ||
1628 | |||
1629 | /** | ||
1630 | * This routine will abort the dummy request. This will alow the hardware to | ||
1631 | * power down parts of the silicon to save power. | ||
1632 | * | ||
1633 | * @sci_port: The port on which the task must be aborted. | ||
1634 | * | ||
1635 | */ | ||
1636 | void scic_sds_port_abort_dummy_request(struct scic_sds_port *sci_port) | ||
1637 | { | ||
1638 | struct scic_sds_controller *scic = sci_port->owning_controller; | ||
1639 | u16 tci = sci_port->reserved_tci; | ||
1640 | struct scu_task_context *tc; | ||
1641 | u32 command; | ||
1642 | |||
1643 | tc = scic_sds_controller_get_task_context_buffer(scic, tci); | ||
1644 | |||
1645 | tc->abort = 1; | ||
1646 | |||
1647 | command = SCU_CONTEXT_COMMAND_REQUEST_POST_TC_ABORT | | ||
1648 | sci_port->physical_port_index << SCU_CONTEXT_COMMAND_LOGICAL_PORT_SHIFT | | ||
1649 | tci; | ||
1650 | |||
1651 | scic_sds_controller_post_request(scic, command); | ||
1652 | } | ||
1653 | |||
1654 | /** | ||
1545 | * | 1655 | * |
1546 | * @this_port: This is the struct scic_sds_port object to resume. | 1656 | * @this_port: This is the struct scic_sds_port object to resume. |
1547 | * | 1657 | * |
@@ -1584,6 +1694,12 @@ static void scic_sds_port_ready_substate_waiting_enter( | |||
1584 | 1694 | ||
1585 | scic_sds_port_suspend_port_task_scheduler(this_port); | 1695 | scic_sds_port_suspend_port_task_scheduler(this_port); |
1586 | 1696 | ||
1697 | /* Kill the dummy task for this port if it has not yet posted | ||
1698 | * the hardware will treat this as a NOP and just return abort | ||
1699 | * complete. | ||
1700 | */ | ||
1701 | scic_sds_port_abort_dummy_request(this_port); | ||
1702 | |||
1587 | this_port->not_ready_reason = SCIC_PORT_NOT_READY_NO_ACTIVE_PHYS; | 1703 | this_port->not_ready_reason = SCIC_PORT_NOT_READY_NO_ACTIVE_PHYS; |
1588 | 1704 | ||
1589 | if (this_port->active_phy_mask != 0) { | 1705 | if (this_port->active_phy_mask != 0) { |
@@ -1629,6 +1745,11 @@ static void scic_sds_port_ready_substate_operational_enter( | |||
1629 | scic_sds_port_update_viit_entry(this_port); | 1745 | scic_sds_port_update_viit_entry(this_port); |
1630 | 1746 | ||
1631 | scic_sds_port_resume_port_task_scheduler(this_port); | 1747 | scic_sds_port_resume_port_task_scheduler(this_port); |
1748 | |||
1749 | /* Post the dummy task for the port so the hardware can schedule | ||
1750 | * io correctly | ||
1751 | */ | ||
1752 | scic_sds_port_post_dummy_request(this_port); | ||
1632 | } | 1753 | } |
1633 | 1754 | ||
1634 | /** | 1755 | /** |
@@ -2062,6 +2183,7 @@ static enum sci_status scic_sds_port_general_complete_io_handler( | |||
2062 | * **************************************************************************** */ | 2183 | * **************************************************************************** */ |
2063 | 2184 | ||
2064 | /** | 2185 | /** |
2186 | * scic_sds_port_stopped_state_start_handler() - stop a port from "started" | ||
2065 | * | 2187 | * |
2066 | * @port: This is the struct sci_base_port object which is cast into a struct scic_sds_port | 2188 | * @port: This is the struct sci_base_port object which is cast into a struct scic_sds_port |
2067 | * object. | 2189 | * object. |
@@ -2075,13 +2197,14 @@ static enum sci_status scic_sds_port_general_complete_io_handler( | |||
2075 | * start request is successful and the struct scic_sds_port object has transitioned to | 2197 | * start request is successful and the struct scic_sds_port object has transitioned to |
2076 | * the SCI_BASE_PORT_STATE_READY. | 2198 | * the SCI_BASE_PORT_STATE_READY. |
2077 | */ | 2199 | */ |
2078 | static enum sci_status scic_sds_port_stopped_state_start_handler( | 2200 | static enum sci_status scic_sds_port_stopped_state_start_handler(struct sci_base_port *base_port) |
2079 | struct sci_base_port *port) | ||
2080 | { | 2201 | { |
2202 | struct scic_sds_port *sci_port = container_of(base_port, typeof(*sci_port), parent); | ||
2203 | struct scic_sds_controller *scic = sci_port->owning_controller; | ||
2204 | enum sci_status status = SCI_SUCCESS; | ||
2081 | u32 phy_mask; | 2205 | u32 phy_mask; |
2082 | struct scic_sds_port *this_port = (struct scic_sds_port *)port; | ||
2083 | 2206 | ||
2084 | if (this_port->assigned_device_count > 0) { | 2207 | if (sci_port->assigned_device_count > 0) { |
2085 | /* | 2208 | /* |
2086 | * / @todo This is a start failure operation because there are still | 2209 | * / @todo This is a start failure operation because there are still |
2087 | * / devices assigned to this port. There must be no devices | 2210 | * / devices assigned to this port. There must be no devices |
@@ -2089,22 +2212,56 @@ static enum sci_status scic_sds_port_stopped_state_start_handler( | |||
2089 | return SCI_FAILURE_UNSUPPORTED_PORT_CONFIGURATION; | 2212 | return SCI_FAILURE_UNSUPPORTED_PORT_CONFIGURATION; |
2090 | } | 2213 | } |
2091 | 2214 | ||
2092 | phy_mask = scic_sds_port_get_phys(this_port); | 2215 | sci_port->timer_handle = isci_event_timer_create(scic, |
2216 | scic_sds_port_timeout_handler, | ||
2217 | sci_port); | ||
2093 | 2218 | ||
2094 | /* | 2219 | if (!sci_port->timer_handle) |
2095 | * There are one or more phys assigned to this port. Make sure | 2220 | return SCI_FAILURE_INSUFFICIENT_RESOURCES; |
2096 | * the port's phy mask is in fact legal and supported by the | ||
2097 | * silicon. */ | ||
2098 | if (scic_sds_port_is_phy_mask_valid(this_port, phy_mask) == true) { | ||
2099 | sci_base_state_machine_change_state( | ||
2100 | scic_sds_port_get_base_state_machine(this_port), | ||
2101 | SCI_BASE_PORT_STATE_READY | ||
2102 | ); | ||
2103 | 2221 | ||
2104 | return SCI_SUCCESS; | 2222 | if (sci_port->reserved_rni == SCU_DUMMY_INDEX) { |
2223 | u16 rni = scic_sds_remote_node_table_allocate_remote_node(&scic->available_remote_nodes, 1); | ||
2224 | |||
2225 | if (rni != SCU_DUMMY_INDEX) | ||
2226 | scic_sds_port_construct_dummy_rnc(sci_port, rni); | ||
2227 | else | ||
2228 | status = SCI_FAILURE_INSUFFICIENT_RESOURCES; | ||
2229 | sci_port->reserved_rni = rni; | ||
2230 | } | ||
2231 | |||
2232 | if (sci_port->reserved_tci == SCU_DUMMY_INDEX) { | ||
2233 | /* Allocate a TCI and remove the sequence nibble */ | ||
2234 | u16 tci = scic_controller_allocate_io_tag(scic); | ||
2235 | |||
2236 | if (tci != SCU_DUMMY_INDEX) | ||
2237 | scic_sds_port_construct_dummy_task(sci_port, tci); | ||
2238 | else | ||
2239 | status = SCI_FAILURE_INSUFFICIENT_RESOURCES; | ||
2240 | sci_port->reserved_tci = tci; | ||
2241 | } | ||
2242 | |||
2243 | if (status == SCI_SUCCESS) { | ||
2244 | phy_mask = scic_sds_port_get_phys(sci_port); | ||
2245 | |||
2246 | /* | ||
2247 | * There are one or more phys assigned to this port. Make sure | ||
2248 | * the port's phy mask is in fact legal and supported by the | ||
2249 | * silicon. | ||
2250 | */ | ||
2251 | if (scic_sds_port_is_phy_mask_valid(sci_port, phy_mask) == true) { | ||
2252 | sci_base_state_machine_change_state( | ||
2253 | scic_sds_port_get_base_state_machine(sci_port), | ||
2254 | SCI_BASE_PORT_STATE_READY); | ||
2255 | |||
2256 | return SCI_SUCCESS; | ||
2257 | } else | ||
2258 | status = SCI_FAILURE; | ||
2105 | } | 2259 | } |
2106 | 2260 | ||
2107 | return SCI_FAILURE_UNSUPPORTED_PORT_CONFIGURATION; | 2261 | if (status != SCI_SUCCESS) |
2262 | scic_sds_port_destroy_dummy_resources(sci_port); | ||
2263 | |||
2264 | return status; | ||
2108 | } | 2265 | } |
2109 | 2266 | ||
2110 | /** | 2267 | /** |
@@ -2467,6 +2624,52 @@ static void scic_sds_port_disable_port_task_scheduler( | |||
2467 | scu_port_task_scheduler_write(this_port, control, pts_control_value); | 2624 | scu_port_task_scheduler_write(this_port, control, pts_control_value); |
2468 | } | 2625 | } |
2469 | 2626 | ||
2627 | void scic_sds_port_post_dummy_remote_node(struct scic_sds_port *sci_port) | ||
2628 | { | ||
2629 | struct scic_sds_controller *scic = sci_port->owning_controller; | ||
2630 | u8 phys_index = sci_port->physical_port_index; | ||
2631 | union scu_remote_node_context *rnc; | ||
2632 | u16 rni = sci_port->reserved_rni; | ||
2633 | u32 command; | ||
2634 | |||
2635 | rnc = &scic->remote_node_context_table[rni]; | ||
2636 | rnc->ssp.is_valid = true; | ||
2637 | |||
2638 | command = SCU_CONTEXT_COMMAND_POST_RNC_32 | | ||
2639 | phys_index << SCU_CONTEXT_COMMAND_LOGICAL_PORT_SHIFT | rni; | ||
2640 | |||
2641 | scic_sds_controller_post_request(scic, command); | ||
2642 | |||
2643 | /* ensure hardware has seen the post rnc command and give it | ||
2644 | * ample time to act before sending the suspend | ||
2645 | */ | ||
2646 | SMU_ISR_READ(scic); /* flush */ | ||
2647 | udelay(10); | ||
2648 | |||
2649 | command = SCU_CONTEXT_COMMAND_POST_RNC_SUSPEND_TX_RX | | ||
2650 | phys_index << SCU_CONTEXT_COMMAND_LOGICAL_PORT_SHIFT | rni; | ||
2651 | |||
2652 | scic_sds_controller_post_request(scic, command); | ||
2653 | } | ||
2654 | |||
2655 | void scic_sds_port_invalidate_dummy_remote_node(struct scic_sds_port *sci_port) | ||
2656 | { | ||
2657 | struct scic_sds_controller *scic = sci_port->owning_controller; | ||
2658 | u8 phys_index = sci_port->physical_port_index; | ||
2659 | union scu_remote_node_context *rnc; | ||
2660 | u16 rni = sci_port->reserved_rni; | ||
2661 | u32 command; | ||
2662 | |||
2663 | rnc = &scic->remote_node_context_table[rni]; | ||
2664 | |||
2665 | rnc->ssp.is_valid = false; | ||
2666 | |||
2667 | command = SCU_CONTEXT_COMMAND_POST_RNC_INVALIDATE | | ||
2668 | phys_index << SCU_CONTEXT_COMMAND_LOGICAL_PORT_SHIFT | rni; | ||
2669 | |||
2670 | scic_sds_controller_post_request(scic, command); | ||
2671 | } | ||
2672 | |||
2470 | /* | 2673 | /* |
2471 | * ****************************************************************************** | 2674 | * ****************************************************************************** |
2472 | * * PORT STATE METHODS | 2675 | * * PORT STATE METHODS |
@@ -2562,6 +2765,9 @@ static void scic_sds_port_ready_state_enter( | |||
2562 | ); | 2765 | ); |
2563 | } | 2766 | } |
2564 | 2767 | ||
2768 | /* Post and suspend the dummy remote node context for this port. */ | ||
2769 | scic_sds_port_post_dummy_remote_node(this_port); | ||
2770 | |||
2565 | /* Start the ready substate machine */ | 2771 | /* Start the ready substate machine */ |
2566 | sci_base_state_machine_start( | 2772 | sci_base_state_machine_start( |
2567 | scic_sds_port_get_ready_substate_machine(this_port) | 2773 | scic_sds_port_get_ready_substate_machine(this_port) |
@@ -2583,6 +2789,8 @@ static void scic_sds_port_ready_state_exit( | |||
2583 | this_port = (struct scic_sds_port *)object; | 2789 | this_port = (struct scic_sds_port *)object; |
2584 | 2790 | ||
2585 | sci_base_state_machine_stop(&this_port->ready_substate_machine); | 2791 | sci_base_state_machine_stop(&this_port->ready_substate_machine); |
2792 | |||
2793 | scic_sds_port_invalidate_dummy_remote_node(this_port); | ||
2586 | } | 2794 | } |
2587 | 2795 | ||
2588 | /** | 2796 | /** |
@@ -2663,6 +2871,8 @@ static void scic_sds_port_stopping_state_exit( | |||
2663 | scic_sds_port_get_controller(this_port), | 2871 | scic_sds_port_get_controller(this_port), |
2664 | this_port->timer_handle | 2872 | this_port->timer_handle |
2665 | ); | 2873 | ); |
2874 | |||
2875 | scic_sds_port_destroy_dummy_resources(this_port); | ||
2666 | } | 2876 | } |
2667 | 2877 | ||
2668 | /** | 2878 | /** |
diff --git a/drivers/scsi/isci/core/scic_sds_port.h b/drivers/scsi/isci/core/scic_sds_port.h index 3eb80cb2ea47..c98caefa7cf2 100644 --- a/drivers/scsi/isci/core/scic_sds_port.h +++ b/drivers/scsi/isci/core/scic_sds_port.h | |||
@@ -73,6 +73,12 @@ | |||
73 | #define SCIC_SDS_DUMMY_PORT 0xFF | 73 | #define SCIC_SDS_DUMMY_PORT 0xFF |
74 | 74 | ||
75 | /** | 75 | /** |
76 | * This constant defines the value utilized by SCI Components to indicate | ||
77 | * an invalid handle. | ||
78 | */ | ||
79 | #define SCI_INVALID_HANDLE 0x0 | ||
80 | |||
81 | /** | ||
76 | * enum SCIC_SDS_PORT_READY_SUBSTATES - | 82 | * enum SCIC_SDS_PORT_READY_SUBSTATES - |
77 | * | 83 | * |
78 | * This enumeration depicts all of the states for the core port ready substate | 84 | * This enumeration depicts all of the states for the core port ready substate |
@@ -134,6 +140,9 @@ struct scic_sds_port { | |||
134 | */ | 140 | */ |
135 | u8 active_phy_mask; | 141 | u8 active_phy_mask; |
136 | 142 | ||
143 | u16 reserved_rni; | ||
144 | u16 reserved_tci; | ||
145 | |||
137 | /** | 146 | /** |
138 | * This field contains the count of the io requests started on this port | 147 | * This field contains the count of the io requests started on this port |
139 | * object. It is used to control controller shutdown. | 148 | * object. It is used to control controller shutdown. |
diff --git a/drivers/scsi/isci/host.c b/drivers/scsi/isci/host.c index 1bc91f2b4f93..40614e9ab41b 100644 --- a/drivers/scsi/isci/host.c +++ b/drivers/scsi/isci/host.c | |||
@@ -381,7 +381,6 @@ int isci_host_init(struct isci_host *isci_host) | |||
381 | int index = 0; | 381 | int index = 0; |
382 | enum sci_status status; | 382 | enum sci_status status; |
383 | struct scic_sds_controller *controller; | 383 | struct scic_sds_controller *controller; |
384 | struct scic_sds_port *scic_port; | ||
385 | union scic_oem_parameters scic_oem_params; | 384 | union scic_oem_parameters scic_oem_params; |
386 | union scic_user_parameters scic_user_params; | 385 | union scic_user_parameters scic_user_params; |
387 | 386 | ||
@@ -517,11 +516,5 @@ int isci_host_init(struct isci_host *isci_host) | |||
517 | for (index = 0; index < SCI_MAX_PHYS; index++) | 516 | for (index = 0; index < SCI_MAX_PHYS; index++) |
518 | isci_phy_init(&isci_host->phys[index], isci_host, index); | 517 | isci_phy_init(&isci_host->phys[index], isci_host, index); |
519 | 518 | ||
520 | /* Start the ports */ | ||
521 | for (index = 0; index < SCI_MAX_PORTS; index++) { | ||
522 | scic_controller_get_port_handle(controller, index, &scic_port); | ||
523 | scic_port_start(scic_port); | ||
524 | } | ||
525 | |||
526 | return 0; | 519 | return 0; |
527 | } | 520 | } |