Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 4 May 2017 05:26:37 +0000 (UTC)
From:      Toomas Soome <tsoome@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r317785 - head/sys/boot/i386/zfsboot
Message-ID:  <201705040526.v445QbfU077237@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: tsoome
Date: Thu May  4 05:26:37 2017
New Revision: 317785
URL: https://svnweb.freebsd.org/changeset/base/317785

Log:
  zfsboot: drvsize() may be unusable on some systems
  
  From user report, the errors are seen:
  error 1
  error 1
  gptzfsboot: error 1 lba 4294967288
  gptzfsboot: error 1 lba 1
  gptzfsboot: no ZFS pools located, can't boot
  
  The first two errors above are from issuing INT13 EAX=0x4800, meaning we
  need to check if EDD is available and use EAX=0x800 if not.
  
  For an workaround I'm using the similar idea as in biosdisk.c - first probe
  ah=8h, then check if we have EDD.
  
  Note we would like to see the correct disk size info, but we *may*
  get away with anything >64MB, so we could at least test 2 zfs pool labels
  on whole disk setup and not to freak out the INT13 interface.
  
  If we get away with initial disk probing, then we have partition sizes from
  the partition table and we should be able to complete the disk probing.
  
  Note: this update does not provide full fix to all errors, but we get
  the drvsize() errors removed.
  
  Reported by:	Michael W. Lucas
  Reviewed by:	julian
  Differential Revision:	https://reviews.freebsd.org/D10591

Modified:
  head/sys/boot/i386/zfsboot/zfsboot.c

Modified: head/sys/boot/i386/zfsboot/zfsboot.c
==============================================================================
--- head/sys/boot/i386/zfsboot/zfsboot.c	Thu May  4 03:11:59 2017	(r317784)
+++ head/sys/boot/i386/zfsboot/zfsboot.c	Thu May  4 05:26:37 2017	(r317785)
@@ -39,6 +39,7 @@ __FBSDID("$FreeBSD$");
 #include "lib.h"
 #include "rbx.h"
 #include "drv.h"
+#include "edd.h"
 #include "util.h"
 #include "cons.h"
 #include "bootargs.h"
@@ -125,6 +126,7 @@ static int parse_cmd(void);
 static void bios_getmem(void);
 void *malloc(size_t n);
 void free(void *ptr);
+int main(void);
 
 void *
 malloc(size_t n)
@@ -469,6 +471,56 @@ copy_dsk(struct dsk *dsk)
 }
 
 /*
+ * Get disk size from eax=0x800 and 0x4800. We need to probe both
+ * because 0x4800 may not be available and we would like to get more
+ * or less correct disk size - if it is possible at all.
+ * Note we do not really want to touch drv.c because that code is shared
+ * with boot2 and we can not afford to grow that code.
+ */
+static uint64_t
+drvsize_ext(struct dsk *dskp)
+{
+	uint64_t size, tmp;
+	int cyl, hds, sec;
+
+	v86.ctl = V86_FLAGS;
+	v86.addr = 0x13;
+	v86.eax = 0x800;
+	v86.edx = dskp->drive;
+	v86int();
+
+	/* Don't error out if we get bad sector number, try EDD as well */
+	if (V86_CY(v86.efl) ||	/* carry set */
+	    (v86.edx & 0xff) <= (unsigned)(dskp->drive & 0x7f)) /* unit # bad */
+		return (0);
+
+	cyl = ((v86.ecx & 0xc0) << 2) + ((v86.ecx & 0xff00) >> 8) + 1;
+	/* Convert max head # -> # of heads */
+	hds = ((v86.edx & 0xff00) >> 8) + 1;
+	sec = v86.ecx & 0x3f;
+
+	size = (uint64_t)cyl * hds * sec;
+
+	/* Determine if we can use EDD with this device. */
+	v86.ctl = V86_FLAGS;
+	v86.addr = 0x13;
+	v86.eax = 0x4100;
+	v86.edx = dskp->drive;
+	v86.ebx = 0x55aa;
+	v86int();
+	if (V86_CY(v86.efl) ||  /* carry set */
+	    (v86.ebx & 0xffff) != 0xaa55 || /* signature */
+	    (v86.ecx & EDD_INTERFACE_FIXED_DISK) == 0)
+		return (size);
+
+	tmp = drvsize(dskp);
+	if (tmp > size)
+		size = tmp;
+
+	return (size);
+}
+
+/*
  * The "layered" ioctl to read disk/partition size. Unfortunately
  * the zfsboot case is hardest, because we do not have full software
  * stack available, so we need to do some manual work here.
@@ -480,7 +532,7 @@ ldi_get_size(void *priv)
 	uint64_t size = dskp->size;
 
 	if (dskp->start == 0)
-		size = drvsize(dskp);
+		size = drvsize_ext(dskp);
 
 	return (size * DEV_BSIZE);
 }
@@ -515,7 +567,7 @@ probe_drive(struct dsk *dsk)
      * out the partition table and probe each slice/partition
      * in turn for a vdev or GELI encrypted vdev.
      */
-    elba = drvsize(dsk);
+    elba = drvsize_ext(dsk);
     if (elba > 0) {
 	elba--;
     }



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201705040526.v445QbfU077237>