From owner-freebsd-bugs@FreeBSD.ORG Thu Nov 1 21:50:03 2007 Return-Path: Delivered-To: freebsd-bugs@hub.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 2306E16A418 for ; Thu, 1 Nov 2007 21:50:03 +0000 (UTC) (envelope-from gnats@FreeBSD.org) Received: from freefall.freebsd.org (freefall.freebsd.org [IPv6:2001:4f8:fff6::28]) by mx1.freebsd.org (Postfix) with ESMTP id 0E96413C4B0 for ; Thu, 1 Nov 2007 21:50:03 +0000 (UTC) (envelope-from gnats@FreeBSD.org) Received: from freefall.freebsd.org (gnats@localhost [127.0.0.1]) by freefall.freebsd.org (8.14.1/8.14.1) with ESMTP id lA1Lo2Bi040751 for ; Thu, 1 Nov 2007 21:50:02 GMT (envelope-from gnats@freefall.freebsd.org) Received: (from gnats@localhost) by freefall.freebsd.org (8.14.1/8.14.1/Submit) id lA1Lo2Qw040750; Thu, 1 Nov 2007 21:50:02 GMT (envelope-from gnats) Date: Thu, 1 Nov 2007 21:50:02 GMT Message-Id: <200711012150.lA1Lo2Qw040750@freefall.freebsd.org> To: freebsd-bugs@FreeBSD.org From: Alexander Sabourenkov Cc: Subject: Re: kern/115337: [ata] Promise SATA300 TX4 breaks with zfs in 7.0-current X-BeenThere: freebsd-bugs@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list Reply-To: Alexander Sabourenkov List-Id: Bug reports List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 01 Nov 2007 21:50:03 -0000 The following reply was made to PR kern/115337; it has been noted by GNATS. From: Alexander Sabourenkov To: bug-followup@FreeBSD.org Cc: ss.alert@online.no Subject: Re: kern/115337: [ata] Promise SATA300 TX4 breaks with zfs in 7.0-current Date: Fri, 02 Nov 2007 01:37:18 +0300 I have ported the workaround for the hardware bug that causes data corruption on Promise SATA300 TX4 cards to RELENG_7. Bug description: SATA300 TX4 hardware chokes if last PRD entry (in a dma transfer) is larger than 164 bytes. This was found while analysing vendor-supplied linux driver. Workaround: Split trailing PRD entry if it's larger that 164 bytes. Two supplied patches do fix problem on my machine. There is, however, a style problem with them. It seems like PRD entry count is limited at 256. I have not found a good way to guarantee that one entry is always available to do the split, thus the ugly solution of patching ata-dma.c. Patches, patched and original files are at http://lxnt.info/tx4/freebsd/. --- ata-chipset.c.orig 2007-11-02 01:05:49.000000000 +0300 +++ ata-chipset.c 2007-11-02 01:05:49.000000000 +0300 @@ -142,6 +142,7 @@ static int ata_promise_mio_command(struct ata_request *request); static void ata_promise_mio_reset(device_t dev); static void ata_promise_mio_dmainit(device_t dev); +static void ata_promise_mio_dmasetprd(void *xsc, bus_dma_segment_t *segs, int nsegs, int error); static void ata_promise_mio_setmode(device_t dev, int mode); static void ata_promise_sx4_intr(void *data); static int ata_promise_sx4_command(struct ata_request *request); @@ -185,7 +186,6 @@ static int ata_check_80pin(device_t dev, int mode); static int ata_mode2idx(int mode); - /* * generic ATA support functions */ @@ -3759,8 +3759,44 @@ static void ata_promise_mio_dmainit(device_t dev) { + struct ata_channel *ch = device_get_softc(dev); + /* note start and stop are not used here */ ata_dmainit(dev); + + if (ch->dma) + ch->dma->setprd = ata_promise_mio_dmasetprd; +} + +static void +ata_promise_mio_dmasetprd(void *xsc, bus_dma_segment_t *segs, int nsegs, int error) +{ + #define PDC_MAXLASTSGSIZE 41*4 + struct ata_dmasetprd_args *args = xsc; + struct ata_dma_prdentry *prd = args->dmatab; + int i; + + if ((args->error = error)) + return; + + for (i = 0; i < nsegs; i++) { + prd[i].addr = htole32(segs[i].ds_addr); + prd[i].count = htole32(segs[i].ds_len); + } + + if (segs[i - 1].ds_len > PDC_MAXLASTSGSIZE) { + /* + printf("splitting trailing PRD of %ld (limit %d)\n", segs[i - 1].ds_len, PDC_MAXLASTSGSIZE); + */ + prd[i - 1].count = htole32(segs[i - 1].ds_len - PDC_MAXLASTSGSIZE); + prd[i].count = htole32(PDC_MAXLASTSGSIZE); + prd[i].addr = htole32(segs[i - 1].ds_addr + PDC_MAXLASTSGSIZE); + i ++; + nsegs ++; + } + + prd[i - 1].count |= htole32(ATA_DMA_EOT); + args->nsegs = nsegs; } static void --- ata-dma.c.orig 2007-11-02 01:05:53.000000000 +0300 +++ ata-dma.c 2007-11-02 01:05:53.000000000 +0300 @@ -113,7 +113,7 @@ if (bus_dma_tag_create(ch->dma->dmatag,ch->dma->alignment,ch->dma->boundary, ch->dma->max_address, BUS_SPACE_MAXADDR, NULL, NULL, ch->dma->max_iosize, - ATA_DMA_ENTRIES, ch->dma->segsize, + ATA_DMA_ENTRIES - 1, ch->dma->segsize, 0, NULL, NULL, &ch->dma->data_tag)) goto error; -- ./lxnt