Module Name:    src
Committed By:   jakllsch
Date:           Fri Jul 22 04:08:10 UTC 2016

Modified Files:
        src/sys/dev/ata: wd.c wdvar.h

Log Message:
Add ATA8-ACS Long Logical Sector Feature Set support to wd(4).


To generate a diff of this commit:
cvs rdiff -u -r1.423 -r1.424 src/sys/dev/ata/wd.c
cvs rdiff -u -r1.42 -r1.43 src/sys/dev/ata/wdvar.h

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

Modified files:

Index: src/sys/dev/ata/wd.c
diff -u src/sys/dev/ata/wd.c:1.423 src/sys/dev/ata/wd.c:1.424
--- src/sys/dev/ata/wd.c:1.423	Thu Jul 21 19:05:03 2016
+++ src/sys/dev/ata/wd.c	Fri Jul 22 04:08:10 2016
@@ -1,4 +1,4 @@
-/*	$NetBSD: wd.c,v 1.423 2016/07/21 19:05:03 jakllsch Exp $ */
+/*	$NetBSD: wd.c,v 1.424 2016/07/22 04:08:10 jakllsch 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.423 2016/07/21 19:05:03 jakllsch Exp $");
+__KERNEL_RCSID(0, "$NetBSD: wd.c,v 1.424 2016/07/22 04:08:10 jakllsch Exp $");
 
 #include "opt_ata.h"
 
@@ -391,7 +391,16 @@ wdattach(device_t parent, device_t self,
 		    wd->sc_params.atap_heads *
 		    wd->sc_params.atap_sectors;
 	}
-	format_bytes(pbuf, sizeof(pbuf), wd->sc_capacity * DEV_BSIZE);
+	if ((wd->sc_params.atap_secsz & ATA_SECSZ_VALID_MASK) == ATA_SECSZ_VALID
+	    && ((wd->sc_params.atap_secsz & ATA_SECSZ_LLS) != 0)) {
+		wd->sc_blksize = 2ULL *
+		    (wd->sc_params.atap_lls_secsz[1] << 16 |
+		     wd->sc_params.atap_lls_secsz[0] <<  0);
+	} else {
+		wd->sc_blksize = 512;
+	}
+	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",
 	    pbuf,
@@ -399,11 +408,17 @@ wdattach(device_t parent, device_t self,
 		(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,
-	    DEV_BSIZE, (unsigned long long)wd->sc_capacity);
+	    wd->sc_blksize, (unsigned long long)wd->sc_capacity);
 
 	ATADEBUG_PRINT(("%s: atap_dmatiming_mimi=%d, atap_dmatiming_recom=%d\n",
 	    device_xname(self), wd->sc_params.atap_dmatiming_mimi,
 	    wd->sc_params.atap_dmatiming_recom), DEBUG_PROBE);
+
+	if (wd->sc_blksize <= 0 || !powerof2(wd->sc_blksize) ||
+	    wd->sc_blksize < DEV_BSIZE || wd->sc_blksize > MAXPHYS) {
+		aprint_normal_dev(self, "WARNING: block size %u "
+		    "might not actually work\n", wd->sc_blksize);
+	}
 out:
 	/*
 	 * Initialize and attach the disk structure.
@@ -544,7 +559,7 @@ wdstrategy(struct buf *bp)
 	 */
 	if (WDPART(bp->b_dev) == RAW_PART) {
 		if (bounds_check_with_mediasize(bp, DEV_BSIZE,
-		    wd->sc_capacity) <= 0)
+		    wd->sc_capacity512) <= 0)
 			goto done;
 	} else {
 		if (bounds_check_with_label(&wd->sc_dk, bp,
@@ -577,7 +592,7 @@ wdstrategy(struct buf *bp)
 	 */
 	if (__predict_false(!SLIST_EMPTY(&wd->sc_bslist))) {
 		struct disk_badsectors *dbs;
-		daddr_t maxblk = blkno + (bp->b_bcount >> DEV_BSHIFT) - 1;
+		daddr_t maxblk = blkno + (bp->b_bcount / wd->sc_blksize) - 1;
 
 		SLIST_FOREACH(dbs, &wd->sc_bslist, dbs_next)
 			if ((dbs->dbs_min <= blkno && blkno <= dbs->dbs_max) ||
@@ -664,8 +679,8 @@ wd_split_mod15_write(struct buf *bp)
 	bp->b_oflags = obp->b_oflags;
 	bp->b_cflags = obp->b_cflags;
 	bp->b_data = (char *)bp->b_data + bp->b_bcount;
-	bp->b_blkno += (bp->b_bcount / 512);
-	bp->b_rawblkno += (bp->b_bcount / 512);
+	bp->b_blkno += (bp->b_bcount / DEV_BSIZE);
+	bp->b_rawblkno += (bp->b_bcount / sc->sc_blksize);
 	s = splbio();
 	wdstart1(sc, bp);
 	splx(s);
@@ -837,7 +852,8 @@ retry2:
 
 			dbs = malloc(sizeof *dbs, M_TEMP, M_WAITOK);
 			dbs->dbs_min = bp->b_rawblkno;
-			dbs->dbs_max = dbs->dbs_min + (bp->b_bcount >> DEV_BSHIFT) - 1;
+			dbs->dbs_max = dbs->dbs_min +
+			    (bp->b_bcount /wd->sc_blksize) - 1;
 			microtime(&dbs->dbs_failedat);
 			SLIST_INSERT_HEAD(&wd->sc_bslist, dbs, dbs_next);
 			wd->sc_bscount++;
@@ -894,9 +910,11 @@ wdrestart(void *v)
 static void
 wdminphys(struct buf *bp)
 {
+	const struct wd_softc * const wd =
+	    device_lookup_private(&wd_cd, WDUNIT(bp->b_dev));
 
-	if (bp->b_bcount > (512 * 128)) {
-		bp->b_bcount = (512 * 128);
+	if (bp->b_bcount > (wd->sc_blksize * 128)) {
+		bp->b_bcount = (wd->sc_blksize * 128);
 	}
 	minphys(bp);
 }
@@ -1065,7 +1083,7 @@ wdgetdefaultlabel(struct wd_softc *wd, s
 	ATADEBUG_PRINT(("wdgetdefaultlabel\n"), DEBUG_FUNCS);
 	memset(lp, 0, sizeof(struct disklabel));
 
-	lp->d_secsize = DEV_BSIZE;
+	lp->d_secsize = wd->sc_blksize;
 	lp->d_ntracks = wd->sc_params.atap_heads;
 	lp->d_nsectors = wd->sc_params.atap_sectors;
 	lp->d_ncylinders = (wd->sc_flags & WDF_LBA) ? wd->sc_capacity /
@@ -1537,8 +1555,8 @@ wddiscard(dev_t dev, off_t pos, off_t le
 		return EIO;
 
 	/* round the start up and the end down */
-	bno = (pos + DEV_BSIZE - 1) >> DEV_BSHIFT;
-	size = ((pos + len) >> DEV_BSHIFT) - bno;
+	bno = (pos + wd->sc_blksize - 1) / wd->sc_blksize;
+	size = ((pos + len) / wd->sc_blksize) - bno;
 
 	done = 0;
 	while (done < size) {
@@ -1737,7 +1755,7 @@ wd_params_to_properties(struct wd_softc 
 	memset(dg, 0, sizeof(*dg));
 
 	dg->dg_secperunit = wd->sc_capacity;
-	dg->dg_secsize = DEV_BSIZE /* XXX 512? */;
+	dg->dg_secsize = wd->sc_blksize;
 	dg->dg_nsectors = wd->sc_params.atap_sectors;
 	dg->dg_ntracks = wd->sc_params.atap_heads;
 	if ((wd->sc_flags & WDF_LBA) == 0)
@@ -2036,6 +2054,30 @@ wi_find(struct buf *bp)
 	return (wi);
 }
 
+static uint
+wi_sector_size(const struct wd_ioctl * const wi)
+{
+	switch (wi->wi_atareq.command) {
+	case WDCC_READ:
+	case WDCC_WRITE:
+	case WDCC_READMULTI:
+	case WDCC_WRITEMULTI:
+	case WDCC_READDMA:
+	case WDCC_WRITEDMA:
+	case WDCC_READ_EXT:
+	case WDCC_WRITE_EXT:
+	case WDCC_READMULTI_EXT:
+	case WDCC_WRITEMULTI_EXT:
+	case WDCC_READDMA_EXT:
+	case WDCC_WRITEDMA_EXT:
+	case WDCC_READ_FPDMA_QUEUED:
+	case WDCC_WRITE_FPDMA_QUEUED:
+		return wi->wi_softc->sc_blksize;
+	default:
+		return 512;
+	}
+}
+
 /*
  * Ioctl pseudo strategy routine
  *
@@ -2087,11 +2129,11 @@ wdioctlstrategy(struct buf *bp)
 
 	/*
 	 * Abort if we didn't get a buffer size that was a multiple of
-	 * our sector size (or was larger than NBBY)
+	 * our sector size (or overflows CHS/LBA28 sector count)
 	 */
 
-	if ((bp->b_bcount % wi->wi_softc->sc_dk.dk_label->d_secsize) != 0 ||
-	    (bp->b_bcount / wi->wi_softc->sc_dk.dk_label->d_secsize) >=
+	if ((bp->b_bcount % wi_sector_size(wi)) != 0 ||
+	    (bp->b_bcount / wi_sector_size(wi)) >=
 	     (1 << NBBY)) {
 		error = EINVAL;
 		goto bad;

Index: src/sys/dev/ata/wdvar.h
diff -u src/sys/dev/ata/wdvar.h:1.42 src/sys/dev/ata/wdvar.h:1.43
--- src/sys/dev/ata/wdvar.h:1.42	Mon Apr 13 16:33:24 2015
+++ src/sys/dev/ata/wdvar.h	Fri Jul 22 04:08:10 2016
@@ -1,4 +1,4 @@
-/*	$NetBSD: wdvar.h,v 1.42 2015/04/13 16:33:24 riastradh Exp $	*/
+/*	$NetBSD: wdvar.h,v 1.43 2016/07/22 04:08:10 jakllsch Exp $	*/
 
 /*
  * Copyright (c) 1998, 2001 Manuel Bouyer.
@@ -60,7 +60,9 @@ struct wd_softc {
 #define WDF_KLABEL	0x080 /* retain label after 'full' close */
 #define WDF_LBA48	0x100 /* using 48-bit LBA mode */
 	uint64_t sc_capacity; /* full capacity of the device */
+	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 */
 
 	int retries; /* number of xfer retry */
 

Reply via email to