diff options
| -rw-r--r-- | drivers/ata/sata_inic162x.c | 270 |
1 files changed, 235 insertions, 35 deletions
diff --git a/drivers/ata/sata_inic162x.c b/drivers/ata/sata_inic162x.c index 97267ab001ed..db57f34d2211 100644 --- a/drivers/ata/sata_inic162x.c +++ b/drivers/ata/sata_inic162x.c | |||
| @@ -35,6 +35,10 @@ enum { | |||
| 35 | 35 | ||
| 36 | NR_PORTS = 2, | 36 | NR_PORTS = 2, |
| 37 | 37 | ||
| 38 | IDMA_CPB_TBL_SIZE = 4 * 32, | ||
| 39 | |||
| 40 | INIC_DMA_BOUNDARY = 0xffffff, | ||
| 41 | |||
| 38 | HOST_ACTRL = 0x08, | 42 | HOST_ACTRL = 0x08, |
| 39 | HOST_CTL = 0x7c, | 43 | HOST_CTL = 0x7c, |
| 40 | HOST_STAT = 0x7e, | 44 | HOST_STAT = 0x7e, |
| @@ -151,11 +155,57 @@ enum { | |||
| 151 | PRD_END = (1 << 7), /* APRD chain end */ | 155 | PRD_END = (1 << 7), /* APRD chain end */ |
| 152 | }; | 156 | }; |
| 153 | 157 | ||
| 158 | /* Comman Parameter Block */ | ||
| 159 | struct inic_cpb { | ||
| 160 | u8 resp_flags; /* Response Flags */ | ||
| 161 | u8 error; /* ATA Error */ | ||
| 162 | u8 status; /* ATA Status */ | ||
| 163 | u8 ctl_flags; /* Control Flags */ | ||
| 164 | __le32 len; /* Total Transfer Length */ | ||
| 165 | __le32 prd; /* First PRD pointer */ | ||
| 166 | u8 rsvd[4]; | ||
| 167 | /* 16 bytes */ | ||
| 168 | u8 feature; /* ATA Feature */ | ||
| 169 | u8 hob_feature; /* ATA Ex. Feature */ | ||
| 170 | u8 device; /* ATA Device/Head */ | ||
| 171 | u8 mirctl; /* Mirror Control */ | ||
| 172 | u8 nsect; /* ATA Sector Count */ | ||
| 173 | u8 hob_nsect; /* ATA Ex. Sector Count */ | ||
| 174 | u8 lbal; /* ATA Sector Number */ | ||
| 175 | u8 hob_lbal; /* ATA Ex. Sector Number */ | ||
| 176 | u8 lbam; /* ATA Cylinder Low */ | ||
| 177 | u8 hob_lbam; /* ATA Ex. Cylinder Low */ | ||
| 178 | u8 lbah; /* ATA Cylinder High */ | ||
| 179 | u8 hob_lbah; /* ATA Ex. Cylinder High */ | ||
| 180 | u8 command; /* ATA Command */ | ||
| 181 | u8 ctl; /* ATA Control */ | ||
| 182 | u8 slave_error; /* Slave ATA Error */ | ||
| 183 | u8 slave_status; /* Slave ATA Status */ | ||
| 184 | /* 32 bytes */ | ||
| 185 | } __packed; | ||
| 186 | |||
| 187 | /* Physical Region Descriptor */ | ||
| 188 | struct inic_prd { | ||
| 189 | __le32 mad; /* Physical Memory Address */ | ||
| 190 | __le16 len; /* Transfer Length */ | ||
| 191 | u8 rsvd; | ||
| 192 | u8 flags; /* Control Flags */ | ||
| 193 | } __packed; | ||
| 194 | |||
| 195 | struct inic_pkt { | ||
| 196 | struct inic_cpb cpb; | ||
| 197 | struct inic_prd prd[LIBATA_MAX_PRD]; | ||
| 198 | } __packed; | ||
| 199 | |||
| 154 | struct inic_host_priv { | 200 | struct inic_host_priv { |
| 155 | u16 cached_hctl; | 201 | u16 cached_hctl; |
| 156 | }; | 202 | }; |
| 157 | 203 | ||
| 158 | struct inic_port_priv { | 204 | struct inic_port_priv { |
| 205 | struct inic_pkt *pkt; | ||
| 206 | dma_addr_t pkt_dma; | ||
| 207 | u32 *cpb_tbl; | ||
| 208 | dma_addr_t cpb_tbl_dma; | ||
| 159 | u8 dfl_prdctl; | 209 | u8 dfl_prdctl; |
| 160 | u8 cached_prdctl; | 210 | u8 cached_prdctl; |
| 161 | u8 cached_pirq_mask; | 211 | u8 cached_pirq_mask; |
| @@ -163,6 +213,7 @@ struct inic_port_priv { | |||
| 163 | 213 | ||
| 164 | static struct scsi_host_template inic_sht = { | 214 | static struct scsi_host_template inic_sht = { |
| 165 | ATA_BMDMA_SHT(DRV_NAME), | 215 | ATA_BMDMA_SHT(DRV_NAME), |
| 216 | .dma_boundary = INIC_DMA_BOUNDARY, | ||
| 166 | }; | 217 | }; |
| 167 | 218 | ||
| 168 | static const int scr_map[] = { | 219 | static const int scr_map[] = { |
| @@ -303,42 +354,112 @@ static u8 inic_bmdma_status(struct ata_port *ap) | |||
| 303 | return ATA_DMA_INTR; | 354 | return ATA_DMA_INTR; |
| 304 | } | 355 | } |
| 305 | 356 | ||
| 306 | static void inic_host_intr(struct ata_port *ap) | 357 | static void inic_stop_idma(struct ata_port *ap) |
| 307 | { | 358 | { |
| 308 | void __iomem *port_base = inic_port_base(ap); | 359 | void __iomem *port_base = inic_port_base(ap); |
| 360 | |||
| 361 | readb(port_base + PORT_RPQ_FIFO); | ||
| 362 | readb(port_base + PORT_RPQ_CNT); | ||
| 363 | writew(0, port_base + PORT_IDMA_CTL); | ||
| 364 | } | ||
| 365 | |||
| 366 | static void inic_host_err_intr(struct ata_port *ap, u8 irq_stat, u16 idma_stat) | ||
| 367 | { | ||
| 309 | struct ata_eh_info *ehi = &ap->link.eh_info; | 368 | struct ata_eh_info *ehi = &ap->link.eh_info; |
| 369 | struct inic_port_priv *pp = ap->private_data; | ||
| 370 | struct inic_cpb *cpb = &pp->pkt->cpb; | ||
| 371 | bool freeze = false; | ||
| 372 | |||
| 373 | ata_ehi_clear_desc(ehi); | ||
| 374 | ata_ehi_push_desc(ehi, "irq_stat=0x%x idma_stat=0x%x", | ||
| 375 | irq_stat, idma_stat); | ||
| 376 | |||
| 377 | inic_stop_idma(ap); | ||
| 378 | |||
| 379 | if (irq_stat & (PIRQ_OFFLINE | PIRQ_ONLINE)) { | ||
| 380 | ata_ehi_push_desc(ehi, "hotplug"); | ||
| 381 | ata_ehi_hotplugged(ehi); | ||
| 382 | freeze = true; | ||
| 383 | } | ||
| 384 | |||
| 385 | if (idma_stat & IDMA_STAT_PERR) { | ||
| 386 | ata_ehi_push_desc(ehi, "PCI error"); | ||
| 387 | freeze = true; | ||
| 388 | } | ||
| 389 | |||
| 390 | if (idma_stat & IDMA_STAT_CPBERR) { | ||
| 391 | ata_ehi_push_desc(ehi, "CPB error"); | ||
| 392 | |||
| 393 | if (cpb->resp_flags & CPB_RESP_IGNORED) { | ||
| 394 | __ata_ehi_push_desc(ehi, " ignored"); | ||
| 395 | ehi->err_mask |= AC_ERR_INVALID; | ||
| 396 | freeze = true; | ||
| 397 | } | ||
| 398 | |||
| 399 | if (cpb->resp_flags & CPB_RESP_ATA_ERR) | ||
| 400 | ehi->err_mask |= AC_ERR_DEV; | ||
| 401 | |||
| 402 | if (cpb->resp_flags & CPB_RESP_SPURIOUS) { | ||
| 403 | __ata_ehi_push_desc(ehi, " spurious-intr"); | ||
| 404 | ehi->err_mask |= AC_ERR_HSM; | ||
| 405 | freeze = true; | ||
| 406 | } | ||
| 407 | |||
| 408 | if (cpb->resp_flags & | ||
| 409 | (CPB_RESP_UNDERFLOW | CPB_RESP_OVERFLOW)) { | ||
| 410 | __ata_ehi_push_desc(ehi, " data-over/underflow"); | ||
| 411 | ehi->err_mask |= AC_ERR_HSM; | ||
| 412 | freeze = true; | ||
| 413 | } | ||
| 414 | } | ||
| 415 | |||
| 416 | if (freeze) | ||
| 417 | ata_port_freeze(ap); | ||
| 418 | else | ||
| 419 | ata_port_abort(ap); | ||
| 420 | } | ||
| 421 | |||
| 422 | static void inic_host_intr(struct ata_port *ap) | ||
| 423 | { | ||
| 424 | void __iomem *port_base = inic_port_base(ap); | ||
| 425 | struct ata_queued_cmd *qc = ata_qc_from_tag(ap, ap->link.active_tag); | ||
| 310 | u8 irq_stat; | 426 | u8 irq_stat; |
| 427 | u16 idma_stat; | ||
| 311 | 428 | ||
| 312 | /* fetch and clear irq */ | 429 | /* read and clear IRQ status */ |
| 313 | irq_stat = readb(port_base + PORT_IRQ_STAT); | 430 | irq_stat = readb(port_base + PORT_IRQ_STAT); |
| 314 | writeb(irq_stat, port_base + PORT_IRQ_STAT); | 431 | writeb(irq_stat, port_base + PORT_IRQ_STAT); |
| 432 | idma_stat = readw(port_base + PORT_IDMA_STAT); | ||
| 433 | |||
| 434 | if (unlikely((irq_stat & PIRQ_ERR) || (idma_stat & IDMA_STAT_ERR))) | ||
| 435 | inic_host_err_intr(ap, irq_stat, idma_stat); | ||
| 436 | |||
| 437 | if (unlikely(!qc || (qc->tf.flags & ATA_TFLAG_POLLING))) { | ||
| 438 | ap->ops->sff_check_status(ap); /* clear ATA interrupt */ | ||
| 439 | goto spurious; | ||
| 440 | } | ||
| 441 | |||
| 442 | if (qc->tf.protocol == ATA_PROT_DMA) { | ||
| 443 | if (likely(idma_stat & IDMA_STAT_DONE)) { | ||
| 444 | inic_stop_idma(ap); | ||
| 315 | 445 | ||
| 316 | if (likely(!(irq_stat & PIRQ_ERR))) { | 446 | /* Depending on circumstances, device error |
| 317 | struct ata_queued_cmd *qc = | 447 | * isn't reported by IDMA, check it explicitly. |
| 318 | ata_qc_from_tag(ap, ap->link.active_tag); | 448 | */ |
| 449 | if (unlikely(readb(port_base + PORT_TF_COMMAND) & | ||
| 450 | (ATA_DF | ATA_ERR))) | ||
| 451 | qc->err_mask |= AC_ERR_DEV; | ||
| 319 | 452 | ||
| 320 | if (unlikely(!qc || (qc->tf.flags & ATA_TFLAG_POLLING))) { | 453 | ata_qc_complete(qc); |
| 321 | ap->ops->sff_check_status(ap); /* clear ATA interrupt */ | ||
| 322 | return; | 454 | return; |
| 323 | } | 455 | } |
| 324 | 456 | } else { | |
| 325 | if (likely(ata_sff_host_intr(ap, qc))) | 457 | if (likely(ata_sff_host_intr(ap, qc))) |
| 326 | return; | 458 | return; |
| 327 | |||
| 328 | ap->ops->sff_check_status(ap); /* clear ATA interrupt */ | ||
| 329 | ata_port_printk(ap, KERN_WARNING, "unhandled " | ||
| 330 | "interrupt, irq_stat=%x\n", irq_stat); | ||
| 331 | return; | ||
| 332 | } | 459 | } |
| 333 | 460 | ||
| 334 | /* error */ | 461 | spurious: |
| 335 | ata_ehi_push_desc(ehi, "irq_stat=0x%x", irq_stat); | 462 | ap->ops->sff_check_status(ap); /* clear ATA interrupt */ |
| 336 | |||
| 337 | if (irq_stat & (PIRQ_OFFLINE | PIRQ_ONLINE)) { | ||
| 338 | ata_ehi_hotplugged(ehi); | ||
| 339 | ata_port_freeze(ap); | ||
| 340 | } else | ||
| 341 | ata_port_abort(ap); | ||
| 342 | } | 463 | } |
| 343 | 464 | ||
| 344 | static irqreturn_t inic_interrupt(int irq, void *dev_instance) | 465 | static irqreturn_t inic_interrupt(int irq, void *dev_instance) |
| @@ -378,22 +499,83 @@ static irqreturn_t inic_interrupt(int irq, void *dev_instance) | |||
| 378 | return IRQ_RETVAL(handled); | 499 | return IRQ_RETVAL(handled); |
| 379 | } | 500 | } |
| 380 | 501 | ||
| 502 | static void inic_fill_sg(struct inic_prd *prd, struct ata_queued_cmd *qc) | ||
| 503 | { | ||
| 504 | struct scatterlist *sg; | ||
| 505 | unsigned int si; | ||
| 506 | u8 flags = PRD_DMA; | ||
| 507 | |||
| 508 | if (qc->tf.flags & ATA_TFLAG_WRITE) | ||
| 509 | flags |= PRD_WRITE; | ||
| 510 | |||
| 511 | for_each_sg(qc->sg, sg, qc->n_elem, si) { | ||
| 512 | prd->mad = cpu_to_le32(sg_dma_address(sg)); | ||
| 513 | prd->len = cpu_to_le16(sg_dma_len(sg)); | ||
| 514 | prd->flags = flags; | ||
| 515 | prd++; | ||
| 516 | } | ||
| 517 | |||
| 518 | WARN_ON(!si); | ||
| 519 | prd[-1].flags |= PRD_END; | ||
| 520 | } | ||
| 521 | |||
| 522 | static void inic_qc_prep(struct ata_queued_cmd *qc) | ||
| 523 | { | ||
| 524 | struct inic_port_priv *pp = qc->ap->private_data; | ||
| 525 | struct inic_pkt *pkt = pp->pkt; | ||
| 526 | struct inic_cpb *cpb = &pkt->cpb; | ||
| 527 | struct inic_prd *prd = pkt->prd; | ||
| 528 | |||
| 529 | VPRINTK("ENTER\n"); | ||
| 530 | |||
| 531 | if (qc->tf.protocol != ATA_PROT_DMA) | ||
| 532 | return; | ||
| 533 | |||
| 534 | /* prepare packet, based on initio driver */ | ||
| 535 | memset(pkt, 0, sizeof(struct inic_pkt)); | ||
| 536 | |||
| 537 | cpb->ctl_flags = CPB_CTL_VALID | CPB_CTL_IEN | CPB_CTL_DATA; | ||
| 538 | |||
| 539 | cpb->len = cpu_to_le32(qc->nbytes); | ||
| 540 | cpb->prd = cpu_to_le32(pp->pkt_dma + offsetof(struct inic_pkt, prd)); | ||
| 541 | |||
| 542 | cpb->device = qc->tf.device; | ||
| 543 | cpb->feature = qc->tf.feature; | ||
| 544 | cpb->nsect = qc->tf.nsect; | ||
| 545 | cpb->lbal = qc->tf.lbal; | ||
| 546 | cpb->lbam = qc->tf.lbam; | ||
| 547 | cpb->lbah = qc->tf.lbah; | ||
| 548 | |||
| 549 | if (qc->tf.flags & ATA_TFLAG_LBA48) { | ||
| 550 | cpb->hob_feature = qc->tf.hob_feature; | ||
| 551 | cpb->hob_nsect = qc->tf.hob_nsect; | ||
| 552 | cpb->hob_lbal = qc->tf.hob_lbal; | ||
| 553 | cpb->hob_lbam = qc->tf.hob_lbam; | ||
| 554 | cpb->hob_lbah = qc->tf.hob_lbah; | ||
| 555 | } | ||
| 556 | |||
| 557 | cpb->command = qc->tf.command; | ||
| 558 | /* don't load ctl - dunno why. it's like that in the initio driver */ | ||
| 559 | |||
| 560 | /* setup sg table */ | ||
| 561 | inic_fill_sg(prd, qc); | ||
| 562 | |||
| 563 | pp->cpb_tbl[0] = pp->pkt_dma; | ||
| 564 | } | ||
| 565 | |||
| 381 | static unsigned int inic_qc_issue(struct ata_queued_cmd *qc) | 566 | static unsigned int inic_qc_issue(struct ata_queued_cmd *qc) |
| 382 | { | 567 | { |
| 383 | struct ata_port *ap = qc->ap; | 568 | struct ata_port *ap = qc->ap; |
| 569 | void __iomem *port_base = inic_port_base(ap); | ||
| 384 | 570 | ||
| 385 | /* ATA IRQ doesn't wait for DMA transfer completion and vice | 571 | if (qc->tf.protocol == ATA_PROT_DMA) { |
| 386 | * versa. Mask IRQ selectively to detect command completion. | 572 | /* fire up the ADMA engine */ |
| 387 | * Without it, ATA DMA read command can cause data corruption. | 573 | writew(HCTL_FTHD0, port_base + HOST_CTL); |
| 388 | * | 574 | writew(IDMA_CTL_GO, port_base + PORT_IDMA_CTL); |
| 389 | * Something similar might be needed for ATAPI writes. I | 575 | writeb(0, port_base + PORT_CPB_PTQFIFO); |
| 390 | * tried a lot of combinations but couldn't find the solution. | 576 | |
| 391 | */ | 577 | return 0; |
| 392 | if (qc->tf.protocol == ATA_PROT_DMA && | 578 | } |
| 393 | !(qc->tf.flags & ATA_TFLAG_WRITE)) | ||
| 394 | inic_set_pirq_mask(ap, PIRQ_MASK_DMA_READ); | ||
| 395 | else | ||
| 396 | inic_set_pirq_mask(ap, PIRQ_MASK_OTHER); | ||
| 397 | 579 | ||
| 398 | /* Issuing a command to yet uninitialized port locks up the | 580 | /* Issuing a command to yet uninitialized port locks up the |
| 399 | * controller. Most of the time, this happens for the first | 581 | * controller. Most of the time, this happens for the first |
| @@ -564,9 +746,15 @@ static void inic_dev_config(struct ata_device *dev) | |||
| 564 | static void init_port(struct ata_port *ap) | 746 | static void init_port(struct ata_port *ap) |
| 565 | { | 747 | { |
| 566 | void __iomem *port_base = inic_port_base(ap); | 748 | void __iomem *port_base = inic_port_base(ap); |
| 749 | struct inic_port_priv *pp = ap->private_data; | ||
| 567 | 750 | ||
| 568 | /* Setup PRD address */ | 751 | /* clear packet and CPB table */ |
| 752 | memset(pp->pkt, 0, sizeof(struct inic_pkt)); | ||
| 753 | memset(pp->cpb_tbl, 0, IDMA_CPB_TBL_SIZE); | ||
| 754 | |||
| 755 | /* setup PRD and CPB lookup table addresses */ | ||
| 569 | writel(ap->prd_dma, port_base + PORT_PRD_ADDR); | 756 | writel(ap->prd_dma, port_base + PORT_PRD_ADDR); |
| 757 | writel(pp->cpb_tbl_dma, port_base + PORT_CPB_CPBLAR); | ||
| 570 | } | 758 | } |
| 571 | 759 | ||
| 572 | static int inic_port_resume(struct ata_port *ap) | 760 | static int inic_port_resume(struct ata_port *ap) |
| @@ -578,12 +766,13 @@ static int inic_port_resume(struct ata_port *ap) | |||
| 578 | static int inic_port_start(struct ata_port *ap) | 766 | static int inic_port_start(struct ata_port *ap) |
| 579 | { | 767 | { |
| 580 | void __iomem *port_base = inic_port_base(ap); | 768 | void __iomem *port_base = inic_port_base(ap); |
| 769 | struct device *dev = ap->host->dev; | ||
| 581 | struct inic_port_priv *pp; | 770 | struct inic_port_priv *pp; |
| 582 | u8 tmp; | 771 | u8 tmp; |
| 583 | int rc; | 772 | int rc; |
| 584 | 773 | ||
| 585 | /* alloc and initialize private data */ | 774 | /* alloc and initialize private data */ |
| 586 | pp = devm_kzalloc(ap->host->dev, sizeof(*pp), GFP_KERNEL); | 775 | pp = devm_kzalloc(dev, sizeof(*pp), GFP_KERNEL); |
| 587 | if (!pp) | 776 | if (!pp) |
| 588 | return -ENOMEM; | 777 | return -ENOMEM; |
| 589 | ap->private_data = pp; | 778 | ap->private_data = pp; |
| @@ -598,6 +787,16 @@ static int inic_port_start(struct ata_port *ap) | |||
| 598 | if (rc) | 787 | if (rc) |
| 599 | return rc; | 788 | return rc; |
| 600 | 789 | ||
| 790 | pp->pkt = dmam_alloc_coherent(dev, sizeof(struct inic_pkt), | ||
| 791 | &pp->pkt_dma, GFP_KERNEL); | ||
| 792 | if (!pp->pkt) | ||
| 793 | return -ENOMEM; | ||
| 794 | |||
| 795 | pp->cpb_tbl = dmam_alloc_coherent(dev, IDMA_CPB_TBL_SIZE, | ||
| 796 | &pp->cpb_tbl_dma, GFP_KERNEL); | ||
| 797 | if (!pp->cpb_tbl) | ||
| 798 | return -ENOMEM; | ||
| 799 | |||
| 601 | init_port(ap); | 800 | init_port(ap); |
| 602 | 801 | ||
| 603 | return 0; | 802 | return 0; |
| @@ -610,6 +809,7 @@ static struct ata_port_operations inic_port_ops = { | |||
| 610 | .bmdma_start = inic_bmdma_start, | 809 | .bmdma_start = inic_bmdma_start, |
| 611 | .bmdma_stop = inic_bmdma_stop, | 810 | .bmdma_stop = inic_bmdma_stop, |
| 612 | .bmdma_status = inic_bmdma_status, | 811 | .bmdma_status = inic_bmdma_status, |
| 812 | .qc_prep = inic_qc_prep, | ||
| 613 | .qc_issue = inic_qc_issue, | 813 | .qc_issue = inic_qc_issue, |
| 614 | .qc_fill_rtf = inic_qc_fill_rtf, | 814 | .qc_fill_rtf = inic_qc_fill_rtf, |
| 615 | 815 | ||
