Mon Jan 10 11:18:15 2011 UTC ()
Don't call bus_dmamap_load(9) and bus_dmamap_sync(9) on command xfers
if (AT_READ|AT_WRITE) in ata_c->flags is set but ata_c->bcount is zero.
Someone actually tries to put such a command and it causes
DIAGNOSTIC panic in x86/bus_dma.c:_bus_dmamap_sync().
I think bus_dma(9) API itself may allow calls with mapsize==0
but there are many MD code that asserts offset>=mapsize or len==0.

The problem is reported and fix is confirmed by Takuro KUBOTA
with XEN DOM0 kernel (which has options DIAGNOSTIC).


(tsutsui)
diff -r1.30 -r1.31 src/sys/dev/ic/ahcisata_core.c

cvs diff -r1.30 -r1.31 src/sys/dev/ic/ahcisata_core.c (expand / switch to unified diff)

--- src/sys/dev/ic/ahcisata_core.c 2010/11/13 13:52:00 1.30
+++ src/sys/dev/ic/ahcisata_core.c 2011/01/10 11:18:14 1.31
@@ -1,14 +1,14 @@ @@ -1,14 +1,14 @@
1/* $NetBSD: ahcisata_core.c,v 1.30 2010/11/13 13:52:00 uebayasi Exp $ */ 1/* $NetBSD: ahcisata_core.c,v 1.31 2011/01/10 11:18:14 tsutsui Exp $ */
2 2
3/* 3/*
4 * Copyright (c) 2006 Manuel Bouyer. 4 * Copyright (c) 2006 Manuel Bouyer.
5 * 5 *
6 * Redistribution and use in source and binary forms, with or without 6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions 7 * modification, are permitted provided that the following conditions
8 * are met: 8 * are met:
9 * 1. Redistributions of source code must retain the above copyright 9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer. 10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright 11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the 12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution. 13 * documentation and/or other materials provided with the distribution.
14 * 14 *
@@ -16,27 +16,27 @@ @@ -16,27 +16,27 @@
16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 * 25 *
26 */ 26 */
27 27
28#include <sys/cdefs.h> 28#include <sys/cdefs.h>
29__KERNEL_RCSID(0, "$NetBSD: ahcisata_core.c,v 1.30 2010/11/13 13:52:00 uebayasi Exp $"); 29__KERNEL_RCSID(0, "$NetBSD: ahcisata_core.c,v 1.31 2011/01/10 11:18:14 tsutsui Exp $");
30 30
31#include <sys/types.h> 31#include <sys/types.h>
32#include <sys/malloc.h> 32#include <sys/malloc.h>
33#include <sys/param.h> 33#include <sys/param.h>
34#include <sys/kernel.h> 34#include <sys/kernel.h>
35#include <sys/systm.h> 35#include <sys/systm.h>
36#include <sys/disklabel.h> 36#include <sys/disklabel.h>
37#include <sys/proc.h> 37#include <sys/proc.h>
38#include <sys/buf.h> 38#include <sys/buf.h>
39 39
40#include <dev/ata/atareg.h> 40#include <dev/ata/atareg.h>
41#include <dev/ata/satavar.h> 41#include <dev/ata/satavar.h>
42#include <dev/ata/satareg.h> 42#include <dev/ata/satareg.h>
@@ -759,27 +759,28 @@ ahci_cmd_start(struct ata_channel *chp,  @@ -759,27 +759,28 @@ ahci_cmd_start(struct ata_channel *chp,
759 AHCIDEBUG_PRINT(("ahci_cmd_start CI 0x%x\n", 759 AHCIDEBUG_PRINT(("ahci_cmd_start CI 0x%x\n",
760 AHCI_READ(sc, AHCI_P_CI(chp->ch_channel))), DEBUG_XFERS); 760 AHCI_READ(sc, AHCI_P_CI(chp->ch_channel))), DEBUG_XFERS);
761 761
762 cmd_tbl = achp->ahcic_cmd_tbl[slot]; 762 cmd_tbl = achp->ahcic_cmd_tbl[slot];
763 AHCIDEBUG_PRINT(("%s port %d tbl %p\n", AHCINAME(sc), chp->ch_channel, 763 AHCIDEBUG_PRINT(("%s port %d tbl %p\n", AHCINAME(sc), chp->ch_channel,
764 cmd_tbl), DEBUG_XFERS); 764 cmd_tbl), DEBUG_XFERS);
765 765
766 satafis_rhd_construct_cmd(ata_c, cmd_tbl->cmdt_cfis); 766 satafis_rhd_construct_cmd(ata_c, cmd_tbl->cmdt_cfis);
767 767
768 cmd_h = &achp->ahcic_cmdh[slot]; 768 cmd_h = &achp->ahcic_cmdh[slot];
769 AHCIDEBUG_PRINT(("%s port %d header %p\n", AHCINAME(sc), 769 AHCIDEBUG_PRINT(("%s port %d header %p\n", AHCINAME(sc),
770 chp->ch_channel, cmd_h), DEBUG_XFERS); 770 chp->ch_channel, cmd_h), DEBUG_XFERS);
771 if (ahci_dma_setup(chp, slot, 771 if (ahci_dma_setup(chp, slot,
772 (ata_c->flags & (AT_READ|AT_WRITE)) ? ata_c->data : NULL, 772 (ata_c->flags & (AT_READ|AT_WRITE) && ata_c->bcount > 0) ?
 773 ata_c->data : NULL,
773 ata_c->bcount, 774 ata_c->bcount,
774 (ata_c->flags & AT_READ) ? BUS_DMA_READ : BUS_DMA_WRITE)) { 775 (ata_c->flags & AT_READ) ? BUS_DMA_READ : BUS_DMA_WRITE)) {
775 ata_c->flags |= AT_DF; 776 ata_c->flags |= AT_DF;
776 ahci_cmd_complete(chp, xfer, slot); 777 ahci_cmd_complete(chp, xfer, slot);
777 return; 778 return;
778 } 779 }
779 cmd_h->cmdh_flags = htole16( 780 cmd_h->cmdh_flags = htole16(
780 ((ata_c->flags & AT_WRITE) ? AHCI_CMDH_F_WR : 0) | 781 ((ata_c->flags & AT_WRITE) ? AHCI_CMDH_F_WR : 0) |
781 RHD_FISLEN / 4); 782 RHD_FISLEN / 4);
782 cmd_h->cmdh_prdbc = 0; 783 cmd_h->cmdh_prdbc = 0;
783 AHCI_CMDH_SYNC(sc, achp, slot, 784 AHCI_CMDH_SYNC(sc, achp, slot,
784 BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 785 BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
785 786
@@ -894,27 +895,27 @@ ahci_cmd_done(struct ata_channel *chp, s @@ -894,27 +895,27 @@ ahci_cmd_done(struct ata_channel *chp, s
894{ 895{
895 struct ahci_softc *sc = (struct ahci_softc *)chp->ch_atac; 896 struct ahci_softc *sc = (struct ahci_softc *)chp->ch_atac;
896 struct ahci_channel *achp = (struct ahci_channel *)chp; 897 struct ahci_channel *achp = (struct ahci_channel *)chp;
897 struct ata_command *ata_c = xfer->c_cmd; 898 struct ata_command *ata_c = xfer->c_cmd;
898 uint16_t *idwordbuf; 899 uint16_t *idwordbuf;
899 int i; 900 int i;
900 901
901 AHCIDEBUG_PRINT(("ahci_cmd_done channel %d\n", chp->ch_channel), 902 AHCIDEBUG_PRINT(("ahci_cmd_done channel %d\n", chp->ch_channel),
902 DEBUG_FUNCS); 903 DEBUG_FUNCS);
903 904
904 /* this comamnd is not active any more */ 905 /* this comamnd is not active any more */
905 achp->ahcic_cmds_active &= ~(1 << slot); 906 achp->ahcic_cmds_active &= ~(1 << slot);
906 907
907 if (ata_c->flags & (AT_READ|AT_WRITE)) { 908 if (ata_c->flags & (AT_READ|AT_WRITE) && ata_c->bcount > 0) {
908 bus_dmamap_sync(sc->sc_dmat, achp->ahcic_datad[slot], 0, 909 bus_dmamap_sync(sc->sc_dmat, achp->ahcic_datad[slot], 0,
909 achp->ahcic_datad[slot]->dm_mapsize, 910 achp->ahcic_datad[slot]->dm_mapsize,
910 (ata_c->flags & AT_READ) ? BUS_DMASYNC_POSTREAD : 911 (ata_c->flags & AT_READ) ? BUS_DMASYNC_POSTREAD :
911 BUS_DMASYNC_POSTWRITE); 912 BUS_DMASYNC_POSTWRITE);
912 bus_dmamap_unload(sc->sc_dmat, achp->ahcic_datad[slot]); 913 bus_dmamap_unload(sc->sc_dmat, achp->ahcic_datad[slot]);
913 } 914 }
914 915
915 AHCI_CMDH_SYNC(sc, achp, slot, 916 AHCI_CMDH_SYNC(sc, achp, slot,
916 BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); 917 BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
917 918
918 /* ata(4) expects IDENTIFY data to be in host endianess */ 919 /* ata(4) expects IDENTIFY data to be in host endianess */
919 if (ata_c->r_command == WDCC_IDENTIFY || 920 if (ata_c->r_command == WDCC_IDENTIFY ||
920 ata_c->r_command == ATAPI_IDENTIFY_DEVICE) { 921 ata_c->r_command == ATAPI_IDENTIFY_DEVICE) {