NetBSD Problem Report #39511

From www@NetBSD.org  Wed Sep 10 15:09:54 2008
Return-Path: <www@NetBSD.org>
Received: from mail.netbsd.org (mail.netbsd.org [204.152.190.11])
	by narn.NetBSD.org (Postfix) with ESMTP id C706163B92A
	for <gnats-bugs@gnats.netbsd.org>; Wed, 10 Sep 2008 15:09:54 +0000 (UTC)
Message-Id: <20080910150954.96C8663B853@narn.NetBSD.org>
Date: Wed, 10 Sep 2008 15:09:54 +0000 (UTC)
From: xtraeme@gmail.com
Reply-To: xtraeme@gmail.com
To: gnats-bugs@NetBSD.org
Subject: ataraid(4): Intel MatrixRAID support
X-Send-Pr-Version: www-1.0

>Number:         39511
>Category:       kern
>Synopsis:       ataraid(4): Intel MatrixRAID support
>Confidential:   no
>Severity:       non-critical
>Priority:       high
>Responsible:    tron
>State:          closed
>Class:          change-request
>Submitter-Id:   net
>Arrival-Date:   Wed Sep 10 15:10:01 +0000 2008
>Closed-Date:    Thu Sep 11 11:32:55 +0000 2008
>Last-Modified:  Thu Sep 11 11:32:55 +0000 2008
>Originator:     Juan RP
>Release:        Latest
>Organization:
>Environment:
NetBSD sasha 4.99.72 NetBSD 4.99.72 (MASTER.DEBUG) #4: Wed Sep 10 16:52:44 CEST 2008  juan@sasha:/home/juan/build/amd64/obj/sys/arch/amd64/compile/MASTER.DEBUG amd64
>Description:
I've adapted the code from FreeBSD's ataraid(4) driver to support
volumes from Intel MatrixRAID controllers.

$ dmesg|grep -E '(ld0|ataraid)'
ataraid0: found 1 RAID volume
ld0 at ataraid0 vendtype 5 unit 0: Intel MatrixRAID ATA RAID-1 array
ld0: 233 GB, 30515 cyl, 255 head, 63 sec, 512 bytes/sect x 490229760 sectors
$

Due to problems encountered when multiple volumes are used, I chose
to only use the first volume available. This should be enough for now.

Will send a patch in a short time.
>How-To-Repeat:

>Fix:

>Release-Note:

