Module Name: src Committed By: jdolecek Date: Mon Apr 13 10:49:35 UTC 2020
Modified Files: src/sys/dev/ata: ata.c ata_recovery.c ata_wdc.c atavar.h satapmp_subr.c wd.c src/sys/dev/ic: ahcisata_core.c mvsata.c siisata.c wdc.c wdcvar.h src/sys/dev/scsipi: atapi_wdc.c Log Message: fix use-after-free for ata xfer on bio submission found by KASAN driver ata_bio hooks read parts of the xfer after ata_exec_xfer() call in order to determine return value, change so that the hook doesn't return any value - callers do not care already, as all I/O requests are asynchronous this problem was uncovered by recent change for wd(4) to not hold wd mutex during ata_bio call, the interrupt for the xfer might thus actually fire immediately adjust also ata_exec_command driver hooks similarily - remove all completion and waiting logic from drivers, upper layer ata code using AT_WAIT/AT_POLL changed to call ata_wait_cmd() itself PR kern/55169 by Nick Hudson To generate a diff of this commit: cvs rdiff -u -r1.154 -r1.155 src/sys/dev/ata/ata.c cvs rdiff -u -r1.3 -r1.4 src/sys/dev/ata/ata_recovery.c cvs rdiff -u -r1.114 -r1.115 src/sys/dev/ata/ata_wdc.c cvs rdiff -u -r1.104 -r1.105 src/sys/dev/ata/atavar.h cvs rdiff -u -r1.15 -r1.16 src/sys/dev/ata/satapmp_subr.c cvs rdiff -u -r1.461 -r1.462 src/sys/dev/ata/wd.c cvs rdiff -u -r1.82 -r1.83 src/sys/dev/ic/ahcisata_core.c cvs rdiff -u -r1.55 -r1.56 src/sys/dev/ic/mvsata.c cvs rdiff -u -r1.41 -r1.42 src/sys/dev/ic/siisata.c cvs rdiff -u -r1.298 -r1.299 src/sys/dev/ic/wdc.c cvs rdiff -u -r1.99 -r1.100 src/sys/dev/ic/wdcvar.h cvs rdiff -u -r1.137 -r1.138 src/sys/dev/scsipi/atapi_wdc.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/dev/ata/ata.c diff -u src/sys/dev/ata/ata.c:1.154 src/sys/dev/ata/ata.c:1.155 --- src/sys/dev/ata/ata.c:1.154 Sat Apr 4 21:36:15 2020 +++ src/sys/dev/ata/ata.c Mon Apr 13 10:49:34 2020 @@ -1,4 +1,4 @@ -/* $NetBSD: ata.c,v 1.154 2020/04/04 21:36:15 jdolecek Exp $ */ +/* $NetBSD: ata.c,v 1.155 2020/04/13 10:49:34 jdolecek Exp $ */ /* * Copyright (c) 1998, 2001 Manuel Bouyer. All rights reserved. @@ -25,7 +25,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: ata.c,v 1.154 2020/04/04 21:36:15 jdolecek Exp $"); +__KERNEL_RCSID(0, "$NetBSD: ata.c,v 1.155 2020/04/13 10:49:34 jdolecek Exp $"); #include "opt_ata.h" @@ -847,13 +847,8 @@ ata_get_params(struct ata_drive_datas *d xfer->c_ata_c.flags = AT_READ | flags; xfer->c_ata_c.data = tb; xfer->c_ata_c.bcount = ATA_BSIZE; - if ((*atac->atac_bustype_ata->ata_exec_command)(drvp, - xfer) != ATACMD_COMPLETE) { - ATADEBUG_PRINT(("ata_get_parms: wdc_exec_command failed\n"), - DEBUG_FUNCS|DEBUG_PROBE); - rv = CMD_AGAIN; - goto out; - } + (*atac->atac_bustype_ata->ata_exec_command)(drvp, xfer); + ata_wait_cmd(chp, xfer); if (xfer->c_ata_c.flags & (AT_ERROR | AT_TIMEOU | AT_DF)) { ATADEBUG_PRINT(("ata_get_parms: ata_c.flags=0x%x\n", xfer->c_ata_c.flags), DEBUG_FUNCS|DEBUG_PROBE); @@ -937,11 +932,8 @@ ata_set_mode(struct ata_drive_datas *drv xfer->c_ata_c.r_count = mode; xfer->c_ata_c.flags = flags; xfer->c_ata_c.timeout = 1000; /* 1s */ - if ((*atac->atac_bustype_ata->ata_exec_command)(drvp, - xfer) != ATACMD_COMPLETE) { - rv = CMD_AGAIN; - goto out; - } + (*atac->atac_bustype_ata->ata_exec_command)(drvp, xfer); + ata_wait_cmd(chp, xfer); if (xfer->c_ata_c.flags & (AT_ERROR | AT_TIMEOU | AT_DF)) { rv = CMD_ERR; goto out; Index: src/sys/dev/ata/ata_recovery.c diff -u src/sys/dev/ata/ata_recovery.c:1.3 src/sys/dev/ata/ata_recovery.c:1.4 --- src/sys/dev/ata/ata_recovery.c:1.3 Sat Apr 4 22:30:02 2020 +++ src/sys/dev/ata/ata_recovery.c Mon Apr 13 10:49:34 2020 @@ -1,4 +1,4 @@ -/* $NetBSD: ata_recovery.c,v 1.3 2020/04/04 22:30:02 jdolecek Exp $ */ +/* $NetBSD: ata_recovery.c,v 1.4 2020/04/13 10:49:34 jdolecek Exp $ */ /*- * Copyright (c) 2018 The NetBSD Foundation, Inc. @@ -27,7 +27,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: ata_recovery.c,v 1.3 2020/04/04 22:30:02 jdolecek Exp $"); +__KERNEL_RCSID(0, "$NetBSD: ata_recovery.c,v 1.4 2020/04/13 10:49:34 jdolecek Exp $"); #include "opt_ata.h" @@ -103,11 +103,9 @@ ata_read_log_ext_ncq(struct ata_drive_da xfer->c_ata_c.data = tb; xfer->c_ata_c.bcount = sizeof(chp->recovery_blk); - if ((*atac->atac_bustype_ata->ata_exec_command)(drvp, - xfer) != ATACMD_COMPLETE) { - rv = EAGAIN; - goto out; - } + (*atac->atac_bustype_ata->ata_exec_command)(drvp, xfer); + ata_wait_cmd(chp, xfer); + if (xfer->c_ata_c.flags & (AT_ERROR | AT_TIMEOU | AT_DF)) { rv = EINVAL; goto out; Index: src/sys/dev/ata/ata_wdc.c diff -u src/sys/dev/ata/ata_wdc.c:1.114 src/sys/dev/ata/ata_wdc.c:1.115 --- src/sys/dev/ata/ata_wdc.c:1.114 Sat Apr 4 21:36:15 2020 +++ src/sys/dev/ata/ata_wdc.c Mon Apr 13 10:49:34 2020 @@ -1,4 +1,4 @@ -/* $NetBSD: ata_wdc.c,v 1.114 2020/04/04 21:36:15 jdolecek Exp $ */ +/* $NetBSD: ata_wdc.c,v 1.115 2020/04/13 10:49:34 jdolecek Exp $ */ /* * Copyright (c) 1998, 2001, 2003 Manuel Bouyer. @@ -54,7 +54,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: ata_wdc.c,v 1.114 2020/04/04 21:36:15 jdolecek Exp $"); +__KERNEL_RCSID(0, "$NetBSD: ata_wdc.c,v 1.115 2020/04/13 10:49:34 jdolecek Exp $"); #include "opt_ata.h" #include "opt_wdc.h" @@ -102,7 +102,7 @@ extern int wdcdebug_wd_mask; /* inited i #define ATA_DELAY 10000 /* 10s for a drive I/O */ -static int wdc_ata_bio(struct ata_drive_datas*, struct ata_xfer *); +static void wdc_ata_bio(struct ata_drive_datas*, struct ata_xfer *); static int wdc_ata_bio_start(struct ata_channel *,struct ata_xfer *); static int _wdc_ata_bio_start(struct ata_channel *,struct ata_xfer *); static void wdc_ata_bio_poll(struct ata_channel *,struct ata_xfer *); @@ -140,10 +140,9 @@ static const struct ata_xfer_ops wdc_bio }; /* - * Handle block I/O operation. Return ATACMD_COMPLETE, ATACMD_QUEUED, or - * ATACMD_TRY_AGAIN. Must be called at splbio(). + * Handle block I/O operation. */ -static int +static void wdc_ata_bio(struct ata_drive_datas *drvp, struct ata_xfer *xfer) { struct ata_channel *chp = drvp->chnl_softc; @@ -171,7 +170,6 @@ wdc_ata_bio(struct ata_drive_datas *drvp xfer->c_bcount = ata_bio->bcount; xfer->ops = &wdc_bio_xfer_ops; ata_exec_xfer(chp, xfer); - return (ata_bio->flags & ATA_ITSDONE) ? ATACMD_COMPLETE : ATACMD_QUEUED; } static int Index: src/sys/dev/ata/atavar.h diff -u src/sys/dev/ata/atavar.h:1.104 src/sys/dev/ata/atavar.h:1.105 --- src/sys/dev/ata/atavar.h:1.104 Sat Apr 4 21:36:15 2020 +++ src/sys/dev/ata/atavar.h Mon Apr 13 10:49:34 2020 @@ -1,4 +1,4 @@ -/* $NetBSD: atavar.h,v 1.104 2020/04/04 21:36:15 jdolecek Exp $ */ +/* $NetBSD: atavar.h,v 1.105 2020/04/13 10:49:34 jdolecek Exp $ */ /* * Copyright (c) 1998, 2001 Manuel Bouyer. @@ -358,10 +358,10 @@ struct ata_drive_datas { */ struct ata_bustype { int bustype_type; /* symbolic name of type */ - int (*ata_bio)(struct ata_drive_datas *, struct ata_xfer *); + void (*ata_bio)(struct ata_drive_datas *, struct ata_xfer *); void (*ata_reset_drive)(struct ata_drive_datas *, int, uint32_t *); void (*ata_reset_channel)(struct ata_channel *, int); - int (*ata_exec_command)(struct ata_drive_datas *, + void (*ata_exec_command)(struct ata_drive_datas *, struct ata_xfer *); #define ATACMD_COMPLETE 0x01 Index: src/sys/dev/ata/satapmp_subr.c diff -u src/sys/dev/ata/satapmp_subr.c:1.15 src/sys/dev/ata/satapmp_subr.c:1.16 --- src/sys/dev/ata/satapmp_subr.c:1.15 Mon Oct 22 20:13:47 2018 +++ src/sys/dev/ata/satapmp_subr.c Mon Apr 13 10:49:34 2020 @@ -1,4 +1,4 @@ -/* $NetBSD: satapmp_subr.c,v 1.15 2018/10/22 20:13:47 jdolecek Exp $ */ +/* $NetBSD: satapmp_subr.c,v 1.16 2020/04/13 10:49:34 jdolecek Exp $ */ /* * Copyright (c) 2012 Manuel Bouyer. All rights reserved. @@ -25,7 +25,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: satapmp_subr.c,v 1.15 2018/10/22 20:13:47 jdolecek Exp $"); +__KERNEL_RCSID(0, "$NetBSD: satapmp_subr.c,v 1.16 2020/04/13 10:49:34 jdolecek Exp $"); #include <sys/param.h> #include <sys/systm.h> @@ -72,13 +72,10 @@ satapmp_read_8(struct ata_channel *chp, xfer->c_ata_c.flags = AT_LBA48 | AT_READREG | AT_WAIT; ata_channel_unlock(chp); - if ((*atac->atac_bustype_ata->ata_exec_command)(drvp, - xfer) != ATACMD_COMPLETE) { - aprint_error_dev(chp->atabus, - "PMP port %d register %d read failed\n", port, reg); - error = EIO; - goto out; - } + + (*atac->atac_bustype_ata->ata_exec_command)(drvp, xfer); + ata_wait_cmd(chp, xfer); + if (xfer->c_ata_c.flags & (AT_TIMEOU | AT_DF)) { aprint_error_dev(chp->atabus, "PMP port %d register %d read failed, flags 0x%x\n", @@ -148,13 +145,10 @@ satapmp_write_8(struct ata_channel *chp, xfer->c_ata_c.flags = AT_LBA48 | AT_WAIT; ata_channel_unlock(chp); - if ((*atac->atac_bustype_ata->ata_exec_command)(drvp, - xfer) != ATACMD_COMPLETE) { - aprint_error_dev(chp->atabus, - "PMP port %d register %d write failed\n", port, reg); - error = EIO; - goto out; - } + + (*atac->atac_bustype_ata->ata_exec_command)(drvp, xfer); + ata_wait_cmd(chp, xfer); + if (xfer->c_ata_c.flags & (AT_TIMEOU | AT_DF)) { aprint_error_dev(chp->atabus, "PMP port %d register %d write failed, flags 0x%x\n", Index: src/sys/dev/ata/wd.c diff -u src/sys/dev/ata/wd.c:1.461 src/sys/dev/ata/wd.c:1.462 --- src/sys/dev/ata/wd.c:1.461 Mon Apr 13 08:05:02 2020 +++ src/sys/dev/ata/wd.c Mon Apr 13 10:49:34 2020 @@ -1,4 +1,4 @@ -/* $NetBSD: wd.c,v 1.461 2020/04/13 08:05:02 maxv Exp $ */ +/* $NetBSD: wd.c,v 1.462 2020/04/13 10:49:34 jdolecek Exp $ */ /* * Copyright (c) 1998, 2001 Manuel Bouyer. All rights reserved. @@ -54,7 +54,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: wd.c,v 1.461 2020/04/13 08:05:02 maxv Exp $"); +__KERNEL_RCSID(0, "$NetBSD: wd.c,v 1.462 2020/04/13 10:49:34 jdolecek Exp $"); #include "opt_ata.h" #include "opt_wd.h" @@ -201,7 +201,7 @@ static int wd_discard(device_t, off_t, o static void wdbioretry(void *); static void wdbiorequeue(void *); static void wddone(device_t, struct ata_xfer *); -static int wd_get_params(struct wd_softc *, uint8_t, struct ataparams *); +static int wd_get_params(struct wd_softc *, struct ataparams *); static void wd_set_geometry(struct wd_softc *); static int wd_flushcache(struct wd_softc *, int, bool); static int wd_trim(struct wd_softc *, daddr_t, long); @@ -336,7 +336,7 @@ wdattach(device_t parent, device_t self, aprint_normal("\n"); /* read our drive info */ - if (wd_get_params(wd, AT_WAIT, &wd->sc_params) != 0) { + if (wd_get_params(wd, &wd->sc_params) != 0) { aprint_error_dev(self, "IDENTIFY failed\n"); goto out; } @@ -760,16 +760,8 @@ wdstart1(struct wd_softc *wd, struct buf wd->inflight++; mutex_exit(&wd->sc_lock); - switch (wd->atabus->ata_bio(wd->drvp, xfer)) { - case ATACMD_TRY_AGAIN: - panic("wdstart1: try again"); - break; - case ATACMD_QUEUED: - case ATACMD_COMPLETE: - break; - default: - panic("wdstart1: bad return code from ata_bio()"); - } + /* Queue the xfer */ + wd->atabus->ata_bio(wd->drvp, xfer); mutex_enter(&wd->sc_lock); } @@ -1165,7 +1157,7 @@ wd_firstopen(device_t self, dev_t dev, i int param_error; /* Load the physical device parameters. */ - param_error = wd_get_params(wd, AT_WAIT, &wd->sc_params); + param_error = wd_get_params(wd, &wd->sc_params); if (param_error != 0) { aprint_error_dev(dksc->sc_dev, "IDENTIFY failed\n"); error = EIO; @@ -1609,18 +1601,9 @@ wd_dumpblocks(device_t dev, void *va, da xfer->c_bio.bcount = nblk * dg->dg_secsize; xfer->c_bio.databuf = va; #ifndef WD_DUMP_NOT_TRUSTED - switch (err = wd->atabus->ata_bio(wd->drvp, xfer)) { - case ATACMD_TRY_AGAIN: - panic("wddump: try again"); - break; - case ATACMD_QUEUED: - panic("wddump: polled command has been queued"); - break; - case ATACMD_COMPLETE: - break; - default: - panic("wddump: unknown atacmd code %d", err); - } + /* This will poll until the bio is complete */ + wd->atabus->ata_bio(wd->drvp, xfer); + switch(err = xfer->c_bio.error) { case TIMEOUT: printf("wddump: device timed out"); @@ -1707,10 +1690,11 @@ wd_set_geometry(struct wd_softc *wd) } int -wd_get_params(struct wd_softc *wd, uint8_t flags, struct ataparams *params) +wd_get_params(struct wd_softc *wd, struct ataparams *params) { int retry = 0; struct ata_channel *chp = wd->drvp->chnl_softc; + const int flags = AT_WAIT; again: switch (wd->atabus->ata_get_params(wd->drvp, flags, params)) { @@ -1755,7 +1739,7 @@ wd_getcache(struct wd_softc *wd, int *bi { struct ataparams params; - if (wd_get_params(wd, AT_WAIT, ¶ms) != 0) + if (wd_get_params(wd, ¶ms) != 0) return EIO; if (params.atap_cmd_set1 == 0x0000 || params.atap_cmd_set1 == 0xffff || @@ -1783,7 +1767,7 @@ wd_setcache(struct wd_softc *wd, int bit struct ata_xfer *xfer; int error; - if (wd_get_params(wd, AT_WAIT, ¶ms) != 0) + if (wd_get_params(wd, ¶ms) != 0) return EIO; if (params.atap_cmd_set1 == 0x0000 || @@ -1806,12 +1790,9 @@ wd_setcache(struct wd_softc *wd, int bit xfer->c_ata_c.r_features = WDSF_WRITE_CACHE_EN; else xfer->c_ata_c.r_features = WDSF_WRITE_CACHE_DS; - if (wd->atabus->ata_exec_command(wd->drvp, xfer) != ATACMD_COMPLETE) { - aprint_error_dev(dksc->sc_dev, - "wd_setcache command not complete\n"); - error = EIO; - goto out; - } + + wd->atabus->ata_exec_command(wd->drvp, xfer); + ata_wait_cmd(wd->drvp->chnl_softc, xfer); if (xfer->c_ata_c.flags & (AT_ERROR | AT_TIMEOU | AT_DF)) { char sbuf[sizeof(at_errbits) + 64]; @@ -1843,12 +1824,10 @@ wd_standby(struct wd_softc *wd, int flag xfer->c_ata_c.r_st_pmask = WDCS_DRDY; xfer->c_ata_c.flags = flags; xfer->c_ata_c.timeout = 30000; /* 30s timeout */ - if (wd->atabus->ata_exec_command(wd->drvp, xfer) != ATACMD_COMPLETE) { - aprint_error_dev(dksc->sc_dev, - "standby immediate command didn't complete\n"); - error = EIO; - goto out; - } + + wd->atabus->ata_exec_command(wd->drvp, xfer); + ata_wait_cmd(wd->drvp->chnl_softc, xfer); + if (xfer->c_ata_c.flags & AT_ERROR) { if (xfer->c_ata_c.r_error == WDCE_ABRT) { /* command not supported */ @@ -1900,12 +1879,10 @@ wd_flushcache(struct wd_softc *wd, int f xfer->c_ata_c.r_st_pmask = WDCS_DRDY; xfer->c_ata_c.flags = flags | AT_READREG; xfer->c_ata_c.timeout = 300000; /* 5m timeout */ - if (wd->atabus->ata_exec_command(wd->drvp, xfer) != ATACMD_COMPLETE) { - aprint_error_dev(dksc->sc_dev, - "flush cache command didn't complete\n"); - error = EIO; - goto out_xfer; - } + + wd->atabus->ata_exec_command(wd->drvp, xfer); + ata_wait_cmd(wd->drvp->chnl_softc, xfer); + if (xfer->c_ata_c.flags & AT_ERROR) { if (xfer->c_ata_c.r_error == WDCE_ABRT) { /* command not supported */ @@ -1969,13 +1946,10 @@ wd_trim(struct wd_softc *wd, daddr_t bno xfer->c_ata_c.data = req; xfer->c_ata_c.bcount = 512; xfer->c_ata_c.flags |= AT_WRITE | AT_WAIT; - if (wd->atabus->ata_exec_command(wd->drvp, xfer) != ATACMD_COMPLETE) { - aprint_error_dev(dksc->sc_dev, - "trim command didn't complete\n"); - kmem_free(req, 512); - error = EIO; - goto out; - } + + wd->atabus->ata_exec_command(wd->drvp, xfer); + ata_wait_cmd(wd->drvp->chnl_softc, xfer); + kmem_free(req, 512); if (xfer->c_ata_c.flags & AT_ERROR) { if (xfer->c_ata_c.r_error == WDCE_ABRT) { @@ -2170,12 +2144,8 @@ wdioctlstrategy(struct buf *bp) xfer->c_ata_c.data = wi->wi_bp.b_data; xfer->c_ata_c.bcount = wi->wi_bp.b_bcount; - if (wi->wi_softc->atabus->ata_exec_command(wi->wi_softc->drvp, xfer) - != ATACMD_COMPLETE) { - wi->wi_atareq.retsts = ATACMD_ERROR; - error = EIO; - goto out; - } + wi->wi_softc->atabus->ata_exec_command(wi->wi_softc->drvp, xfer); + ata_wait_cmd(wi->wi_softc->drvp->chnl_softc, xfer); if (xfer->c_ata_c.flags & (AT_ERROR | AT_TIMEOU | AT_DF)) { if (xfer->c_ata_c.flags & AT_ERROR) { Index: src/sys/dev/ic/ahcisata_core.c diff -u src/sys/dev/ic/ahcisata_core.c:1.82 src/sys/dev/ic/ahcisata_core.c:1.83 --- src/sys/dev/ic/ahcisata_core.c:1.82 Wed Feb 19 16:04:39 2020 +++ src/sys/dev/ic/ahcisata_core.c Mon Apr 13 10:49:34 2020 @@ -1,4 +1,4 @@ -/* $NetBSD: ahcisata_core.c,v 1.82 2020/02/19 16:04:39 riastradh Exp $ */ +/* $NetBSD: ahcisata_core.c,v 1.83 2020/04/13 10:49:34 jdolecek Exp $ */ /* * Copyright (c) 2006 Manuel Bouyer. @@ -26,7 +26,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: ahcisata_core.c,v 1.82 2020/02/19 16:04:39 riastradh Exp $"); +__KERNEL_RCSID(0, "$NetBSD: ahcisata_core.c,v 1.83 2020/04/13 10:49:34 jdolecek Exp $"); #include <sys/types.h> #include <sys/malloc.h> @@ -57,12 +57,12 @@ int ahcidebug_mask = 0; static void ahci_probe_drive(struct ata_channel *); static void ahci_setup_channel(struct ata_channel *); -static int ahci_ata_bio(struct ata_drive_datas *, struct ata_xfer *); +static void ahci_ata_bio(struct ata_drive_datas *, struct ata_xfer *); static int ahci_do_reset_drive(struct ata_channel *, int, int, uint32_t *, uint8_t); static void ahci_reset_drive(struct ata_drive_datas *, int, uint32_t *); static void ahci_reset_channel(struct ata_channel *, int); -static int ahci_exec_command(struct ata_drive_datas *, struct ata_xfer *); +static void ahci_exec_command(struct ata_drive_datas *, struct ata_xfer *); static int ahci_ata_addref(struct ata_drive_datas *); static void ahci_ata_delref(struct ata_drive_datas *); static void ahci_killpending(struct ata_drive_datas *); @@ -1101,13 +1101,11 @@ static const struct ata_xfer_ops ahci_cm .c_kill_xfer = ahci_cmd_kill_xfer, }; -static int +static void ahci_exec_command(struct ata_drive_datas *drvp, struct ata_xfer *xfer) { struct ata_channel *chp = drvp->chnl_softc; struct ata_command *ata_c = &xfer->c_ata_c; - int ret; - int s; AHCIDEBUG_PRINT(("ahci_exec_command port %d CI 0x%x\n", chp->ch_channel, @@ -1121,25 +1119,8 @@ ahci_exec_command(struct ata_drive_datas xfer->c_databuf = ata_c->data; xfer->c_bcount = ata_c->bcount; xfer->ops = &ahci_cmd_xfer_ops; - s = splbio(); + ata_exec_xfer(chp, xfer); -#ifdef DIAGNOSTIC - if ((ata_c->flags & AT_POLL) != 0 && - (ata_c->flags & AT_DONE) == 0) - panic("ahci_exec_command: polled command not done"); -#endif - if (ata_c->flags & AT_DONE) { - ret = ATACMD_COMPLETE; - } else { - if (ata_c->flags & AT_WAIT) { - ata_wait_cmd(chp, xfer); - ret = ATACMD_COMPLETE; - } else { - ret = ATACMD_QUEUED; - } - } - splx(s); - return ret; } static int @@ -1374,7 +1355,7 @@ static const struct ata_xfer_ops ahci_bi .c_kill_xfer = ahci_bio_kill_xfer, }; -static int +static void ahci_ata_bio(struct ata_drive_datas *drvp, struct ata_xfer *xfer) { struct ata_channel *chp = drvp->chnl_softc; @@ -1391,7 +1372,6 @@ ahci_ata_bio(struct ata_drive_datas *drv xfer->c_bcount = ata_bio->bcount; xfer->ops = &ahci_bio_xfer_ops; ata_exec_xfer(chp, xfer); - return (ata_bio->flags & ATA_ITSDONE) ? ATACMD_COMPLETE : ATACMD_QUEUED; } static int Index: src/sys/dev/ic/mvsata.c diff -u src/sys/dev/ic/mvsata.c:1.55 src/sys/dev/ic/mvsata.c:1.56 --- src/sys/dev/ic/mvsata.c:1.55 Sat Apr 4 21:36:15 2020 +++ src/sys/dev/ic/mvsata.c Mon Apr 13 10:49:34 2020 @@ -1,4 +1,4 @@ -/* $NetBSD: mvsata.c,v 1.55 2020/04/04 21:36:15 jdolecek Exp $ */ +/* $NetBSD: mvsata.c,v 1.56 2020/04/13 10:49:34 jdolecek Exp $ */ /* * Copyright (c) 2008 KIYOHARA Takashi * All rights reserved. @@ -26,7 +26,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: mvsata.c,v 1.55 2020/04/04 21:36:15 jdolecek Exp $"); +__KERNEL_RCSID(0, "$NetBSD: mvsata.c,v 1.56 2020/04/13 10:49:34 jdolecek Exp $"); #include "opt_mvsata.h" @@ -121,9 +121,9 @@ static void mvsata_probe_drive(struct at #ifndef MVSATA_WITHOUTDMA static void mvsata_reset_channel(struct ata_channel *, int); -static int mvsata_bio(struct ata_drive_datas *, struct ata_xfer *); +static void mvsata_bio(struct ata_drive_datas *, struct ata_xfer *); static void mvsata_reset_drive(struct ata_drive_datas *, int, uint32_t *); -static int mvsata_exec_command(struct ata_drive_datas *, struct ata_xfer *); +static void mvsata_exec_command(struct ata_drive_datas *, struct ata_xfer *); static int mvsata_addref(struct ata_drive_datas *); static void mvsata_delref(struct ata_drive_datas *); static void mvsata_killpending(struct ata_drive_datas *); @@ -985,7 +985,7 @@ static const struct ata_xfer_ops mvsata_ .c_kill_xfer = mvsata_bio_kill_xfer, }; -static int +static void mvsata_bio(struct ata_drive_datas *drvp, struct ata_xfer *xfer) { struct ata_channel *chp = drvp->chnl_softc; @@ -1009,7 +1009,6 @@ mvsata_bio(struct ata_drive_datas *drvp, xfer->c_bcount = ata_bio->bcount; xfer->ops = &mvsata_bio_xfer_ops; ata_exec_xfer(chp, xfer); - return (ata_bio->flags & ATA_ITSDONE) ? ATACMD_COMPLETE : ATACMD_QUEUED; } static int @@ -1601,12 +1600,11 @@ static const struct ata_xfer_ops mvsata_ .c_kill_xfer = mvsata_wdc_cmd_kill_xfer, }; -static int +static void mvsata_exec_command(struct ata_drive_datas *drvp, struct ata_xfer *xfer) { struct ata_channel *chp = drvp->chnl_softc; struct ata_command *ata_c = &xfer->c_ata_c; - int rv, s; DPRINTF(DEBUG_FUNCS|DEBUG_XFERS, ("%s:%d: mvsata_exec_command: drive=%d, bcount=%d," @@ -1625,24 +1623,8 @@ mvsata_exec_command(struct ata_drive_dat xfer->c_databuf = ata_c->data; xfer->c_bcount = ata_c->bcount; xfer->ops = &mvsata_wdc_cmd_xfer_ops; - s = splbio(); + ata_exec_xfer(chp, xfer); -#ifdef DIAGNOSTIC - if ((ata_c->flags & AT_POLL) != 0 && - (ata_c->flags & AT_DONE) == 0) - panic("mvsata_exec_command: polled command not done"); -#endif - if (ata_c->flags & AT_DONE) - rv = ATACMD_COMPLETE; - else { - if (ata_c->flags & AT_WAIT) { - ata_wait_cmd(chp, xfer); - rv = ATACMD_COMPLETE; - } else - rv = ATACMD_QUEUED; - } - splx(s); - return rv; } static int Index: src/sys/dev/ic/siisata.c diff -u src/sys/dev/ic/siisata.c:1.41 src/sys/dev/ic/siisata.c:1.42 --- src/sys/dev/ic/siisata.c:1.41 Wed Feb 19 16:04:39 2020 +++ src/sys/dev/ic/siisata.c Mon Apr 13 10:49:34 2020 @@ -1,4 +1,4 @@ -/* $NetBSD: siisata.c,v 1.41 2020/02/19 16:04:39 riastradh Exp $ */ +/* $NetBSD: siisata.c,v 1.42 2020/04/13 10:49:34 jdolecek Exp $ */ /* from ahcisata_core.c */ @@ -79,7 +79,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: siisata.c,v 1.41 2020/02/19 16:04:39 riastradh Exp $"); +__KERNEL_RCSID(0, "$NetBSD: siisata.c,v 1.42 2020/04/13 10:49:34 jdolecek Exp $"); #include <sys/types.h> #include <sys/param.h> @@ -140,7 +140,7 @@ static void siisata_intr_port(struct sii void siisata_probe_drive(struct ata_channel *); void siisata_setup_channel(struct ata_channel *); -int siisata_ata_bio(struct ata_drive_datas *, struct ata_xfer *); +void siisata_ata_bio(struct ata_drive_datas *, struct ata_xfer *); void siisata_reset_drive(struct ata_drive_datas *, int, uint32_t *); void siisata_reset_channel(struct ata_channel *, int); int siisata_ata_addref(struct ata_drive_datas *); @@ -160,7 +160,7 @@ int siisata_bio_complete(struct ata_chan void siisata_bio_poll(struct ata_channel *, struct ata_xfer *); void siisata_bio_abort(struct ata_channel *, struct ata_xfer *); void siisata_bio_kill_xfer(struct ata_channel *, struct ata_xfer *, int); -int siisata_exec_command(struct ata_drive_datas *, struct ata_xfer *); +void siisata_exec_command(struct ata_drive_datas *, struct ata_xfer *); static int siisata_reinit_port(struct ata_channel *, int); static void siisata_device_reset(struct ata_channel *); @@ -930,13 +930,11 @@ static const struct ata_xfer_ops siisata .c_kill_xfer = siisata_cmd_kill_xfer, }; -int +void siisata_exec_command(struct ata_drive_datas *drvp, struct ata_xfer *xfer) { struct ata_channel *chp = drvp->chnl_softc; struct ata_command *ata_c = &xfer->c_ata_c; - int ret; - int s; SIISATA_DEBUG_PRINT(("%s: %s begins\n", SIISATANAME((struct siisata_softc *)chp->ch_atac), __func__), @@ -950,28 +948,12 @@ siisata_exec_command(struct ata_drive_da xfer->c_databuf = ata_c->data; xfer->c_bcount = ata_c->bcount; xfer->ops = &siisata_cmd_xfer_ops; - s = splbio(); + ata_exec_xfer(chp, xfer); -#ifdef DIAGNOSTIC - if ((ata_c->flags & AT_POLL) != 0 && - (ata_c->flags & AT_DONE) == 0) - panic("%s: polled command not done", __func__); -#endif - if (ata_c->flags & AT_DONE) { - ret = ATACMD_COMPLETE; - } else { - if (ata_c->flags & AT_WAIT) { - ata_wait_cmd(chp, xfer); - ret = ATACMD_COMPLETE; - } else { - ret = ATACMD_QUEUED; - } - } - splx(s); + SIISATA_DEBUG_PRINT( ("%s: %s ends\n", SIISATANAME((struct siisata_softc *)chp->ch_atac), __func__), DEBUG_FUNCS); - return ret; } int @@ -1190,7 +1172,7 @@ static const struct ata_xfer_ops siisata .c_kill_xfer = siisata_bio_kill_xfer, }; -int +void siisata_ata_bio(struct ata_drive_datas *drvp, struct ata_xfer *xfer) { struct ata_channel *chp = drvp->chnl_softc; @@ -1200,8 +1182,6 @@ siisata_ata_bio(struct ata_drive_datas * SIISATANAME((struct siisata_softc *)chp->ch_atac), __func__), DEBUG_FUNCS); - if (xfer == NULL) - return ATACMD_TRY_AGAIN; if (ata_bio->flags & ATA_POLL) xfer->c_flags |= C_POLL; xfer->c_drive = drvp->drive; @@ -1209,8 +1189,6 @@ siisata_ata_bio(struct ata_drive_datas * xfer->c_bcount = ata_bio->bcount; xfer->ops = &siisata_bio_xfer_ops; ata_exec_xfer(chp, xfer); - return (ata_bio->flags & ATA_ITSDONE) ? - ATACMD_COMPLETE : ATACMD_QUEUED; } int Index: src/sys/dev/ic/wdc.c diff -u src/sys/dev/ic/wdc.c:1.298 src/sys/dev/ic/wdc.c:1.299 --- src/sys/dev/ic/wdc.c:1.298 Sat Apr 4 21:36:15 2020 +++ src/sys/dev/ic/wdc.c Mon Apr 13 10:49:34 2020 @@ -1,4 +1,4 @@ -/* $NetBSD: wdc.c,v 1.298 2020/04/04 21:36:15 jdolecek Exp $ */ +/* $NetBSD: wdc.c,v 1.299 2020/04/13 10:49:34 jdolecek Exp $ */ /* * Copyright (c) 1998, 2001, 2003 Manuel Bouyer. All rights reserved. @@ -58,7 +58,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: wdc.c,v 1.298 2020/04/04 21:36:15 jdolecek Exp $"); +__KERNEL_RCSID(0, "$NetBSD: wdc.c,v 1.299 2020/04/13 10:49:34 jdolecek Exp $"); #include "opt_ata.h" #include "opt_wdc.h" @@ -1391,12 +1391,11 @@ static const struct ata_xfer_ops wdc_cmd .c_kill_xfer = __wdccommand_kill_xfer, }; -int +void wdc_exec_command(struct ata_drive_datas *drvp, struct ata_xfer *xfer) { struct ata_channel *chp = drvp->chnl_softc; struct ata_command *ata_c = &xfer->c_ata_c; - int s, ret; ATADEBUG_PRINT(("wdc_exec_command %s:%d:%d\n", device_xname(chp->ch_atac->atac_dev), chp->ch_channel, @@ -1414,25 +1413,7 @@ wdc_exec_command(struct ata_drive_datas xfer->c_bcount = ata_c->bcount; xfer->ops = &wdc_cmd_xfer_ops; - s = splbio(); ata_exec_xfer(chp, xfer); -#ifdef DIAGNOSTIC - if ((ata_c->flags & AT_POLL) != 0 && - (ata_c->flags & AT_DONE) == 0) - panic("wdc_exec_command: polled command not done"); -#endif - if (ata_c->flags & AT_DONE) { - ret = ATACMD_COMPLETE; - } else { - if (ata_c->flags & AT_WAIT) { - ata_wait_cmd(chp, xfer); - ret = ATACMD_COMPLETE; - } else { - ret = ATACMD_QUEUED; - } - } - splx(s); - return ret; } static int Index: src/sys/dev/ic/wdcvar.h diff -u src/sys/dev/ic/wdcvar.h:1.99 src/sys/dev/ic/wdcvar.h:1.100 --- src/sys/dev/ic/wdcvar.h:1.99 Sat Sep 14 17:11:39 2019 +++ src/sys/dev/ic/wdcvar.h Mon Apr 13 10:49:34 2020 @@ -1,4 +1,4 @@ -/* $NetBSD: wdcvar.h,v 1.99 2019/09/14 17:11:39 tsutsui Exp $ */ +/* $NetBSD: wdcvar.h,v 1.100 2020/04/13 10:49:34 jdolecek Exp $ */ /*- * Copyright (c) 1998, 2003, 2004 The NetBSD Foundation, Inc. @@ -175,7 +175,7 @@ void wdc_reset_drive(struct ata_drive_da void wdc_reset_channel(struct ata_channel *, int); void wdc_do_reset(struct ata_channel *, int); -int wdc_exec_command(struct ata_drive_datas *, struct ata_xfer *); +void wdc_exec_command(struct ata_drive_datas *, struct ata_xfer *); /* * ST506 spec says that if READY or SEEKCMPLT go off, then the read or write Index: src/sys/dev/scsipi/atapi_wdc.c diff -u src/sys/dev/scsipi/atapi_wdc.c:1.137 src/sys/dev/scsipi/atapi_wdc.c:1.138 --- src/sys/dev/scsipi/atapi_wdc.c:1.137 Sat Apr 4 21:36:15 2020 +++ src/sys/dev/scsipi/atapi_wdc.c Mon Apr 13 10:49:34 2020 @@ -1,4 +1,4 @@ -/* $NetBSD: atapi_wdc.c,v 1.137 2020/04/04 21:36:15 jdolecek Exp $ */ +/* $NetBSD: atapi_wdc.c,v 1.138 2020/04/13 10:49:34 jdolecek Exp $ */ /* * Copyright (c) 1998, 2001 Manuel Bouyer. @@ -25,7 +25,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: atapi_wdc.c,v 1.137 2020/04/04 21:36:15 jdolecek Exp $"); +__KERNEL_RCSID(0, "$NetBSD: atapi_wdc.c,v 1.138 2020/04/13 10:49:34 jdolecek Exp $"); #ifndef ATADEBUG #define ATADEBUG @@ -222,12 +222,10 @@ wdc_atapi_get_params(struct scsipi_chann xfer->c_ata_c.r_st_pmask = 0; xfer->c_ata_c.flags = AT_WAIT | AT_POLL; xfer->c_ata_c.timeout = WDC_RESET_WAIT; - if (wdc_exec_command(&chp->ch_drive[drive], xfer) != ATACMD_COMPLETE) { - printf("wdc_atapi_get_params: ATAPI_SOFT_RESET failed for" - " drive %s:%d:%d: driver failed\n", - device_xname(atac->atac_dev), chp->ch_channel, drive); - panic("wdc_atapi_get_params"); - } + + wdc_exec_command(&chp->ch_drive[drive], xfer); + ata_wait_cmd(chp, xfer); + if (xfer->c_ata_c.flags & (AT_ERROR | AT_TIMEOU | AT_DF)) { ATADEBUG_PRINT(("wdc_atapi_get_params: ATAPI_SOFT_RESET " "failed for drive %s:%d:%d: error 0x%x\n",