From patchwork Thu Aug 2 14:55:12 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Paolo Bonzini X-Patchwork-Id: 174765 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (Client did not present a certificate) by ozlabs.org (Postfix) with ESMTPS id 660B32C0093 for ; Fri, 3 Aug 2012 00:55:45 +1000 (EST) Received: from localhost ([::1]:41190 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1SwwoR-0000De-Jj for incoming@patchwork.ozlabs.org; Thu, 02 Aug 2012 10:55:43 -0400 Received: from eggs.gnu.org ([208.118.235.92]:55022) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1SwwoC-0000DX-VX for qemu-devel@nongnu.org; Thu, 02 Aug 2012 10:55:35 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1Swwo4-00041e-I4 for qemu-devel@nongnu.org; Thu, 02 Aug 2012 10:55:28 -0400 Received: from mail-gg0-f173.google.com ([209.85.161.173]:34066) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1Swwo4-000419-AX for qemu-devel@nongnu.org; Thu, 02 Aug 2012 10:55:20 -0400 Received: by ggnp1 with SMTP id p1so8521562ggn.4 for ; Thu, 02 Aug 2012 07:55:19 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=sender:message-id:date:from:user-agent:mime-version:to:cc:subject :references:in-reply-to:content-type; bh=5bF7mCAyYB/8FDg600TQAKEzp7dKYu0PlBGz7CXNNZM=; b=F4Zd2pwVceJlpCX1JYQ53j9gGsC3pl8QStJU5TjalwARXLtZY6ZgLKcZ3PEQFAN1J+ KMx5Hn/H12NvZbLflWwGOg4TSujMoMdoHfcn1Yo0XmUg+dlN9a/h6a/R+8xeQM7kvIqk YoIX3t7b8anfs5ED5DpBOjOOLUMkzo5h1aMXSsMdY24aIQ16Ekv28o8ly6a/6RX5K98j 6wzOaKEOlT9SCPtOzvU3EJ0y931uSkUjDh/904x+sRHZ47bv05isQcJBfh76vazdQu9Y 0utpRBJKp5DLCyMe8qR4dx8VZzpt/4mz80ngZuTBW5WUedmHXwUcxpE9Xw02DmEoLQP+ D1ig== Received: by 10.50.213.98 with SMTP id nr2mr3938874igc.71.1343919318675; Thu, 02 Aug 2012 07:55:18 -0700 (PDT) Received: from yakj.usersys.redhat.com (93-34-169-1.ip50.fastwebnet.it. [93.34.169.1]) by mx.google.com with ESMTPS id o1sm17288622igm.16.2012.08.02.07.55.15 (version=TLSv1/SSLv3 cipher=OTHER); Thu, 02 Aug 2012 07:55:17 -0700 (PDT) Message-ID: <501A94D0.3080502@redhat.com> Date: Thu, 02 Aug 2012 16:55:12 +0200 From: Paolo Bonzini User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:13.0) Gecko/20120615 Thunderbird/13.0.1 MIME-Version: 1.0 To: =?UTF-8?B?SGVydsOpIFBvdXNzaW5lYXU=?= References: <1343896676-3178-1-git-send-email-hpoussin@reactos.org> In-Reply-To: <1343896676-3178-1-git-send-email-hpoussin@reactos.org> X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 209.85.161.173 Cc: Blue Swirl , =?UTF-8?B?QW5kcmVhcyBGw6RyYmVy?= , qemu-devel@nongnu.org Subject: Re: [Qemu-devel] [PATCH v2] esp: add Tekram DC-390 emulation (PC SCSI adapter) 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+incoming=patchwork.ozlabs.org@nongnu.org Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Il 02/08/2012 10:37, Hervé Poussineau ha scritto: > Difference with AMD PCscsi is that DC-390 contains a EEPROM, > and that a romfile is available to add INT13 support. > > This has been successfully tested on: > - MS DOS 6.22 (using DC390 ASPI driver) > - MS Windows 98 SE (using DC390 driver) > - MS Windows NT 3.1 (using DC390 driver) > - MS Windows NT 4.0 (using DC390 driver) > - hard disk and cdrom boot > > Signed-off-by: Hervé Poussineau I can take this patch in the SCSI tree, but... do we really need two models, considering that the PCI id is the same and that (for the coolness factor of installing NT 3.1 onto an empty VM) we can just add ESP support to SeaBIOS? Does the option ROM not work without the EEPROM? (Regarding ESP support in SeaBIOS, I have an almost working patch; however, Windows XP setup fails at "Starting Windows" and I don't have any older images nor time to investigate... I attach both the QEMU and SeaBIOS changes, feel free to pick them up). Paolo From 59d5f4c18187a0b20ab4e1b93f4619e48f909df8 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Thu, 2 Aug 2012 14:56:05 +0200 Subject: [PATCH] scsi: add AMD PCscsi driver MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is a driver for an AMD PCscsi (am53c974) SCSI card. It can be used together with DOS or old operating systems such as Windows NT 3.1, Windows 3.1 or Windows 98. Cc: Hervé Poussineau Signed-off-by: Paolo Bonzini --- Makefile | 2 +- src/Kconfig | 6 ++ src/block.c | 1 + src/blockcmd.c | 3 + src/disk.h | 1 + src/esp-scsi.c | 231 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/post.c | 2 + 7 files changed, 245 insertions(+), 1 deletion(-) create mode 100644 src/esp-scsi.c diff --git a/Makefile b/Makefile index 1167799..4dce77b 100644 --- a/Makefile +++ b/Makefile @@ -13,7 +13,7 @@ SRCBOTH=misc.c stacks.c pmm.c output.c util.c block.c floppy.c ata.c mouse.c \ pnpbios.c pirtable.c vgahooks.c ramdisk.c pcibios.c blockcmd.c \ usb.c usb-uhci.c usb-ohci.c usb-ehci.c usb-hid.c usb-msc.c \ virtio-ring.c virtio-pci.c virtio-blk.c virtio-scsi.c apm.c ahci.c \ - usb-uas.c lsi-scsi.c + usb-uas.c lsi-scsi.c esp-scsi.c SRC16=$(SRCBOTH) system.c disk.c font.c SRC32FLAT=$(SRCBOTH) post.c shadow.c memmap.c coreboot.c boot.c \ acpi.c smm.c mptable.c smbios.c pciinit.c optionroms.c mtrr.c \ diff --git a/src/Kconfig b/src/Kconfig index bc343ee..6de3e71 100644 --- a/src/Kconfig +++ b/src/Kconfig @@ -119,6 +119,12 @@ menu "Hardware support" default y help Support boot from virtio-scsi storage. + config ESP_SCSI + depends on DRIVES && !COREBOOT + bool "AMD PCscsi controllers" + default y + help + Support boot from AMD PCscsi storage. config LSI_SCSI depends on DRIVES && !COREBOOT bool "lsi53c895a scsi controllers" diff --git a/src/block.c b/src/block.c index 1c200cc..243428e 100644 --- a/src/block.c +++ b/src/block.c @@ -335,6 +335,7 @@ process_op(struct disk_op_s *op) case DTYPE_UAS: case DTYPE_VIRTIO_SCSI: case DTYPE_LSI_SCSI: + case DTYPE_ESP_SCSI: return process_scsi_op(op); default: op->count = 0; diff --git a/src/blockcmd.c b/src/blockcmd.c index 4365650..97c72a6 100644 --- a/src/blockcmd.c +++ b/src/blockcmd.c @@ -15,6 +15,7 @@ #include "usb-uas.h" // usb_cmd_data #include "virtio-scsi.h" // virtio_scsi_cmd_data #include "lsi-scsi.h" // lsi_scsi_cmd_data +#include "esp-scsi.h" // esp_scsi_cmd_data #include "boot.h" // boot_add_hd // Route command to low-level handler. @@ -35,6 +36,8 @@ cdb_cmd_data(struct disk_op_s *op, void *cdbcmd, u16 blocksize) return virtio_scsi_cmd_data(op, cdbcmd, blocksize); case DTYPE_LSI_SCSI: return lsi_scsi_cmd_data(op, cdbcmd, blocksize); + case DTYPE_ESP_SCSI: + return esp_scsi_cmd_data(op, cdbcmd, blocksize); default: op->count = 0; return DISK_RET_EPARAM; diff --git a/src/disk.h b/src/disk.h index 2b2511f..3d07372 100644 --- a/src/disk.h +++ b/src/disk.h @@ -234,6 +234,7 @@ struct drive_s { #define DTYPE_USB 0x0a #define DTYPE_UAS 0x0b #define DTYPE_LSI_SCSI 0x0c +#define DTYPE_ESP_SCSI 0x0d #define MAXDESCSIZE 80 diff --git a/src/esp-scsi.c b/src/esp-scsi.c new file mode 100644 index 0000000..daafa1e --- /dev/null +++ b/src/esp-scsi.c @@ -0,0 +1,231 @@ +// AMD PCscsi boot support. +// +// Copyright (C) 2012 Red Hat Inc. +// +// Authors: +// Paolo Bonzini +// +// based on lsi-scsi.c which is written by: +// Gerd Hoffman +// +// This file may be distributed under the terms of the GNU LGPLv3 license. + +#include "util.h" // dprintf +#include "pci.h" // foreachpci +#include "config.h" // CONFIG_* +#include "biosvar.h" // GET_GLOBAL +#include "pci_ids.h" // PCI_DEVICE_ID +#include "pci_regs.h" // PCI_VENDOR_ID +#include "boot.h" // bootprio_find_scsi_device +#include "blockcmd.h" // scsi_init_drive +#include "disk.h" + +#define ESP_TCLO 0x00 +#define ESP_TCMID 0x04 +#define ESP_FIFO 0x08 +#define ESP_CMD 0x0c +#define ESP_WBUSID 0x10 +#define ESP_TCHI 0x38 + +#define ESP_RSTAT 0x10 +#define ESP_RINTR 0x14 +#define ESP_RFLAGS 0x1c + +#define ESP_DMA_CMD 0x40 +#define ESP_DMA_STC 0x44 +#define ESP_DMA_SPA 0x48 +#define ESP_DMA_WBC 0x4c +#define ESP_DMA_WAC 0x50 +#define ESP_DMA_STAT 0x54 +#define ESP_DMA_SMDLA 0x58 +#define ESP_DMA_WMAC 0x58c + +#define ESP_CMD_DMA 0x80 +#define ESP_CMD_RESET 0x02 +#define ESP_CMD_TI 0x10 +#define ESP_CMD_ICCS 0x11 +#define ESP_CMD_SELATN 0x42 + +#define ESP_STAT_DI 0x01 +#define ESP_STAT_CD 0x02 +#define ESP_STAT_MSG 0x04 +#define ESP_STAT_TC 0x10 + +#define ESP_INTR_DC 0x20 + +struct esp_lun_s { + struct drive_s drive; + struct pci_device *pci; + u32 iobase; + u8 target; + u8 lun; +}; + +static void +esp_scsi_dma(u32 iobase, u32 buf, u32 len, int read) +{ + outb(len & 0xff, iobase + ESP_TCLO); + outb((len >> 8) & 0xff, iobase + ESP_TCMID); + outb((len >> 16) & 0xff, iobase + ESP_TCHI); + outl(buf, iobase + ESP_DMA_SPA); + outl(len, iobase + ESP_DMA_STC); + outb(read ? 0x83 : 0x03, iobase + ESP_DMA_CMD); +} + +static int +esp_scsi_cmd(struct esp_lun_s *llun, struct disk_op_s *op, + u8 *cdbcmd, u16 target, u16 lun, u16 blocksize) +{ + u32 iobase = GET_GLOBAL(llun->iobase); + int i, state; + u8 status; + + outb(target, iobase + ESP_WBUSID); + + /* + * We need to pass the LUN at the beginning of the command, and the FIFO + * is only 16 bytes, so we cannot support 16-byte CDBs. The alternative + * would be to use DMA for the 17-byte command too, which is quite + * overkill. + */ + outb(lun, iobase + ESP_FIFO); + cdbcmd[1] &= 0x1f; + cdbcmd[1] |= lun << 5; + for (i = 0; i < 12; i++) + outb(cdbcmd[i], iobase + ESP_FIFO); + outb(ESP_CMD_SELATN, iobase + ESP_CMD); + + for (state = 0;;) { + u8 stat = inb(iobase + ESP_RSTAT); + + /* Detect disconnected device. */ + if (state == 0 && (inb(iobase + ESP_RINTR) & ESP_INTR_DC)) { + return DISK_RET_ENOTREADY; + } + + /* HBA reads command, clears CD, sets TC -> do DMA if needed. */ + if (state == 0 && (stat & ESP_STAT_TC)) { + state++; + if (op->count && blocksize) { + /* Data phase. */ + u32 count = (u32)op->count * blocksize; + esp_scsi_dma(iobase, (u32)op->buf_fl, count, + cdb_is_read(cdbcmd, blocksize)); + outb(ESP_CMD_TI | ESP_CMD_DMA, iobase + ESP_CMD); + continue; + } + } + + /* At end of DMA TC is set again -> complete command. */ + if (state == 1 && (stat & ESP_STAT_TC)) { + state++; + outb(ESP_CMD_ICCS, iobase + ESP_CMD); + continue; + } + + /* Finally read data from the message in phase. */ + if (state == 2 && (stat & ESP_STAT_MSG)) { + state++; + status = inb(iobase + ESP_FIFO); + inb(iobase + ESP_FIFO); + break; + } + usleep(5); + } + + if (status == 0) { + return DISK_RET_SUCCESS; + } + + return DISK_RET_EBADTRACK; +} + +int +esp_scsi_cmd_data(struct disk_op_s *op, void *cdbcmd, u16 blocksize) +{ + if (!CONFIG_ESP_SCSI) + return DISK_RET_EBADTRACK; + + struct esp_lun_s *llun = + container_of(op->drive_g, struct esp_lun_s, drive); + + return esp_scsi_cmd(llun, op, cdbcmd, + GET_GLOBAL(llun->target), GET_GLOBAL(llun->lun), + blocksize); +} + +static int +esp_scsi_add_lun(struct pci_device *pci, u32 iobase, u8 target, u8 lun) +{ + struct esp_lun_s *llun = malloc_fseg(sizeof(*llun)); + if (!llun) { + warn_noalloc(); + return -1; + } + memset(llun, 0, sizeof(*llun)); + llun->drive.type = DTYPE_ESP_SCSI; + llun->drive.cntl_id = pci->bdf; + llun->pci = pci; + llun->target = target; + llun->lun = lun; + llun->iobase = iobase; + + char *name = znprintf(16, "esp %02x:%02x.%x %d:%d", + pci_bdf_to_bus(pci->bdf), pci_bdf_to_dev(pci->bdf), + pci_bdf_to_fn(pci->bdf), target, lun); + int prio = bootprio_find_scsi_device(pci, target, lun); + int ret = scsi_init_drive(&llun->drive, name, prio); + free(name); + if (ret) + goto fail; + return 0; + +fail: + free(llun); + return -1; +} + +static void +esp_scsi_scan_target(struct pci_device *pci, u32 iobase, u8 target) +{ + esp_scsi_add_lun(pci, iobase, target, 0); +} + +static void +init_esp_scsi(struct pci_device *pci) +{ + u16 bdf = pci->bdf; + u32 iobase = pci_config_readl(pci->bdf, PCI_BASE_ADDRESS_0) + & PCI_BASE_ADDRESS_IO_MASK; + + dprintf(1, "found esp at %02x:%02x.%x, io @ %x\n", + pci_bdf_to_bus(bdf), pci_bdf_to_dev(bdf), + pci_bdf_to_fn(bdf), iobase); + + // reset + outb(ESP_CMD_RESET, iobase + ESP_CMD); + + int i; + for (i = 0; i <= 7; i++) + esp_scsi_scan_target(pci, iobase, i); + + return; +} + +void +esp_scsi_setup(void) +{ + ASSERT32FLAT(); + if (!CONFIG_ESP_SCSI) + return; + + dprintf(3, "init esp\n"); + + struct pci_device *pci; + foreachpci(pci) { + if (pci->vendor != PCI_VENDOR_ID_AMD + || pci->device != PCI_DEVICE_ID_AMD_SCSI) + continue; + init_esp_scsi(pci); + } +} diff --git a/src/post.c b/src/post.c index 0f31b4c..924b311 100644 --- a/src/post.c +++ b/src/post.c @@ -28,6 +28,7 @@ #include "virtio-blk.h" // virtio_blk_setup #include "virtio-scsi.h" // virtio_scsi_setup #include "lsi-scsi.h" // lsi_scsi_setup +#include "esp-scsi.h" // esp_scsi_setup /**************************************************************** @@ -196,6 +197,7 @@ init_hw(void) virtio_blk_setup(); virtio_scsi_setup(); lsi_scsi_setup(); + esp_scsi_setup(); } // Begin the boot process by invoking an int0x19 in 16bit mode. -- 1.7.10.4