diff options
| author | Tejun Heo <htejun@gmail.com> | 2006-05-15 08:03:46 -0400 | 
|---|---|---|
| committer | Tejun Heo <htejun@gmail.com> | 2006-05-15 08:03:46 -0400 | 
| commit | e8ee84518c159a663c07bf691ace187527380f61 (patch) | |
| tree | ffd6d89b4e38ff2a70463125a3022771f69b2286 | |
| parent | 3dc1d88193b9c65b01b64fb2dc730e486306649f (diff) | |
[PATCH] libata-ncq: update EH to handle NCQ
Update EH to handle NCQ.  ata_eh_autopsy() is updated to call
ata_eh_analyze_ncq_error() which reads log page 10h on NCQ device
error and updates eh_context accordingly.  ata_eh_report() is updated
to report SActive.
Signed-off-by: Tejun Heo <htejun@gmail.com>
| -rw-r--r-- | drivers/scsi/libata-eh.c | 171 | 
1 files changed, 163 insertions, 8 deletions
diff --git a/drivers/scsi/libata-eh.c b/drivers/scsi/libata-eh.c index e401f353f848..7244caff13a0 100644 --- a/drivers/scsi/libata-eh.c +++ b/drivers/scsi/libata-eh.c  | |||
| @@ -685,6 +685,98 @@ static const char * ata_err_string(unsigned int err_mask) | |||
| 685 | } | 685 | } | 
| 686 | 686 | ||
| 687 | /** | 687 | /** | 
| 688 | * ata_read_log_page - read a specific log page | ||
| 689 | * @dev: target device | ||
| 690 | * @page: page to read | ||
| 691 | * @buf: buffer to store read page | ||
| 692 | * @sectors: number of sectors to read | ||
| 693 | * | ||
| 694 | * Read log page using READ_LOG_EXT command. | ||
| 695 | * | ||
| 696 | * LOCKING: | ||
| 697 | * Kernel thread context (may sleep). | ||
| 698 | * | ||
| 699 | * RETURNS: | ||
| 700 | * 0 on success, AC_ERR_* mask otherwise. | ||
| 701 | */ | ||
| 702 | static unsigned int ata_read_log_page(struct ata_device *dev, | ||
| 703 | u8 page, void *buf, unsigned int sectors) | ||
| 704 | { | ||
| 705 | struct ata_taskfile tf; | ||
| 706 | unsigned int err_mask; | ||
| 707 | |||
| 708 | DPRINTK("read log page - page %d\n", page); | ||
| 709 | |||
| 710 | ata_tf_init(dev, &tf); | ||
| 711 | tf.command = ATA_CMD_READ_LOG_EXT; | ||
| 712 | tf.lbal = page; | ||
| 713 | tf.nsect = sectors; | ||
| 714 | tf.hob_nsect = sectors >> 8; | ||
| 715 | tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_LBA48 | ATA_TFLAG_DEVICE; | ||
| 716 | tf.protocol = ATA_PROT_PIO; | ||
| 717 | |||
| 718 | err_mask = ata_exec_internal(dev, &tf, NULL, DMA_FROM_DEVICE, | ||
| 719 | buf, sectors * ATA_SECT_SIZE); | ||
| 720 | |||
| 721 | DPRINTK("EXIT, err_mask=%x\n", err_mask); | ||
| 722 | return err_mask; | ||
| 723 | } | ||
| 724 | |||
| 725 | /** | ||
| 726 | * ata_eh_read_log_10h - Read log page 10h for NCQ error details | ||
| 727 | * @dev: Device to read log page 10h from | ||
| 728 | * @tag: Resulting tag of the failed command | ||
| 729 | * @tf: Resulting taskfile registers of the failed command | ||
| 730 | * | ||
| 731 | * Read log page 10h to obtain NCQ error details and clear error | ||
| 732 | * condition. | ||
| 733 | * | ||
| 734 | * LOCKING: | ||
| 735 | * Kernel thread context (may sleep). | ||
| 736 | * | ||
| 737 | * RETURNS: | ||
| 738 | * 0 on success, -errno otherwise. | ||
| 739 | */ | ||
| 740 | static int ata_eh_read_log_10h(struct ata_device *dev, | ||
| 741 | int *tag, struct ata_taskfile *tf) | ||
| 742 | { | ||
| 743 | u8 *buf = dev->ap->sector_buf; | ||
| 744 | unsigned int err_mask; | ||
| 745 | u8 csum; | ||
| 746 | int i; | ||
| 747 | |||
| 748 | err_mask = ata_read_log_page(dev, ATA_LOG_SATA_NCQ, buf, 1); | ||
| 749 | if (err_mask) | ||
| 750 | return -EIO; | ||
| 751 | |||
| 752 | csum = 0; | ||
| 753 | for (i = 0; i < ATA_SECT_SIZE; i++) | ||
| 754 | csum += buf[i]; | ||
| 755 | if (csum) | ||
| 756 | ata_dev_printk(dev, KERN_WARNING, | ||
| 757 | "invalid checksum 0x%x on log page 10h\n", csum); | ||
| 758 | |||
| 759 | if (buf[0] & 0x80) | ||
| 760 | return -ENOENT; | ||
| 761 | |||
| 762 | *tag = buf[0] & 0x1f; | ||
| 763 | |||
| 764 | tf->command = buf[2]; | ||
| 765 | tf->feature = buf[3]; | ||
| 766 | tf->lbal = buf[4]; | ||
| 767 | tf->lbam = buf[5]; | ||
| 768 | tf->lbah = buf[6]; | ||
| 769 | tf->device = buf[7]; | ||
| 770 | tf->hob_lbal = buf[8]; | ||
| 771 | tf->hob_lbam = buf[9]; | ||
| 772 | tf->hob_lbah = buf[10]; | ||
| 773 | tf->nsect = buf[12]; | ||
| 774 | tf->hob_nsect = buf[13]; | ||
| 775 | |||
| 776 | return 0; | ||
| 777 | } | ||
| 778 | |||
| 779 | /** | ||
| 688 | * atapi_eh_request_sense - perform ATAPI REQUEST_SENSE | 780 | * atapi_eh_request_sense - perform ATAPI REQUEST_SENSE | 
| 689 | * @dev: device to perform REQUEST_SENSE to | 781 | * @dev: device to perform REQUEST_SENSE to | 
| 690 | * @sense_buf: result sense data buffer (SCSI_SENSE_BUFFERSIZE bytes long) | 782 | * @sense_buf: result sense data buffer (SCSI_SENSE_BUFFERSIZE bytes long) | 
| @@ -783,6 +875,66 @@ static void ata_eh_analyze_serror(struct ata_port *ap) | |||
| 783 | } | 875 | } | 
| 784 | 876 | ||
| 785 | /** | 877 | /** | 
| 878 | * ata_eh_analyze_ncq_error - analyze NCQ error | ||
| 879 | * @ap: ATA port to analyze NCQ error for | ||
| 880 | * | ||
| 881 | * Read log page 10h, determine the offending qc and acquire | ||
| 882 | * error status TF. For NCQ device errors, all LLDDs have to do | ||
| 883 | * is setting AC_ERR_DEV in ehi->err_mask. This function takes | ||
| 884 | * care of the rest. | ||
| 885 | * | ||
| 886 | * LOCKING: | ||
| 887 | * Kernel thread context (may sleep). | ||
| 888 | */ | ||
| 889 | static void ata_eh_analyze_ncq_error(struct ata_port *ap) | ||
| 890 | { | ||
| 891 | struct ata_eh_context *ehc = &ap->eh_context; | ||
| 892 | struct ata_device *dev = ap->device; | ||
| 893 | struct ata_queued_cmd *qc; | ||
| 894 | struct ata_taskfile tf; | ||
| 895 | int tag, rc; | ||
| 896 | |||
| 897 | /* if frozen, we can't do much */ | ||
| 898 | if (ap->flags & ATA_FLAG_FROZEN) | ||
| 899 | return; | ||
| 900 | |||
| 901 | /* is it NCQ device error? */ | ||
| 902 | if (!ap->sactive || !(ehc->i.err_mask & AC_ERR_DEV)) | ||
| 903 | return; | ||
| 904 | |||
| 905 | /* has LLDD analyzed already? */ | ||
| 906 | for (tag = 0; tag < ATA_MAX_QUEUE; tag++) { | ||
| 907 | qc = __ata_qc_from_tag(ap, tag); | ||
| 908 | |||
| 909 | if (!(qc->flags & ATA_QCFLAG_FAILED)) | ||
| 910 | continue; | ||
| 911 | |||
| 912 | if (qc->err_mask) | ||
| 913 | return; | ||
| 914 | } | ||
| 915 | |||
| 916 | /* okay, this error is ours */ | ||
| 917 | rc = ata_eh_read_log_10h(dev, &tag, &tf); | ||
| 918 | if (rc) { | ||
| 919 | ata_port_printk(ap, KERN_ERR, "failed to read log page 10h " | ||
| 920 | "(errno=%d)\n", rc); | ||
| 921 | return; | ||
| 922 | } | ||
| 923 | |||
| 924 | if (!(ap->sactive & (1 << tag))) { | ||
| 925 | ata_port_printk(ap, KERN_ERR, "log page 10h reported " | ||
| 926 | "inactive tag %d\n", tag); | ||
| 927 | return; | ||
| 928 | } | ||
| 929 | |||
| 930 | /* we've got the perpetrator, condemn it */ | ||
| 931 | qc = __ata_qc_from_tag(ap, tag); | ||
| 932 | memcpy(&qc->result_tf, &tf, sizeof(tf)); | ||
| 933 | qc->err_mask |= AC_ERR_DEV; | ||
| 934 | ehc->i.err_mask &= ~AC_ERR_DEV; | ||
| 935 | } | ||
| 936 | |||
| 937 | /** | ||
| 786 | * ata_eh_analyze_tf - analyze taskfile of a failed qc | 938 | * ata_eh_analyze_tf - analyze taskfile of a failed qc | 
| 787 | * @qc: qc to analyze | 939 | * @qc: qc to analyze | 
| 788 | * @tf: Taskfile registers to analyze | 940 | * @tf: Taskfile registers to analyze | 
| @@ -999,6 +1151,9 @@ static void ata_eh_autopsy(struct ata_port *ap) | |||
| 999 | } else if (rc != -EOPNOTSUPP) | 1151 | } else if (rc != -EOPNOTSUPP) | 
| 1000 | action |= ATA_EH_HARDRESET; | 1152 | action |= ATA_EH_HARDRESET; | 
| 1001 | 1153 | ||
| 1154 | /* analyze NCQ failure */ | ||
| 1155 | ata_eh_analyze_ncq_error(ap); | ||
| 1156 | |||
| 1002 | /* any real error trumps AC_ERR_OTHER */ | 1157 | /* any real error trumps AC_ERR_OTHER */ | 
| 1003 | if (ehc->i.err_mask & ~AC_ERR_OTHER) | 1158 | if (ehc->i.err_mask & ~AC_ERR_OTHER) | 
| 1004 | ehc->i.err_mask &= ~AC_ERR_OTHER; | 1159 | ehc->i.err_mask &= ~AC_ERR_OTHER; | 
| @@ -1093,17 +1248,17 @@ static void ata_eh_report(struct ata_port *ap) | |||
| 1093 | frozen = " frozen"; | 1248 | frozen = " frozen"; | 
| 1094 | 1249 | ||
| 1095 | if (ehc->i.dev) { | 1250 | if (ehc->i.dev) { | 
| 1096 | ata_dev_printk(ehc->i.dev, KERN_ERR, | 1251 | ata_dev_printk(ehc->i.dev, KERN_ERR, "exception Emask 0x%x " | 
| 1097 | "exception Emask 0x%x SErr 0x%x action 0x%x%s\n", | 1252 | "SAct 0x%x SErr 0x%x action 0x%x%s\n", | 
| 1098 | ehc->i.err_mask, ehc->i.serror, ehc->i.action, | 1253 | ehc->i.err_mask, ap->sactive, ehc->i.serror, | 
| 1099 | frozen); | 1254 | ehc->i.action, frozen); | 
| 1100 | if (desc) | 1255 | if (desc) | 
| 1101 | ata_dev_printk(ehc->i.dev, KERN_ERR, "(%s)\n", desc); | 1256 | ata_dev_printk(ehc->i.dev, KERN_ERR, "(%s)\n", desc); | 
| 1102 | } else { | 1257 | } else { | 
| 1103 | ata_port_printk(ap, KERN_ERR, | 1258 | ata_port_printk(ap, KERN_ERR, "exception Emask 0x%x " | 
| 1104 | "exception Emask 0x%x SErr 0x%x action 0x%x%s\n", | 1259 | "SAct 0x%x SErr 0x%x action 0x%x%s\n", | 
| 1105 | ehc->i.err_mask, ehc->i.serror, ehc->i.action, | 1260 | ehc->i.err_mask, ap->sactive, ehc->i.serror, | 
| 1106 | frozen); | 1261 | ehc->i.action, frozen); | 
| 1107 | if (desc) | 1262 | if (desc) | 
| 1108 | ata_port_printk(ap, KERN_ERR, "(%s)\n", desc); | 1263 | ata_port_printk(ap, KERN_ERR, "(%s)\n", desc); | 
| 1109 | } | 1264 | } | 
