diff options
-rw-r--r-- | drivers/scsi/sata_sil24.c | 50 |
1 files changed, 45 insertions, 5 deletions
diff --git a/drivers/scsi/sata_sil24.c b/drivers/scsi/sata_sil24.c index 032d9c093979..b65194c755f8 100644 --- a/drivers/scsi/sata_sil24.c +++ b/drivers/scsi/sata_sil24.c | |||
@@ -41,7 +41,7 @@ | |||
41 | #include <asm/io.h> | 41 | #include <asm/io.h> |
42 | 42 | ||
43 | #define DRV_NAME "sata_sil24" | 43 | #define DRV_NAME "sata_sil24" |
44 | #define DRV_VERSION "0.21" /* Silicon Image's preview driver was 0.10 */ | 44 | #define DRV_VERSION "0.22" /* Silicon Image's preview driver was 0.10 */ |
45 | 45 | ||
46 | #define NR_PORTS 4 | 46 | #define NR_PORTS 4 |
47 | 47 | ||
@@ -216,6 +216,7 @@ struct sil24_cmd_block { | |||
216 | struct sil24_port_priv { | 216 | struct sil24_port_priv { |
217 | struct sil24_cmd_block *cmd_block; /* 32 cmd blocks */ | 217 | struct sil24_cmd_block *cmd_block; /* 32 cmd blocks */ |
218 | dma_addr_t cmd_block_dma; /* DMA base addr for them */ | 218 | dma_addr_t cmd_block_dma; /* DMA base addr for them */ |
219 | struct ata_taskfile tf; /* Cached taskfile registers */ | ||
219 | }; | 220 | }; |
220 | 221 | ||
221 | /* ap->host_set->private_data */ | 222 | /* ap->host_set->private_data */ |
@@ -322,14 +323,25 @@ static struct ata_port_info sil24_port_info[] = { | |||
322 | }, | 323 | }, |
323 | }; | 324 | }; |
324 | 325 | ||
326 | static inline void sil24_update_tf(struct ata_port *ap) | ||
327 | { | ||
328 | struct sil24_port_priv *pp = ap->private_data; | ||
329 | void *port = (void *)ap->ioaddr.cmd_addr; | ||
330 | struct sil24_prb *prb = port; | ||
331 | |||
332 | ata_tf_from_fis(prb->fis, &pp->tf); | ||
333 | } | ||
334 | |||
325 | static u8 sil24_check_status(struct ata_port *ap) | 335 | static u8 sil24_check_status(struct ata_port *ap) |
326 | { | 336 | { |
327 | return ATA_DRDY; | 337 | struct sil24_port_priv *pp = ap->private_data; |
338 | return pp->tf.command; | ||
328 | } | 339 | } |
329 | 340 | ||
330 | static u8 sil24_check_err(struct ata_port *ap) | 341 | static u8 sil24_check_err(struct ata_port *ap) |
331 | { | 342 | { |
332 | return 0; | 343 | struct sil24_port_priv *pp = ap->private_data; |
344 | return pp->tf.feature; | ||
333 | } | 345 | } |
334 | 346 | ||
335 | static int sil24_scr_map[] = { | 347 | static int sil24_scr_map[] = { |
@@ -485,6 +497,7 @@ static void sil24_eng_timeout(struct ata_port *ap) | |||
485 | static void sil24_error_intr(struct ata_port *ap, u32 slot_stat) | 497 | static void sil24_error_intr(struct ata_port *ap, u32 slot_stat) |
486 | { | 498 | { |
487 | struct ata_queued_cmd *qc = ata_qc_from_tag(ap, ap->active_tag); | 499 | struct ata_queued_cmd *qc = ata_qc_from_tag(ap, ap->active_tag); |
500 | struct sil24_port_priv *pp = ap->private_data; | ||
488 | void *port = (void *)ap->ioaddr.cmd_addr; | 501 | void *port = (void *)ap->ioaddr.cmd_addr; |
489 | u32 irq_stat, cmd_err, sstatus, serror; | 502 | u32 irq_stat, cmd_err, sstatus, serror; |
490 | 503 | ||
@@ -509,8 +522,22 @@ static void sil24_error_intr(struct ata_port *ap, u32 slot_stat) | |||
509 | " stat=0x%x irq=0x%x cmd_err=%d sstatus=0x%x serror=0x%x\n", | 522 | " stat=0x%x irq=0x%x cmd_err=%d sstatus=0x%x serror=0x%x\n", |
510 | ap->id, ap->port_no, slot_stat, irq_stat, cmd_err, sstatus, serror); | 523 | ap->id, ap->port_no, slot_stat, irq_stat, cmd_err, sstatus, serror); |
511 | 524 | ||
525 | if (cmd_err == PORT_CERR_DEV || cmd_err == PORT_CERR_SDB) { | ||
526 | /* | ||
527 | * Device is reporting error, tf registers are valid. | ||
528 | */ | ||
529 | sil24_update_tf(ap); | ||
530 | } else { | ||
531 | /* | ||
532 | * Other errors. libata currently doesn't have any | ||
533 | * mechanism to report these errors. Just turn on | ||
534 | * ATA_ERR. | ||
535 | */ | ||
536 | pp->tf.command = ATA_ERR; | ||
537 | } | ||
538 | |||
512 | if (qc) | 539 | if (qc) |
513 | ata_qc_complete(qc, ATA_ERR); | 540 | ata_qc_complete(qc, pp->tf.command); |
514 | 541 | ||
515 | sil24_reset_controller(ap); | 542 | sil24_reset_controller(ap); |
516 | } | 543 | } |
@@ -523,8 +550,19 @@ static inline void sil24_host_intr(struct ata_port *ap) | |||
523 | 550 | ||
524 | slot_stat = readl(port + PORT_SLOT_STAT); | 551 | slot_stat = readl(port + PORT_SLOT_STAT); |
525 | if (!(slot_stat & HOST_SSTAT_ATTN)) { | 552 | if (!(slot_stat & HOST_SSTAT_ATTN)) { |
553 | struct sil24_port_priv *pp = ap->private_data; | ||
554 | /* | ||
555 | * !HOST_SSAT_ATTN guarantees successful completion, | ||
556 | * so reading back tf registers is unnecessary for | ||
557 | * most commands. TODO: read tf registers for | ||
558 | * commands which require these values on successful | ||
559 | * completion (EXECUTE DEVICE DIAGNOSTIC, CHECK POWER, | ||
560 | * DEVICE RESET and READ PORT MULTIPLIER (any more?). | ||
561 | */ | ||
562 | sil24_update_tf(ap); | ||
563 | |||
526 | if (qc) | 564 | if (qc) |
527 | ata_qc_complete(qc, 0); | 565 | ata_qc_complete(qc, pp->tf.command); |
528 | } else | 566 | } else |
529 | sil24_error_intr(ap, slot_stat); | 567 | sil24_error_intr(ap, slot_stat); |
530 | } | 568 | } |
@@ -579,6 +617,8 @@ static int sil24_port_start(struct ata_port *ap) | |||
579 | return -ENOMEM; | 617 | return -ENOMEM; |
580 | memset(pp, 0, sizeof(*pp)); | 618 | memset(pp, 0, sizeof(*pp)); |
581 | 619 | ||
620 | pp->tf.command = ATA_DRDY; | ||
621 | |||
582 | cb = dma_alloc_coherent(dev, cb_size, &cb_dma, GFP_KERNEL); | 622 | cb = dma_alloc_coherent(dev, cb_size, &cb_dma, GFP_KERNEL); |
583 | if (!cb) { | 623 | if (!cb) { |
584 | kfree(pp); | 624 | kfree(pp); |