aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/scsi/sata_sil.c92
1 files changed, 91 insertions, 1 deletions
diff --git a/drivers/scsi/sata_sil.c b/drivers/scsi/sata_sil.c
index f926883fd16c..03c1d1b1a04c 100644
--- a/drivers/scsi/sata_sil.c
+++ b/drivers/scsi/sata_sil.c
@@ -111,6 +111,8 @@ static void sil_dev_config(struct ata_port *ap, struct ata_device *dev);
111static u32 sil_scr_read (struct ata_port *ap, unsigned int sc_reg); 111static u32 sil_scr_read (struct ata_port *ap, unsigned int sc_reg);
112static void sil_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val); 112static void sil_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
113static void sil_post_set_mode (struct ata_port *ap); 113static void sil_post_set_mode (struct ata_port *ap);
114static irqreturn_t sil_interrupt(int irq, void *dev_instance,
115 struct pt_regs *regs);
114static void sil_freeze(struct ata_port *ap); 116static void sil_freeze(struct ata_port *ap);
115static void sil_thaw(struct ata_port *ap); 117static void sil_thaw(struct ata_port *ap);
116 118
@@ -196,7 +198,7 @@ static const struct ata_port_operations sil_ops = {
196 .thaw = sil_thaw, 198 .thaw = sil_thaw,
197 .error_handler = ata_bmdma_error_handler, 199 .error_handler = ata_bmdma_error_handler,
198 .post_internal_cmd = ata_bmdma_post_internal_cmd, 200 .post_internal_cmd = ata_bmdma_post_internal_cmd,
199 .irq_handler = ata_interrupt, 201 .irq_handler = sil_interrupt,
200 .irq_clear = ata_bmdma_irq_clear, 202 .irq_clear = ata_bmdma_irq_clear,
201 .scr_read = sil_scr_read, 203 .scr_read = sil_scr_read,
202 .scr_write = sil_scr_write, 204 .scr_write = sil_scr_write,
@@ -336,6 +338,94 @@ static void sil_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val)
336 writel(val, mmio); 338 writel(val, mmio);
337} 339}
338 340
341static void sil_host_intr(struct ata_port *ap, u32 bmdma2)
342{
343 struct ata_queued_cmd *qc = ata_qc_from_tag(ap, ap->active_tag);
344 u8 status;
345
346 if (unlikely(!qc || qc->tf.ctl & ATA_NIEN))
347 goto freeze;
348
349 /* Check whether we are expecting interrupt in this state */
350 switch (ap->hsm_task_state) {
351 case HSM_ST_FIRST:
352 /* Some pre-ATAPI-4 devices assert INTRQ
353 * at this state when ready to receive CDB.
354 */
355
356 /* Check the ATA_DFLAG_CDB_INTR flag is enough here.
357 * The flag was turned on only for atapi devices.
358 * No need to check is_atapi_taskfile(&qc->tf) again.
359 */
360 if (!(qc->dev->flags & ATA_DFLAG_CDB_INTR))
361 goto err_hsm;
362 break;
363 case HSM_ST_LAST:
364 if (qc->tf.protocol == ATA_PROT_DMA ||
365 qc->tf.protocol == ATA_PROT_ATAPI_DMA) {
366 /* clear DMA-Start bit */
367 ap->ops->bmdma_stop(qc);
368
369 if (bmdma2 & SIL_DMA_ERROR) {
370 qc->err_mask |= AC_ERR_HOST_BUS;
371 ap->hsm_task_state = HSM_ST_ERR;
372 }
373 }
374 break;
375 case HSM_ST:
376 break;
377 default:
378 goto err_hsm;
379 }
380
381 /* check main status, clearing INTRQ */
382 status = ata_chk_status(ap);
383 if (unlikely(status & ATA_BUSY))
384 goto err_hsm;
385
386 /* ack bmdma irq events */
387 ata_bmdma_irq_clear(ap);
388
389 /* kick HSM in the ass */
390 ata_hsm_move(ap, qc, status, 0);
391
392 return;
393
394 err_hsm:
395 qc->err_mask |= AC_ERR_HSM;
396 freeze:
397 ata_port_freeze(ap);
398}
399
400static irqreturn_t sil_interrupt(int irq, void *dev_instance,
401 struct pt_regs *regs)
402{
403 struct ata_host_set *host_set = dev_instance;
404 void __iomem *mmio_base = host_set->mmio_base;
405 int handled = 0;
406 int i;
407
408 spin_lock(&host_set->lock);
409
410 for (i = 0; i < host_set->n_ports; i++) {
411 struct ata_port *ap = host_set->ports[i];
412 u32 bmdma2 = readl(mmio_base + sil_port[ap->port_no].bmdma2);
413
414 if (unlikely(!ap || ap->flags & ATA_FLAG_DISABLED))
415 continue;
416
417 if (!(bmdma2 & SIL_DMA_COMPLETE))
418 continue;
419
420 sil_host_intr(ap, bmdma2);
421 handled = 1;
422 }
423
424 spin_unlock(&host_set->lock);
425
426 return IRQ_RETVAL(handled);
427}
428
339static void sil_freeze(struct ata_port *ap) 429static void sil_freeze(struct ata_port *ap)
340{ 430{
341 void __iomem *mmio_base = ap->host_set->mmio_base; 431 void __iomem *mmio_base = ap->host_set->mmio_base;