aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi/libata-eh.c
diff options
context:
space:
mode:
authorTejun Heo <htejun@gmail.com>2006-05-15 07:58:09 -0400
committerTejun Heo <htejun@gmail.com>2006-05-15 07:58:09 -0400
commite318049949b07152d851dbfebbd93e560af45ebe (patch)
treecbc322c94717c9ac5d7e2c48a9f690a2e0145b81 /drivers/scsi/libata-eh.c
parent7b70fc039824bc7303e4007a5f758f832de56611 (diff)
[PATCH] libata-eh-fw: implement freeze/thaw
Freezing is performed atomic w.r.t. host_set->lock and once frozen LLDD is not allowed to access the port or any qc on it. Also, libata makes sure that no new qc gets issued to a frozen port. A frozen port is thawed after a reset operation completes successfully, so reset methods must do its job while the port is frozen. During initialization all ports get frozen before requesting IRQ, so reset methods are always invoked on a frozen port. Optional ->freeze and ->thaw operations notify LLDD that the port is being frozen and thawed, respectively. LLDD can disable/enable hardware interrupt in these callbacks if the controller's IRQ mask can be changed dynamically. If the controller doesn't allow such operation, LLDD can check for frozen state in the interrupt handler and ack/clear interrupts unconditionally while frozen. Signed-off-by: Tejun Heo <htejun@gmail.com>
Diffstat (limited to 'drivers/scsi/libata-eh.c')
-rw-r--r--drivers/scsi/libata-eh.c103
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 */
312static 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 */
336int 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 */
357void 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 */
378void 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
294static void ata_eh_scsidone(struct scsi_cmnd *scmd) 397static void ata_eh_scsidone(struct scsi_cmnd *scmd)
295{ 398{
296 /* nada */ 399 /* nada */