From patchwork Thu Nov 19 10:07:12 2009 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jan Kiszka X-Patchwork-Id: 38824 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [199.232.76.165]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (Client did not present a certificate) by ozlabs.org (Postfix) with ESMTPS id AAF0D1007D3 for ; Thu, 19 Nov 2009 21:20:08 +1100 (EST) Received: from localhost ([127.0.0.1]:38390 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1NB47R-0006D3-E6 for incoming@patchwork.ozlabs.org; Thu, 19 Nov 2009 05:20:05 -0500 Received: from mailman by lists.gnu.org with tmda-scanned (Exim 4.43) id 1NB3vv-00021U-P9 for qemu-devel@nongnu.org; Thu, 19 Nov 2009 05:08:11 -0500 Received: from exim by lists.gnu.org with spam-scanned (Exim 4.43) id 1NB3vp-0001yf-Kg for qemu-devel@nongnu.org; Thu, 19 Nov 2009 05:08:10 -0500 Received: from [199.232.76.173] (port=52210 helo=monty-python.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1NB3vo-0001yJ-UF for qemu-devel@nongnu.org; Thu, 19 Nov 2009 05:08:05 -0500 Received: from goliath.siemens.de ([192.35.17.28]:20733) by monty-python.gnu.org with esmtps (TLS-1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.60) (envelope-from ) id 1NB3vo-0001L7-47 for qemu-devel@nongnu.org; Thu, 19 Nov 2009 05:08:04 -0500 Received: from mail1.siemens.de (localhost [127.0.0.1]) by goliath.siemens.de (8.12.11.20060308/8.12.11) with ESMTP id nAJA7xxu010609; Thu, 19 Nov 2009 11:08:00 +0100 Received: from [139.25.109.167] (mchn012c.ww002.siemens.net [139.25.109.167] (may be forged)) by mail1.siemens.de (8.12.11.20060308/8.12.11) with ESMTP id nAJA7xSX028219; Thu, 19 Nov 2009 11:07:59 +0100 Resent-From: Jan Kiszka Resent-To: qemu-devel Resent-Cc: "Ast, Laszlo" Resent-Date: Thu, 19 Nov 2009 11:07:59 +0100 Resent-Message-Id: <4B0518FF.3080108@siemens.com> Resent-User-Agent: Mozilla/5.0 (X11; U; Linux i686 (x86_64); de; rv:1.8.1.12) Gecko/20080226 SUSE/2.0.0.12-1.1 Thunderbird/2.0.0.12 Mnenhy/0.7.5.666 From: Jan Kiszka To: qemu-devel@nongnu.org Date: Thu, 19 Nov 2009 11:07:12 +0100 Message-ID: <20091119100712.16666.41897.stgit@mchn012c.ww002.siemens.net> In-Reply-To: <20091119100711.16666.2282.stgit@mchn012c.ww002.siemens.net> References: <20091119100711.16666.2282.stgit@mchn012c.ww002.siemens.net> User-Agent: StGIT/0.14.3 MIME-Version: 1.0 X-detected-operating-system: by monty-python.gnu.org: GNU/Linux 2.4-2.6 Resent-Date: Thu, 19 Nov 2009 05:08:10 -0500 Cc: Laszlo Ast Subject: [Qemu-devel] [PATCH 7/7] lsi53c895a: Implement IRQ on reselection X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: qemu-devel.nongnu.org List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org From: Laszlo Ast The critical part of this change is how to deal with simultaneaous generation of interrupts. The only (normal) case when this happens in the emulation is near simultaneous reselection + selection. If selection comes first, there is no problem, since the target attempting reselection loses the arbitration (in the emulation it only means that the reselect function will not be started). In the worst case the host adapter is reselected, but the device driver already started a selection, so we jump to the alternative address to handle the situation. The SCRIPTS code can trigger another interrupt to notify the driver that the new task has to be postponed. I suppose that on real hardware there is enough time after the reselection interrupt to set the SIP bit before the next interrupt comes, so it would result in 2 stacked interrupts (a SCSI and a DMA one). However, in the emulation there is no interrupt stacking, so there is a good chance that the 2 interrupts will get to the interrupt handler at the same time. Nevertheless, it should not make a big difference in interrupt handling, since in both cases both interrupts have to be fetched first, and after that the new task (that failed during the selection phase) has to be prepared/reset for a later restart, and the reconnected device has to be serviced. The changes do not modify the host adapter's behavior if this interrupt is not enabled. See also LSI53C895A technical manual, SCID and SIEN0. Signed-off-by: Laszlo Ast Signed-off-by: Jan Kiszka --- hw/lsi53c895a.c | 43 ++++++++++++++++++++++++++++++++++++++++--- 1 files changed, 40 insertions(+), 3 deletions(-) diff --git a/hw/lsi53c895a.c b/hw/lsi53c895a.c index 480fbca..32236aa 100644 --- a/hw/lsi53c895a.c +++ b/hw/lsi53c895a.c @@ -152,6 +152,9 @@ do { fprintf(stderr, "lsi_scsi: error: " fmt , ## __VA_ARGS__);} while (0) #define LSI_CCNTL1_DDAC 0x08 #define LSI_CCNTL1_ZMOD 0x80 +/* Enable Response to Reselection */ +#define LSI_SCID_RRE 0x60 + #define LSI_CCNTL1_40BIT (LSI_CCNTL1_EN64TIBMV|LSI_CCNTL1_64TIMOD) #define PHASE_DO 0 @@ -270,6 +273,11 @@ typedef struct { uint32_t script_ram[2048]; } LSIState; +static inline int lsi_irq_on_rsl(LSIState *s) +{ + return (s->sien0 & LSI_SIST0_RSL) && (s->scid & LSI_SCID_RRE); +} + static void lsi_soft_reset(LSIState *s) { DPRINTF("Reset\n"); @@ -360,6 +368,7 @@ static int lsi_dma_64bit(LSIState *s) static uint8_t lsi_reg_readb(LSIState *s, int offset); static void lsi_reg_writeb(LSIState *s, int offset, uint8_t val); static void lsi_execute_script(LSIState *s); +static void lsi_reselect(LSIState *s, uint32_t tag); static inline uint32_t read_dword(LSIState *s, uint32_t addr) { @@ -380,6 +389,7 @@ static void lsi_stop_script(LSIState *s) static void lsi_update_irq(LSIState *s) { + int i; int level; static int last_level; @@ -411,6 +421,17 @@ static void lsi_update_irq(LSIState *s) last_level = level; } qemu_set_irq(s->dev.irq[0], level); + + if (!level && lsi_irq_on_rsl(s) && !(s->scntl1 & LSI_SCNTL1_CON)) { + DPRINTF("Handled IRQs & disconnected, looking for pending " + "processes\n"); + for (i = 0; i < s->active_commands; i++) { + if (s->queue[i].pending) { + lsi_reselect(s, s->queue[i].tag); + break; + } + } + } } /* Stop SCRIPTS execution and raise a SCSI interrupt. */ @@ -605,6 +626,10 @@ static void lsi_reselect(LSIState *s, uint32_t tag) if (n != s->active_commands) { s->queue[n] = s->queue[s->active_commands]; } + + if (lsi_irq_on_rsl(s)) { + lsi_script_scsi_interrupt(s, LSI_SIST0_RSL, 0); + } } /* Record that data is available for a queued command. Returns zero if @@ -620,7 +645,14 @@ static int lsi_queue_tag(LSIState *s, uint32_t tag, uint32_t arg) BADF("Multiple IO pending for tag %d\n", tag); } p->pending = arg; - if (s->waiting == 1) { + /* Reselect if waiting for it, or if reselection triggers an IRQ + and the bus is free. + Since no interrupt stacking is implemented in the emulation, it + is also required that there are no pending interrupts waiting + for service from the device driver. */ + if (s->waiting == 1 || + (lsi_irq_on_rsl(s) && !(s->scntl1 & LSI_SCNTL1_CON) && + !(s->istat0 & (LSI_ISTAT0_SIP | LSI_ISTAT0_DIP)))) { /* Reselect device. */ lsi_reselect(s, tag); return 0; @@ -657,10 +689,13 @@ static void lsi_command_complete(SCSIBus *bus, int reason, uint32_t tag, return; } - if (s->waiting == 1 || tag != s->current_tag) { + if (s->waiting == 1 || tag != s->current_tag || + (lsi_irq_on_rsl(s) && !(s->scntl1 & LSI_SCNTL1_CON))) { if (lsi_queue_tag(s, tag, arg)) return; } + + /* host adapter (re)connected */ DPRINTF("Data ready tag=0x%x len=%d\n", tag, arg); s->current_dma_len = arg; s->command_complete = 1; @@ -1069,7 +1104,9 @@ again: s->scntl1 &= ~LSI_SCNTL1_CON; break; case 2: /* Wait Reselect */ - lsi_wait_reselect(s); + if (!lsi_irq_on_rsl(s)) { + lsi_wait_reselect(s); + } break; case 3: /* Set */ DPRINTF("Set%s%s%s%s\n",