diff options
author | Jeff Skirvin <jeffrey.d.skirvin@intel.com> | 2012-03-09 01:41:54 -0500 |
---|---|---|
committer | Dan Williams <dan.j.williams@intel.com> | 2012-05-17 17:33:38 -0400 |
commit | 14aaa9f0a318bd04cbb9d822524b817e95d8b343 (patch) | |
tree | 5f6292ec671d0993c1df51586dea4fb7750d1cd9 /drivers/scsi/isci/remote_device.c | |
parent | d80ecd5726ce49b5da457d562804b40f0183e8f7 (diff) |
isci: Redesign device suspension, abort, cleanup.
This commit changes the means by which outstanding I/Os are handled
for cleanup.
The likelihood is that this commit will be broken into smaller pieces,
however that will be a later revision. Among the changes:
- All completion structures have been removed from the tmf and
abort paths.
- Now using one completed I/O list, with the I/O completed in host bit being
used to select error or normal callback paths.
Signed-off-by: Jeff Skirvin <jeffrey.d.skirvin@intel.com>
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
Diffstat (limited to 'drivers/scsi/isci/remote_device.c')
-rw-r--r-- | drivers/scsi/isci/remote_device.c | 255 |
1 files changed, 119 insertions, 136 deletions
diff --git a/drivers/scsi/isci/remote_device.c b/drivers/scsi/isci/remote_device.c index 3048e02aeb7b..c47304cea45d 100644 --- a/drivers/scsi/isci/remote_device.c +++ b/drivers/scsi/isci/remote_device.c | |||
@@ -81,49 +81,6 @@ static enum sci_status sci_remote_device_suspend(struct isci_remote_device *idev | |||
81 | } | 81 | } |
82 | 82 | ||
83 | /** | 83 | /** |
84 | * isci_remote_device_not_ready() - This function is called by the ihost when | ||
85 | * the remote device is not ready. We mark the isci device as ready (not | ||
86 | * "ready_for_io") and signal the waiting proccess. | ||
87 | * @isci_host: This parameter specifies the isci host object. | ||
88 | * @isci_device: This parameter specifies the remote device | ||
89 | * | ||
90 | * sci_lock is held on entrance to this function. | ||
91 | */ | ||
92 | static void isci_remote_device_not_ready(struct isci_host *ihost, | ||
93 | struct isci_remote_device *idev, u32 reason) | ||
94 | { | ||
95 | struct isci_request *ireq; | ||
96 | |||
97 | dev_dbg(&ihost->pdev->dev, | ||
98 | "%s: isci_device = %p\n", __func__, idev); | ||
99 | |||
100 | switch (reason) { | ||
101 | case SCIC_REMOTE_DEVICE_NOT_READY_STOP_REQUESTED: | ||
102 | set_bit(IDEV_GONE, &idev->flags); | ||
103 | break; | ||
104 | case SCIC_REMOTE_DEVICE_NOT_READY_SATA_SDB_ERROR_FIS_RECEIVED: | ||
105 | set_bit(IDEV_IO_NCQERROR, &idev->flags); | ||
106 | |||
107 | /* Suspend the remote device so the I/O can be terminated. */ | ||
108 | sci_remote_device_suspend(idev); | ||
109 | |||
110 | /* Kill all outstanding requests for the device. */ | ||
111 | list_for_each_entry(ireq, &idev->reqs_in_process, dev_node) { | ||
112 | |||
113 | dev_dbg(&ihost->pdev->dev, | ||
114 | "%s: isci_device = %p request = %p\n", | ||
115 | __func__, idev, ireq); | ||
116 | |||
117 | sci_controller_terminate_request(ihost, idev, ireq); | ||
118 | } | ||
119 | /* Fall through into the default case... */ | ||
120 | default: | ||
121 | clear_bit(IDEV_IO_READY, &idev->flags); | ||
122 | break; | ||
123 | } | ||
124 | } | ||
125 | |||
126 | /** | ||
127 | * isci_remote_device_ready() - This function is called by the ihost when the | 84 | * isci_remote_device_ready() - This function is called by the ihost when the |
128 | * remote device is ready. We mark the isci device as ready and signal the | 85 | * remote device is ready. We mark the isci device as ready and signal the |
129 | * waiting proccess. | 86 | * waiting proccess. |
@@ -142,49 +99,121 @@ static void isci_remote_device_ready(struct isci_host *ihost, struct isci_remote | |||
142 | wake_up(&ihost->eventq); | 99 | wake_up(&ihost->eventq); |
143 | } | 100 | } |
144 | 101 | ||
145 | static int isci_remote_device_suspendcheck(struct isci_remote_device *idev) | 102 | static enum sci_status sci_remote_device_terminate_req( |
103 | struct isci_host *ihost, | ||
104 | struct isci_remote_device *idev, | ||
105 | int check_abort, | ||
106 | struct isci_request *ireq) | ||
107 | { | ||
108 | dev_dbg(&ihost->pdev->dev, | ||
109 | "%s: idev=%p; flags=%lx; req=%p; req target=%p\n", | ||
110 | __func__, idev, idev->flags, ireq, ireq->target_device); | ||
111 | |||
112 | if (!test_bit(IREQ_ACTIVE, &ireq->flags) || | ||
113 | (ireq->target_device != idev) || | ||
114 | (check_abort && !test_bit(IREQ_PENDING_ABORT, &ireq->flags))) | ||
115 | return SCI_SUCCESS; | ||
116 | |||
117 | set_bit(IREQ_ABORT_PATH_ACTIVE, &ireq->flags); | ||
118 | |||
119 | return sci_controller_terminate_request(ihost, idev, ireq); | ||
120 | } | ||
121 | |||
122 | static enum sci_status sci_remote_device_terminate_reqs_checkabort( | ||
123 | struct isci_remote_device *idev, | ||
124 | int chk) | ||
146 | { | 125 | { |
147 | return test_bit(IDEV_TXRX_SUSPENDED, &idev->flags) | 126 | struct isci_host *ihost = idev->owning_port->owning_controller; |
148 | || !test_bit(IDEV_ALLOCATED, &idev->flags); | 127 | enum sci_status status = SCI_SUCCESS; |
128 | u32 i; | ||
129 | |||
130 | for (i = 0; i < SCI_MAX_IO_REQUESTS; i++) { | ||
131 | struct isci_request *ireq = ihost->reqs[i]; | ||
132 | enum sci_status s; | ||
133 | |||
134 | s = sci_remote_device_terminate_req(ihost, idev, chk, ireq); | ||
135 | if (s != SCI_SUCCESS) | ||
136 | status = s; | ||
137 | } | ||
138 | return status; | ||
149 | } | 139 | } |
150 | 140 | ||
151 | enum sci_status isci_remote_device_suspend( | 141 | enum sci_status isci_remote_device_terminate_requests( |
152 | struct isci_host *ihost, | 142 | struct isci_host *ihost, |
153 | struct isci_remote_device *idev) | 143 | struct isci_remote_device *idev, |
144 | struct isci_request *ireq) | ||
154 | { | 145 | { |
155 | enum sci_status status; | 146 | enum sci_status status = SCI_SUCCESS; |
156 | unsigned long flags; | 147 | unsigned long flags; |
157 | 148 | ||
158 | spin_lock_irqsave(&ihost->scic_lock, flags); | 149 | spin_lock_irqsave(&ihost->scic_lock, flags); |
159 | if (isci_get_device(idev->domain_dev) == NULL) { | 150 | if (isci_get_device(idev) == NULL) { |
151 | dev_dbg(&ihost->pdev->dev, "%s: failed isci_get_device(idev=%p)\n", | ||
152 | __func__, idev); | ||
160 | spin_unlock_irqrestore(&ihost->scic_lock, flags); | 153 | spin_unlock_irqrestore(&ihost->scic_lock, flags); |
161 | status = SCI_FAILURE; | 154 | status = SCI_FAILURE; |
162 | } else { | 155 | } else { |
163 | status = sci_remote_device_suspend(idev); | 156 | dev_dbg(&ihost->pdev->dev, |
164 | spin_unlock_irqrestore(&ihost->scic_lock, flags); | 157 | "%s: idev=%p, ireq=%p; started_request_count=%d, " |
165 | if (status == SCI_SUCCESS) { | 158 | "about to wait\n", |
166 | dev_dbg(&ihost->pdev->dev, | 159 | __func__, idev, ireq, idev->started_request_count); |
167 | "%s: idev=%p, about to wait\n", | 160 | if (ireq) { |
168 | __func__, idev); | 161 | /* Terminate a specific TC. */ |
169 | wait_event(ihost->eventq, | 162 | sci_remote_device_terminate_req(ihost, idev, 0, ireq); |
170 | isci_remote_device_suspendcheck(idev)); | 163 | spin_unlock_irqrestore(&ihost->scic_lock, flags); |
171 | status = test_bit(IDEV_TXRX_SUSPENDED, &idev->flags) | 164 | wait_event(ihost->eventq, !test_bit(IREQ_ACTIVE, |
172 | ? SCI_SUCCESS : SCI_FAILURE; | 165 | &ireq->flags)); |
173 | dev_dbg(&ihost->pdev->dev, | ||
174 | "%s: idev=%p, wait done, device is %s\n", | ||
175 | __func__, idev, | ||
176 | test_bit(IDEV_TXRX_SUSPENDED, &idev->flags) | ||
177 | ? "<suspended>" : "<deallocated!>"); | ||
178 | 166 | ||
179 | } else | 167 | } else { |
180 | dev_dbg(scirdev_to_dev(idev), | 168 | /* Terminate all TCs. */ |
181 | "%s: sci_remote_device_suspend failed, " | 169 | sci_remote_device_terminate_requests(idev); |
182 | "status = %d\n", __func__, status); | 170 | spin_unlock_irqrestore(&ihost->scic_lock, flags); |
171 | wait_event(ihost->eventq, | ||
172 | idev->started_request_count == 0); | ||
173 | } | ||
174 | dev_dbg(&ihost->pdev->dev, "%s: idev=%p, wait done\n", | ||
175 | __func__, idev); | ||
183 | isci_put_device(idev); | 176 | isci_put_device(idev); |
184 | } | 177 | } |
185 | return status; | 178 | return status; |
186 | } | 179 | } |
187 | 180 | ||
181 | /** | ||
182 | * isci_remote_device_not_ready() - This function is called by the ihost when | ||
183 | * the remote device is not ready. We mark the isci device as ready (not | ||
184 | * "ready_for_io") and signal the waiting proccess. | ||
185 | * @isci_host: This parameter specifies the isci host object. | ||
186 | * @isci_device: This parameter specifies the remote device | ||
187 | * | ||
188 | * sci_lock is held on entrance to this function. | ||
189 | */ | ||
190 | static void isci_remote_device_not_ready(struct isci_host *ihost, | ||
191 | struct isci_remote_device *idev, | ||
192 | u32 reason) | ||
193 | { | ||
194 | dev_dbg(&ihost->pdev->dev, | ||
195 | "%s: isci_device = %p\n", __func__, idev); | ||
196 | |||
197 | switch (reason) { | ||
198 | case SCIC_REMOTE_DEVICE_NOT_READY_STOP_REQUESTED: | ||
199 | set_bit(IDEV_GONE, &idev->flags); | ||
200 | break; | ||
201 | case SCIC_REMOTE_DEVICE_NOT_READY_SATA_SDB_ERROR_FIS_RECEIVED: | ||
202 | set_bit(IDEV_IO_NCQERROR, &idev->flags); | ||
203 | |||
204 | /* Suspend the remote device so the I/O can be terminated. */ | ||
205 | sci_remote_device_suspend(idev); | ||
206 | |||
207 | /* Kill all outstanding requests for the device. */ | ||
208 | sci_remote_device_terminate_requests(idev); | ||
209 | |||
210 | /* Fall through into the default case... */ | ||
211 | default: | ||
212 | clear_bit(IDEV_IO_READY, &idev->flags); | ||
213 | break; | ||
214 | } | ||
215 | } | ||
216 | |||
188 | /* called once the remote node context is ready to be freed. | 217 | /* called once the remote node context is ready to be freed. |
189 | * The remote device can now report that its stop operation is complete. none | 218 | * The remote device can now report that its stop operation is complete. none |
190 | */ | 219 | */ |
@@ -196,36 +225,10 @@ static void rnc_destruct_done(void *_dev) | |||
196 | sci_change_state(&idev->sm, SCI_DEV_STOPPED); | 225 | sci_change_state(&idev->sm, SCI_DEV_STOPPED); |
197 | } | 226 | } |
198 | 227 | ||
199 | static enum sci_status sci_remote_device_terminate_requests_checkabort( | ||
200 | struct isci_remote_device *idev, | ||
201 | int check_abort_pending) | ||
202 | { | ||
203 | struct isci_host *ihost = idev->owning_port->owning_controller; | ||
204 | enum sci_status status = SCI_SUCCESS; | ||
205 | u32 i; | ||
206 | |||
207 | for (i = 0; i < SCI_MAX_IO_REQUESTS; i++) { | ||
208 | struct isci_request *ireq = ihost->reqs[i]; | ||
209 | enum sci_status s; | ||
210 | |||
211 | if (!test_bit(IREQ_ACTIVE, &ireq->flags) || | ||
212 | (ireq->target_device != idev) || | ||
213 | (check_abort_pending && !test_bit(IREQ_PENDING_ABORT, | ||
214 | &ireq->flags))) | ||
215 | continue; | ||
216 | |||
217 | s = sci_controller_terminate_request(ihost, idev, ireq); | ||
218 | if (s != SCI_SUCCESS) | ||
219 | status = s; | ||
220 | } | ||
221 | |||
222 | return status; | ||
223 | } | ||
224 | |||
225 | enum sci_status sci_remote_device_terminate_requests( | 228 | enum sci_status sci_remote_device_terminate_requests( |
226 | struct isci_remote_device *idev) | 229 | struct isci_remote_device *idev) |
227 | { | 230 | { |
228 | return sci_remote_device_terminate_requests_checkabort(idev, 0); | 231 | return sci_remote_device_terminate_reqs_checkabort(idev, 0); |
229 | } | 232 | } |
230 | 233 | ||
231 | enum sci_status sci_remote_device_stop(struct isci_remote_device *idev, | 234 | enum sci_status sci_remote_device_stop(struct isci_remote_device *idev, |
@@ -771,10 +774,6 @@ enum sci_status sci_remote_device_start_task(struct isci_host *ihost, | |||
771 | if (status != SCI_SUCCESS) | 774 | if (status != SCI_SUCCESS) |
772 | return status; | 775 | return status; |
773 | 776 | ||
774 | status = sci_remote_node_context_start_task(&idev->rnc, ireq); | ||
775 | if (status != SCI_SUCCESS) | ||
776 | goto out; | ||
777 | |||
778 | status = sci_request_start(ireq); | 777 | status = sci_request_start(ireq); |
779 | if (status != SCI_SUCCESS) | 778 | if (status != SCI_SUCCESS) |
780 | goto out; | 779 | goto out; |
@@ -796,8 +795,9 @@ enum sci_status sci_remote_device_start_task(struct isci_host *ihost, | |||
796 | sci_remote_node_context_suspend( | 795 | sci_remote_node_context_suspend( |
797 | &idev->rnc, SCI_SOFTWARE_SUSPENSION, | 796 | &idev->rnc, SCI_SOFTWARE_SUSPENSION, |
798 | SCI_SOFTWARE_SUSPEND_EXPECTED_EVENT, NULL, NULL); | 797 | SCI_SOFTWARE_SUSPEND_EXPECTED_EVENT, NULL, NULL); |
799 | sci_remote_node_context_resume( | 798 | |
800 | &idev->rnc, sci_remote_device_continue_request, idev); | 799 | status = sci_remote_node_context_start_task(&idev->rnc, ireq, |
800 | sci_remote_device_continue_request, idev); | ||
801 | 801 | ||
802 | out: | 802 | out: |
803 | sci_remote_device_start_request(idev, ireq, status); | 803 | sci_remote_device_start_request(idev, ireq, status); |
@@ -811,7 +811,9 @@ enum sci_status sci_remote_device_start_task(struct isci_host *ihost, | |||
811 | if (status != SCI_SUCCESS) | 811 | if (status != SCI_SUCCESS) |
812 | return status; | 812 | return status; |
813 | 813 | ||
814 | status = sci_remote_node_context_start_task(&idev->rnc, ireq); | 814 | /* Resume the RNC as needed: */ |
815 | status = sci_remote_node_context_start_task(&idev->rnc, ireq, | ||
816 | NULL, NULL); | ||
815 | if (status != SCI_SUCCESS) | 817 | if (status != SCI_SUCCESS) |
816 | break; | 818 | break; |
817 | 819 | ||
@@ -1322,20 +1324,6 @@ static enum sci_status isci_remote_device_construct(struct isci_port *iport, | |||
1322 | return status; | 1324 | return status; |
1323 | } | 1325 | } |
1324 | 1326 | ||
1325 | void isci_remote_device_nuke_requests(struct isci_host *ihost, struct isci_remote_device *idev) | ||
1326 | { | ||
1327 | DECLARE_COMPLETION_ONSTACK(aborted_task_completion); | ||
1328 | |||
1329 | dev_dbg(&ihost->pdev->dev, | ||
1330 | "%s: idev = %p\n", __func__, idev); | ||
1331 | |||
1332 | /* Cleanup all requests pending for this device. */ | ||
1333 | isci_terminate_pending_requests(ihost, idev); | ||
1334 | |||
1335 | dev_dbg(&ihost->pdev->dev, | ||
1336 | "%s: idev = %p, done\n", __func__, idev); | ||
1337 | } | ||
1338 | |||
1339 | /** | 1327 | /** |
1340 | * This function builds the isci_remote_device when a libsas dev_found message | 1328 | * This function builds the isci_remote_device when a libsas dev_found message |
1341 | * is received. | 1329 | * is received. |
@@ -1495,32 +1483,28 @@ int isci_remote_device_found(struct domain_device *dev) | |||
1495 | return status == SCI_SUCCESS ? 0 : -ENODEV; | 1483 | return status == SCI_SUCCESS ? 0 : -ENODEV; |
1496 | } | 1484 | } |
1497 | 1485 | ||
1498 | enum sci_status isci_remote_device_reset( | 1486 | enum sci_status isci_remote_device_suspend_terminate( |
1499 | struct isci_host *ihost, | 1487 | struct isci_host *ihost, |
1500 | struct isci_remote_device *idev) | 1488 | struct isci_remote_device *idev, |
1489 | struct isci_request *ireq) | ||
1501 | { | 1490 | { |
1502 | unsigned long flags; | 1491 | unsigned long flags; |
1503 | enum sci_status status; | 1492 | enum sci_status status; |
1504 | 1493 | ||
1505 | /* Put the device into a reset state so the suspension will not | 1494 | /* Put the device into suspension. */ |
1506 | * automatically resume. | ||
1507 | */ | ||
1508 | spin_lock_irqsave(&ihost->scic_lock, flags); | 1495 | spin_lock_irqsave(&ihost->scic_lock, flags); |
1509 | status = sci_remote_device_reset(idev); | 1496 | sci_remote_device_suspend(idev); |
1510 | spin_unlock_irqrestore(&ihost->scic_lock, flags); | 1497 | spin_unlock_irqrestore(&ihost->scic_lock, flags); |
1511 | if (status != SCI_SUCCESS) { | 1498 | |
1512 | dev_dbg(&ihost->pdev->dev, | 1499 | /* Terminate and wait for the completions. */ |
1513 | "%s: sci_remote_device_reset(%p) returned %d!\n", | 1500 | status = isci_remote_device_terminate_requests(ihost, idev, ireq); |
1514 | __func__, idev, status); | 1501 | if (status != SCI_SUCCESS) |
1515 | return status; | ||
1516 | } | ||
1517 | /* Wait for the device suspend. */ | ||
1518 | status = isci_remote_device_suspend(ihost, idev); | ||
1519 | if (status != SCI_SUCCESS) { | ||
1520 | dev_dbg(&ihost->pdev->dev, | 1502 | dev_dbg(&ihost->pdev->dev, |
1521 | "%s: isci_remote_device_suspend(%p) returned %d!\n", | 1503 | "%s: isci_remote_device_terminate_requests(%p) " |
1504 | "returned %d!\n", | ||
1522 | __func__, idev, status); | 1505 | __func__, idev, status); |
1523 | } | 1506 | |
1507 | /* NOTE: RNC resumption is left to the caller! */ | ||
1524 | return status; | 1508 | return status; |
1525 | } | 1509 | } |
1526 | 1510 | ||
@@ -1533,7 +1517,7 @@ int isci_remote_device_is_safe_to_abort( | |||
1533 | enum sci_status sci_remote_device_abort_requests_pending_abort( | 1517 | enum sci_status sci_remote_device_abort_requests_pending_abort( |
1534 | struct isci_remote_device *idev) | 1518 | struct isci_remote_device *idev) |
1535 | { | 1519 | { |
1536 | return sci_remote_device_terminate_requests_checkabort(idev, 1); | 1520 | return sci_remote_device_terminate_reqs_checkabort(idev, 1); |
1537 | } | 1521 | } |
1538 | 1522 | ||
1539 | enum sci_status isci_remote_device_reset_complete( | 1523 | enum sci_status isci_remote_device_reset_complete( |
@@ -1545,7 +1529,6 @@ enum sci_status isci_remote_device_reset_complete( | |||
1545 | 1529 | ||
1546 | spin_lock_irqsave(&ihost->scic_lock, flags); | 1530 | spin_lock_irqsave(&ihost->scic_lock, flags); |
1547 | status = sci_remote_device_reset_complete(idev); | 1531 | status = sci_remote_device_reset_complete(idev); |
1548 | sci_remote_device_resume(idev, NULL, NULL); | ||
1549 | spin_unlock_irqrestore(&ihost->scic_lock, flags); | 1532 | spin_unlock_irqrestore(&ihost->scic_lock, flags); |
1550 | 1533 | ||
1551 | return status; | 1534 | return status; |