diff options
author | Dan Williams <dan.j.williams@intel.com> | 2011-06-16 14:26:12 -0400 |
---|---|---|
committer | Dan Williams <dan.j.williams@intel.com> | 2011-07-03 07:04:51 -0400 |
commit | f2088267514b39af1a94409168101527769a911c (patch) | |
tree | 9155ce7eb3edf40ecdabc690bff34622ecea1294 /drivers/scsi/isci/task.c | |
parent | 209fae14fabfd48525e5630bebbbd4ca15090c60 (diff) |
isci: kill isci_remote_device_change_state()
Now that "stopping/stopped" are one in the same and signalled by a NULL device
pointer the rest of the device status infrastructure can be removed (->status
and ->state_lock). The "not ready for i/o state" is replaced with a state
flag, and is evaluated under scic_lock so that we don't see transients from
taking the device reference to submitting the i/o.
This also fixes a potential leakage of can_queue slots in the rare case that
SAS_TASK_ABORTED is set at submission.
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
Diffstat (limited to 'drivers/scsi/isci/task.c')
-rw-r--r-- | drivers/scsi/isci/task.c | 68 |
1 files changed, 22 insertions, 46 deletions
diff --git a/drivers/scsi/isci/task.c b/drivers/scsi/isci/task.c index dd5e9de1ffb5..c313bc16c218 100644 --- a/drivers/scsi/isci/task.c +++ b/drivers/scsi/isci/task.c | |||
@@ -147,10 +147,10 @@ int isci_task_execute_task(struct sas_task *task, int num, gfp_t gfp_flags) | |||
147 | { | 147 | { |
148 | struct isci_host *ihost = dev_to_ihost(task->dev); | 148 | struct isci_host *ihost = dev_to_ihost(task->dev); |
149 | struct isci_remote_device *idev; | 149 | struct isci_remote_device *idev; |
150 | enum sci_status status; | ||
150 | unsigned long flags; | 151 | unsigned long flags; |
152 | bool io_ready; | ||
151 | int ret; | 153 | int ret; |
152 | enum sci_status status; | ||
153 | enum isci_status device_status; | ||
154 | 154 | ||
155 | dev_dbg(&ihost->pdev->dev, "%s: num=%d\n", __func__, num); | 155 | dev_dbg(&ihost->pdev->dev, "%s: num=%d\n", __func__, num); |
156 | 156 | ||
@@ -163,64 +163,40 @@ int isci_task_execute_task(struct sas_task *task, int num, gfp_t gfp_flags) | |||
163 | } | 163 | } |
164 | 164 | ||
165 | for_each_sas_task(num, task) { | 165 | for_each_sas_task(num, task) { |
166 | dev_dbg(&ihost->pdev->dev, | ||
167 | "task = %p, num = %d; dev = %p; cmd = %p\n", | ||
168 | task, num, task->dev, task->uldd_task); | ||
169 | spin_lock_irqsave(&ihost->scic_lock, flags); | 166 | spin_lock_irqsave(&ihost->scic_lock, flags); |
170 | idev = isci_lookup_device(task->dev); | 167 | idev = isci_lookup_device(task->dev); |
168 | io_ready = idev ? test_bit(IDEV_IO_READY, &idev->flags) : 0; | ||
171 | spin_unlock_irqrestore(&ihost->scic_lock, flags); | 169 | spin_unlock_irqrestore(&ihost->scic_lock, flags); |
172 | 170 | ||
173 | if (idev) | 171 | dev_dbg(&ihost->pdev->dev, |
174 | device_status = idev->status; | 172 | "task: %p, num: %d dev: %p idev: %p:%#lx cmd = %p\n", |
175 | else | 173 | task, num, task->dev, idev, idev ? idev->flags : 0, |
176 | device_status = isci_freed; | 174 | task->uldd_task); |
177 | |||
178 | /* From this point onward, any process that needs to guarantee | ||
179 | * that there is no kernel I/O being started will have to wait | ||
180 | * for the quiesce spinlock. | ||
181 | */ | ||
182 | |||
183 | if (device_status != isci_ready_for_io) { | ||
184 | 175 | ||
185 | /* Forces a retry from scsi mid layer. */ | 176 | if (!idev) { |
186 | dev_dbg(&ihost->pdev->dev, | 177 | isci_task_refuse(ihost, task, SAS_TASK_UNDELIVERED, |
187 | "%s: task %p: isci_host->status = %d, " | 178 | SAS_DEVICE_UNKNOWN); |
188 | "device = %p; device_status = 0x%x\n\n", | 179 | isci_host_can_dequeue(ihost, 1); |
189 | __func__, | 180 | } else if (!io_ready) { |
190 | task, | 181 | /* Indicate QUEUE_FULL so that the scsi midlayer |
191 | isci_host_get_state(ihost), | 182 | * retries. |
192 | idev, | 183 | */ |
193 | device_status); | 184 | isci_task_refuse(ihost, task, SAS_TASK_COMPLETE, |
194 | 185 | SAS_QUEUE_FULL); | |
195 | if (device_status == isci_ready) { | ||
196 | /* Indicate QUEUE_FULL so that the scsi midlayer | ||
197 | * retries. | ||
198 | */ | ||
199 | isci_task_refuse(ihost, task, | ||
200 | SAS_TASK_COMPLETE, | ||
201 | SAS_QUEUE_FULL); | ||
202 | } else { | ||
203 | /* Else, the device is going down. */ | ||
204 | isci_task_refuse(ihost, task, | ||
205 | SAS_TASK_UNDELIVERED, | ||
206 | SAS_DEVICE_UNKNOWN); | ||
207 | } | ||
208 | isci_host_can_dequeue(ihost, 1); | 186 | isci_host_can_dequeue(ihost, 1); |
209 | } else { | 187 | } else { |
210 | /* There is a device and it's ready for I/O. */ | 188 | /* There is a device and it's ready for I/O. */ |
211 | spin_lock_irqsave(&task->task_state_lock, flags); | 189 | spin_lock_irqsave(&task->task_state_lock, flags); |
212 | 190 | ||
213 | if (task->task_state_flags & SAS_TASK_STATE_ABORTED) { | 191 | if (task->task_state_flags & SAS_TASK_STATE_ABORTED) { |
214 | 192 | /* The I/O was aborted. */ | |
215 | spin_unlock_irqrestore(&task->task_state_lock, | 193 | spin_unlock_irqrestore(&task->task_state_lock, |
216 | flags); | 194 | flags); |
217 | 195 | ||
218 | isci_task_refuse(ihost, task, | 196 | isci_task_refuse(ihost, task, |
219 | SAS_TASK_UNDELIVERED, | 197 | SAS_TASK_UNDELIVERED, |
220 | SAM_STAT_TASK_ABORTED); | 198 | SAM_STAT_TASK_ABORTED); |
221 | 199 | isci_host_can_dequeue(ihost, 1); | |
222 | /* The I/O was aborted. */ | ||
223 | |||
224 | } else { | 200 | } else { |
225 | task->task_state_flags |= SAS_TASK_AT_INITIATOR; | 201 | task->task_state_flags |= SAS_TASK_AT_INITIATOR; |
226 | spin_unlock_irqrestore(&task->task_state_lock, flags); | 202 | spin_unlock_irqrestore(&task->task_state_lock, flags); |
@@ -323,11 +299,11 @@ int isci_task_execute_tmf(struct isci_host *ihost, | |||
323 | /* sanity check, return TMF_RESP_FUNC_FAILED | 299 | /* sanity check, return TMF_RESP_FUNC_FAILED |
324 | * if the device is not there and ready. | 300 | * if the device is not there and ready. |
325 | */ | 301 | */ |
326 | if (!isci_device || isci_device->status != isci_ready_for_io) { | 302 | if (!isci_device || !test_bit(IDEV_IO_READY, &isci_device->flags)) { |
327 | dev_dbg(&ihost->pdev->dev, | 303 | dev_dbg(&ihost->pdev->dev, |
328 | "%s: isci_device = %p not ready (%d)\n", | 304 | "%s: isci_device = %p not ready (%#lx)\n", |
329 | __func__, | 305 | __func__, |
330 | isci_device, isci_device->status); | 306 | isci_device, isci_device ? isci_device->flags : 0); |
331 | return TMF_RESP_FUNC_FAILED; | 307 | return TMF_RESP_FUNC_FAILED; |
332 | } else | 308 | } else |
333 | dev_dbg(&ihost->pdev->dev, | 309 | dev_dbg(&ihost->pdev->dev, |