X-Git-Url: https://git.karo-electronics.de/?a=blobdiff_plain;f=drivers%2Fscsi%2Fisci%2Fremote_device.c;h=4f76dcd1cec2593898f8e3b1151fa42ce1c293ac;hb=5b6bf225e7fc249c703e19bf2c983d1a59178874;hp=8f501b0a81d6e7842a9d9caaaae1d228b996f2ab;hpb=2533c2cfbff8f0ee53b8448d6362b54c272125aa;p=karo-tx-linux.git diff --git a/drivers/scsi/isci/remote_device.c b/drivers/scsi/isci/remote_device.c index 8f501b0a81d6..4f76dcd1cec2 100644 --- a/drivers/scsi/isci/remote_device.c +++ b/drivers/scsi/isci/remote_device.c @@ -133,6 +133,59 @@ static void isci_remote_device_ready(struct isci_host *ihost, struct isci_remote wake_up(&ihost->eventq); } +static enum sci_status sci_remote_device_suspend( + struct isci_remote_device *idev) +{ + return sci_remote_node_context_suspend( + &idev->rnc, + SCI_SOFTWARE_SUSPENSION, + SCI_SOFTWARE_SUSPEND_EXPECTED_EVENT, + NULL, NULL); +} + +static int isci_remote_device_suspendcheck(struct isci_remote_device *idev) +{ + return test_bit(IDEV_TXRX_SUSPENDED, &idev->flags) + || !test_bit(IDEV_ALLOCATED, &idev->flags); +} + +enum sci_status isci_remote_device_suspend( + struct isci_host *ihost, + struct isci_remote_device *idev) +{ + enum sci_status status; + unsigned long flags; + + spin_lock_irqsave(&ihost->scic_lock, flags); + if (isci_get_device(idev->domain_dev) == NULL) { + spin_unlock_irqrestore(&ihost->scic_lock, flags); + status = SCI_FAILURE; + } else { + status = sci_remote_device_suspend(idev); + spin_unlock_irqrestore(&ihost->scic_lock, flags); + if (status == SCI_SUCCESS) { + dev_dbg(&ihost->pdev->dev, + "%s: idev=%p, about to wait\n", + __func__, idev); + wait_event(ihost->eventq, + isci_remote_device_suspendcheck(idev)); + status = test_bit(IDEV_TXRX_SUSPENDED, &idev->flags) + ? SCI_SUCCESS : SCI_FAILURE; + dev_dbg(&ihost->pdev->dev, + "%s: idev=%p, wait done, device is %s\n", + __func__, idev, + test_bit(IDEV_TXRX_SUSPENDED, &idev->flags) + ? "" : ""); + + } else + dev_dbg(scirdev_to_dev(idev), + "%s: sci_remote_device_suspend failed, " + "status = %d\n", __func__, status); + isci_put_device(idev); + } + return status; +} + /* called once the remote node context is ready to be freed. * The remote device can now report that its stop operation is complete. none */ @@ -144,7 +197,9 @@ static void rnc_destruct_done(void *_dev) sci_change_state(&idev->sm, SCI_DEV_STOPPED); } -static enum sci_status sci_remote_device_terminate_requests(struct isci_remote_device *idev) +static enum sci_status sci_remote_device_terminate_requests_checkabort( + struct isci_remote_device *idev, + int check_abort_pending) { struct isci_host *ihost = idev->owning_port->owning_controller; enum sci_status status = SCI_SUCCESS; @@ -155,7 +210,9 @@ static enum sci_status sci_remote_device_terminate_requests(struct isci_remote_d enum sci_status s; if (!test_bit(IREQ_ACTIVE, &ireq->flags) || - ireq->target_device != idev) + (ireq->target_device != idev) || + (check_abort_pending && !test_bit(IREQ_PENDING_ABORT, + &ireq->flags))) continue; s = sci_controller_terminate_request(ihost, idev, ireq); @@ -166,6 +223,12 @@ static enum sci_status sci_remote_device_terminate_requests(struct isci_remote_d return status; } +enum sci_status sci_remote_device_terminate_requests( + struct isci_remote_device *idev) +{ + return sci_remote_device_terminate_requests_checkabort(idev, 0); +} + enum sci_status sci_remote_device_stop(struct isci_remote_device *idev, u32 timeout) { @@ -265,22 +328,6 @@ enum sci_status sci_remote_device_reset_complete(struct isci_remote_device *idev return SCI_SUCCESS; } -enum sci_status sci_remote_device_suspend(struct isci_remote_device *idev, - u32 suspend_type) -{ - struct sci_base_state_machine *sm = &idev->sm; - enum sci_remote_device_states state = sm->current_state_id; - - if (state != SCI_STP_DEV_CMD) { - dev_warn(scirdev_to_dev(idev), "%s: in wrong state: %s\n", - __func__, dev_state_name(state)); - return SCI_FAILURE_INVALID_STATE; - } - - return sci_remote_node_context_suspend(&idev->rnc, - suspend_type, NULL, NULL); -} - enum sci_status sci_remote_device_frame_handler(struct isci_remote_device *idev, u32 frame_index) { @@ -412,8 +459,6 @@ static void atapi_remote_device_resume_done(void *_dev) enum sci_status sci_remote_device_event_handler(struct isci_remote_device *idev, u32 event_code) { - struct sci_base_state_machine *sm = &idev->sm; - enum sci_remote_device_states state = sm->current_state_id; enum sci_status status; switch (scu_get_event_type(event_code)) { @@ -427,9 +472,11 @@ enum sci_status sci_remote_device_event_handler(struct isci_remote_device *idev, status = SCI_SUCCESS; /* Suspend the associated RNC */ - sci_remote_node_context_suspend(&idev->rnc, - SCI_SOFTWARE_SUSPENSION, - NULL, NULL); + sci_remote_node_context_suspend( + &idev->rnc, + SCI_SOFTWARE_SUSPENSION, + SCI_SOFTWARE_SUSPEND_EXPECTED_EVENT, + NULL, NULL); dev_dbg(scirdev_to_dev(idev), "%s: device: %p event code: %x: %s\n", @@ -455,26 +502,6 @@ enum sci_status sci_remote_device_event_handler(struct isci_remote_device *idev, if (status != SCI_SUCCESS) return status; - if (state == SCI_STP_DEV_ATAPI_ERROR) { - /* For ATAPI error state resume the RNC right away. */ - if (scu_get_event_type(event_code) == SCU_EVENT_TYPE_RNC_SUSPEND_TX || - scu_get_event_type(event_code) == SCU_EVENT_TYPE_RNC_SUSPEND_TX_RX) { - return sci_remote_node_context_resume(&idev->rnc, - atapi_remote_device_resume_done, - idev); - } - } - - if (state == SCI_STP_DEV_IDLE) { - - /* We pick up suspension events to handle specifically to this - * state. We resume the RNC right away. - */ - if (scu_get_event_type(event_code) == SCU_EVENT_TYPE_RNC_SUSPEND_TX || - scu_get_event_type(event_code) == SCU_EVENT_TYPE_RNC_SUSPEND_TX_RX) - status = sci_remote_node_context_resume(&idev->rnc, NULL, NULL); - } - return status; } @@ -765,11 +792,11 @@ enum sci_status sci_remote_device_start_task(struct isci_host *ihost, * the correct action when the remote node context is suspended * and later resumed. */ - sci_remote_node_context_suspend(&idev->rnc, - SCI_SOFTWARE_SUSPENSION, NULL, NULL); - sci_remote_node_context_resume(&idev->rnc, - sci_remote_device_continue_request, - idev); + sci_remote_node_context_suspend( + &idev->rnc, SCI_SOFTWARE_SUSPENSION, + SCI_SOFTWARE_SUSPEND_EXPECTED_EVENT, NULL, NULL); + sci_remote_node_context_resume( + &idev->rnc, sci_remote_device_continue_request, idev); out: sci_remote_device_start_request(idev, ireq, status); @@ -954,14 +981,23 @@ static void sci_remote_device_ready_state_exit(struct sci_base_state_machine *sm static void sci_remote_device_resetting_state_enter(struct sci_base_state_machine *sm) { struct isci_remote_device *idev = container_of(sm, typeof(*idev), sm); + struct isci_host *ihost = idev->owning_port->owning_controller; + + dev_dbg(&ihost->pdev->dev, + "%s: isci_device = %p\n", __func__, idev); sci_remote_node_context_suspend( - &idev->rnc, SCI_SOFTWARE_SUSPENSION, NULL, NULL); + &idev->rnc, SCI_SOFTWARE_SUSPENSION, + SCI_SOFTWARE_SUSPEND_EXPECTED_EVENT, NULL, NULL); } static void sci_remote_device_resetting_state_exit(struct sci_base_state_machine *sm) { struct isci_remote_device *idev = container_of(sm, typeof(*idev), sm); + struct isci_host *ihost = idev->owning_port->owning_controller; + + dev_dbg(&ihost->pdev->dev, + "%s: isci_device = %p\n", __func__, idev); sci_remote_node_context_resume(&idev->rnc, NULL, NULL); } @@ -1004,6 +1040,21 @@ static void sci_stp_remote_device_ready_ncq_error_substate_enter(struct sci_base idev->not_ready_reason); } +static void sci_stp_remote_device_atapi_error_substate_enter( + struct sci_base_state_machine *sm) +{ + struct isci_remote_device *idev = container_of(sm, typeof(*idev), sm); + + /* This state is entered when an I/O is decoded with an error + * condition. By this point the RNC expected suspension state is set. + * The error conditions suspend the device, so unsuspend here if + * possible. + */ + sci_remote_node_context_resume(&idev->rnc, + atapi_remote_device_resume_done, + idev); +} + static void sci_smp_remote_device_ready_idle_substate_enter(struct sci_base_state_machine *sm) { struct isci_remote_device *idev = container_of(sm, typeof(*idev), sm); @@ -1054,7 +1105,9 @@ static const struct sci_base_state sci_remote_device_state_table[] = { [SCI_STP_DEV_NCQ_ERROR] = { .enter_state = sci_stp_remote_device_ready_ncq_error_substate_enter, }, - [SCI_STP_DEV_ATAPI_ERROR] = { }, + [SCI_STP_DEV_ATAPI_ERROR] = { + .enter_state = sci_stp_remote_device_atapi_error_substate_enter, + }, [SCI_STP_DEV_AWAIT_RESET] = { }, [SCI_SMP_DEV_IDLE] = { .enter_state = sci_smp_remote_device_ready_idle_substate_enter, @@ -1113,33 +1166,20 @@ static enum sci_status sci_remote_device_da_construct(struct isci_port *iport, { enum sci_status status; struct sci_port_properties properties; - struct domain_device *dev = idev->domain_dev; sci_remote_device_construct(iport, idev); - /* - * This information is request to determine how many remote node context - * entries will be needed to store the remote node. - */ - idev->is_direct_attached = true; - sci_port_get_properties(iport, &properties); /* Get accurate port width from port's phy mask for a DA device. */ idev->device_port_width = hweight32(properties.phy_mask); status = sci_controller_allocate_remote_node_context(iport->owning_controller, - idev, - &idev->rnc.remote_node_index); + idev, + &idev->rnc.remote_node_index); if (status != SCI_SUCCESS) return status; - if (dev->dev_type == SAS_END_DEV || dev->dev_type == SATA_DEV || - (dev->tproto & SAS_PROTOCOL_STP) || dev_is_expander(dev)) - /* pass */; - else - return SCI_FAILURE_UNSUPPORTED_PROTOCOL; - idev->connection_rate = sci_port_get_max_allowed_speed(iport); return SCI_SUCCESS; @@ -1171,19 +1211,13 @@ static enum sci_status sci_remote_device_ea_construct(struct isci_port *iport, if (status != SCI_SUCCESS) return status; - if (dev->dev_type == SAS_END_DEV || dev->dev_type == SATA_DEV || - (dev->tproto & SAS_PROTOCOL_STP) || dev_is_expander(dev)) - /* pass */; - else - return SCI_FAILURE_UNSUPPORTED_PROTOCOL; - - /* - * For SAS-2 the physical link rate is actually a logical link + /* For SAS-2 the physical link rate is actually a logical link * rate that incorporates multiplexing. The SCU doesn't * incorporate multiplexing and for the purposes of the * connection the logical link rate is that same as the * physical. Furthermore, the SAS-2 and SAS-1.1 fields overlay - * one another, so this code works for both situations. */ + * one another, so this code works for both situations. + */ idev->connection_rate = min_t(u16, sci_port_get_max_allowed_speed(iport), dev->linkrate); @@ -1193,6 +1227,35 @@ static enum sci_status sci_remote_device_ea_construct(struct isci_port *iport, return SCI_SUCCESS; } +enum sci_status sci_remote_device_resume( + struct isci_remote_device *idev, + scics_sds_remote_node_context_callback cb_fn, + void *cb_p) +{ + enum sci_status status; + + status = sci_remote_node_context_resume(&idev->rnc, cb_fn, cb_p); + if (status != SCI_SUCCESS) + dev_dbg(scirdev_to_dev(idev), "%s: failed to resume: %d\n", + __func__, status); + return status; +} + +enum sci_status isci_remote_device_resume( + struct isci_host *ihost, + struct isci_remote_device *idev, + scics_sds_remote_node_context_callback cb_fn, + void *cb_p) +{ + unsigned long flags; + enum sci_status status; + + spin_lock_irqsave(&ihost->scic_lock, flags); + status = sci_remote_device_resume(idev, cb_fn, cb_p); + spin_unlock_irqrestore(&ihost->scic_lock, flags); + + return status; +} /** * sci_remote_device_start() - This method will start the supplied remote * device. This method enables normal IO requests to flow through to the @@ -1207,7 +1270,7 @@ static enum sci_status sci_remote_device_ea_construct(struct isci_port *iport, * the device when there have been no phys added to it. */ static enum sci_status sci_remote_device_start(struct isci_remote_device *idev, - u32 timeout) + u32 timeout) { struct sci_base_state_machine *sm = &idev->sm; enum sci_remote_device_states state = sm->current_state_id; @@ -1219,9 +1282,8 @@ static enum sci_status sci_remote_device_start(struct isci_remote_device *idev, return SCI_FAILURE_INVALID_STATE; } - status = sci_remote_node_context_resume(&idev->rnc, - remote_device_resume_done, - idev); + status = sci_remote_device_resume(idev, remote_device_resume_done, + idev); if (status != SCI_SUCCESS) return status; @@ -1434,3 +1496,60 @@ int isci_remote_device_found(struct domain_device *dev) return status == SCI_SUCCESS ? 0 : -ENODEV; } + +enum sci_status isci_remote_device_reset( + struct isci_host *ihost, + struct isci_remote_device *idev) +{ + unsigned long flags; + enum sci_status status; + + /* Put the device into a reset state so the suspension will not + * automatically resume. + */ + spin_lock_irqsave(&ihost->scic_lock, flags); + status = sci_remote_device_reset(idev); + spin_unlock_irqrestore(&ihost->scic_lock, flags); + if (status != SCI_SUCCESS) { + dev_dbg(&ihost->pdev->dev, + "%s: sci_remote_device_reset(%p) returned %d!\n", + __func__, idev, status); + return status; + } + /* Wait for the device suspend. */ + status = isci_remote_device_suspend(ihost, idev); + if (status != SCI_SUCCESS) { + dev_dbg(&ihost->pdev->dev, + "%s: isci_remote_device_suspend(%p) returned %d!\n", + __func__, idev, status); + } + return status; +} + +int isci_remote_device_is_safe_to_abort( + struct isci_remote_device *idev) +{ + return sci_remote_node_context_is_safe_to_abort(&idev->rnc); +} + +enum sci_status sci_remote_device_abort_requests_pending_abort( + struct isci_remote_device *idev) +{ + return sci_remote_device_terminate_requests_checkabort(idev, 1); +} + +enum sci_status isci_remote_device_reset_complete( + struct isci_host *ihost, + struct isci_remote_device *idev) +{ + unsigned long flags; + enum sci_status status; + + spin_lock_irqsave(&ihost->scic_lock, flags); + status = sci_remote_device_reset_complete(idev); + sci_remote_device_resume(idev, NULL, NULL); + spin_unlock_irqrestore(&ihost->scic_lock, flags); + + return status; +} +