diff options
Diffstat (limited to 'drivers/scsi/isci/remote_node_context.c')
-rw-r--r-- | drivers/scsi/isci/remote_node_context.c | 412 |
1 files changed, 115 insertions, 297 deletions
diff --git a/drivers/scsi/isci/remote_node_context.c b/drivers/scsi/isci/remote_node_context.c index 1910100638a..748e8339d1e 100644 --- a/drivers/scsi/isci/remote_node_context.c +++ b/drivers/scsi/isci/remote_node_context.c | |||
@@ -52,7 +52,7 @@ | |||
52 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 52 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
53 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 53 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
54 | */ | 54 | */ |
55 | #include <scsi/sas_ata.h> | 55 | |
56 | #include "host.h" | 56 | #include "host.h" |
57 | #include "isci.h" | 57 | #include "isci.h" |
58 | #include "remote_device.h" | 58 | #include "remote_device.h" |
@@ -60,15 +60,18 @@ | |||
60 | #include "scu_event_codes.h" | 60 | #include "scu_event_codes.h" |
61 | #include "scu_task_context.h" | 61 | #include "scu_task_context.h" |
62 | 62 | ||
63 | #undef C | ||
64 | #define C(a) (#a) | ||
65 | const char *rnc_state_name(enum scis_sds_remote_node_context_states state) | ||
66 | { | ||
67 | static const char * const strings[] = RNC_STATES; | ||
68 | 63 | ||
69 | return strings[state]; | 64 | /** |
70 | } | 65 | * |
71 | #undef C | 66 | * @sci_rnc: The RNC for which the is posted request is being made. |
67 | * | ||
68 | * This method will return true if the RNC is not in the initial state. In all | ||
69 | * other states the RNC is considered active and this will return true. The | ||
70 | * destroy request of the state machine drives the RNC back to the initial | ||
71 | * state. If the state machine changes then this routine will also have to be | ||
72 | * changed. bool true if the state machine is not in the initial state false if | ||
73 | * the state machine is in the initial state | ||
74 | */ | ||
72 | 75 | ||
73 | /** | 76 | /** |
74 | * | 77 | * |
@@ -90,15 +93,6 @@ bool sci_remote_node_context_is_ready( | |||
90 | return false; | 93 | return false; |
91 | } | 94 | } |
92 | 95 | ||
93 | bool sci_remote_node_context_is_suspended(struct sci_remote_node_context *sci_rnc) | ||
94 | { | ||
95 | u32 current_state = sci_rnc->sm.current_state_id; | ||
96 | |||
97 | if (current_state == SCI_RNC_TX_RX_SUSPENDED) | ||
98 | return true; | ||
99 | return false; | ||
100 | } | ||
101 | |||
102 | static union scu_remote_node_context *sci_rnc_by_id(struct isci_host *ihost, u16 id) | 96 | static union scu_remote_node_context *sci_rnc_by_id(struct isci_host *ihost, u16 id) |
103 | { | 97 | { |
104 | if (id < ihost->remote_node_entries && | 98 | if (id < ihost->remote_node_entries && |
@@ -140,7 +134,7 @@ static void sci_remote_node_context_construct_buffer(struct sci_remote_node_cont | |||
140 | 134 | ||
141 | rnc->ssp.arbitration_wait_time = 0; | 135 | rnc->ssp.arbitration_wait_time = 0; |
142 | 136 | ||
143 | if (dev_is_sata(dev)) { | 137 | if (dev->dev_type == SATA_DEV || (dev->tproto & SAS_PROTOCOL_STP)) { |
144 | rnc->ssp.connection_occupancy_timeout = | 138 | rnc->ssp.connection_occupancy_timeout = |
145 | ihost->user_parameters.stp_max_occupancy_timeout; | 139 | ihost->user_parameters.stp_max_occupancy_timeout; |
146 | rnc->ssp.connection_inactivity_timeout = | 140 | rnc->ssp.connection_inactivity_timeout = |
@@ -160,6 +154,7 @@ static void sci_remote_node_context_construct_buffer(struct sci_remote_node_cont | |||
160 | rnc->ssp.oaf_source_zone_group = 0; | 154 | rnc->ssp.oaf_source_zone_group = 0; |
161 | rnc->ssp.oaf_more_compatibility_features = 0; | 155 | rnc->ssp.oaf_more_compatibility_features = 0; |
162 | } | 156 | } |
157 | |||
163 | /** | 158 | /** |
164 | * | 159 | * |
165 | * @sci_rnc: | 160 | * @sci_rnc: |
@@ -173,30 +168,23 @@ static void sci_remote_node_context_construct_buffer(struct sci_remote_node_cont | |||
173 | static void sci_remote_node_context_setup_to_resume( | 168 | static void sci_remote_node_context_setup_to_resume( |
174 | struct sci_remote_node_context *sci_rnc, | 169 | struct sci_remote_node_context *sci_rnc, |
175 | scics_sds_remote_node_context_callback callback, | 170 | scics_sds_remote_node_context_callback callback, |
176 | void *callback_parameter, | 171 | void *callback_parameter) |
177 | enum sci_remote_node_context_destination_state dest_param) | ||
178 | { | 172 | { |
179 | if (sci_rnc->destination_state != RNC_DEST_FINAL) { | 173 | if (sci_rnc->destination_state != SCIC_SDS_REMOTE_NODE_DESTINATION_STATE_FINAL) { |
180 | sci_rnc->destination_state = dest_param; | 174 | sci_rnc->destination_state = SCIC_SDS_REMOTE_NODE_DESTINATION_STATE_READY; |
181 | if (callback != NULL) { | 175 | sci_rnc->user_callback = callback; |
182 | sci_rnc->user_callback = callback; | 176 | sci_rnc->user_cookie = callback_parameter; |
183 | sci_rnc->user_cookie = callback_parameter; | ||
184 | } | ||
185 | } | 177 | } |
186 | } | 178 | } |
187 | 179 | ||
188 | static void sci_remote_node_context_setup_to_destroy( | 180 | static void sci_remote_node_context_setup_to_destory( |
189 | struct sci_remote_node_context *sci_rnc, | 181 | struct sci_remote_node_context *sci_rnc, |
190 | scics_sds_remote_node_context_callback callback, | 182 | scics_sds_remote_node_context_callback callback, |
191 | void *callback_parameter) | 183 | void *callback_parameter) |
192 | { | 184 | { |
193 | struct isci_host *ihost = idev_to_ihost(rnc_to_dev(sci_rnc)); | 185 | sci_rnc->destination_state = SCIC_SDS_REMOTE_NODE_DESTINATION_STATE_FINAL; |
194 | |||
195 | sci_rnc->destination_state = RNC_DEST_FINAL; | ||
196 | sci_rnc->user_callback = callback; | 186 | sci_rnc->user_callback = callback; |
197 | sci_rnc->user_cookie = callback_parameter; | 187 | sci_rnc->user_cookie = callback_parameter; |
198 | |||
199 | wake_up(&ihost->eventq); | ||
200 | } | 188 | } |
201 | 189 | ||
202 | /** | 190 | /** |
@@ -218,19 +206,9 @@ static void sci_remote_node_context_notify_user( | |||
218 | 206 | ||
219 | static void sci_remote_node_context_continue_state_transitions(struct sci_remote_node_context *rnc) | 207 | static void sci_remote_node_context_continue_state_transitions(struct sci_remote_node_context *rnc) |
220 | { | 208 | { |
221 | switch (rnc->destination_state) { | 209 | if (rnc->destination_state == SCIC_SDS_REMOTE_NODE_DESTINATION_STATE_READY) |
222 | case RNC_DEST_READY: | ||
223 | case RNC_DEST_SUSPENDED_RESUME: | ||
224 | rnc->destination_state = RNC_DEST_READY; | ||
225 | /* Fall through... */ | ||
226 | case RNC_DEST_FINAL: | ||
227 | sci_remote_node_context_resume(rnc, rnc->user_callback, | 210 | sci_remote_node_context_resume(rnc, rnc->user_callback, |
228 | rnc->user_cookie); | 211 | rnc->user_cookie); |
229 | break; | ||
230 | default: | ||
231 | rnc->destination_state = RNC_DEST_UNSPECIFIED; | ||
232 | break; | ||
233 | } | ||
234 | } | 212 | } |
235 | 213 | ||
236 | static void sci_remote_node_context_validate_context_buffer(struct sci_remote_node_context *sci_rnc) | 214 | static void sci_remote_node_context_validate_context_buffer(struct sci_remote_node_context *sci_rnc) |
@@ -244,12 +222,13 @@ static void sci_remote_node_context_validate_context_buffer(struct sci_remote_no | |||
244 | 222 | ||
245 | rnc_buffer->ssp.is_valid = true; | 223 | rnc_buffer->ssp.is_valid = true; |
246 | 224 | ||
247 | if (dev_is_sata(dev) && dev->parent) { | 225 | if (!idev->is_direct_attached && |
226 | (dev->dev_type == SATA_DEV || (dev->tproto & SAS_PROTOCOL_STP))) { | ||
248 | sci_remote_device_post_request(idev, SCU_CONTEXT_COMMAND_POST_RNC_96); | 227 | sci_remote_device_post_request(idev, SCU_CONTEXT_COMMAND_POST_RNC_96); |
249 | } else { | 228 | } else { |
250 | sci_remote_device_post_request(idev, SCU_CONTEXT_COMMAND_POST_RNC_32); | 229 | sci_remote_device_post_request(idev, SCU_CONTEXT_COMMAND_POST_RNC_32); |
251 | 230 | ||
252 | if (!dev->parent) | 231 | if (idev->is_direct_attached) |
253 | sci_port_setup_transports(idev->owning_port, | 232 | sci_port_setup_transports(idev->owning_port, |
254 | sci_rnc->remote_node_index); | 233 | sci_rnc->remote_node_index); |
255 | } | 234 | } |
@@ -272,18 +251,13 @@ static void sci_remote_node_context_invalidate_context_buffer(struct sci_remote_ | |||
272 | static void sci_remote_node_context_initial_state_enter(struct sci_base_state_machine *sm) | 251 | static void sci_remote_node_context_initial_state_enter(struct sci_base_state_machine *sm) |
273 | { | 252 | { |
274 | struct sci_remote_node_context *rnc = container_of(sm, typeof(*rnc), sm); | 253 | struct sci_remote_node_context *rnc = container_of(sm, typeof(*rnc), sm); |
275 | struct isci_remote_device *idev = rnc_to_dev(rnc); | ||
276 | struct isci_host *ihost = idev->owning_port->owning_controller; | ||
277 | 254 | ||
278 | /* Check to see if we have gotten back to the initial state because | 255 | /* Check to see if we have gotten back to the initial state because |
279 | * someone requested to destroy the remote node context object. | 256 | * someone requested to destroy the remote node context object. |
280 | */ | 257 | */ |
281 | if (sm->previous_state_id == SCI_RNC_INVALIDATING) { | 258 | if (sm->previous_state_id == SCI_RNC_INVALIDATING) { |
282 | rnc->destination_state = RNC_DEST_UNSPECIFIED; | 259 | rnc->destination_state = SCIC_SDS_REMOTE_NODE_DESTINATION_STATE_UNSPECIFIED; |
283 | sci_remote_node_context_notify_user(rnc); | 260 | sci_remote_node_context_notify_user(rnc); |
284 | |||
285 | smp_wmb(); | ||
286 | wake_up(&ihost->eventq); | ||
287 | } | 261 | } |
288 | } | 262 | } |
289 | 263 | ||
@@ -298,8 +272,6 @@ static void sci_remote_node_context_invalidating_state_enter(struct sci_base_sta | |||
298 | { | 272 | { |
299 | struct sci_remote_node_context *rnc = container_of(sm, typeof(*rnc), sm); | 273 | struct sci_remote_node_context *rnc = container_of(sm, typeof(*rnc), sm); |
300 | 274 | ||
301 | /* Terminate all outstanding requests. */ | ||
302 | sci_remote_device_terminate_requests(rnc_to_dev(rnc)); | ||
303 | sci_remote_node_context_invalidate_context_buffer(rnc); | 275 | sci_remote_node_context_invalidate_context_buffer(rnc); |
304 | } | 276 | } |
305 | 277 | ||
@@ -318,8 +290,10 @@ static void sci_remote_node_context_resuming_state_enter(struct sci_base_state_m | |||
318 | * resume because of a target reset we also need to update | 290 | * resume because of a target reset we also need to update |
319 | * the STPTLDARNI register with the RNi of the device | 291 | * the STPTLDARNI register with the RNi of the device |
320 | */ | 292 | */ |
321 | if (dev_is_sata(dev) && !dev->parent) | 293 | if ((dev->dev_type == SATA_DEV || (dev->tproto & SAS_PROTOCOL_STP)) && |
322 | sci_port_setup_transports(idev->owning_port, rnc->remote_node_index); | 294 | idev->is_direct_attached) |
295 | sci_port_setup_transports(idev->owning_port, | ||
296 | rnc->remote_node_index); | ||
323 | 297 | ||
324 | sci_remote_device_post_request(idev, SCU_CONTEXT_COMMAND_POST_RNC_RESUME); | 298 | sci_remote_device_post_request(idev, SCU_CONTEXT_COMMAND_POST_RNC_RESUME); |
325 | } | 299 | } |
@@ -327,22 +301,10 @@ static void sci_remote_node_context_resuming_state_enter(struct sci_base_state_m | |||
327 | static void sci_remote_node_context_ready_state_enter(struct sci_base_state_machine *sm) | 301 | static void sci_remote_node_context_ready_state_enter(struct sci_base_state_machine *sm) |
328 | { | 302 | { |
329 | struct sci_remote_node_context *rnc = container_of(sm, typeof(*rnc), sm); | 303 | struct sci_remote_node_context *rnc = container_of(sm, typeof(*rnc), sm); |
330 | enum sci_remote_node_context_destination_state dest_select; | ||
331 | int tell_user = 1; | ||
332 | |||
333 | dest_select = rnc->destination_state; | ||
334 | rnc->destination_state = RNC_DEST_UNSPECIFIED; | ||
335 | 304 | ||
336 | if ((dest_select == RNC_DEST_SUSPENDED) || | 305 | rnc->destination_state = SCIC_SDS_REMOTE_NODE_DESTINATION_STATE_UNSPECIFIED; |
337 | (dest_select == RNC_DEST_SUSPENDED_RESUME)) { | ||
338 | sci_remote_node_context_suspend( | ||
339 | rnc, rnc->suspend_reason, | ||
340 | SCI_SOFTWARE_SUSPEND_EXPECTED_EVENT); | ||
341 | 306 | ||
342 | if (dest_select == RNC_DEST_SUSPENDED_RESUME) | 307 | if (rnc->user_callback) |
343 | tell_user = 0; /* Wait until ready again. */ | ||
344 | } | ||
345 | if (tell_user) | ||
346 | sci_remote_node_context_notify_user(rnc); | 308 | sci_remote_node_context_notify_user(rnc); |
347 | } | 309 | } |
348 | 310 | ||
@@ -356,34 +318,10 @@ static void sci_remote_node_context_tx_suspended_state_enter(struct sci_base_sta | |||
356 | static void sci_remote_node_context_tx_rx_suspended_state_enter(struct sci_base_state_machine *sm) | 318 | static void sci_remote_node_context_tx_rx_suspended_state_enter(struct sci_base_state_machine *sm) |
357 | { | 319 | { |
358 | struct sci_remote_node_context *rnc = container_of(sm, typeof(*rnc), sm); | 320 | struct sci_remote_node_context *rnc = container_of(sm, typeof(*rnc), sm); |
359 | struct isci_remote_device *idev = rnc_to_dev(rnc); | ||
360 | struct isci_host *ihost = idev->owning_port->owning_controller; | ||
361 | u32 new_count = rnc->suspend_count + 1; | ||
362 | |||
363 | if (new_count == 0) | ||
364 | rnc->suspend_count = 1; | ||
365 | else | ||
366 | rnc->suspend_count = new_count; | ||
367 | smp_wmb(); | ||
368 | 321 | ||
369 | /* Terminate outstanding requests pending abort. */ | ||
370 | sci_remote_device_abort_requests_pending_abort(idev); | ||
371 | |||
372 | wake_up(&ihost->eventq); | ||
373 | sci_remote_node_context_continue_state_transitions(rnc); | 322 | sci_remote_node_context_continue_state_transitions(rnc); |
374 | } | 323 | } |
375 | 324 | ||
376 | static void sci_remote_node_context_await_suspend_state_exit( | ||
377 | struct sci_base_state_machine *sm) | ||
378 | { | ||
379 | struct sci_remote_node_context *rnc | ||
380 | = container_of(sm, typeof(*rnc), sm); | ||
381 | struct isci_remote_device *idev = rnc_to_dev(rnc); | ||
382 | |||
383 | if (dev_is_sata(idev->domain_dev)) | ||
384 | isci_dev_set_hang_detection_timeout(idev, 0); | ||
385 | } | ||
386 | |||
387 | static const struct sci_base_state sci_remote_node_context_state_table[] = { | 325 | static const struct sci_base_state sci_remote_node_context_state_table[] = { |
388 | [SCI_RNC_INITIAL] = { | 326 | [SCI_RNC_INITIAL] = { |
389 | .enter_state = sci_remote_node_context_initial_state_enter, | 327 | .enter_state = sci_remote_node_context_initial_state_enter, |
@@ -406,9 +344,7 @@ static const struct sci_base_state sci_remote_node_context_state_table[] = { | |||
406 | [SCI_RNC_TX_RX_SUSPENDED] = { | 344 | [SCI_RNC_TX_RX_SUSPENDED] = { |
407 | .enter_state = sci_remote_node_context_tx_rx_suspended_state_enter, | 345 | .enter_state = sci_remote_node_context_tx_rx_suspended_state_enter, |
408 | }, | 346 | }, |
409 | [SCI_RNC_AWAIT_SUSPENSION] = { | 347 | [SCI_RNC_AWAIT_SUSPENSION] = { }, |
410 | .exit_state = sci_remote_node_context_await_suspend_state_exit, | ||
411 | }, | ||
412 | }; | 348 | }; |
413 | 349 | ||
414 | void sci_remote_node_context_construct(struct sci_remote_node_context *rnc, | 350 | void sci_remote_node_context_construct(struct sci_remote_node_context *rnc, |
@@ -417,7 +353,7 @@ void sci_remote_node_context_construct(struct sci_remote_node_context *rnc, | |||
417 | memset(rnc, 0, sizeof(struct sci_remote_node_context)); | 353 | memset(rnc, 0, sizeof(struct sci_remote_node_context)); |
418 | 354 | ||
419 | rnc->remote_node_index = remote_node_index; | 355 | rnc->remote_node_index = remote_node_index; |
420 | rnc->destination_state = RNC_DEST_UNSPECIFIED; | 356 | rnc->destination_state = SCIC_SDS_REMOTE_NODE_DESTINATION_STATE_UNSPECIFIED; |
421 | 357 | ||
422 | sci_init_sm(&rnc->sm, sci_remote_node_context_state_table, SCI_RNC_INITIAL); | 358 | sci_init_sm(&rnc->sm, sci_remote_node_context_state_table, SCI_RNC_INITIAL); |
423 | } | 359 | } |
@@ -426,7 +362,6 @@ enum sci_status sci_remote_node_context_event_handler(struct sci_remote_node_con | |||
426 | u32 event_code) | 362 | u32 event_code) |
427 | { | 363 | { |
428 | enum scis_sds_remote_node_context_states state; | 364 | enum scis_sds_remote_node_context_states state; |
429 | u32 next_state; | ||
430 | 365 | ||
431 | state = sci_rnc->sm.current_state_id; | 366 | state = sci_rnc->sm.current_state_id; |
432 | switch (state) { | 367 | switch (state) { |
@@ -441,18 +376,18 @@ enum sci_status sci_remote_node_context_event_handler(struct sci_remote_node_con | |||
441 | break; | 376 | break; |
442 | case SCI_RNC_INVALIDATING: | 377 | case SCI_RNC_INVALIDATING: |
443 | if (scu_get_event_code(event_code) == SCU_EVENT_POST_RNC_INVALIDATE_COMPLETE) { | 378 | if (scu_get_event_code(event_code) == SCU_EVENT_POST_RNC_INVALIDATE_COMPLETE) { |
444 | if (sci_rnc->destination_state == RNC_DEST_FINAL) | 379 | if (sci_rnc->destination_state == SCIC_SDS_REMOTE_NODE_DESTINATION_STATE_FINAL) |
445 | next_state = SCI_RNC_INITIAL; | 380 | state = SCI_RNC_INITIAL; |
446 | else | 381 | else |
447 | next_state = SCI_RNC_POSTING; | 382 | state = SCI_RNC_POSTING; |
448 | sci_change_state(&sci_rnc->sm, next_state); | 383 | sci_change_state(&sci_rnc->sm, state); |
449 | } else { | 384 | } else { |
450 | switch (scu_get_event_type(event_code)) { | 385 | switch (scu_get_event_type(event_code)) { |
451 | case SCU_EVENT_TYPE_RNC_SUSPEND_TX: | 386 | case SCU_EVENT_TYPE_RNC_SUSPEND_TX: |
452 | case SCU_EVENT_TYPE_RNC_SUSPEND_TX_RX: | 387 | case SCU_EVENT_TYPE_RNC_SUSPEND_TX_RX: |
453 | /* We really dont care if the hardware is going to suspend | 388 | /* We really dont care if the hardware is going to suspend |
454 | * the device since it's being invalidated anyway */ | 389 | * the device since it's being invalidated anyway */ |
455 | dev_warn(scirdev_to_dev(rnc_to_dev(sci_rnc)), | 390 | dev_dbg(scirdev_to_dev(rnc_to_dev(sci_rnc)), |
456 | "%s: SCIC Remote Node Context 0x%p was " | 391 | "%s: SCIC Remote Node Context 0x%p was " |
457 | "suspeneded by hardware while being " | 392 | "suspeneded by hardware while being " |
458 | "invalidated.\n", __func__, sci_rnc); | 393 | "invalidated.\n", __func__, sci_rnc); |
@@ -471,7 +406,7 @@ enum sci_status sci_remote_node_context_event_handler(struct sci_remote_node_con | |||
471 | case SCU_EVENT_TYPE_RNC_SUSPEND_TX_RX: | 406 | case SCU_EVENT_TYPE_RNC_SUSPEND_TX_RX: |
472 | /* We really dont care if the hardware is going to suspend | 407 | /* We really dont care if the hardware is going to suspend |
473 | * the device since it's being resumed anyway */ | 408 | * the device since it's being resumed anyway */ |
474 | dev_warn(scirdev_to_dev(rnc_to_dev(sci_rnc)), | 409 | dev_dbg(scirdev_to_dev(rnc_to_dev(sci_rnc)), |
475 | "%s: SCIC Remote Node Context 0x%p was " | 410 | "%s: SCIC Remote Node Context 0x%p was " |
476 | "suspeneded by hardware while being resumed.\n", | 411 | "suspeneded by hardware while being resumed.\n", |
477 | __func__, sci_rnc); | 412 | __func__, sci_rnc); |
@@ -485,11 +420,11 @@ enum sci_status sci_remote_node_context_event_handler(struct sci_remote_node_con | |||
485 | switch (scu_get_event_type(event_code)) { | 420 | switch (scu_get_event_type(event_code)) { |
486 | case SCU_EVENT_TL_RNC_SUSPEND_TX: | 421 | case SCU_EVENT_TL_RNC_SUSPEND_TX: |
487 | sci_change_state(&sci_rnc->sm, SCI_RNC_TX_SUSPENDED); | 422 | sci_change_state(&sci_rnc->sm, SCI_RNC_TX_SUSPENDED); |
488 | sci_rnc->suspend_type = scu_get_event_type(event_code); | 423 | sci_rnc->suspension_code = scu_get_event_specifier(event_code); |
489 | break; | 424 | break; |
490 | case SCU_EVENT_TL_RNC_SUSPEND_TX_RX: | 425 | case SCU_EVENT_TL_RNC_SUSPEND_TX_RX: |
491 | sci_change_state(&sci_rnc->sm, SCI_RNC_TX_RX_SUSPENDED); | 426 | sci_change_state(&sci_rnc->sm, SCI_RNC_TX_RX_SUSPENDED); |
492 | sci_rnc->suspend_type = scu_get_event_type(event_code); | 427 | sci_rnc->suspension_code = scu_get_event_specifier(event_code); |
493 | break; | 428 | break; |
494 | default: | 429 | default: |
495 | goto out; | 430 | goto out; |
@@ -498,29 +433,27 @@ enum sci_status sci_remote_node_context_event_handler(struct sci_remote_node_con | |||
498 | case SCI_RNC_AWAIT_SUSPENSION: | 433 | case SCI_RNC_AWAIT_SUSPENSION: |
499 | switch (scu_get_event_type(event_code)) { | 434 | switch (scu_get_event_type(event_code)) { |
500 | case SCU_EVENT_TL_RNC_SUSPEND_TX: | 435 | case SCU_EVENT_TL_RNC_SUSPEND_TX: |
501 | next_state = SCI_RNC_TX_SUSPENDED; | 436 | sci_change_state(&sci_rnc->sm, SCI_RNC_TX_SUSPENDED); |
437 | sci_rnc->suspension_code = scu_get_event_specifier(event_code); | ||
502 | break; | 438 | break; |
503 | case SCU_EVENT_TL_RNC_SUSPEND_TX_RX: | 439 | case SCU_EVENT_TL_RNC_SUSPEND_TX_RX: |
504 | next_state = SCI_RNC_TX_RX_SUSPENDED; | 440 | sci_change_state(&sci_rnc->sm, SCI_RNC_TX_RX_SUSPENDED); |
441 | sci_rnc->suspension_code = scu_get_event_specifier(event_code); | ||
505 | break; | 442 | break; |
506 | default: | 443 | default: |
507 | goto out; | 444 | goto out; |
508 | } | 445 | } |
509 | if (sci_rnc->suspend_type == scu_get_event_type(event_code)) | ||
510 | sci_change_state(&sci_rnc->sm, next_state); | ||
511 | break; | 446 | break; |
512 | default: | 447 | default: |
513 | dev_warn(scirdev_to_dev(rnc_to_dev(sci_rnc)), | 448 | dev_warn(scirdev_to_dev(rnc_to_dev(sci_rnc)), |
514 | "%s: invalid state: %s\n", __func__, | 449 | "%s: invalid state %d\n", __func__, state); |
515 | rnc_state_name(state)); | ||
516 | return SCI_FAILURE_INVALID_STATE; | 450 | return SCI_FAILURE_INVALID_STATE; |
517 | } | 451 | } |
518 | return SCI_SUCCESS; | 452 | return SCI_SUCCESS; |
519 | 453 | ||
520 | out: | 454 | out: |
521 | dev_warn(scirdev_to_dev(rnc_to_dev(sci_rnc)), | 455 | dev_warn(scirdev_to_dev(rnc_to_dev(sci_rnc)), |
522 | "%s: code: %#x state: %s\n", __func__, event_code, | 456 | "%s: code: %#x state: %d\n", __func__, event_code, state); |
523 | rnc_state_name(state)); | ||
524 | return SCI_FAILURE; | 457 | return SCI_FAILURE; |
525 | 458 | ||
526 | } | 459 | } |
@@ -534,23 +467,20 @@ enum sci_status sci_remote_node_context_destruct(struct sci_remote_node_context | |||
534 | state = sci_rnc->sm.current_state_id; | 467 | state = sci_rnc->sm.current_state_id; |
535 | switch (state) { | 468 | switch (state) { |
536 | case SCI_RNC_INVALIDATING: | 469 | case SCI_RNC_INVALIDATING: |
537 | sci_remote_node_context_setup_to_destroy(sci_rnc, cb_fn, cb_p); | 470 | sci_remote_node_context_setup_to_destory(sci_rnc, cb_fn, cb_p); |
538 | return SCI_SUCCESS; | 471 | return SCI_SUCCESS; |
539 | case SCI_RNC_POSTING: | 472 | case SCI_RNC_POSTING: |
540 | case SCI_RNC_RESUMING: | 473 | case SCI_RNC_RESUMING: |
541 | case SCI_RNC_READY: | 474 | case SCI_RNC_READY: |
542 | case SCI_RNC_TX_SUSPENDED: | 475 | case SCI_RNC_TX_SUSPENDED: |
543 | case SCI_RNC_TX_RX_SUSPENDED: | 476 | case SCI_RNC_TX_RX_SUSPENDED: |
544 | sci_remote_node_context_setup_to_destroy(sci_rnc, cb_fn, cb_p); | ||
545 | sci_change_state(&sci_rnc->sm, SCI_RNC_INVALIDATING); | ||
546 | return SCI_SUCCESS; | ||
547 | case SCI_RNC_AWAIT_SUSPENSION: | 477 | case SCI_RNC_AWAIT_SUSPENSION: |
548 | sci_remote_node_context_setup_to_destroy(sci_rnc, cb_fn, cb_p); | 478 | sci_remote_node_context_setup_to_destory(sci_rnc, cb_fn, cb_p); |
479 | sci_change_state(&sci_rnc->sm, SCI_RNC_INVALIDATING); | ||
549 | return SCI_SUCCESS; | 480 | return SCI_SUCCESS; |
550 | case SCI_RNC_INITIAL: | 481 | case SCI_RNC_INITIAL: |
551 | dev_warn(scirdev_to_dev(rnc_to_dev(sci_rnc)), | 482 | dev_warn(scirdev_to_dev(rnc_to_dev(sci_rnc)), |
552 | "%s: invalid state: %s\n", __func__, | 483 | "%s: invalid state %d\n", __func__, state); |
553 | rnc_state_name(state)); | ||
554 | /* We have decided that the destruct request on the remote node context | 484 | /* We have decided that the destruct request on the remote node context |
555 | * can not fail since it is either in the initial/destroyed state or is | 485 | * can not fail since it is either in the initial/destroyed state or is |
556 | * can be destroyed. | 486 | * can be destroyed. |
@@ -558,101 +488,35 @@ enum sci_status sci_remote_node_context_destruct(struct sci_remote_node_context | |||
558 | return SCI_SUCCESS; | 488 | return SCI_SUCCESS; |
559 | default: | 489 | default: |
560 | dev_warn(scirdev_to_dev(rnc_to_dev(sci_rnc)), | 490 | dev_warn(scirdev_to_dev(rnc_to_dev(sci_rnc)), |
561 | "%s: invalid state %s\n", __func__, | 491 | "%s: invalid state %d\n", __func__, state); |
562 | rnc_state_name(state)); | ||
563 | return SCI_FAILURE_INVALID_STATE; | 492 | return SCI_FAILURE_INVALID_STATE; |
564 | } | 493 | } |
565 | } | 494 | } |
566 | 495 | ||
567 | enum sci_status sci_remote_node_context_suspend( | 496 | enum sci_status sci_remote_node_context_suspend(struct sci_remote_node_context *sci_rnc, |
568 | struct sci_remote_node_context *sci_rnc, | 497 | u32 suspend_type, |
569 | enum sci_remote_node_suspension_reasons suspend_reason, | 498 | scics_sds_remote_node_context_callback cb_fn, |
570 | u32 suspend_type) | 499 | void *cb_p) |
571 | { | 500 | { |
572 | enum scis_sds_remote_node_context_states state | 501 | enum scis_sds_remote_node_context_states state; |
573 | = sci_rnc->sm.current_state_id; | ||
574 | struct isci_remote_device *idev = rnc_to_dev(sci_rnc); | ||
575 | enum sci_status status = SCI_FAILURE_INVALID_STATE; | ||
576 | enum sci_remote_node_context_destination_state dest_param = | ||
577 | RNC_DEST_UNSPECIFIED; | ||
578 | |||
579 | dev_dbg(scirdev_to_dev(idev), | ||
580 | "%s: current state %s, current suspend_type %x dest state %d," | ||
581 | " arg suspend_reason %d, arg suspend_type %x", | ||
582 | __func__, rnc_state_name(state), sci_rnc->suspend_type, | ||
583 | sci_rnc->destination_state, suspend_reason, | ||
584 | suspend_type); | ||
585 | |||
586 | /* Disable automatic state continuations if explicitly suspending. */ | ||
587 | if ((suspend_reason == SCI_HW_SUSPEND) || | ||
588 | (sci_rnc->destination_state == RNC_DEST_FINAL)) | ||
589 | dest_param = sci_rnc->destination_state; | ||
590 | |||
591 | switch (state) { | ||
592 | case SCI_RNC_READY: | ||
593 | break; | ||
594 | case SCI_RNC_INVALIDATING: | ||
595 | if (sci_rnc->destination_state == RNC_DEST_FINAL) { | ||
596 | dev_warn(scirdev_to_dev(idev), | ||
597 | "%s: already destroying %p\n", | ||
598 | __func__, sci_rnc); | ||
599 | return SCI_FAILURE_INVALID_STATE; | ||
600 | } | ||
601 | /* Fall through and handle like SCI_RNC_POSTING */ | ||
602 | case SCI_RNC_RESUMING: | ||
603 | /* Fall through and handle like SCI_RNC_POSTING */ | ||
604 | case SCI_RNC_POSTING: | ||
605 | /* Set the destination state to AWAIT - this signals the | ||
606 | * entry into the SCI_RNC_READY state that a suspension | ||
607 | * needs to be done immediately. | ||
608 | */ | ||
609 | if (sci_rnc->destination_state != RNC_DEST_FINAL) | ||
610 | sci_rnc->destination_state = RNC_DEST_SUSPENDED; | ||
611 | sci_rnc->suspend_type = suspend_type; | ||
612 | sci_rnc->suspend_reason = suspend_reason; | ||
613 | return SCI_SUCCESS; | ||
614 | 502 | ||
615 | case SCI_RNC_TX_SUSPENDED: | 503 | state = sci_rnc->sm.current_state_id; |
616 | if (suspend_type == SCU_EVENT_TL_RNC_SUSPEND_TX) | 504 | if (state != SCI_RNC_READY) { |
617 | status = SCI_SUCCESS; | ||
618 | break; | ||
619 | case SCI_RNC_TX_RX_SUSPENDED: | ||
620 | if (suspend_type == SCU_EVENT_TL_RNC_SUSPEND_TX_RX) | ||
621 | status = SCI_SUCCESS; | ||
622 | break; | ||
623 | case SCI_RNC_AWAIT_SUSPENSION: | ||
624 | if ((sci_rnc->suspend_type == SCU_EVENT_TL_RNC_SUSPEND_TX_RX) | ||
625 | || (suspend_type == sci_rnc->suspend_type)) | ||
626 | return SCI_SUCCESS; | ||
627 | break; | ||
628 | default: | ||
629 | dev_warn(scirdev_to_dev(rnc_to_dev(sci_rnc)), | 505 | dev_warn(scirdev_to_dev(rnc_to_dev(sci_rnc)), |
630 | "%s: invalid state %s\n", __func__, | 506 | "%s: invalid state %d\n", __func__, state); |
631 | rnc_state_name(state)); | ||
632 | return SCI_FAILURE_INVALID_STATE; | 507 | return SCI_FAILURE_INVALID_STATE; |
633 | } | 508 | } |
634 | sci_rnc->destination_state = dest_param; | ||
635 | sci_rnc->suspend_type = suspend_type; | ||
636 | sci_rnc->suspend_reason = suspend_reason; | ||
637 | 509 | ||
638 | if (status == SCI_SUCCESS) { /* Already in the destination state? */ | 510 | sci_rnc->user_callback = cb_fn; |
639 | struct isci_host *ihost = idev->owning_port->owning_controller; | 511 | sci_rnc->user_cookie = cb_p; |
512 | sci_rnc->suspension_code = suspend_type; | ||
640 | 513 | ||
641 | wake_up_all(&ihost->eventq); /* Let observers look. */ | 514 | if (suspend_type == SCI_SOFTWARE_SUSPENSION) { |
642 | return SCI_SUCCESS; | 515 | sci_remote_device_post_request(rnc_to_dev(sci_rnc), |
516 | SCU_CONTEXT_COMMAND_POST_RNC_SUSPEND_TX); | ||
643 | } | 517 | } |
644 | if ((suspend_reason == SCI_SW_SUSPEND_NORMAL) || | ||
645 | (suspend_reason == SCI_SW_SUSPEND_LINKHANG_DETECT)) { | ||
646 | |||
647 | if (suspend_reason == SCI_SW_SUSPEND_LINKHANG_DETECT) | ||
648 | isci_dev_set_hang_detection_timeout(idev, 0x00000001); | ||
649 | |||
650 | sci_remote_device_post_request( | ||
651 | idev, SCI_SOFTWARE_SUSPEND_CMD); | ||
652 | } | ||
653 | if (state != SCI_RNC_AWAIT_SUSPENSION) | ||
654 | sci_change_state(&sci_rnc->sm, SCI_RNC_AWAIT_SUSPENSION); | ||
655 | 518 | ||
519 | sci_change_state(&sci_rnc->sm, SCI_RNC_AWAIT_SUSPENSION); | ||
656 | return SCI_SUCCESS; | 520 | return SCI_SUCCESS; |
657 | } | 521 | } |
658 | 522 | ||
@@ -661,86 +525,56 @@ enum sci_status sci_remote_node_context_resume(struct sci_remote_node_context *s | |||
661 | void *cb_p) | 525 | void *cb_p) |
662 | { | 526 | { |
663 | enum scis_sds_remote_node_context_states state; | 527 | enum scis_sds_remote_node_context_states state; |
664 | struct isci_remote_device *idev = rnc_to_dev(sci_rnc); | ||
665 | 528 | ||
666 | state = sci_rnc->sm.current_state_id; | 529 | state = sci_rnc->sm.current_state_id; |
667 | dev_dbg(scirdev_to_dev(idev), | ||
668 | "%s: state %s, cb_fn = %p, cb_p = %p; dest_state = %d; " | ||
669 | "dev resume path %s\n", | ||
670 | __func__, rnc_state_name(state), cb_fn, cb_p, | ||
671 | sci_rnc->destination_state, | ||
672 | test_bit(IDEV_ABORT_PATH_ACTIVE, &idev->flags) | ||
673 | ? "<abort active>" : "<normal>"); | ||
674 | |||
675 | switch (state) { | 530 | switch (state) { |
676 | case SCI_RNC_INITIAL: | 531 | case SCI_RNC_INITIAL: |
677 | if (sci_rnc->remote_node_index == SCIC_SDS_REMOTE_NODE_CONTEXT_INVALID_INDEX) | 532 | if (sci_rnc->remote_node_index == SCIC_SDS_REMOTE_NODE_CONTEXT_INVALID_INDEX) |
678 | return SCI_FAILURE_INVALID_STATE; | 533 | return SCI_FAILURE_INVALID_STATE; |
679 | 534 | ||
680 | sci_remote_node_context_setup_to_resume(sci_rnc, cb_fn, cb_p, | 535 | sci_remote_node_context_setup_to_resume(sci_rnc, cb_fn, cb_p); |
681 | RNC_DEST_READY); | 536 | sci_remote_node_context_construct_buffer(sci_rnc); |
682 | if (!test_bit(IDEV_ABORT_PATH_ACTIVE, &idev->flags)) { | 537 | sci_change_state(&sci_rnc->sm, SCI_RNC_POSTING); |
683 | sci_remote_node_context_construct_buffer(sci_rnc); | ||
684 | sci_change_state(&sci_rnc->sm, SCI_RNC_POSTING); | ||
685 | } | ||
686 | return SCI_SUCCESS; | 538 | return SCI_SUCCESS; |
687 | |||
688 | case SCI_RNC_POSTING: | 539 | case SCI_RNC_POSTING: |
689 | case SCI_RNC_INVALIDATING: | 540 | case SCI_RNC_INVALIDATING: |
690 | case SCI_RNC_RESUMING: | 541 | case SCI_RNC_RESUMING: |
691 | /* We are still waiting to post when a resume was | 542 | if (sci_rnc->destination_state != SCIC_SDS_REMOTE_NODE_DESTINATION_STATE_READY) |
692 | * requested. | 543 | return SCI_FAILURE_INVALID_STATE; |
693 | */ | ||
694 | switch (sci_rnc->destination_state) { | ||
695 | case RNC_DEST_SUSPENDED: | ||
696 | case RNC_DEST_SUSPENDED_RESUME: | ||
697 | /* Previously waiting to suspend after posting. | ||
698 | * Now continue onto resumption. | ||
699 | */ | ||
700 | sci_remote_node_context_setup_to_resume( | ||
701 | sci_rnc, cb_fn, cb_p, | ||
702 | RNC_DEST_SUSPENDED_RESUME); | ||
703 | break; | ||
704 | default: | ||
705 | sci_remote_node_context_setup_to_resume( | ||
706 | sci_rnc, cb_fn, cb_p, | ||
707 | RNC_DEST_READY); | ||
708 | break; | ||
709 | } | ||
710 | return SCI_SUCCESS; | ||
711 | 544 | ||
712 | case SCI_RNC_TX_SUSPENDED: | 545 | sci_rnc->user_callback = cb_fn; |
713 | case SCI_RNC_TX_RX_SUSPENDED: | 546 | sci_rnc->user_cookie = cb_p; |
714 | { | 547 | return SCI_SUCCESS; |
715 | struct domain_device *dev = idev->domain_dev; | 548 | case SCI_RNC_TX_SUSPENDED: { |
716 | /* If this is an expander attached SATA device we must | 549 | struct isci_remote_device *idev = rnc_to_dev(sci_rnc); |
717 | * invalidate and repost the RNC since this is the only | 550 | struct domain_device *dev = idev->domain_dev; |
718 | * way to clear the TCi to NCQ tag mapping table for | 551 | |
719 | * the RNi. All other device types we can just resume. | 552 | sci_remote_node_context_setup_to_resume(sci_rnc, cb_fn, cb_p); |
720 | */ | 553 | |
721 | sci_remote_node_context_setup_to_resume( | 554 | /* TODO: consider adding a resume action of NONE, INVALIDATE, WRITE_TLCR */ |
722 | sci_rnc, cb_fn, cb_p, RNC_DEST_READY); | 555 | if (dev->dev_type == SAS_END_DEV || dev_is_expander(dev)) |
723 | 556 | sci_change_state(&sci_rnc->sm, SCI_RNC_RESUMING); | |
724 | if (!test_bit(IDEV_ABORT_PATH_ACTIVE, &idev->flags)) { | 557 | else if (dev->dev_type == SATA_DEV || (dev->tproto & SAS_PROTOCOL_STP)) { |
725 | if ((dev_is_sata(dev) && dev->parent) || | 558 | if (idev->is_direct_attached) { |
726 | (sci_rnc->destination_state == RNC_DEST_FINAL)) | 559 | /* @todo Fix this since I am being silly in writing to the STPTLDARNI register. */ |
727 | sci_change_state(&sci_rnc->sm, | 560 | sci_change_state(&sci_rnc->sm, SCI_RNC_RESUMING); |
728 | SCI_RNC_INVALIDATING); | 561 | } else { |
729 | else | 562 | sci_change_state(&sci_rnc->sm, SCI_RNC_INVALIDATING); |
730 | sci_change_state(&sci_rnc->sm, | ||
731 | SCI_RNC_RESUMING); | ||
732 | } | 563 | } |
733 | } | 564 | } else |
565 | return SCI_FAILURE; | ||
734 | return SCI_SUCCESS; | 566 | return SCI_SUCCESS; |
735 | 567 | } | |
568 | case SCI_RNC_TX_RX_SUSPENDED: | ||
569 | sci_remote_node_context_setup_to_resume(sci_rnc, cb_fn, cb_p); | ||
570 | sci_change_state(&sci_rnc->sm, SCI_RNC_RESUMING); | ||
571 | return SCI_FAILURE_INVALID_STATE; | ||
736 | case SCI_RNC_AWAIT_SUSPENSION: | 572 | case SCI_RNC_AWAIT_SUSPENSION: |
737 | sci_remote_node_context_setup_to_resume( | 573 | sci_remote_node_context_setup_to_resume(sci_rnc, cb_fn, cb_p); |
738 | sci_rnc, cb_fn, cb_p, RNC_DEST_SUSPENDED_RESUME); | ||
739 | return SCI_SUCCESS; | 574 | return SCI_SUCCESS; |
740 | default: | 575 | default: |
741 | dev_warn(scirdev_to_dev(rnc_to_dev(sci_rnc)), | 576 | dev_warn(scirdev_to_dev(rnc_to_dev(sci_rnc)), |
742 | "%s: invalid state %s\n", __func__, | 577 | "%s: invalid state %d\n", __func__, state); |
743 | rnc_state_name(state)); | ||
744 | return SCI_FAILURE_INVALID_STATE; | 578 | return SCI_FAILURE_INVALID_STATE; |
745 | } | 579 | } |
746 | } | 580 | } |
@@ -759,51 +593,35 @@ enum sci_status sci_remote_node_context_start_io(struct sci_remote_node_context | |||
759 | case SCI_RNC_TX_RX_SUSPENDED: | 593 | case SCI_RNC_TX_RX_SUSPENDED: |
760 | case SCI_RNC_AWAIT_SUSPENSION: | 594 | case SCI_RNC_AWAIT_SUSPENSION: |
761 | dev_warn(scirdev_to_dev(rnc_to_dev(sci_rnc)), | 595 | dev_warn(scirdev_to_dev(rnc_to_dev(sci_rnc)), |
762 | "%s: invalid state %s\n", __func__, | 596 | "%s: invalid state %d\n", __func__, state); |
763 | rnc_state_name(state)); | ||
764 | return SCI_FAILURE_REMOTE_DEVICE_RESET_REQUIRED; | 597 | return SCI_FAILURE_REMOTE_DEVICE_RESET_REQUIRED; |
765 | default: | 598 | default: |
766 | dev_dbg(scirdev_to_dev(rnc_to_dev(sci_rnc)), | 599 | break; |
767 | "%s: invalid state %s\n", __func__, | ||
768 | rnc_state_name(state)); | ||
769 | return SCI_FAILURE_INVALID_STATE; | ||
770 | } | 600 | } |
601 | dev_dbg(scirdev_to_dev(rnc_to_dev(sci_rnc)), | ||
602 | "%s: requested to start IO while still resuming, %d\n", | ||
603 | __func__, state); | ||
604 | return SCI_FAILURE_INVALID_STATE; | ||
771 | } | 605 | } |
772 | 606 | ||
773 | enum sci_status sci_remote_node_context_start_task( | 607 | enum sci_status sci_remote_node_context_start_task(struct sci_remote_node_context *sci_rnc, |
774 | struct sci_remote_node_context *sci_rnc, | 608 | struct isci_request *ireq) |
775 | struct isci_request *ireq, | ||
776 | scics_sds_remote_node_context_callback cb_fn, | ||
777 | void *cb_p) | ||
778 | { | ||
779 | enum sci_status status = sci_remote_node_context_resume(sci_rnc, | ||
780 | cb_fn, cb_p); | ||
781 | if (status != SCI_SUCCESS) | ||
782 | dev_warn(scirdev_to_dev(rnc_to_dev(sci_rnc)), | ||
783 | "%s: resume failed: %d\n", __func__, status); | ||
784 | return status; | ||
785 | } | ||
786 | |||
787 | int sci_remote_node_context_is_safe_to_abort( | ||
788 | struct sci_remote_node_context *sci_rnc) | ||
789 | { | 609 | { |
790 | enum scis_sds_remote_node_context_states state; | 610 | enum scis_sds_remote_node_context_states state; |
791 | 611 | ||
792 | state = sci_rnc->sm.current_state_id; | 612 | state = sci_rnc->sm.current_state_id; |
793 | switch (state) { | 613 | switch (state) { |
794 | case SCI_RNC_INVALIDATING: | ||
795 | case SCI_RNC_TX_RX_SUSPENDED: | ||
796 | return 1; | ||
797 | case SCI_RNC_POSTING: | ||
798 | case SCI_RNC_RESUMING: | 614 | case SCI_RNC_RESUMING: |
799 | case SCI_RNC_READY: | 615 | case SCI_RNC_READY: |
800 | case SCI_RNC_TX_SUSPENDED: | ||
801 | case SCI_RNC_AWAIT_SUSPENSION: | 616 | case SCI_RNC_AWAIT_SUSPENSION: |
802 | case SCI_RNC_INITIAL: | 617 | return SCI_SUCCESS; |
803 | return 0; | 618 | case SCI_RNC_TX_SUSPENDED: |
619 | case SCI_RNC_TX_RX_SUSPENDED: | ||
620 | sci_remote_node_context_resume(sci_rnc, NULL, NULL); | ||
621 | return SCI_SUCCESS; | ||
804 | default: | 622 | default: |
805 | dev_warn(scirdev_to_dev(rnc_to_dev(sci_rnc)), | 623 | dev_warn(scirdev_to_dev(rnc_to_dev(sci_rnc)), |
806 | "%s: invalid state %d\n", __func__, state); | 624 | "%s: invalid state %d\n", __func__, state); |
807 | return 0; | 625 | return SCI_FAILURE_INVALID_STATE; |
808 | } | 626 | } |
809 | } | 627 | } |