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 /drivers/scsi/libata-eh.c | |
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>
Diffstat (limited to 'drivers/scsi/libata-eh.c')
-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 | } |