diff options
Diffstat (limited to 'drivers/ata/sata_inic162x.c')
-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 | ||