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

Commit a7dac447 authored by Jeff Garzik's avatar Jeff Garzik
Browse files

[libata] change ata_qc_complete() to take error mask as second arg

The second argument to ata_qc_complete() was being used for two
purposes: communicate the ATA Status register to the completion
function, and indicate an error.  On legacy PCI IDE hardware, the latter
is often implicit in the former.  On more modern hardware, the driver
often completely emulated a Status register value, passing ATA_ERR as an
indication that something went wrong.

Now that previous code changes have eliminated the need to use drv_stat
arg to communicate the ATA Status register value, we can convert it to a
mask of possible error classes.

This will lead to more flexible error handling in the future.
parent 81cfb886
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
@@ -600,7 +600,7 @@ static void ahci_eng_timeout(struct ata_port *ap)
	 	 * not being called from the SCSI EH.
	 	 */
		qc->scsidone = scsi_finish_command;
		ata_qc_complete(qc, ATA_ERR);
		ata_qc_complete(qc, AC_ERR_OTHER);
	}

	spin_unlock_irqrestore(&host_set->lock, flags);
@@ -629,7 +629,7 @@ static inline int ahci_host_intr(struct ata_port *ap, struct ata_queued_cmd *qc)
	if (status & PORT_IRQ_FATAL) {
		ahci_intr_error(ap, status);
		if (qc)
			ata_qc_complete(qc, ATA_ERR);
			ata_qc_complete(qc, AC_ERR_OTHER);
	}

	return 1;
+15 −16
Original line number Diff line number Diff line
@@ -2663,7 +2663,7 @@ static int ata_sg_setup(struct ata_queued_cmd *qc)
 *	None.  (grabs host lock)
 */

void ata_poll_qc_complete(struct ata_queued_cmd *qc, u8 drv_stat)
void ata_poll_qc_complete(struct ata_queued_cmd *qc, unsigned int err_mask)
{
	struct ata_port *ap = qc->ap;
	unsigned long flags;
@@ -2671,7 +2671,7 @@ void ata_poll_qc_complete(struct ata_queued_cmd *qc, u8 drv_stat)
	spin_lock_irqsave(&ap->host_set->lock, flags);
	ap->flags &= ~ATA_FLAG_NOINTR;
	ata_irq_on(ap);
	ata_qc_complete(qc, drv_stat);
	ata_qc_complete(qc, err_mask);
	spin_unlock_irqrestore(&ap->host_set->lock, flags);
}

@@ -2768,7 +2768,7 @@ static int ata_pio_complete (struct ata_port *ap)

	ap->hsm_task_state = HSM_ST_IDLE;

	ata_poll_qc_complete(qc, drv_stat);
	ata_poll_qc_complete(qc, 0);

	/* another command may start at this point */

@@ -3136,18 +3136,15 @@ static void ata_pio_block(struct ata_port *ap)
static void ata_pio_error(struct ata_port *ap)
{
	struct ata_queued_cmd *qc;
	u8 drv_stat;

	printk(KERN_WARNING "ata%u: PIO error\n", ap->id);

	qc = ata_qc_from_tag(ap, ap->active_tag);
	assert(qc != NULL);

	drv_stat = ata_chk_status(ap);
	printk(KERN_WARNING "ata%u: PIO error, drv_stat 0x%x\n",
	       ap->id, drv_stat);

	ap->hsm_task_state = HSM_ST_IDLE;

	ata_poll_qc_complete(qc, drv_stat | ATA_ERR);
	ata_poll_qc_complete(qc, AC_ERR_ATA_BUS);
}

static void ata_pio_task(void *_data)
@@ -3270,7 +3267,7 @@ static void ata_qc_timeout(struct ata_queued_cmd *qc)
		       ap->id, qc->tf.command, drv_stat, host_stat);

		/* complete taskfile transaction */
		ata_qc_complete(qc, drv_stat);
		ata_qc_complete(qc, ac_err_mask(drv_stat));
		break;
	}

@@ -3375,7 +3372,7 @@ struct ata_queued_cmd *ata_qc_new_init(struct ata_port *ap,
	return qc;
}

int ata_qc_complete_noop(struct ata_queued_cmd *qc, u8 drv_stat)
int ata_qc_complete_noop(struct ata_queued_cmd *qc, unsigned int err_mask)
{
	return 0;
}
@@ -3434,7 +3431,7 @@ void ata_qc_free(struct ata_queued_cmd *qc)
 *	spin_lock_irqsave(host_set lock)
 */

