diff options
Diffstat (limited to 'drivers/scsi/libata-eh.c')
-rw-r--r-- | drivers/scsi/libata-eh.c | 103 |
1 files changed, 103 insertions, 0 deletions
diff --git a/drivers/scsi/libata-eh.c b/drivers/scsi/libata-eh.c index 037a561809f5..cb4e2b8d32d9 100644 --- a/drivers/scsi/libata-eh.c +++ b/drivers/scsi/libata-eh.c | |||
@@ -291,6 +291,109 @@ int ata_port_abort(struct ata_port *ap) | |||
291 | return nr_aborted; | 291 | return nr_aborted; |
292 | } | 292 | } |
293 | 293 | ||
294 | /** | ||
295 | * __ata_port_freeze - freeze port | ||
296 | * @ap: ATA port to freeze | ||
297 | * | ||
298 | * This function is called when HSM violation or some other | ||
299 | * condition disrupts normal operation of the port. Frozen port | ||
300 | * is not allowed to perform any operation until the port is | ||
301 | * thawed, which usually follows a successful reset. | ||
302 | * | ||
303 | * ap->ops->freeze() callback can be used for freezing the port | ||
304 | * hardware-wise (e.g. mask interrupt and stop DMA engine). If a | ||
305 | * port cannot be frozen hardware-wise, the interrupt handler | ||
306 | * must ack and clear interrupts unconditionally while the port | ||
307 | * is frozen. | ||
308 | * | ||
309 | * LOCKING: | ||
310 | * spin_lock_irqsave(host_set lock) | ||
311 | */ | ||
312 | static void __ata_port_freeze(struct ata_port *ap) | ||
313 | { | ||
314 | WARN_ON(!ap->ops->error_handler); | ||
315 | |||
316 | if (ap->ops->freeze) | ||
317 | ap->ops->freeze(ap); | ||
318 | |||
319 | ap->flags |= ATA_FLAG_FROZEN; | ||
320 | |||
321 | DPRINTK("ata%u port frozen\n", ap->id); | ||
322 | } | ||
323 | |||
324 | /** | ||
325 | * ata_port_freeze - abort & freeze port | ||
326 | * @ap: ATA port to freeze | ||
327 | * | ||
328 | * Abort and freeze @ap. | ||
329 | * | ||
330 | * LOCKING: | ||
331 | * spin_lock_irqsave(host_set lock) | ||
332 | * | ||
333 | * RETURNS: | ||
334 | * Number of aborted commands. | ||
335 | */ | ||
336 | int ata_port_freeze(struct ata_port *ap) | ||
337 | { | ||
338 | int nr_aborted; | ||
339 | |||
340 | WARN_ON(!ap->ops->error_handler); | ||
341 | |||
342 | nr_aborted = ata_port_abort(ap); | ||
343 | __ata_port_freeze(ap); | ||
344 | |||
345 | return nr_aborted; | ||
346 | } | ||
347 | |||
348 | /** | ||
349 | * ata_eh_freeze_port - EH helper to freeze port | ||
350 | * @ap: ATA port to freeze | ||
351 | * | ||
352 | * Freeze @ap. | ||
353 | * | ||
354 | * LOCKING: | ||
355 | * None. | ||
356 | */ | ||
357 | void ata_eh_freeze_port(struct ata_port *ap) | ||
358 | { | ||
359 | unsigned long flags; | ||
360 | |||
361 | if (!ap->ops->error_handler) | ||
362 | return; | ||
363 | |||
364 | spin_lock_irqsave(&ap->host_set->lock, flags); | ||
365 | __ata_port_freeze(ap); | ||
366 | spin_unlock_irqrestore(&ap->host_set->lock, flags); | ||
367 | } | ||
368 | |||
369 | /** | ||
370 | * ata_port_thaw_port - EH helper to thaw port | ||
371 | * @ap: ATA port to thaw | ||
372 | * | ||
373 | * Thaw frozen port @ap. | ||
374 | * | ||
375 | * LOCKING: | ||
376 | * None. | ||
377 | */ | ||
378 | void ata_eh_thaw_port(struct ata_port *ap) | ||
379 | { | ||
380 | unsigned long flags; | ||
381 | |||
382 | if (!ap->ops->error_handler) | ||
383 | return; | ||
384 | |||
385 | spin_lock_irqsave(&ap->host_set->lock, flags); | ||
386 | |||
387 | ap->flags &= ~ATA_FLAG_FROZEN; | ||
388 | |||
389 | if (ap->ops->thaw) | ||
390 | ap->ops->thaw(ap); | ||
391 | |||
392 | spin_unlock_irqrestore(&ap->host_set->lock, flags); | ||
393 | |||
394 | DPRINTK("ata%u port thawed\n", ap->id); | ||
395 | } | ||
396 | |||
294 | static void ata_eh_scsidone(struct scsi_cmnd *scmd) | 397 | static void ata_eh_scsidone(struct scsi_cmnd *scmd) |
295 | { | 398 | { |
296 | /* nada */ | 399 | /* nada */ |