Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 3655d1d3 authored by Albert Lee's avatar Albert Lee Committed by Jeff Garzik
Browse files

[PATCH] libata: Fix the HSM error_mask mapping (was: Re: libata-tj and SMART)



Fix the HSM error_mask mapping.

Changes:
- Better mapping in ac_err_mask()
- In HSM_ST_FIRST ans HSM_ST state, check ATA_ERR|ATA_DF and map it to AC_ERR_DEV instead of AC_ERR_HSM.
- In HSM_ST_FIRST and HSM_ST state, map DRQ=1 ERR=1 to AC_ERR_HSM.
- For PIO data in and DRQ=1 ERR=1, add check after the junk data block is read.

Signed-off-by: default avatarAlbert Lee <albertcc@tw.ibm.com>
Signed-off-by: default avatarJeff Garzik <jeff@garzik.org>
parent 3d71b3b0
Loading
Loading
Loading
Loading
+24 −7
Original line number Original line Diff line number Diff line
@@ -4009,9 +4009,15 @@ static int ata_hsm_move(struct ata_port *ap, struct ata_queued_cmd *qc,
		poll_next = (qc->tf.flags & ATA_TFLAG_POLLING);
		poll_next = (qc->tf.flags & ATA_TFLAG_POLLING);


		/* check device status */
		/* check device status */
		if (unlikely((status & (ATA_BUSY | ATA_DRQ)) != ATA_DRQ)) {
		if (unlikely((status & ATA_DRQ) == 0)) {
			/* Wrong status. Let EH handle this */
			/* handle BSY=0, DRQ=0 as error */
			if (likely(status & (ATA_ERR | ATA_DF)))
				/* device stops HSM for abort/error */
				qc->err_mask |= AC_ERR_DEV;
			else
				/* HSM violation. Let EH handle this */
				qc->err_mask |= AC_ERR_HSM;
				qc->err_mask |= AC_ERR_HSM;

			ap->hsm_task_state = HSM_ST_ERR;
			ap->hsm_task_state = HSM_ST_ERR;
			goto fsm_start;
			goto fsm_start;
		}
		}
@@ -4025,7 +4031,7 @@ static int ata_hsm_move(struct ata_port *ap, struct ata_queued_cmd *qc,
		if (unlikely(status & (ATA_ERR | ATA_DF))) {
		if (unlikely(status & (ATA_ERR | ATA_DF))) {
			printk(KERN_WARNING "ata%d: DRQ=1 with device error, dev_stat 0x%X\n",
			printk(KERN_WARNING "ata%d: DRQ=1 with device error, dev_stat 0x%X\n",
			       ap->id, status);
			       ap->id, status);
			qc->err_mask |= AC_ERR_DEV;
			qc->err_mask |= AC_ERR_HSM;
			ap->hsm_task_state = HSM_ST_ERR;
			ap->hsm_task_state = HSM_ST_ERR;
			goto fsm_start;
			goto fsm_start;
		}
		}
@@ -4067,7 +4073,9 @@ static int ata_hsm_move(struct ata_port *ap, struct ata_queued_cmd *qc,
		if (qc->tf.protocol == ATA_PROT_ATAPI) {
		if (qc->tf.protocol == ATA_PROT_ATAPI) {
			/* ATAPI PIO protocol */
			/* ATAPI PIO protocol */
			if ((status & ATA_DRQ) == 0) {
			if ((status & ATA_DRQ) == 0) {
				/* no more data to transfer */
				/* No more data to transfer or device error.
				 * Device error will be tagged in HSM_ST_LAST.
				 */
				ap->hsm_task_state = HSM_ST_LAST;
				ap->hsm_task_state = HSM_ST_LAST;
				goto fsm_start;
				goto fsm_start;
			}
			}
@@ -4081,7 +4089,7 @@ static int ata_hsm_move(struct ata_port *ap, struct ata_queued_cmd *qc,
			if (unlikely(status & (ATA_ERR | ATA_DF))) {
			if (unlikely(status & (ATA_ERR | ATA_DF))) {
				printk(KERN_WARNING "ata%d: DRQ=1 with device error, dev_stat 0x%X\n",
				printk(KERN_WARNING "ata%d: DRQ=1 with device error, dev_stat 0x%X\n",
				       ap->id, status);
				       ap->id, status);
				qc->err_mask |= AC_ERR_DEV;
				qc->err_mask |= AC_ERR_HSM;
				ap->hsm_task_state = HSM_ST_ERR;
				ap->hsm_task_state = HSM_ST_ERR;
				goto fsm_start;
				goto fsm_start;
			}
			}
@@ -4096,7 +4104,13 @@ static int ata_hsm_move(struct ata_port *ap, struct ata_queued_cmd *qc,
			/* ATA PIO protocol */
			/* ATA PIO protocol */
			if (unlikely((status & ATA_DRQ) == 0)) {
			if (unlikely((status & ATA_DRQ) == 0)) {
				/* handle BSY=0, DRQ=0 as error */
				/* handle BSY=0, DRQ=0 as error */
				if (likely(status & (ATA_ERR | ATA_DF)))
					/* device stops HSM for abort/error */
					qc->err_mask |= AC_ERR_DEV;
				else
					/* HSM violation. Let EH handle this */
					qc->err_mask |= AC_ERR_HSM;
					qc->err_mask |= AC_ERR_HSM;

				ap->hsm_task_state = HSM_ST_ERR;
				ap->hsm_task_state = HSM_ST_ERR;
				goto fsm_start;
				goto fsm_start;
			}
			}
@@ -4121,6 +4135,9 @@ static int ata_hsm_move(struct ata_port *ap, struct ata_queued_cmd *qc,
					status = ata_wait_idle(ap);
					status = ata_wait_idle(ap);
				}
				}


				if (status & (ATA_BUSY | ATA_DRQ))
					qc->err_mask |= AC_ERR_HSM;

				/* ata_pio_sectors() might change the
				/* ata_pio_sectors() might change the
				 * state to HSM_ST_LAST. so, the state
				 * state to HSM_ST_LAST. so, the state
				 * is changed after ata_pio_sectors().
				 * is changed after ata_pio_sectors().
+1 −1
Original line number Original line Diff line number Diff line
@@ -1062,7 +1062,7 @@ static inline int ata_try_flush_cache(const struct ata_device *dev)


static inline unsigned int ac_err_mask(u8 status)
static inline unsigned int ac_err_mask(u8 status)
{
{
	if (status & ATA_BUSY)
	if (status & (ATA_BUSY | ATA_DRQ))
		return AC_ERR_HSM;
		return AC_ERR_HSM;
	if (status & (ATA_ERR | ATA_DF))
	if (status & (ATA_ERR | ATA_DF))
		return AC_ERR_DEV;
		return AC_ERR_DEV;