diff options
Diffstat (limited to 'drivers/scsi/sata_sil.c')
-rw-r--r-- | drivers/scsi/sata_sil.c | 92 |
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); | |||
111 | static u32 sil_scr_read (struct ata_port *ap, unsigned int sc_reg); | 111 | static u32 sil_scr_read (struct ata_port *ap, unsigned int sc_reg); |
112 | static void sil_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val); | 112 | static void sil_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val); |
113 | static void sil_post_set_mode (struct ata_port *ap); | 113 | static void sil_post_set_mode (struct ata_port *ap); |
114 | static irqreturn_t sil_interrupt(int irq, void *dev_instance, | ||
115 | struct pt_regs *regs); | ||
114 | static void sil_freeze(struct ata_port *ap); | 116 | static void sil_freeze(struct ata_port *ap); |
115 | static void sil_thaw(struct ata_port *ap); | 117 | static 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 | ||
341 | static 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 | |||
400 | static 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 | |||
339 | static void sil_freeze(struct ata_port *ap) | 429 | static 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; |