>Audit-Trail:
From: Juan RP <xtraeme@gmail.com>
To: gnats-bugs@NetBSD.org
Cc: 
Subject: Re: kern/39511: ataraid(4): Intel MatrixRAID support
Date: Wed, 10 Sep 2008 17:14:17 +0200

 Here's the patch:

 Index: share/man/man4/ataraid.4
 ===================================================================
 RCS file: /cvsroot/src/share/man/man4/ataraid.4,v
 retrieving revision 1.10
 diff -b -u -p -r1.10 ataraid.4
 --- share/man/man4/ataraid.4	5 Sep 2008 13:38:58 -0000	1.10
 +++ share/man/man4/ataraid.4	10 Sep 2008 15:11:41 -0000
 @@ -27,7 +27,7 @@
  .\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  .\" POSSIBILITY OF SUCH DAMAGE.
  .\"
 -.Dd September 5, 2008
 +.Dd September 10, 2008
  .Dt ATARAID 4
  .Os
  .Sh NAME
 @@ -35,6 +35,7 @@
  .Nd software BIOS RAID
  .Sh SYNOPSIS
  .Cd "pseudo-device ataraid"
 +.Cd "ld* at ataraid? vendtype ? unit ?"
  .Sh DESCRIPTION
  The
  .Nm
 @@ -50,6 +51,8 @@ The driver currently supports RAID forma
  .It
  Adaptec HostRAID (found in Intel 6300ESB)
  .It
 +Intel MatrixRAID
 +.It
  JMicron RAID
  .It
  nVidia MediaShield
 @@ -83,3 +86,7 @@ state, and it does not do the right thin
  .Pp
  At least part of the reason for this is that the publically-available
  information on these formats is quite limited.
 +.Pp
 +The support with Intel MatrixRAID controller is incomplete, and only
 +the first volume found will be used. This will be fixed in future
 +revisions of this driver.
 Index: sys/dev/ata/ata_raid.c
 ===================================================================
 RCS file: /cvsroot/src/sys/dev/ata/ata_raid.c,v
 retrieving revision 1.31
 diff -b -u -p -r1.31 ata_raid.c
 --- sys/dev/ata/ata_raid.c	5 Sep 2008 12:37:13 -0000	1.31
 +++ sys/dev/ata/ata_raid.c	10 Sep 2008 15:11:41 -0000
 @@ -116,7 +116,8 @@ ata_raid_type_name(u_int type)
  		"Adaptec",
  		"VIA V-RAID",
  		"nVidia",
 -		"JMicron"
 +		"JMicron",
 +		"Intel MatrixRAID"
  	};

  	if (type < __arraycount(ata_raid_type_names))
 @@ -250,6 +251,8 @@ ata_raid_check_component(device_t self)
  		return;
  	if (ata_raid_read_config_jmicron(sc) == 0)
  		return;
 +	if (ata_raid_read_config_intel(sc) == 0)
 +		return;
  }

  struct ataraid_array_info *
 Index: sys/dev/ata/ata_raid_intel.c
 ===================================================================
 RCS file: sys/dev/ata/ata_raid_intel.c
 diff -N sys/dev/ata/ata_raid_intel.c
 --- /dev/null	1 Jan 1970 00:00:00 -0000
 +++ sys/dev/ata/ata_raid_intel.c	10 Sep 2008 15:11:41 -0000
 @@ -0,0 +1,281 @@
 +/*	$NetBSD$	*/
 +
 +/*-
 + * Copyright (c) 2000-2008 S_ren Schmidt <sos@FreeBSD.org>
 + * All rights reserved.
 + *
 + * Redistribution and use in source and binary forms, with or without
 + * modification, are permitted provided that the following conditions
 + * are met:
 + * 1. Redistributions of source code must retain the above copyright
 + *    notice, this list of conditions and the following disclaimer,
 + *    without modification, immediately at the beginning of the file.
 + * 2. Redistributions in binary form must reproduce the above copyright
 + *    notice, this list of conditions and the following disclaimer in the
 + *    documentation and/or other materials provided with the distribution.
 + *
 + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
 + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
 + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 + */
 +
 +/*
 + * Support for parsing Intel MatrixRAID controller configuration blocks.
 + *
 + * Adapted to NetBSD by Juan Romero Pardines (xtraeme@gmail.org).
 + */
 +
 +#include <sys/cdefs.h>
 +__KERNEL_RCSID(0, "$NetBSD: ata_raid_jmicron.c,v 1.1 2008/09/05 12:37:13 tron Exp $");
 +
 +#include <sys/param.h>
 +#include <sys/buf.h>
 +#include <sys/bufq.h>
 +#include <sys/conf.h>
 +#include <sys/device.h>
 +#include <sys/disk.h>
 +#include <sys/disklabel.h>
 +#include <sys/fcntl.h>
 +#include <sys/malloc.h>
 +#include <sys/vnode.h>
 +#include <sys/kauth.h>
 +
 +#include <miscfs/specfs/specdev.h>
 +
 +#include <dev/ata/atareg.h>
 +#include <dev/ata/atavar.h>
 +#include <dev/ata/wdvar.h>
 +
 +#include <dev/ata/ata_raidreg.h>
 +#include <dev/ata/ata_raidvar.h>
 +
 +#ifdef ATA_RAID_DEBUG
 +#define	DPRINTF(x)	printf x
 +#else
 +#define	DPRINTF(x)	/* nothing */
 +#endif
 +
 +#ifdef ATA_RAID_DEBUG
 +static const char *
 +ata_raid_intel_type(int type)
 +{
 +	static char buffer[16];
 +
 +	switch (type) {
 +	case INTEL_T_RAID0:
 +		return "RAID0";
 +	case INTEL_T_RAID1:
 +		return "RAID1";
 +	case INTEL_T_RAID5:
 +		return "RAID5";
 +	default:
 +		sprintf(buffer, "UNKNOWN 0x%02x", type);
 +		return buffer;
 +	}
 +}
 +
 +static void
 +ata_raid_intel_print_info(struct intel_raid_conf *info)
 +{
 +	struct intel_raid_mapping *map;
 +	int i, j;
 + 
 +	printf("********* ATA Intel MatrixRAID Metadata *********\n");
 +	printf("intel_id		<%.24s>\n", info->intel_id);
 +	printf("version			<%.6s>\n", info->version);
 +	printf("checksum		0x%08x\n", info->checksum);
 +	printf("config_size		0x%08x\n", info->config_size);
 +	printf("config_id		0x%08x\n", info->config_id);
 +	printf("generation		0x%08x\n", info->generation);
 +	printf("total_disks		%u\n", info->total_disks);
 +	printf("total_volumes		%u\n", info->total_volumes);
 +	printf("DISK#	serial	disk	sectors	disk_id	flags\n");
 +	for (i = 0; i < info->total_disks; i++) {
 +		printf("    %d <%16.s> %u 0x%08x 0x%08x\n",
 +		    i, info->disk[i].serial, info->disk[i].sectors,
 +		    info->disk[i].id, info->disk[i].flags);
 +	}
 +
 +	map = (struct intel_raid_mapping *)&info->disk[info->total_disks];
 +	for (j = 0; j < info->total_volumes; j++) {
 +		printf("name		%.16s\n", map->name);
 +		printf("total_sectors	%ju\n", map->total_sectors);
 +		printf("state		%u\n", map->state);
 +		printf("reserved	%u\n", map->reserved);
 +		printf("offset		%u\n", map->offset);
 +		printf("disk_sectors	%u\n", map->disk_sectors);
 +		printf("stripe_count	%u\n", map->stripe_count);
 +		printf("stripe_sectors	%u\n", map->stripe_sectors);
 +		printf("status		%u\n", map->status);
 +		printf("type		%s\n", ata_raid_intel_type(map->type));
 +		printf("total_disks	%u\n", map->total_disks);
 +		printf("magic[0]	0x%02x\n", map->magic[0]);
 +		printf("magic[1]	0x%02x\n", map->magic[1]);
 +		printf("magic[2]	0x%02x\n", map->magic[2]);
 +		for (i = 0; i < map->total_disks; i++)
 +			printf("    disk %d at disk_idx 0x%08x\n",
 +			    i, map->disk_idx[i]);
 +
 +		map = (struct intel_raid_mapping *)
 +		    &map->disk_idx[map->total_disks];
 +	}
 +	printf("=================================================\n");
 +}
 +#endif
 +
 +int
 +ata_raid_read_config_intel(struct wd_softc *sc)
 +{
 +	struct intel_raid_conf *info;
 +	struct intel_raid_mapping *map;
 +	struct ataraid_array_info *aai;
 +	struct ataraid_disk_info *adi;
 +	struct vnode *vp;
 +	uint32_t checksum, *ptr;
 +	static int curdrive;
 +	int bmajor, count, error = 0;
 +	char *tmp;
 +	dev_t dev;
 +
 +	info = malloc(1536, M_DEVBUF, M_WAITOK|M_ZERO);
 +
 +	bmajor = devsw_name2blk(device_xname(sc->sc_dev), NULL, 0);
 +
 +	/* Get a vnode for the raw partition of this disk. */
 +	dev = MAKEDISKDEV(bmajor, device_unit(sc->sc_dev), RAW_PART);
 +	error = bdevvp(dev, &vp);
 +	if (error)
 +		goto out;
 +
 +	error = VOP_OPEN(vp, FREAD, NOCRED);
 +	if (error) {
 +		vput(vp);
 +		goto out;
 +	}
 +
 +	error = ata_raid_config_block_rw(vp, INTEL_LBA(sc), info,
 +	    1024, B_READ);
 +	VOP_CLOSE(vp, FREAD, NOCRED);
 +	vput(vp);
 +	if (error) {
 +		DPRINTF(("%s: error %d reading Intel MatrixRAID config block\n",
 +		    device_xname(sc->sc_dev), error));
 +		goto out;
 +	}
 +
 +	tmp = (char *)info;
 +	(void)memcpy(tmp + 1024, tmp, 512);
 +	(void)memcpy(tmp, tmp + 512, 1024);
 +	(void)memset(tmp + 1024, 0, 512);
 +
 +	/* Check if this is a Intel RAID struct */
 +	if (strncmp(info->intel_id, INTEL_MAGIC, strlen(INTEL_MAGIC))) {
 +		DPRINTF(("%s: Intel MatrixRAID signature check failed\n",
 +		    device_xname(sc->sc_dev)));
 +		error = ESRCH;
 +		goto out;
 +	}
 +
 +	/* calculate checksum and compare for valid */
 +	for (checksum = 0, ptr = (uint32_t *)info, count = 0;
 +	     count < (info->config_size / sizeof(uint32_t)); count++)
 +		checksum += *ptr++;
 +
 +	checksum -= info->checksum;
 +	if (checksum != info->checksum) {
 +		DPRINTF(("%s: Intel MatrixRAID checksum failed 0x%x != 0x%x\n",
 +		    device_xname(sc->sc_dev), checksum, info->checksum));
 +		error = ESRCH;
 +		goto out;
 +	}
 +
 +#ifdef ATA_RAID_DEBUG
 +	ata_raid_intel_print_info(info);
 +#endif
 +
 +	/* This one points to the first volume */
 +	map = (struct intel_raid_mapping *)&info->disk[info->total_disks];
 +
 +	/*
 +	 * Lookup or allocate a new array info structure for this array.
 +	 *
 +	 * TODO:
 +	 * We only look at the first volume. Need to solve a few issues before
 +	 * multiple volumes are working correctly.
 +	 */
 +	aai = ata_raid_get_array_info(ATA_RAID_TYPE_INTEL, 0); 
 +
 +	/* Fill in array info */
 +	aai->aai_generation = info->generation;
 +	aai->aai_status = AAI_S_READY;
 +
 +	switch (map->type) {
 +	case INTEL_T_RAID0:
 +		aai->aai_level = AAI_L_RAID0;
 +		aai->aai_width = info->total_disks;
 +		break;
 +	case INTEL_T_RAID1:
 +		aai->aai_level = AAI_L_RAID1;
 +		aai->aai_width = 1;
 +		break;
 +	default:
 +		DPRINTF(("%s: unknown Intel MatrixRAID type 0x%02x\n",
 +		    sc->sc_dev->dv_xname, map->type));
 +		error = EINVAL;
 +		goto out;
 +	}
 +
 +	switch (map->state) {
 +	case INTEL_S_DEGRADED:
 +		aai->aai_status |= AAI_S_DEGRADED;
 +		break;
 +	case INTEL_S_DISABLED:
 +	case INTEL_S_FAILURE:
 +		aai->aai_status &= ~AAI_S_READY;
 +		break;
 +	}
 +
 +	aai->aai_type = ATA_RAID_TYPE_INTEL;
 +	aai->aai_capacity = map->total_sectors;
 +	aai->aai_interleave = map->stripe_sectors;
 +	aai->aai_ndisks = map->total_disks;
 +	aai->aai_heads = 255;
 +	aai->aai_sectors = 63;
 +	aai->aai_cylinders =
 +	    aai->aai_capacity / (aai->aai_heads * aai->aai_sectors);
 +	aai->aai_offset = map->offset;
 +	aai->aai_reserved = 3;
 +
 +	/* Fill in disk info */
 +	adi = &aai->aai_disks[curdrive];
 +	adi->adi_status = 0;
 +
 +	if (info->disk[curdrive].flags & INTEL_F_ONLINE)
 +		adi->adi_status |= ADI_S_ONLINE;
 +	if (info->disk[curdrive].flags & INTEL_F_ASSIGNED)
 +		adi->adi_status |= ADI_S_ASSIGNED;
 +	if (info->disk[curdrive].flags & INTEL_F_SPARE) {
 +		adi->adi_status &= ~ADI_S_ONLINE;
 +		adi->adi_status |= ADI_S_SPARE;
 +	}
 +	if (info->disk[curdrive].flags & INTEL_F_DOWN)
 +		adi->adi_status &= ~ADI_S_ONLINE;
 +
 +	if (adi->adi_status) {
 +		adi->adi_dev = sc->sc_dev;
 +		adi->adi_sectors = info->disk[curdrive].sectors;
 +		adi->adi_compsize = adi->adi_sectors - aai->aai_reserved;
 +		curdrive++;
 +	}
 +
 + out:
 +	free(info, M_DEVBUF);
 +	return error;
 +}
 Index: sys/dev/ata/ata_raidreg.h
 ===================================================================
 RCS file: /cvsroot/src/sys/dev/ata/ata_raidreg.h,v
 retrieving revision 1.7
 diff -b -u -p -r1.7 ata_raidreg.h
 --- sys/dev/ata/ata_raidreg.h	5 Sep 2008 12:37:13 -0000	1.7
 +++ sys/dev/ata/ata_raidreg.h	10 Sep 2008 15:11:42 -0000
 @@ -293,4 +293,67 @@ struct jmicron_raid_conf {
  	uint8_t 	filler_5[384];
  };

 +/* Intel MatrixRAID metadata */
 +#define INTEL_LBA(wd)		((wd)->sc_capacity - 3)
 +
 +struct intel_raid_conf {
 +	uint8_t		intel_id[24];
 +#define INTEL_MAGIC		"Intel Raid ISM Cfg Sig. "
 +
 +	uint8_t		version[6];
 +#define INTEL_VERSION_1100	"1.1.00"
 +#define INTEL_VERSION_1201	"1.2.01"
 +#define INTEL_VERSION_1202	"1.2.02"
 +
 +	uint8_t		dummy_0[2];
 +	uint32_t	checksum;
 +	uint32_t	config_size;
 +	uint32_t	config_id;
 +	uint32_t	generation;
 +	uint32_t	dummy_1[2];
 +	uint8_t		total_disks;
 +	uint8_t		total_volumes;
 +	uint8_t 	dummy_2[2];
 +	uint32_t	filler_0[39];
 +	struct {
 +		uint8_t		serial[16];
 +		uint32_t	sectors;
 +		uint32_t	id;
 +		uint32_t	flags;
 +#define INTEL_F_SPARE			0x01
 +#define INTEL_F_ASSIGNED		0x02
 +#define INTEL_F_DOWN			0x04
 +#define INTEL_F_ONLINE			0x08
 +		uint32_t	filler[5];
 +	} __packed disk[1];
 +	uint32_t	filler_1[62];
 +} __packed;
 +
 +struct intel_raid_mapping {
 +	uint8_t		name[16];
 +	uint64_t	total_sectors __packed;
 +	uint32_t	state;
 +	uint32_t	reserved;
 +	uint32_t	filler_0[20];
 +	uint32_t	offset;
 +	uint32_t	disk_sectors;
 +	uint32_t	stripe_count;
 +	uint16_t	stripe_sectors;
 +	uint8_t		status;
 +#define INTEL_S_READY		0x00
 +#define INTEL_S_DISABLED	0x01
 +#define INTEL_S_DEGRADED	0x02
 +#define INTEL_S_FAILURE		0x03
 +
 +	uint8_t		type;
 +#define INTEL_T_RAID0		0x00
 +#define INTEL_T_RAID1		0x01
 +#define INTEL_T_RAID5		0x05
 +
 +	uint8_t		total_disks;
 +	uint8_t		magic[3];
 +	uint32_t	filler_1[7];
 +	uint32_t	disk_idx[1];
 +} __packed;
 +
  #endif /* _DEV_PCI_PCIIDE_PROMISE_RAID_H_ */
 Index: sys/dev/ata/ata_raidvar.h
 ===================================================================
 RCS file: /cvsroot/src/sys/dev/ata/ata_raidvar.h,v
 retrieving revision 1.7
 diff -b -u -p -r1.7 ata_raidvar.h
 --- sys/dev/ata/ata_raidvar.h	5 Sep 2008 12:37:13 -0000	1.7
 +++ sys/dev/ata/ata_raidvar.h	10 Sep 2008 15:11:42 -0000
 @@ -53,7 +53,8 @@
  #define	ATA_RAID_TYPE_VIA	2
  #define	ATA_RAID_TYPE_NVIDIA	3
  #define ATA_RAID_TYPE_JMICRON	4
 -#define	ATA_RAID_TYPE_MAX	4
 +#define	ATA_RAID_TYPE_INTEL	5
 +#define	ATA_RAID_TYPE_MAX	5

  /*
   * Max # of disks supported by a single array.  This is limited by
 @@ -138,4 +139,7 @@ int	ata_raid_read_config_nvidia(struct w
  /* JMicron RAID support */
  int	ata_raid_read_config_jmicron(struct wd_softc *);

 +/* Intel MatrixRAID support */
 +int	ata_raid_read_config_intel(struct wd_softc *);
 +
  #endif /* _DEV_ATA_ATA_RAIDVAR_H_ */
 Index: sys/dev/ata/files.ata
 ===================================================================
 RCS file: /cvsroot/src/sys/dev/ata/files.ata,v
 retrieving revision 1.18
 diff -b -u -p -r1.18 files.ata
 --- sys/dev/ata/files.ata	5 Sep 2008 12:37:13 -0000	1.18
 +++ sys/dev/ata/files.ata	10 Sep 2008 15:11:42 -0000
 @@ -23,6 +23,7 @@ file	dev/ata/ata_raid_adaptec.c	ataraid
  file	dev/ata/ata_raid_nvidia.c	ataraid
  file	dev/ata/ata_raid_via.c		ataraid
  file	dev/ata/ata_raid_jmicron.c	ataraid
 +file	dev/ata/ata_raid_intel.c	ataraid

  attach	ld at ataraid with ld_ataraid
  file	dev/ata/ld_ataraid.c		ld_ataraid