void ata_qc_complete(struct ata_queued_cmd *qc, u8 drv_stat)
void ata_qc_complete(struct ata_queued_cmd *qc, unsigned int err_mask)
{
	int rc;

@@ -3451,7 +3448,7 @@ void ata_qc_complete(struct ata_queued_cmd *qc, u8 drv_stat)
	qc->flags &= ~ATA_QCFLAG_ACTIVE;

	/* call completion callback */
	rc = qc->complete_fn(qc, drv_stat);
	rc = qc->complete_fn(qc, err_mask);

	/* if callback indicates not to complete command (non-zero),
	 * return immediately
@@ -3889,7 +3886,7 @@ inline unsigned int ata_host_intr (struct ata_port *ap,
		ap->ops->irq_clear(ap);

		/* complete taskfile transaction */
		ata_qc_complete(qc, status);
		ata_qc_complete(qc, ac_err_mask(status));
		break;

	default:
@@ -3984,7 +3981,7 @@ static void atapi_packet_task(void *_data)
	/* sleep-wait for BSY to clear */
	DPRINTK("busy wait\n");
	if (ata_busy_sleep(ap, ATA_TMOUT_CDB_QUICK, ATA_TMOUT_CDB))
		goto err_out;
		goto err_out_status;

	/* make sure DRQ is set */
	status = ata_chk_status(ap);
@@ -4021,8 +4018,10 @@ static void atapi_packet_task(void *_data)

	return;

err_out_status:
	status = ata_chk_status(ap);
err_out:
	ata_poll_qc_complete(qc, ATA_ERR);
	ata_poll_qc_complete(qc, __ac_err_mask(status));
}


