Module Name:    src
Committed By:   martin
Date:           Sat Mar 21 15:18:58 UTC 2020

Modified Files:
        src/external/cddl/osnet/dist/uts/common/fs/zfs [netbsd-9]: vdev_disk.c
        src/sys/dev [netbsd-9]: cgd.c
        src/sys/dev/ata [netbsd-9]: wd.c wdvar.h
        src/sys/dev/dkwedge [netbsd-9]: dk.c
        src/sys/kern [netbsd-9]: subr_disk_open.c
        src/sys/sys [netbsd-9]: disk.h dkio.h

Log Message:
Pull up following revision(s) (requested by riastradh in ticket #788):

        sys/sys/dkio.h: revision 1.26
        sys/dev/dkwedge/dk.c: revision 1.100
        sys/sys/disk.h: revision 1.75
        external/cddl/osnet/dist/uts/common/fs/zfs/vdev_disk.c: revision 1.14
        external/cddl/osnet/dist/uts/common/fs/zfs/vdev_disk.c: revision 1.15
        sys/dev/cgd.c: revision 1.121
        sys/dev/ata/wdvar.h: revision 1.50
        sys/kern/subr_disk_open.c: revision 1.15
        sys/dev/ata/wd.c: revision 1.459

New ioctl DIOCGSECTORALIGN returns sector alignment parameters.

struct disk_sectoralign {
        /* First aligned sector number.  */
        uint32_t dsa_firstaligned;
        /* Number of sectors per aligned unit.  */
        uint32_t dsa_alignment;
};

- Teach wd(4) to get it from ATA.
- Teach cgd(4) to pass it through from the underlying disk.
- Teach dk(4) to pass it through with adjustments.
- Teach zpool (zfs) to take advantage of it.
  => XXX zpool doesn't seem to understand when the vdev's starting
     sector is misaligned.

Missing:
- ccd(4) and raidframe(4) support -- these should support _using_
  DIOCGSECTORALIGN to decide where to start putting ccd or raid
  stripes on disk, and these should perhaps _implement_
  DIOCGSECTORALIGN by reporting the stripe/interleave factor.
- sd(4) support -- I don't know any obvious way to get it from SCSI,
  but if any SCSI wizards know better than I, please feel free to
  teach sd(4) about it!
- any ld(4) attachments -- might be worth teaching the ld drivers for
  nvme and various raid controllers to get the aligned sector size

There's some duplicate logic here for now.  I'm doing it this way,
rather than gathering the logic into a new disklabel_sectoralign
function or something, so that this change is limited to adding a new
ioctl, without any new kernel symbols, in order to make it easy to
pull up to netbsd-9 without worrying about the module ABI.

Make getdiskinfo() compatible with a DIOCGWEDGEINFO.

dkw_parent is defined to hold the disk name as used by disk_find(), not
a partition (i.e. no partition letter appended).

Use utility functions to handle disk geometry.


To generate a diff of this commit:
cvs rdiff -u -r1.11.2.2 -r1.11.2.3 \
    src/external/cddl/osnet/dist/uts/common/fs/zfs/vdev_disk.c
cvs rdiff -u -r1.116 -r1.116.10.1 src/sys/dev/cgd.c
cvs rdiff -u -r1.452 -r1.452.2.1 src/sys/dev/ata/wd.c
cvs rdiff -u -r1.49 -r1.49.4.1 src/sys/dev/ata/wdvar.h
cvs rdiff -u -r1.97 -r1.97.8.1 src/sys/dev/dkwedge/dk.c
cvs rdiff -u -r1.14 -r1.14.4.1 src/sys/kern/subr_disk_open.c
cvs rdiff -u -r1.74 -r1.74.2.1 src/sys/sys/disk.h
cvs rdiff -u -r1.25 -r1.25.4.1 src/sys/sys/dkio.h

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

Modified files:

Index: src/external/cddl/osnet/dist/uts/common/fs/zfs/vdev_disk.c
diff -u src/external/cddl/osnet/dist/uts/common/fs/zfs/vdev_disk.c:1.11.2.2 src/external/cddl/osnet/dist/uts/common/fs/zfs/vdev_disk.c:1.11.2.3
--- src/external/cddl/osnet/dist/uts/common/fs/zfs/vdev_disk.c:1.11.2.2	Sun Dec  8 14:39:07 2019
+++ src/external/cddl/osnet/dist/uts/common/fs/zfs/vdev_disk.c	Sat Mar 21 15:18:57 2020
@@ -35,7 +35,6 @@
 #include <sys/sunldi.h>
 #include <sys/fm/fs/zfs.h>
 #include <sys/disk.h>
-#include <sys/disklabel.h>
 #include <sys/dkio.h>
 #include <sys/workqueue.h>
 
@@ -147,10 +146,12 @@ vdev_disk_open(vdev_t *vd, uint64_t *psi
 	spa_t *spa = vd->vdev_spa;
 	vdev_disk_t *dvd;
 	vnode_t *vp;
-	struct dkwedge_info dkw;
-	struct disk *pdk;
 	int error, cmd;
-	struct partinfo pinfo;
+	uint64_t numsecs;
+	unsigned secsize;
+	struct disk *pdk;
+	struct dkwedge_info dkw;
+	struct disk_sectoralign dsa;
 
 	/*
 	 * We must have a pathname, and it must be absolute.
@@ -219,33 +220,15 @@ vdev_disk_open(vdev_t *vd, uint64_t *psi
 		return (SET_ERROR(EINVAL));
 	}
 
+	pdk = NULL;
+	if (getdiskinfo(vp, &dkw) == 0)
+		pdk = disk_find(dkw.dkw_parent);
+
 	/* XXXNETBSD Once tls-maxphys gets merged this block becomes:
-		if (VOP_IOCTL(vp, DIOCGWEDGEINFO, &dkw, FREAD, NOCRED) == 0)
-			pdk = disk_find(dkw.dkw_parent);
-		else
-			pdk = disk_find_blk(vp->v_rdev);
 		dvd->vd_maxphys = (pdk ? disk_maxphys(pdk) : MACHINE_MAXPHYS);
 	*/
 	{
 		struct buf buf = { .b_bcount = MAXPHYS };
-
-		if (VOP_IOCTL(vp, DIOCGWEDGEINFO, &dkw, FREAD, NOCRED) == 0) {
-			pdk = disk_find(dkw.dkw_parent);
-		} else {
-			const char *dev_name;
-
-			dev_name = devsw_blk2name(major(vp->v_rdev));
-			if (dev_name) {
-				char disk_name[16];
-
-				snprintf(disk_name, sizeof(disk_name), "%s%d",
-				    dev_name, DISKUNIT(vp->v_rdev));
-				pdk = disk_find(disk_name);
-			} else {
-				pdk = NULL;
-			}
-			buf.b_dev = vp->v_rdev;
-		}
 		if (pdk && pdk->dk_driver && pdk->dk_driver->d_minphys)
 			(*pdk->dk_driver->d_minphys)(&buf);
 		dvd->vd_maxphys = buf.b_bcount;
@@ -268,32 +251,38 @@ vdev_disk_open(vdev_t *vd, uint64_t *psi
 	dvd->vd_vp = vp;
 
 skip_open:
-	/*
-	 * Determine the actual size of the device.
-	 * Try wedge info first as it supports larger disks.
-	 */
-	error = VOP_IOCTL(vp, DIOCGWEDGEINFO, &dkw, FREAD, NOCRED);
-	if (error == 0) {
-		pdk = disk_find(dkw.dkw_parent);
-		if (pdk) {
-			pinfo.pi_secsize = (1 << pdk->dk_byteshift);
-			pinfo.pi_size = dkw.dkw_size;
-			pinfo.pi_offset = dkw.dkw_offset;
-		} else	
-			error = ENODEV;
-	}
-	if (error)
-		error = VOP_IOCTL(vp, DIOCGPARTINFO, &pinfo, FREAD, kcred);
+	error = getdisksize(vp, &numsecs, &secsize);
 	if (error != 0) {
 		vd->vdev_stat.vs_aux = VDEV_AUX_OPEN_FAILED;
 		return (SET_ERROR(error));
 	}
-	*psize = pinfo.pi_size * pinfo.pi_secsize;
+
+	*psize = numsecs * secsize;
 	*max_psize = *psize;
 
-	*ashift = highbit(MAX(pinfo.pi_secsize, SPA_MINBLOCKSIZE)) - 1;
-	*pashift = *ashift;
-	vd->vdev_wholedisk = (pinfo.pi_offset == 0); /* XXXNETBSD */
+	*ashift = highbit(MAX(secsize, SPA_MINBLOCKSIZE)) - 1;
+
+	/*
+	 * Try to determine whether the disk has a preferred physical
+	 * sector size even if it can emulate a smaller logical sector
+	 * size with r/m/w cycles, e.g. a disk with 4096-byte sectors
+	 * that for compatibility claims to support 512-byte ones.
+	 */
+	if (VOP_IOCTL(vp, DIOCGSECTORALIGN, &dsa, FREAD, NOCRED) == 0) {
+		*pashift = highbit(dsa.dsa_alignment * secsize) - 1;
+		if (dsa.dsa_firstaligned % dsa.dsa_alignment)
+			printf("ZFS WARNING: vdev %s: sectors are misaligned"
+			    " (alignment=%"PRIu32", firstaligned=%"PRIu32")\n",
+			    vd->vdev_path,
+			    dsa.dsa_alignment, dsa.dsa_firstaligned);
+	} else {
+		*pashift = *ashift;
+	}
+
+	vd->vdev_wholedisk = 0;
+	if (getdiskinfo(vp, &dkw) != 0 &&
+	    dkw.dkw_offset == 0 && dkw.dkw_size == numsecs)
+		vd->vdev_wholedisk = 1,
 
 	/*
 	 * Clear the nowritecache bit, so that on a vdev_reopen() we will

Index: src/sys/dev/cgd.c
diff -u src/sys/dev/cgd.c:1.116 src/sys/dev/cgd.c:1.116.10.1
--- src/sys/dev/cgd.c:1.116	Tue Jan 23 22:42:29 2018
+++ src/sys/dev/cgd.c	Sat Mar 21 15:18:57 2020
@@ -1,4 +1,4 @@
-/* $NetBSD: cgd.c,v 1.116 2018/01/23 22:42:29 pgoyette Exp $ */
+/* $NetBSD: cgd.c,v 1.116.10.1 2020/03/21 15:18:57 martin Exp $ */
 
 /*-
  * Copyright (c) 2002 The NetBSD Foundation, Inc.
@@ -30,7 +30,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: cgd.c,v 1.116 2018/01/23 22:42:29 pgoyette Exp $");
+__KERNEL_RCSID(0, "$NetBSD: cgd.c,v 1.116.10.1 2020/03/21 15:18:57 martin Exp $");
 
 #include <sys/types.h>
 #include <sys/param.h>
@@ -722,6 +722,33 @@ cgdioctl(dev_t dev, u_long cmd, void *da
 		 * We pass this call down to the underlying disk.
 		 */
 		return VOP_IOCTL(cs->sc_tvn, cmd, data, flag, l->l_cred);
+	case DIOCGSECTORALIGN: {
+		struct disk_sectoralign *dsa = data;
+		int error;
+
+		if (!DK_ATTACHED(dksc))
+			return ENOENT;
+
+		/* Get the underlying disk's sector alignment.  */
+		error = VOP_IOCTL(cs->sc_tvn, cmd, data, flag, l->l_cred);
+		if (error)
+			return error;
+
+		/* Adjust for the disklabel partition if necessary.  */
+		if (part != RAW_PART) {
+			struct disklabel *lp = dksc->sc_dkdev.dk_label;
+			daddr_t offset = lp->d_partitions[part].p_offset;
+			uint32_t r = offset % dsa->dsa_alignment;
+
+			if (r < dsa->dsa_firstaligned)
+				dsa->dsa_firstaligned = dsa->dsa_firstaligned
+				    - r;
+			else
+				dsa->dsa_firstaligned = (dsa->dsa_firstaligned
+				    + dsa->dsa_alignment) - r;
+		}
+		return 0;
+	}
 	case DIOCGSTRATEGY:
 	case DIOCSSTRATEGY:
 		if (!DK_ATTACHED(dksc))

Index: src/sys/dev/ata/wd.c
diff -u src/sys/dev/ata/wd.c:1.452 src/sys/dev/ata/wd.c:1.452.2.1
--- src/sys/dev/ata/wd.c:1.452	Thu Jun  6 20:55:43 2019
+++ src/sys/dev/ata/wd.c	Sat Mar 21 15:18:57 2020
@@ -1,4 +1,4 @@
-/*	$NetBSD: wd.c,v 1.452 2019/06/06 20:55:43 mlelstv Exp $ */
+/*	$NetBSD: wd.c,v 1.452.2.1 2020/03/21 15:18:57 martin 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.452 2019/06/06 20:55:43 mlelstv Exp $");
+__KERNEL_RCSID(0, "$NetBSD: wd.c,v 1.452.2.1 2020/03/21 15:18:57 martin Exp $");
 
 #include "opt_ata.h"
 #include "opt_wd.h"
@@ -430,16 +430,40 @@ wdattach(device_t parent, device_t self,
 	} else {
 		wd->sc_blksize = 512;
 	}
+	wd->sc_sectoralign.dsa_firstaligned = 0;
+	wd->sc_sectoralign.dsa_alignment = 1;
+	if ((wd->sc_params.atap_secsz & ATA_SECSZ_VALID_MASK) == ATA_SECSZ_VALID
+	    && ((wd->sc_params.atap_secsz & ATA_SECSZ_LPS) != 0)) {
+		wd->sc_sectoralign.dsa_alignment = 1 <<
+		    (wd->sc_params.atap_secsz & ATA_SECSZ_LPS_SZMSK);
+		if ((wd->sc_params.atap_logical_align & ATA_LA_VALID_MASK) ==
+		    ATA_LA_VALID) {
+			wd->sc_sectoralign.dsa_firstaligned =
+			    (wd->sc_sectoralign.dsa_alignment -
+				(wd->sc_params.atap_logical_align &
+				    ATA_LA_MASK));
+		}
+	}
 	wd->sc_capacity512 = (wd->sc_capacity * wd->sc_blksize) / DEV_BSIZE;
 	format_bytes(pbuf, sizeof(pbuf), wd->sc_capacity * wd->sc_blksize);
 	aprint_normal_dev(self, "%s, %d cyl, %d head, %d sec, "
-	    "%d bytes/sect x %llu sectors\n",
+	    "%d bytes/sect x %llu sectors",
 	    pbuf,
 	    (wd->sc_flags & WDF_LBA) ? (int)(wd->sc_capacity /
 		(wd->sc_params.atap_heads * wd->sc_params.atap_sectors)) :
 		wd->sc_params.atap_cylinders,
 	    wd->sc_params.atap_heads, wd->sc_params.atap_sectors,
 	    wd->sc_blksize, (unsigned long long)wd->sc_capacity);
+	if (wd->sc_sectoralign.dsa_alignment != 1) {
+		aprint_normal(" (%d bytes/physsect",
+		    wd->sc_sectoralign.dsa_alignment & wd->sc_blksize);
+		if (wd->sc_sectoralign.dsa_firstaligned != 0) {
+			aprint_normal("; first aligned sector: %jd",
+			    (intmax_t)wd->sc_sectoralign.dsa_firstaligned);
+		}
+		aprint_normal(")");
+	}
+	aprint_normal("\n");
 
 	ATADEBUG_PRINT(("%s: atap_dmatiming_mimi=%d, atap_dmatiming_recom=%d\n",
 	    device_xname(self), wd->sc_params.atap_dmatiming_mimi,
@@ -1409,6 +1433,27 @@ wdioctl(dev_t dev, u_long cmd, void *add
 		return(error1);
 		}
 
+	case DIOCGSECTORALIGN: {
+		struct disk_sectoralign *dsa = addr;
+		int part = WDPART(dev);
+
+		*dsa = wd->sc_sectoralign;
+		if (part != RAW_PART) {
+			struct disklabel *lp = dksc->sc_dkdev.dk_label;
+			daddr_t offset = lp->d_partitions[part].p_offset;
+			uint32_t r = offset % dsa->dsa_alignment;
+
+			if (r < dsa->dsa_firstaligned)
+				dsa->dsa_firstaligned = dsa->dsa_firstaligned
+				    - r;
+			else
+				dsa->dsa_firstaligned = (dsa->dsa_firstaligned
+				    + dsa->dsa_alignment) - r;
+		}
+
+		return 0;
+	}
+
 	default:
 		return dk_ioctl(dksc, dev, cmd, addr, flag, l);
 	}

Index: src/sys/dev/ata/wdvar.h
diff -u src/sys/dev/ata/wdvar.h:1.49 src/sys/dev/ata/wdvar.h:1.49.4.1
--- src/sys/dev/ata/wdvar.h:1.49	Fri Apr  5 18:23:45 2019
+++ src/sys/dev/ata/wdvar.h	Sat Mar 21 15:18:57 2020
@@ -1,4 +1,4 @@
-/*	$NetBSD: wdvar.h,v 1.49 2019/04/05 18:23:45 bouyer Exp $	*/
+/*	$NetBSD: wdvar.h,v 1.49.4.1 2020/03/21 15:18:57 martin Exp $	*/
 
 /*
  * Copyright (c) 1998, 2001 Manuel Bouyer.
@@ -59,6 +59,7 @@ struct wd_softc {
 	uint64_t sc_capacity512; /* ... in DEV_BSIZE blocks */
 	uint32_t sc_capacity28; /* capacity accessible with LBA28 commands */
 	uint32_t sc_blksize; /* logical block size, in bytes */
+	struct disk_sectoralign sc_sectoralign; /* sector alignment */
 
 #ifdef WD_SOFTBADSECT
 	SLIST_HEAD(, disk_badsectors)	sc_bslist;

Index: src/sys/dev/dkwedge/dk.c
diff -u src/sys/dev/dkwedge/dk.c:1.97 src/sys/dev/dkwedge/dk.c:1.97.8.1
--- src/sys/dev/dkwedge/dk.c:1.97	Sat May 12 10:33:06 2018
+++ src/sys/dev/dkwedge/dk.c	Sat Mar 21 15:18:57 2020
@@ -1,4 +1,4 @@
-/*	$NetBSD: dk.c,v 1.97 2018/05/12 10:33:06 mlelstv Exp $	*/
+/*	$NetBSD: dk.c,v 1.97.8.1 2020/03/21 15:18:57 martin Exp $	*/
 
 /*-
  * Copyright (c) 2004, 2005, 2006, 2007 The NetBSD Foundation, Inc.
@@ -30,7 +30,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: dk.c,v 1.97 2018/05/12 10:33:06 mlelstv Exp $");
+__KERNEL_RCSID(0, "$NetBSD: dk.c,v 1.97.8.1 2020/03/21 15:18:57 martin Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_dkwedge.h"
@@ -1501,7 +1501,24 @@ dkioctl(dev_t dev, u_long cmd, void *dat
 
 		break;
 	    }
+	case DIOCGSECTORALIGN:
+	    {
+		struct disk_sectoralign *dsa = data;
+		uint32_t r;
+
+		error = VOP_IOCTL(sc->sc_parent->dk_rawvp, cmd, dsa, flag,
+		    l != NULL ? l->l_cred : NOCRED);
+		if (error)
+			break;
 
+		r = sc->sc_offset % dsa->dsa_alignment;
+		if (r < dsa->dsa_firstaligned)
+			dsa->dsa_firstaligned = dsa->dsa_firstaligned - r;
+		else
+			dsa->dsa_firstaligned = (dsa->dsa_firstaligned +
+			    dsa->dsa_alignment) - r;
+		break;
+	    }
 	default:
 		error = ENOTTY;
 	}

Index: src/sys/kern/subr_disk_open.c
diff -u src/sys/kern/subr_disk_open.c:1.14 src/sys/kern/subr_disk_open.c:1.14.4.1
--- src/sys/kern/subr_disk_open.c:1.14	Wed Feb 20 10:02:51 2019
+++ src/sys/kern/subr_disk_open.c	Sat Mar 21 15:18:57 2020
@@ -1,4 +1,4 @@
-/*	$NetBSD: subr_disk_open.c,v 1.14 2019/02/20 10:02:51 hannken Exp $	*/
+/*	$NetBSD: subr_disk_open.c,v 1.14.4.1 2020/03/21 15:18:57 martin Exp $	*/
 
 /*-
  * Copyright (c) 2006 The NetBSD Foundation, Inc.
@@ -27,7 +27,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: subr_disk_open.c,v 1.14 2019/02/20 10:02:51 hannken Exp $");
+__KERNEL_RCSID(0, "$NetBSD: subr_disk_open.c,v 1.14.4.1 2020/03/21 15:18:57 martin Exp $");
 
 #include <sys/param.h>
 #include <sys/conf.h>
@@ -160,7 +160,8 @@ getdiskinfo(struct vnode *vp, struct dkw
 
 	dkw->dkw_wname[0] = '\0';
 
-	strlcpy(dkw->dkw_parent, dkw->dkw_devname, sizeof(dkw->dkw_parent));
+	snprintf(dkw->dkw_parent, sizeof(dkw->dkw_parent), "%s%" PRId32,
+	    devsw_blk2name(major(dev)), DISKUNIT(dev));
 
 	dkw->dkw_size = pi.pi_size;
 	dkw->dkw_offset = pi.pi_offset;

Index: src/sys/sys/disk.h
diff -u src/sys/sys/disk.h:1.74 src/sys/sys/disk.h:1.74.2.1
--- src/sys/sys/disk.h:1.74	Wed May 22 08:47:02 2019
+++ src/sys/sys/disk.h	Sat Mar 21 15:18:57 2020
@@ -1,4 +1,4 @@
-/*	$NetBSD: disk.h,v 1.74 2019/05/22 08:47:02 hannken Exp $	*/
+/*	$NetBSD: disk.h,v 1.74.2.1 2020/03/21 15:18:57 martin Exp $	*/
 
 /*-
  * Copyright (c) 1996, 1997, 2004 The NetBSD Foundation, Inc.
@@ -300,6 +300,12 @@ struct disk_strategy {
 	size_t dks_paramlen;		/* notyet; should be 0 */
 };
 
+/* Sector alignment */
+struct disk_sectoralign {
+	uint32_t	dsa_firstaligned; /* first aligned sector # */
+	uint32_t	dsa_alignment;	  /* sectors per aligned sector */
+};
+
 #ifdef _KERNEL
 #include <sys/device.h>
 #include <sys/mutex.h>

Index: src/sys/sys/dkio.h
diff -u src/sys/sys/dkio.h:1.25 src/sys/sys/dkio.h:1.25.4.1
--- src/sys/sys/dkio.h:1.25	Wed Mar 27 19:13:33 2019
+++ src/sys/sys/dkio.h	Sat Mar 21 15:18:57 2020
@@ -1,4 +1,4 @@
-/*	$NetBSD: dkio.h,v 1.25 2019/03/27 19:13:33 martin Exp $	*/
+/*	$NetBSD: dkio.h,v 1.25.4.1 2020/03/21 15:18:57 martin Exp $	*/
 
 /*
  * Copyright (c) 1987, 1988, 1993
@@ -133,4 +133,7 @@
 		/* mass removal */
 #define	DIOCRMWEDGES	_IOR('d', 134, int)	/* remove all wedges */
 
+		/* sector alignment */
+#define	DIOCGSECTORALIGN _IOR('d', 135, struct disk_sectoralign)
+
 #endif /* _SYS_DKIO_H_ */

Reply via email to