Responsible-Changed-From-To: kern-bug-people->tron
Responsible-Changed-By: tron@NetBSD.org
Responsible-Changed-When: Thu, 11 Sep 2008 10:50:28 +0000
Responsible-Changed-Why:
I'll handle this PR.


From: Matthias Scheler <tron@netbsd.org>
To: gnats-bugs@gnats.NetBSD.org
Cc: 
Subject: PR/39511 CVS commit: src
Date: Thu, 11 Sep 2008 11:08:50 +0000 (UTC)

 Module Name:	src
 Committed By:	tron
 Date:		Thu Sep 11 11:08:50 UTC 2008

 Modified Files:
 	src/share/man/man4: ataraid.4
 	src/sys/dev/ata: ata_raid.c ata_raidreg.h ata_raidvar.h files.ata
 Added Files:
 	src/sys/dev/ata: ata_raid_intel.c

 Log Message:
 Add support for Intel MatrixRAID to ataraid(4). It is currently limited
 to one volume.

 The driver was provided by Juan RP in PR kern/39511.


 To generate a diff of this commit:
 cvs rdiff -r1.10 -r1.11 src/share/man/man4/ataraid.4
 cvs rdiff -r1.31 -r1.32 src/sys/dev/ata/ata_raid.c
 cvs rdiff -r0 -r1.1 src/sys/dev/ata/ata_raid_intel.c
 cvs rdiff -r1.7 -r1.8 src/sys/dev/ata/ata_raidreg.h \
     src/sys/dev/ata/ata_raidvar.h
 cvs rdiff -r1.18 -r1.19 src/sys/dev/ata/files.ata

 Please note that diffs are not public domain; they are subject to the
 copyright notices on the relevant files.

State-Changed-From-To: open->closed
State-Changed-By: tron@NetBSD.org
State-Changed-When: Thu, 11 Sep 2008 11:32:55 +0000
State-Changed-Why:
I've committed your code changes. Thanks a lot for the contribution.


>Unformatted:

NetBSD Home
NetBSD PR Database Search

(Contact us) $NetBSD: query-full-pr,v 1.39 2013/11/01 18:47:49 spz Exp $
$NetBSD: gnats_config.sh,v 1.8 2006/05/07 09:23:38 tsutsui Exp $
Copyright © 1994-2007 The NetBSD Foundation, Inc. ALL RIGHTS RESERVED.