+28 −18
Original line number Diff line number Diff line
@@ -560,7 +560,7 @@ void ata_gen_ata_desc_sense(struct ata_queued_cmd *qc)
	 * Use ata_to_sense_error() to map status register bits
	 * onto sense key, asc & ascq.
	 */
	if (unlikely(tf->command & (ATA_BUSY | ATA_DF | ATA_ERR | ATA_DRQ))) {
	if (tf->command & (ATA_BUSY | ATA_DF | ATA_ERR | ATA_DRQ)) {
		ata_to_sense_error(qc->ap->id, tf->command, tf->feature,
				   &sb[1], &sb[2], &sb[3]);
		sb[1] &= 0x0f;
@@ -635,7 +635,7 @@ void ata_gen_fixed_sense(struct ata_queued_cmd *qc)
	 * Use ata_to_sense_error() to map status register bits
	 * onto sense key, asc & ascq.
	 */
	if (unlikely(tf->command & (ATA_BUSY | ATA_DF | ATA_ERR | ATA_DRQ))) {
	if (tf->command & (ATA_BUSY | ATA_DF | ATA_ERR | ATA_DRQ)) {
		ata_to_sense_error(qc->ap->id, tf->command, tf->feature,
				   &sb[2], &sb[12], &sb[13]);
		sb[2] &= 0x0f;
@@ -644,7 +644,11 @@ void ata_gen_fixed_sense(struct ata_queued_cmd *qc)
	sb[0] = 0x70;
	sb[7] = 0x0a;

	if (tf->flags & ATA_TFLAG_LBA && !(tf->flags & ATA_TFLAG_LBA48)) {
	if (tf->flags & ATA_TFLAG_LBA48) {
		/* TODO: find solution for LBA48 descriptors */
	}

	else if (tf->flags & ATA_TFLAG_LBA) {
		/* A small (28b) LBA will fit in the 32b info field */
		sb[0] |= 0x80;		/* set valid bit */
		sb[3] = tf->device & 0x0f;
@@ -652,6 +656,10 @@ void ata_gen_fixed_sense(struct ata_queued_cmd *qc)
		sb[5] = tf->lbam;
		sb[6] = tf->lbal;
	}

	else {
		/* TODO: C/H/S */
	}
}

/**
@@ -1199,10 +1207,12 @@ static unsigned int ata_scsi_rw_xlat(struct ata_queued_cmd *qc, const u8 *scsicm
	return 1;
}

static int ata_scsi_qc_complete(struct ata_queued_cmd *qc, u8 drv_stat)
static int ata_scsi_qc_complete(struct ata_queued_cmd *qc,
				unsigned int err_mask)
{
	struct scsi_cmnd *cmd = qc->scsicmd;
 	int need_sense = drv_stat & (ATA_ERR | ATA_BUSY | ATA_DRQ);
	u8 *cdb = cmd->cmnd;
 	int need_sense = (err_mask != 0);

	/* For ATA pass thru (SAT) commands, generate a sense block if
	 * user mandated it or if there's an error.  Note that if we
@@ -1211,8 +1221,8 @@ static int ata_scsi_qc_complete(struct ata_queued_cmd *qc, u8 drv_stat)
	 * whether the command completed successfully or not. If there
	 * was no error, SK, ASC and ASCQ will all be zero.
	 */
	if (((cmd->cmnd[0] == ATA_16) || (cmd->cmnd[0] == ATA_12)) &&
 	    ((cmd->cmnd[2] & 0x20) || need_sense)) {
	if (((cdb[0] == ATA_16) || (cdb[0] == ATA_12)) &&
 	    ((cdb[2] & 0x20) || need_sense)) {
 		ata_gen_ata_desc_sense(qc);
	} else {
		if (!need_sense) {
@@ -1995,21 +2005,13 @@ void atapi_request_sense(struct ata_port *ap, struct ata_device *dev,
	DPRINTK("EXIT\n");
}

static int atapi_qc_complete(struct ata_queued_cmd *qc, u8 drv_stat)
static int atapi_qc_complete(struct ata_queued_cmd *qc, unsigned int err_mask)
{
	struct scsi_cmnd *cmd = qc->scsicmd;

	VPRINTK("ENTER, drv_stat == 0x%x\n", drv_stat);

	if (unlikely(drv_stat & (ATA_BUSY | ATA_DRQ)))
		/* FIXME: not quite right; we don't want the
		 * translation of taskfile registers into
		 * a sense descriptors, since that's only
		 * correct for ATA, not ATAPI
		 */
		ata_gen_ata_desc_sense(qc);
	VPRINTK("ENTER, err_mask 0x%X\n", err_mask);

	else if (unlikely(drv_stat & ATA_ERR)) {
	if (unlikely(err_mask & AC_ERR_DEV)) {
		DPRINTK("request check condition\n");

		/* FIXME: command completion with check condition
@@ -2026,6 +2028,14 @@ static int atapi_qc_complete(struct ata_queued_cmd *qc, u8 drv_stat)
		return 1;
	}

	else if (unlikely(err_mask))
		/* FIXME: not quite right; we don't want the
		 * translation of taskfile registers into
		 * a sense descriptors, since that's only
		 * correct for ATA, not ATAPI
		 */
		ata_gen_ata_desc_sense(qc);

	else {
		u8 *scsicmd = cmd->cmnd;

+1 −1
Original line number Diff line number Diff line
@@ -39,7 +39,7 @@ struct ata_scsi_args {

/* libata-core.c */
extern int atapi_enabled;
extern int ata_qc_complete_noop(struct ata_queued_cmd *qc, u8 drv_stat);
extern int ata_qc_complete_noop(struct ata_queued_cmd *qc, unsigned int err_mask);
extern struct ata_queued_cmd *ata_qc_new_init(struct ata_port *ap,
				      struct ata_device *dev);
extern void ata_rwcmd_protocol(struct ata_queued_cmd *qc);
+8 −5
Original line number Diff line number Diff line
@@ -451,7 +451,7 @@ static inline unsigned int adma_intr_pkt(struct ata_host_set *host_set)
		struct adma_port_priv *pp;
		struct ata_queued_cmd *qc;
		void __iomem *chan = ADMA_REGS(mmio_base, port_no);
		u8 drv_stat = 0, status = readb(chan + ADMA_STATUS);
		u8 status = readb(chan + ADMA_STATUS);

		if (status == 0)
			continue;
@@ -464,11 +464,14 @@ static inline unsigned int adma_intr_pkt(struct ata_host_set *host_set)
			continue;
		qc = ata_qc_from_tag(ap, ap->active_tag);
		if (qc && (!(qc->tf.ctl & ATA_NIEN))) {
			unsigned int err_mask = 0;

			if ((status & (aPERR | aPSD | aUIRQ)))
				drv_stat = ATA_ERR;
				err_mask = AC_ERR_OTHER;
			else if (pp->pkt[0] != cDONE)
				drv_stat = ATA_ERR;
			ata_qc_complete(qc, drv_stat);
				err_mask = AC_ERR_OTHER;

			ata_qc_complete(qc, err_mask);
		}
	}
	return handled;
@@ -498,7 +501,7 @@ static inline unsigned int adma_intr_mmio(struct ata_host_set *host_set)
		
				/* complete taskfile transaction */
				pp->state = adma_state_idle;
				ata_qc_complete(qc, status);
				ata_qc_complete(qc, ac_err_mask(status));
				handled = 1;
			}
		}
Loading