From owner-freebsd-current@FreeBSD.ORG Mon Aug 2 16:15:24 2004 Return-Path: Delivered-To: freebsd-current@freebsd.org Received: from mx1.FreeBSD.org (mx1.freebsd.org [216.136.204.125]) by hub.freebsd.org (Postfix) with ESMTP id 2253416A4CE for ; Mon, 2 Aug 2004 16:15:24 +0000 (GMT) Received: from will.iki.fi (will.iki.fi [217.169.64.20]) by mx1.FreeBSD.org (Postfix) with ESMTP id D18AB43D1F for ; Mon, 2 Aug 2004 16:15:23 +0000 (GMT) (envelope-from will+freebsd-current@will.iki.fi) Received: from [10.129.39.131] (b212-54-23-216.elisa-laajakaista.fi [212.54.23.216]) by will.iki.fi (Postfix) with ESMTP id B826161; Mon, 2 Aug 2004 19:15:20 +0300 (EEST) Message-ID: <410E688D.7020709@will.iki.fi> Date: Mon, 02 Aug 2004 19:15:09 +0300 From: Ville-Pertti Keinonen User-Agent: Mozilla Thunderbird 0.7.1 (X11/20040708) X-Accept-Language: en-us, en MIME-Version: 1.0 To: freebsd-current@freebsd.org, =?ISO-8859-1?Q?S=F8ren_Schmidt?= Content-Type: multipart/mixed; boundary="------------080006000409020906080504" Subject: ATA driver races with interrupts X-BeenThere: freebsd-current@freebsd.org X-Mailman-Version: 2.1.1 Precedence: list List-Id: Discussions about the use of FreeBSD-current List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 02 Aug 2004 16:15:24 -0000 This is a multi-part message in MIME format. --------------080006000409020906080504 Content-Type: text/plain; charset=ISO-8859-1; format=flowed Content-Transfer-Encoding: 7bit I've finally had time to track down a long-standing, easily repeatable (on my system, anyhow) lockup. When accessing two SATA disks on different channels of the same controller simultaneously (both channels sharing the same interrupt), an interrupt on one channel could retire the request on the other channel if the interrupt occurred during ata_generic_transaction (after ch->running is set, before the actual transaction begins), leaving the device stuck (with ch->dma->flags set as ATA_DMA_ACTIVE but ch->running == NULL), often with a message of "already active DMA on this device". Attached is a patch against -current as of a couple of days ago (before the #if 0 of PREEMPTION). I'm not sure whether this is the right way to fix this (e.g. disabling interrupts altogether might be safer), but it seems to work for me. --------------080006000409020906080504 Content-Type: text/plain; name="atafix.diff" Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename="atafix.diff" Index: ata-all.h =================================================================== RCS file: /data/freebsd/src/sys/dev/ata/ata-all.h,v retrieving revision 1.79 diff -u -r1.79 ata-all.h --- ata-all.h 30 Apr 2004 16:21:34 -0000 1.79 +++ ata-all.h 2 Aug 2004 15:54:50 -0000 @@ -339,6 +339,7 @@ #define ATA_48BIT_ACTIVE 0x10 #define ATA_IMMEDIATE_MODE 0x20 #define ATA_HWGONE 0x40 +#define ATA_EXPECT_INTR 0x80 struct ata_device device[2]; /* devices on this channel */ #define MASTER 0x00 Index: ata-lowlevel.c =================================================================== RCS file: /data/freebsd/src/sys/dev/ata/ata-lowlevel.c,v retrieving revision 1.40 diff -u -r1.40 ata-lowlevel.c --- ata-lowlevel.c 24 Jul 2004 19:03:28 -0000 1.40 +++ ata-lowlevel.c 2 Aug 2004 16:11:23 -0000 @@ -81,6 +81,7 @@ } /* record the request as running */ + ch->flags &= ~ATA_EXPECT_INTR; ch->running = request; ATA_DEBUG_RQ(request, "transaction"); @@ -140,6 +141,7 @@ } /* return and wait for interrupt */ + ch->flags |= ATA_EXPECT_INTR; return ATA_OP_CONTINUES; /* ATA DMA data transfer commands */ @@ -169,6 +171,7 @@ } /* return and wait for interrupt */ + ch->flags |= ATA_EXPECT_INTR; return ATA_OP_CONTINUES; /* ATAPI PIO commands */ @@ -225,6 +228,7 @@ ATA_PROTO_ATAPI_12 ? 6 : 8); /* return and wait for interrupt */ + ch->flags |= ATA_EXPECT_INTR; return ATA_OP_CONTINUES; case ATA_R_ATAPI|ATA_R_DMA: @@ -290,6 +294,7 @@ } /* return and wait for interrupt */ + ch->flags |= ATA_EXPECT_INTR; return ATA_OP_CONTINUES; } @@ -308,7 +313,7 @@ int length; /* ignore this interrupt if there is no running request */ - if (!request) + if (!request || !(ch->flags & ATA_EXPECT_INTR)) return; ATA_DEBUG_RQ(request, "interrupt"); --------------080006000409020906080504--