From patchwork Wed Jan 20 06:51:32 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: John Snow X-Patchwork-Id: 8069181 Return-Path: X-Original-To: patchwork-qemu-devel@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork1.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.136]) by patchwork1.web.kernel.org (Postfix) with ESMTP id EB55F9F440 for ; Wed, 20 Jan 2016 06:57:14 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 3F64320263 for ; Wed, 20 Jan 2016 06:57:14 +0000 (UTC) Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 70B9520260 for ; Wed, 20 Jan 2016 06:57:13 +0000 (UTC) Received: from localhost ([::1]:40525 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1aLmhc-0007kV-TQ for patchwork-qemu-devel@patchwork.kernel.org; Wed, 20 Jan 2016 01:57:12 -0500 Received: from eggs.gnu.org ([2001:4830:134:3::10]:42458) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1aLmcQ-0005b8-Et for qemu-devel@nongnu.org; Wed, 20 Jan 2016 01:51:51 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1aLmcP-0004eS-Cm for qemu-devel@nongnu.org; Wed, 20 Jan 2016 01:51:50 -0500 Received: from mx1.redhat.com ([209.132.183.28]:44616) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1aLmcL-0004cj-8Q; Wed, 20 Jan 2016 01:51:45 -0500 Received: from int-mx14.intmail.prod.int.phx2.redhat.com (int-mx14.intmail.prod.int.phx2.redhat.com [10.5.11.27]) by mx1.redhat.com (Postfix) with ESMTPS id D1ECC42E5D8; Wed, 20 Jan 2016 06:51:44 +0000 (UTC) Received: from scv.usersys.redhat.com (vpn-54-49.rdu2.redhat.com [10.10.54.49]) by int-mx14.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id u0K6pZwA019741; Wed, 20 Jan 2016 01:51:44 -0500 From: John Snow To: qemu-block@nongnu.org Date: Wed, 20 Jan 2016 01:51:32 -0500 Message-Id: <1453272694-17106-11-git-send-email-jsnow@redhat.com> In-Reply-To: <1453272694-17106-1-git-send-email-jsnow@redhat.com> References: <1453272694-17106-1-git-send-email-jsnow@redhat.com> X-Scanned-By: MIMEDefang 2.68 on 10.5.11.27 X-detected-operating-system: by eggs.gnu.org: GNU/Linux 3.x X-Received-From: 209.132.183.28 Cc: kwolf@redhat.com, John Snow , armbru@redhat.com, qemu-devel@nongnu.org Subject: [Qemu-devel] [PATCH v4 10/12] fdc: rework pick_geometry X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Sender: qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org X-Spam-Status: No, score=-6.9 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_HI, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP This one is the crazy one. fd_revalidate currently uses pick_geometry to tell if the diskette geometry has changed upon an eject/insert event, but it won't allow us to insert a 1.44MB diskette into a 2.88MB drive. This is inflexible. The new algorithm applies a new heuristic to guessing disk geometries that allows us to switch diskette types as long as the physical size matches before falling back to the old heuristic. The old one is roughly: - If the size (sectors) and type matches, choose it. - Fall back to the first geometry that matched our type. The new one is: - If the size (sectors) and type matches, choose it. - If the size (sectors) and physical size match, choose it. - If the size (sectors) matches at all, choose it begrudgingly. - Fall back to the first geometry that matched our type. Signed-off-by: John Snow --- hw/block/fdc.c | 63 ++++++++++++++++++++++++++++++++++++++-------------------- 1 file changed, 42 insertions(+), 21 deletions(-) diff --git a/hw/block/fdc.c b/hw/block/fdc.c index 8a9747c..f8f7e6d 100644 --- a/hw/block/fdc.c +++ b/hw/block/fdc.c @@ -124,7 +124,6 @@ static const FDFormat fd_formats[] = { { FLOPPY_DRIVE_TYPE_NONE, -1, -1, 0, 0, }, }; -__attribute__((__unused__)) static FDriveSize drive_size(FloppyDriveType drive) { switch (drive) { @@ -283,45 +282,67 @@ static int pick_geometry(FDrive *drv) BlockBackend *blk = drv->blk; const FDFormat *parse; uint64_t nb_sectors, size; - int i, first_match, match; + int i; + int match, size_match, type_match; + bool magic = drv->drive == FLOPPY_DRIVE_TYPE_AUTO; /* We can only pick a geometry if we have a diskette. */ if ((!drv->media_inserted) || (drv->drive == FLOPPY_DRIVE_TYPE_NONE)) { return -1; } + /* We need to determine the likely geometry of the inserted medium. + * In order of preference, we look for: + * (1) The same drive type and number of sectors, + * (2) The same diskette size and number of sectors, + * (3) The same number of sectors, + * (4) The same drive type. + * + * In all cases, matches that occur higher in the drive table will take + * precedence over matches that occur later in the table. + */ blk_get_geometry(blk, &nb_sectors); - match = -1; - first_match = -1; + match = size_match = type_match = -1; for (i = 0; ; i++) { parse = &fd_formats[i]; if (parse->drive == FLOPPY_DRIVE_TYPE_NONE) { break; } - if (drv->drive == parse->drive || - drv->drive == FLOPPY_DRIVE_TYPE_AUTO) { - size = (parse->max_head + 1) * parse->max_track * - parse->last_sect; - if (nb_sectors == size) { - match = i; - break; + size = (parse->max_head + 1) * parse->max_track * parse->last_sect; + if (nb_sectors == size) { + if (magic || parse->drive == drv->drive) { + /* (1) perfect match */ + goto out; + } else if (drive_size(parse->drive) == drive_size(drv->drive)) { + /* (2) physical size match */ + match = (match == -1) ? i : match; + } else { + /* (3) nsectors match only */ + size_match = (size_match == -1) ? i : size_match; } - if (first_match == -1) { - first_match = i; + } else if (type_match == -1) { + if ((parse->drive == drv->drive) || + (magic && (parse->drive == get_fallback_drive_type(drv)))) { + /* (4) type matches, or type matches the autodetect default if + * we are using the autodetect mechanism. */ + type_match = i; } } } + if (match == -1) { - if (first_match == -1) { - error_setg(&error_abort, "No candidate geometries present in table " - " for floppy drive type '%s'", - FloppyDriveType_lookup[drv->drive]); - } else { - match = first_match; - } - parse = &fd_formats[match]; + match = (size_match != -1) ? size_match : type_match; + } + + if (match == -1) { + error_setg(&error_abort, "No candidate geometries present in table " + " for floppy drive type '%s'", + FloppyDriveType_lookup[drv->drive]); } + parse = &(fd_formats[match]); + + out: if (parse->max_head == 0) { drv->flags &= ~FDISK_DBL_SIDES; } else {