aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi/libata-eh.c
diff options
context:
space:
mode:
authorTejun Heo <htejun@gmail.com>2006-05-15 08:03:46 -0400
committerTejun Heo <htejun@gmail.com>2006-05-15 08:03:46 -0400
commite8ee84518c159a663c07bf691ace187527380f61 (patch)
treeffd6d89b4e38ff2a70463125a3022771f69b2286 /drivers/scsi/libata-eh.c
parent3dc1d88193b9c65b01b64fb2dc730e486306649f (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.c171
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 */
702static 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 */
740static 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 */
889static 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 }