diff options
Diffstat (limited to 'drivers/scsi/isci/port.c')
| -rw-r--r-- | drivers/scsi/isci/port.c | 429 |
1 files changed, 231 insertions, 198 deletions
diff --git a/drivers/scsi/isci/port.c b/drivers/scsi/isci/port.c index ac7f27749f9..13098b09a82 100644 --- a/drivers/scsi/isci/port.c +++ b/drivers/scsi/isci/port.c @@ -60,18 +60,29 @@ #define SCIC_SDS_PORT_HARD_RESET_TIMEOUT (1000) #define SCU_DUMMY_INDEX (0xFFFF) -static void isci_port_change_state(struct isci_port *iport, enum isci_status status) +#undef C +#define C(a) (#a) +const char *port_state_name(enum sci_port_states state) { - unsigned long flags; + static const char * const strings[] = PORT_STATES; + + return strings[state]; +} +#undef C + +static struct device *sciport_to_dev(struct isci_port *iport) +{ + int i = iport->physical_port_index; + struct isci_port *table; + struct isci_host *ihost; - dev_dbg(&iport->isci_host->pdev->dev, - "%s: iport = %p, state = 0x%x\n", - __func__, iport, status); + if (i == SCIC_SDS_DUMMY_PORT) + i = SCI_MAX_PORTS+1; - /* XXX pointless lock */ - spin_lock_irqsave(&iport->state_lock, flags); - iport->status = status; - spin_unlock_irqrestore(&iport->state_lock, flags); + table = iport - i; + ihost = container_of(table, typeof(*ihost), ports[0]); + + return &ihost->pdev->dev; } static void sci_port_get_protocols(struct isci_port *iport, struct sci_phy_proto *proto) @@ -114,7 +125,7 @@ static u32 sci_port_get_phys(struct isci_port *iport) * value is returned if the specified port is not valid. When this value is * returned, no data is copied to the properties output parameter. */ -static enum sci_status sci_port_get_properties(struct isci_port *iport, +enum sci_status sci_port_get_properties(struct isci_port *iport, struct sci_port_properties *prop) { if (!iport || iport->logical_port_index == SCIC_SDS_DUMMY_PORT) @@ -165,21 +176,15 @@ static void isci_port_link_up(struct isci_host *isci_host, struct sci_port_properties properties; unsigned long success = true; - BUG_ON(iphy->isci_port != NULL); - - iphy->isci_port = iport; - dev_dbg(&isci_host->pdev->dev, "%s: isci_port = %p\n", __func__, iport); spin_lock_irqsave(&iphy->sas_phy.frame_rcvd_lock, flags); - isci_port_change_state(iphy->isci_port, isci_starting); - sci_port_get_properties(iport, &properties); - if (iphy->protocol == SCIC_SDS_PHY_PROTOCOL_SATA) { + if (iphy->protocol == SAS_PROTOCOL_SATA) { u64 attached_sas_address; iphy->sas_phy.oob_mode = SATA_OOB_MODE; @@ -199,7 +204,7 @@ static void isci_port_link_up(struct isci_host *isci_host, memcpy(&iphy->sas_phy.attached_sas_addr, &attached_sas_address, sizeof(attached_sas_address)); - } else if (iphy->protocol == SCIC_SDS_PHY_PROTOCOL_SAS) { + } else if (iphy->protocol == SAS_PROTOCOL_SSP) { iphy->sas_phy.oob_mode = SAS_OOB_MODE; iphy->sas_phy.frame_rcvd_size = sizeof(struct sas_identify_frame); @@ -207,7 +212,7 @@ static void isci_port_link_up(struct isci_host *isci_host, memcpy(iphy->sas_phy.attached_sas_addr, iphy->frame_rcvd.iaf.sas_addr, SAS_ADDR_SIZE); } else { - dev_err(&isci_host->pdev->dev, "%s: unkown target\n", __func__); + dev_err(&isci_host->pdev->dev, "%s: unknown target\n", __func__); success = false; } @@ -246,10 +251,10 @@ static void isci_port_link_down(struct isci_host *isci_host, if (isci_phy->sas_phy.port && isci_phy->sas_phy.port->num_phys == 1) { /* change the state for all devices on this port. The - * next task sent to this device will be returned as - * SAS_TASK_UNDELIVERED, and the scsi mid layer will - * remove the target - */ + * next task sent to this device will be returned as + * SAS_TASK_UNDELIVERED, and the scsi mid layer will + * remove the target + */ list_for_each_entry(isci_device, &isci_port->remote_dev_list, node) { @@ -258,7 +263,6 @@ static void isci_port_link_down(struct isci_host *isci_host, __func__, isci_device); set_bit(IDEV_GONE, &isci_device->flags); } - isci_port_change_state(isci_port, isci_stopping); } } @@ -269,52 +273,10 @@ static void isci_port_link_down(struct isci_host *isci_host, isci_host->sas_ha.notify_phy_event(&isci_phy->sas_phy, PHYE_LOSS_OF_SIGNAL); - isci_phy->isci_port = NULL; - dev_dbg(&isci_host->pdev->dev, "%s: isci_port = %p - Done\n", __func__, isci_port); } - -/** - * isci_port_ready() - This function is called by the sci core when a link - * becomes ready. - * @isci_host: This parameter specifies the isci host object. - * @port: This parameter specifies the sci port with the active link. - * - */ -static void isci_port_ready(struct isci_host *isci_host, struct isci_port *isci_port) -{ - dev_dbg(&isci_host->pdev->dev, - "%s: isci_port = %p\n", __func__, isci_port); - - complete_all(&isci_port->start_complete); - isci_port_change_state(isci_port, isci_ready); - return; -} - -/** - * isci_port_not_ready() - This function is called by the sci core when a link - * is not ready. All remote devices on this link will be removed if they are - * in the stopping state. - * @isci_host: This parameter specifies the isci host object. - * @port: This parameter specifies the sci port with the active link. - * - */ -static void isci_port_not_ready(struct isci_host *isci_host, struct isci_port *isci_port) -{ - dev_dbg(&isci_host->pdev->dev, - "%s: isci_port = %p\n", __func__, isci_port); -} - -static void isci_port_stop_complete(struct isci_host *ihost, - struct isci_port *iport, - enum sci_status completion_status) -{ - dev_dbg(&ihost->pdev->dev, "Port stop complete\n"); -} - - static bool is_port_ready_state(enum sci_port_states state) { switch (state) { @@ -353,7 +315,9 @@ static void port_state_machine_change(struct isci_port *iport, static void isci_port_hard_reset_complete(struct isci_port *isci_port, enum sci_status completion_status) { - dev_dbg(&isci_port->isci_host->pdev->dev, + struct isci_host *ihost = isci_port->owning_controller; + + dev_dbg(&ihost->pdev->dev, "%s: isci_port = %p, completion_status=%x\n", __func__, isci_port, completion_status); @@ -364,23 +328,24 @@ static void isci_port_hard_reset_complete(struct isci_port *isci_port, /* The reset failed. The port state is now SCI_PORT_FAILED. */ if (isci_port->active_phy_mask == 0) { + int phy_idx = isci_port->last_active_phy; + struct isci_phy *iphy = &ihost->phys[phy_idx]; /* Generate the link down now to the host, since it * was intercepted by the hard reset state machine when * it really happened. */ - isci_port_link_down(isci_port->isci_host, - &isci_port->isci_host->phys[ - isci_port->last_active_phy], - isci_port); + isci_port_link_down(ihost, iphy, isci_port); } /* Advance the port state so that link state changes will be - * noticed. - */ + * noticed. + */ port_state_machine_change(isci_port, SCI_PORT_SUB_WAITING); } - complete_all(&isci_port->hard_reset_complete); + clear_bit(IPORT_RESET_PENDING, &isci_port->state); + wake_up(&ihost->eventq); + } /* This method will return a true value if the specified phy can be assigned to @@ -552,7 +517,7 @@ void sci_port_get_attached_sas_address(struct isci_port *iport, struct sci_sas_a */ iphy = sci_port_get_a_connected_phy(iport); if (iphy) { - if (iphy->protocol != SCIC_SDS_PHY_PROTOCOL_SATA) { + if (iphy->protocol != SAS_PROTOCOL_SATA) { sci_phy_get_attached_sas_address(iphy, sas); } else { sci_phy_get_sas_address(iphy, sas); @@ -647,19 +612,26 @@ void sci_port_setup_transports(struct isci_port *iport, u32 device_id) } } -static void sci_port_activate_phy(struct isci_port *iport, struct isci_phy *iphy, - bool do_notify_user) +static void sci_port_resume_phy(struct isci_port *iport, struct isci_phy *iphy) +{ + sci_phy_resume(iphy); + iport->enabled_phy_mask |= 1 << iphy->phy_index; +} + +static void sci_port_activate_phy(struct isci_port *iport, + struct isci_phy *iphy, + u8 flags) { struct isci_host *ihost = iport->owning_controller; - if (iphy->protocol != SCIC_SDS_PHY_PROTOCOL_SATA) + if (iphy->protocol != SAS_PROTOCOL_SATA && (flags & PF_RESUME)) sci_phy_resume(iphy); iport->active_phy_mask |= 1 << iphy->phy_index; sci_controller_clear_invalid_phy(ihost, iphy); - if (do_notify_user == true) + if (flags & PF_NOTIFY) isci_port_link_up(ihost, iport, iphy); } @@ -669,14 +641,19 @@ void sci_port_deactivate_phy(struct isci_port *iport, struct isci_phy *iphy, struct isci_host *ihost = iport->owning_controller; iport->active_phy_mask &= ~(1 << iphy->phy_index); + iport->enabled_phy_mask &= ~(1 << iphy->phy_index); if (!iport->active_phy_mask) iport->last_active_phy = iphy->phy_index; iphy->max_negotiated_speed = SAS_LINK_RATE_UNKNOWN; - /* Re-assign the phy back to the LP as if it were a narrow port */ - writel(iphy->phy_index, - &iport->port_pe_configuration_register[iphy->phy_index]); + /* Re-assign the phy back to the LP as if it were a narrow port for APC + * mode. For MPC mode, the phy will remain in the port. + */ + if (iport->owning_controller->oem_parameters.controller.mode_type == + SCIC_PORT_AUTOMATIC_CONFIGURATION_MODE) + writel(iphy->phy_index, + &iport->port_pe_configuration_register[iphy->phy_index]); if (do_notify_user == true) isci_port_link_down(ihost, iphy, iport); @@ -701,18 +678,16 @@ static void sci_port_invalid_link_up(struct isci_port *iport, struct isci_phy *i * sci_port_general_link_up_handler - phy can be assigned to port? * @sci_port: sci_port object for which has a phy that has gone link up. * @sci_phy: This is the struct isci_phy object that has gone link up. - * @do_notify_user: This parameter specifies whether to inform the user (via - * sci_port_link_up()) as to the fact that a new phy as become ready. + * @flags: PF_RESUME, PF_NOTIFY to sci_port_activate_phy * - * Determine if this phy can be assigned to this - * port . If the phy is not a valid PHY for - * this port then the function will notify the user. A PHY can only be - * part of a port if it's attached SAS ADDRESS is the same as all other PHYs in - * the same port. none + * Determine if this phy can be assigned to this port . If the phy is + * not a valid PHY for this port then the function will notify the user. + * A PHY can only be part of a port if it's attached SAS ADDRESS is the + * same as all other PHYs in the same port. */ static void sci_port_general_link_up_handler(struct isci_port *iport, - struct isci_phy *iphy, - bool do_notify_user) + struct isci_phy *iphy, + u8 flags) { struct sci_sas_address port_sas_address; struct sci_sas_address phy_sas_address; @@ -730,7 +705,7 @@ static void sci_port_general_link_up_handler(struct isci_port *iport, iport->active_phy_mask == 0) { struct sci_base_state_machine *sm = &iport->sm; - sci_port_activate_phy(iport, iphy, do_notify_user); + sci_port_activate_phy(iport, iphy, flags); if (sm->current_state_id == SCI_PORT_RESETTING) port_state_machine_change(iport, SCI_PORT_READY); } else @@ -776,16 +751,19 @@ static bool sci_port_is_wide(struct isci_port *iport) * wide ports and direct attached phys. Since there are no wide ported SATA * devices this could become an invalid port configuration. */ -bool sci_port_link_detected( - struct isci_port *iport, - struct isci_phy *iphy) +bool sci_port_link_detected(struct isci_port *iport, struct isci_phy *iphy) { if ((iport->logical_port_index != SCIC_SDS_DUMMY_PORT) && - (iphy->protocol == SCIC_SDS_PHY_PROTOCOL_SATA) && - sci_port_is_wide(iport)) { - sci_port_invalid_link_up(iport, iphy); - - return false; + (iphy->protocol == SAS_PROTOCOL_SATA)) { + if (sci_port_is_wide(iport)) { + sci_port_invalid_link_up(iport, iphy); + return false; + } else { + struct isci_host *ihost = iport->owning_controller; + struct isci_port *dst_port = &(ihost->ports[iphy->phy_index]); + writel(iphy->phy_index, + &dst_port->port_pe_configuration_register[iphy->phy_index]); + } } return true; @@ -820,10 +798,9 @@ static void port_timeout(unsigned long data) __func__, iport); } else if (current_state == SCI_PORT_STOPPING) { - /* if the port is still stopping then the stop has not completed */ - isci_port_stop_complete(iport->owning_controller, - iport, - SCI_FAILURE_TIMEOUT); + dev_dbg(sciport_to_dev(iport), + "%s: port%d: stop complete timeout\n", + __func__, iport->physical_port_index); } else { /* The port is in the ready state and we have a timer * reporting a timeout this should not happen. @@ -975,26 +952,34 @@ static void sci_port_ready_substate_waiting_enter(struct sci_base_state_machine } } +static void scic_sds_port_ready_substate_waiting_exit( + struct sci_base_state_machine *sm) +{ + struct isci_port *iport = container_of(sm, typeof(*iport), sm); + sci_port_resume_port_task_scheduler(iport); +} + static void sci_port_ready_substate_operational_enter(struct sci_base_state_machine *sm) { u32 index; struct isci_port *iport = container_of(sm, typeof(*iport), sm); struct isci_host *ihost = iport->owning_controller; - isci_port_ready(ihost, iport); + dev_dbg(&ihost->pdev->dev, "%s: port%d ready\n", + __func__, iport->physical_port_index); for (index = 0; index < SCI_MAX_PHYS; index++) { if (iport->phy_table[index]) { writel(iport->physical_port_index, &iport->port_pe_configuration_register[ iport->phy_table[index]->phy_index]); + if (((iport->active_phy_mask^iport->enabled_phy_mask) & (1 << index)) != 0) + sci_port_resume_phy(iport, iport->phy_table[index]); } } sci_port_update_viit_entry(iport); - sci_port_resume_port_task_scheduler(iport); - /* * Post the dummy task for the port so the hardware can schedule * io correctly @@ -1047,7 +1032,8 @@ static void sci_port_ready_substate_operational_exit(struct sci_base_state_machi */ sci_port_abort_dummy_request(iport); - isci_port_not_ready(ihost, iport); + dev_dbg(&ihost->pdev->dev, "%s: port%d !ready\n", + __func__, iport->physical_port_index); if (iport->ready_exit) sci_port_invalidate_dummy_remote_node(iport); @@ -1059,22 +1045,12 @@ static void sci_port_ready_substate_configuring_enter(struct sci_base_state_mach struct isci_host *ihost = iport->owning_controller; if (iport->active_phy_mask == 0) { - isci_port_not_ready(ihost, iport); - - port_state_machine_change(iport, - SCI_PORT_SUB_WAITING); - } else if (iport->started_request_count == 0) - port_state_machine_change(iport, - SCI_PORT_SUB_OPERATIONAL); -} - -static void sci_port_ready_substate_configuring_exit(struct sci_base_state_machine *sm) -{ - struct isci_port *iport = container_of(sm, typeof(*iport), sm); + dev_dbg(&ihost->pdev->dev, "%s: port%d !ready\n", + __func__, iport->physical_port_index); - sci_port_suspend_port_task_scheduler(iport); - if (iport->ready_exit) - sci_port_invalidate_dummy_remote_node(iport); + port_state_machine_change(iport, SCI_PORT_SUB_WAITING); + } else + port_state_machine_change(iport, SCI_PORT_SUB_OPERATIONAL); } enum sci_status sci_port_start(struct isci_port *iport) @@ -1086,8 +1062,8 @@ enum sci_status sci_port_start(struct isci_port *iport) state = iport->sm.current_state_id; if (state != SCI_PORT_STOPPED) { - dev_warn(sciport_to_dev(iport), - "%s: in wrong state: %d\n", __func__, state); + dev_warn(sciport_to_dev(iport), "%s: in wrong state: %s\n", + __func__, port_state_name(state)); return SCI_FAILURE_INVALID_STATE; } @@ -1161,8 +1137,8 @@ enum sci_status sci_port_stop(struct isci_port *iport) SCI_PORT_STOPPING); return SCI_SUCCESS; default: - dev_warn(sciport_to_dev(iport), - "%s: in wrong state: %d\n", __func__, state); + dev_warn(sciport_to_dev(iport), "%s: in wrong state: %s\n", + __func__, port_state_name(state)); return SCI_FAILURE_INVALID_STATE; } } @@ -1176,8 +1152,8 @@ static enum sci_status sci_port_hard_reset(struct isci_port *iport, u32 timeout) state = iport->sm.current_state_id; if (state != SCI_PORT_SUB_OPERATIONAL) { - dev_warn(sciport_to_dev(iport), - "%s: in wrong state: %d\n", __func__, state); + dev_warn(sciport_to_dev(iport), "%s: in wrong state: %s\n", + __func__, port_state_name(state)); return SCI_FAILURE_INVALID_STATE; } @@ -1223,6 +1199,8 @@ enum sci_status sci_port_add_phy(struct isci_port *iport, enum sci_status status; enum sci_port_states state; + sci_port_bcn_enable(iport); + state = iport->sm.current_state_id; switch (state) { case SCI_PORT_STOPPED: { @@ -1252,7 +1230,7 @@ enum sci_status sci_port_add_phy(struct isci_port *iport, if (status != SCI_SUCCESS) return status; - sci_port_general_link_up_handler(iport, iphy, true); + sci_port_general_link_up_handler(iport, iphy, PF_NOTIFY|PF_RESUME); iport->not_ready_reason = SCIC_PORT_NOT_READY_RECONFIGURING; port_state_machine_change(iport, SCI_PORT_SUB_CONFIGURING); @@ -1262,7 +1240,7 @@ enum sci_status sci_port_add_phy(struct isci_port *iport, if (status != SCI_SUCCESS) return status; - sci_port_general_link_up_handler(iport, iphy, true); + sci_port_general_link_up_handler(iport, iphy, PF_NOTIFY); /* Re-enter the configuring state since this may be the last phy in * the port. @@ -1271,8 +1249,8 @@ enum sci_status sci_port_add_phy(struct isci_port *iport, SCI_PORT_SUB_CONFIGURING); return SCI_SUCCESS; default: - dev_warn(sciport_to_dev(iport), - "%s: in wrong state: %d\n", __func__, state); + dev_warn(sciport_to_dev(iport), "%s: in wrong state: %s\n", + __func__, port_state_name(state)); return SCI_FAILURE_INVALID_STATE; } } @@ -1321,8 +1299,8 @@ enum sci_status sci_port_remove_phy(struct isci_port *iport, SCI_PORT_SUB_CONFIGURING); return SCI_SUCCESS; default: - dev_warn(sciport_to_dev(iport), - "%s: in wrong state: %d\n", __func__, state); + dev_warn(sciport_to_dev(iport), "%s: in wrong state: %s\n", + __func__, port_state_name(state)); return SCI_FAILURE_INVALID_STATE; } } @@ -1338,13 +1316,13 @@ enum sci_status sci_port_link_up(struct isci_port *iport, /* Since this is the first phy going link up for the port we * can just enable it and continue */ - sci_port_activate_phy(iport, iphy, true); + sci_port_activate_phy(iport, iphy, PF_NOTIFY|PF_RESUME); port_state_machine_change(iport, SCI_PORT_SUB_OPERATIONAL); return SCI_SUCCESS; case SCI_PORT_SUB_OPERATIONAL: - sci_port_general_link_up_handler(iport, iphy, true); + sci_port_general_link_up_handler(iport, iphy, PF_NOTIFY|PF_RESUME); return SCI_SUCCESS; case SCI_PORT_RESETTING: /* TODO We should make sure that the phy that has gone @@ -1361,11 +1339,11 @@ enum sci_status sci_port_link_up(struct isci_port *iport, /* In the resetting state we don't notify the user regarding * link up and link down notifications. */ - sci_port_general_link_up_handler(iport, iphy, false); + sci_port_general_link_up_handler(iport, iphy, PF_RESUME); return SCI_SUCCESS; default: - dev_warn(sciport_to_dev(iport), - "%s: in wrong state: %d\n", __func__, state); + dev_warn(sciport_to_dev(iport), "%s: in wrong state: %s\n", + __func__, port_state_name(state)); return SCI_FAILURE_INVALID_STATE; } } @@ -1394,8 +1372,8 @@ enum sci_status sci_port_link_down(struct isci_port *iport, sci_port_deactivate_phy(iport, iphy, false); return SCI_SUCCESS; default: - dev_warn(sciport_to_dev(iport), - "%s: in wrong state: %d\n", __func__, state); + dev_warn(sciport_to_dev(iport), "%s: in wrong state: %s\n", + __func__, port_state_name(state)); return SCI_FAILURE_INVALID_STATE; } } @@ -1414,8 +1392,8 @@ enum sci_status sci_port_start_io(struct isci_port *iport, iport->started_request_count++; return SCI_SUCCESS; default: - dev_warn(sciport_to_dev(iport), - "%s: in wrong state: %d\n", __func__, state); + dev_warn(sciport_to_dev(iport), "%s: in wrong state: %s\n", + __func__, port_state_name(state)); return SCI_FAILURE_INVALID_STATE; } } @@ -1429,8 +1407,8 @@ enum sci_status sci_port_complete_io(struct isci_port *iport, state = iport->sm.current_state_id; switch (state) { case SCI_PORT_STOPPED: - dev_warn(sciport_to_dev(iport), - "%s: in wrong state: %d\n", __func__, state); + dev_warn(sciport_to_dev(iport), "%s: in wrong state: %s\n", + __func__, port_state_name(state)); return SCI_FAILURE_INVALID_STATE; case SCI_PORT_STOPPING: sci_port_decrement_request_count(iport); @@ -1536,7 +1514,8 @@ static void sci_port_ready_state_enter(struct sci_base_state_machine *sm) if (prev_state == SCI_PORT_RESETTING) isci_port_hard_reset_complete(iport, SCI_SUCCESS); else - isci_port_not_ready(ihost, iport); + dev_dbg(&ihost->pdev->dev, "%s: port%d !ready\n", + __func__, iport->physical_port_index); /* Post and suspend the dummy remote node context for this port. */ sci_port_post_dummy_remote_node(iport); @@ -1569,6 +1548,29 @@ static void sci_port_failed_state_enter(struct sci_base_state_machine *sm) isci_port_hard_reset_complete(iport, SCI_FAILURE_TIMEOUT); } +void sci_port_set_hang_detection_timeout(struct isci_port *iport, u32 timeout) +{ + int phy_index; + u32 phy_mask = iport->active_phy_mask; + + if (timeout) + ++iport->hang_detect_users; + else if (iport->hang_detect_users > 1) + --iport->hang_detect_users; + else + iport->hang_detect_users = 0; + + if (timeout || (iport->hang_detect_users == 0)) { + for (phy_index = 0; phy_index < SCI_MAX_PHYS; phy_index++) { + if ((phy_mask >> phy_index) & 1) { + writel(timeout, + &iport->phy_table[phy_index] + ->link_layer_registers + ->link_layer_hang_detection_timeout); + } + } + } +} /* --------------------------------------------------------------------------- */ static const struct sci_base_state sci_port_state_table[] = { @@ -1584,14 +1586,14 @@ static const struct sci_base_state sci_port_state_table[] = { }, [SCI_PORT_SUB_WAITING] = { .enter_state = sci_port_ready_substate_waiting_enter, + .exit_state = scic_sds_port_ready_substate_waiting_exit, }, [SCI_PORT_SUB_OPERATIONAL] = { .enter_state = sci_port_ready_substate_operational_enter, .exit_state = sci_port_ready_substate_operational_exit }, [SCI_PORT_SUB_CONFIGURING] = { - .enter_state = sci_port_ready_substate_configuring_enter, - .exit_state = sci_port_ready_substate_configuring_exit + .enter_state = sci_port_ready_substate_configuring_enter }, [SCI_PORT_RESETTING] = { .exit_state = sci_port_resetting_state_exit @@ -1609,6 +1611,7 @@ void sci_port_construct(struct isci_port *iport, u8 index, iport->logical_port_index = SCIC_SDS_DUMMY_PORT; iport->physical_port_index = index; iport->active_phy_mask = 0; + iport->enabled_phy_mask = 0; iport->last_active_phy = 0; iport->ready_exit = false; @@ -1616,6 +1619,7 @@ void sci_port_construct(struct isci_port *iport, u8 index, iport->started_request_count = 0; iport->assigned_device_count = 0; + iport->hang_detect_users = 0; iport->reserved_rni = SCU_DUMMY_INDEX; iport->reserved_tag = SCI_CONTROLLER_INVALID_IO_TAG; @@ -1628,28 +1632,6 @@ void sci_port_construct(struct isci_port *iport, u8 index, iport->phy_table[index] = NULL; } -void isci_port_init(struct isci_port *iport, struct isci_host *ihost, int index) -{ - INIT_LIST_HEAD(&iport->remote_dev_list); - INIT_LIST_HEAD(&iport->domain_dev_list); - spin_lock_init(&iport->state_lock); - init_completion(&iport->start_complete); - iport->isci_host = ihost; - isci_port_change_state(iport, isci_freed); -} - -/** - * isci_port_get_state() - This function gets the status of the port object. - * @isci_port: This parameter points to the isci_port object - * - * status of the object as a isci_status enum. - */ -enum isci_status isci_port_get_state( - struct isci_port *isci_port) -{ - return isci_port->status; -} - void sci_port_broadcast_change_received(struct isci_port *iport, struct isci_phy *iphy) { struct isci_host *ihost = iport->owning_controller; @@ -1658,6 +1640,11 @@ void sci_port_broadcast_change_received(struct isci_port *iport, struct isci_phy isci_port_bc_change_received(ihost, iport, iphy); } +static void wait_port_reset(struct isci_host *ihost, struct isci_port *iport) +{ + wait_event(ihost->eventq, !test_bit(IPORT_RESET_PENDING, &iport->state)); +} + int isci_port_perform_hard_reset(struct isci_host *ihost, struct isci_port *iport, struct isci_phy *iphy) { @@ -1668,9 +1655,8 @@ int isci_port_perform_hard_reset(struct isci_host *ihost, struct isci_port *ipor dev_dbg(&ihost->pdev->dev, "%s: iport = %p\n", __func__, iport); - init_completion(&iport->hard_reset_complete); - spin_lock_irqsave(&ihost->scic_lock, flags); + set_bit(IPORT_RESET_PENDING, &iport->state); #define ISCI_PORT_RESET_TIMEOUT SCIC_SDS_SIGNATURE_FIS_TIMEOUT status = sci_port_hard_reset(iport, ISCI_PORT_RESET_TIMEOUT); @@ -1678,7 +1664,7 @@ int isci_port_perform_hard_reset(struct isci_host *ihost, struct isci_port *ipor spin_unlock_irqrestore(&ihost->scic_lock, flags); if (status == SCI_SUCCESS) { - wait_for_completion(&iport->hard_reset_complete); + wait_port_reset(ihost, iport); dev_dbg(&ihost->pdev->dev, "%s: iport = %p; hard reset completion\n", @@ -1692,6 +1678,8 @@ int isci_port_perform_hard_reset(struct isci_host *ihost, struct isci_port *ipor __func__, iport, iport->hard_reset_status); } } else { + clear_bit(IPORT_RESET_PENDING, &iport->state); + wake_up(&ihost->eventq); ret = TMF_RESP_FUNC_FAILED; dev_err(&ihost->pdev->dev, @@ -1700,38 +1688,83 @@ int isci_port_perform_hard_reset(struct isci_host *ihost, struct isci_port *ipor __func__, iport, status); } + return ret; +} - /* If the hard reset for the port has failed, consider this - * the same as link failures on all phys in the port. - */ - if (ret != TMF_RESP_FUNC_COMPLETE) { +int isci_ata_check_ready(struct domain_device *dev) +{ + struct isci_port *iport = dev->port->lldd_port; + struct isci_host *ihost = dev_to_ihost(dev); + struct isci_remote_device *idev; + unsigned long flags; + int rc = 0; - dev_err(&ihost->pdev->dev, - "%s: iport = %p; hard reset failed " - "(0x%x) - driving explicit link fail for all phys\n", - __func__, iport, iport->hard_reset_status); - } - return ret; + spin_lock_irqsave(&ihost->scic_lock, flags); + idev = isci_lookup_device(dev); + spin_unlock_irqrestore(&ihost->scic_lock, flags); + + if (!idev) + goto out; + + if (test_bit(IPORT_RESET_PENDING, &iport->state)) + goto out; + + rc = !!iport->active_phy_mask; + out: + isci_put_device(idev); + + return rc; } -/** - * isci_port_deformed() - This function is called by libsas when a port becomes - * inactive. - * @phy: This parameter specifies the libsas phy with the inactive port. - * - */ void isci_port_deformed(struct asd_sas_phy *phy) { - pr_debug("%s: sas_phy = %p\n", __func__, phy); + struct isci_host *ihost = phy->ha->lldd_ha; + struct isci_port *iport = phy->port->lldd_port; + unsigned long flags; + int i; + + /* we got a port notification on a port that was subsequently + * torn down and libsas is just now catching up + */ + if (!iport) + return; + + spin_lock_irqsave(&ihost->scic_lock, flags); + for (i = 0; i < SCI_MAX_PHYS; i++) { + if (iport->active_phy_mask & 1 << i) + break; + } + spin_unlock_irqrestore(&ihost->scic_lock, flags); + + if (i >= SCI_MAX_PHYS) + dev_dbg(&ihost->pdev->dev, "%s: port: %ld\n", + __func__, (long) (iport - &ihost->ports[0])); } -/** - * isci_port_formed() - This function is called by libsas when a port becomes - * active. - * @phy: This parameter specifies the libsas phy with the active port. - * - */ void isci_port_formed(struct asd_sas_phy *phy) { - pr_debug("%s: sas_phy = %p, sas_port = %p\n", __func__, phy, phy->port); + struct isci_host *ihost = phy->ha->lldd_ha; + struct isci_phy *iphy = to_iphy(phy); + struct asd_sas_port *port = phy->port; + struct isci_port *iport = NULL; + unsigned long flags; + int i; + + /* initial ports are formed as the driver is still initializing, + * wait for that process to complete + */ + wait_for_start(ihost); + + spin_lock_irqsave(&ihost->scic_lock, flags); + for (i = 0; i < SCI_MAX_PORTS; i++) { + iport = &ihost->ports[i]; + if (iport->active_phy_mask & 1 << iphy->phy_index) + break; + } + spin_unlock_irqrestore(&ihost->scic_lock, flags); + + if (i >= SCI_MAX_PORTS) + iport = NULL; + + port->lldd_port = iport; } |
