aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter Grehan <grehan@FreeBSD.org>2014-07-15 00:25:54 +0000
committerPeter Grehan <grehan@FreeBSD.org>2014-07-15 00:25:54 +0000
commitc4813fadf1a19da97ccd0e6f0250611e3ba4211f (patch)
treeaeb64b137797417667e3bf4462976ce138bd0a8e
parentd634b1f709fa192cb8ff6ebbb0d869aac4f90865 (diff)
downloadsrc-c4813fadf1a19da97ccd0e6f0250611e3ba4211f.tar.gz
src-c4813fadf1a19da97ccd0e6f0250611e3ba4211f.zip
Add a call to synthesize a C/H/S value for block emulations
that require it (ahci). The algorithm used is from the VHD specification.
Notes
Notes: svn path=/head/; revision=268638
-rw-r--r--usr.sbin/bhyve/block_if.c49
-rw-r--r--usr.sbin/bhyve/block_if.h2
2 files changed, 51 insertions, 0 deletions
diff --git a/usr.sbin/bhyve/block_if.c b/usr.sbin/bhyve/block_if.c
index b29bc7856e86..1ec0344f3fca 100644
--- a/usr.sbin/bhyve/block_if.c
+++ b/usr.sbin/bhyve/block_if.c
@@ -390,6 +390,55 @@ blockif_close(struct blockif_ctxt *bc)
}
/*
+ * Return virtual C/H/S values for a given block. Use the algorithm
+ * outlined in the VHD specification to calculate values.
+ */
+void
+blockif_chs(struct blockif_ctxt *bc, uint16_t *c, uint8_t *h, uint8_t *s)
+{
+ off_t sectors; /* total sectors of the block dev */
+ off_t hcyl; /* cylinders times heads */
+ uint16_t secpt; /* sectors per track */
+ uint8_t heads;
+
+ assert(bc->bc_magic == BLOCKIF_SIG);
+
+ sectors = bc->bc_size / bc->bc_sectsz;
+
+ /* Clamp the size to the largest possible with CHS */
+ if (sectors > 65535UL*16*255)
+ sectors = 65535UL*16*255;
+
+ if (sectors >= 65536UL*16*63) {
+ secpt = 255;
+ heads = 16;
+ hcyl = sectors / secpt;
+ } else {
+ secpt = 17;
+ hcyl = sectors / secpt;
+ heads = (hcyl + 1023) / 1024;
+
+ if (heads < 4)
+ heads = 4;
+
+ if (hcyl >= (heads * 1024) || heads > 16) {
+ secpt = 31;
+ heads = 16;
+ hcyl = sectors / secpt;
+ }
+ if (hcyl >= (heads * 1024)) {
+ secpt = 63;
+ heads = 16;
+ hcyl = sectors / secpt;
+ }
+ }
+
+ *c = hcyl / heads;
+ *h = heads;
+ *s = secpt;
+}
+
+/*
* Accessors
*/
off_t
diff --git a/usr.sbin/bhyve/block_if.h b/usr.sbin/bhyve/block_if.h
index e0c0bb1f8c8b..c2c21f657446 100644
--- a/usr.sbin/bhyve/block_if.h
+++ b/usr.sbin/bhyve/block_if.h
@@ -52,6 +52,8 @@ struct blockif_req {
struct blockif_ctxt;
struct blockif_ctxt *blockif_open(const char *optstr, const char *ident);
off_t blockif_size(struct blockif_ctxt *bc);
+void blockif_chs(struct blockif_ctxt *bc, uint16_t *c, uint8_t *h,
+ uint8_t *s);
int blockif_sectsz(struct blockif_ctxt *bc);
int blockif_queuesz(struct blockif_ctxt *bc);
int blockif_is_ro(struct blockif_ctxt *bc);