Received: by 2002:ac0:a5b6:0:0:0:0:0 with SMTP id m51-v6csp833241imm; Tue, 5 Jun 2018 05:19:17 -0700 (PDT) X-Google-Smtp-Source: ADUXVKJT0R4Sc7qiydN4bX/Y0aMS19dZP7WIDAw1COwEEAJBUFvlIZPwBEkleL4hn78OkprwAA3w X-Received: by 2002:a17:902:56e:: with SMTP id 101-v6mr26498978plf.25.1528201157748; Tue, 05 Jun 2018 05:19:17 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1528201157; cv=none; d=google.com; s=arc-20160816; b=r8qAwAQVRQJpFhzn3e8WdhovdtJbrEm60RnTRODJzMH5IJe3/tEKflA4TtHfTCJp5X 3J+qq/16ODMBCvYiR89ucrIWwaGjqcGn1qlnTkU9LQDNp0bvmfITSy2U8xbng79stSqE qQQRPglxYqAg+O4s0JeLcihqf43U1Ls/CNeYc4jQ/7ObpEKgRqAZXXu5PKX1h+R6Rfnk 3rbvPT45/rpu9m+C0Cv1leJuqmBoCQT0d/0owUTbPpo1Jf6+L8/rshVcHUctmiUD3vqY uhmV5sTQijWDTnJdQAgDfYQBeOSYidXcZOn2FH9NXnvTbk5Gx95T9MAxhr7dD8EuD/bW aZqQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:content-transfer-encoding:mime-version :organization:references:in-reply-to:message-id:subject:cc:to:from :date:arc-authentication-results; bh=t1zgclgL3nyrGuZKeH4bIFi2B6T5E3LwNPTxB7RqvCo=; b=lA5r8yjFVegr2CHmOtsSQtiNWAZjdYe5Pd3fcRxTldmYfXKWWDeEzV9rn3+0Do2EGf K5QG9WQZ++RbAcXXCna/OCLyjWu8wNg5TAbJpIXR2nHxKBGV85LMAQ8G+qWFnvf/ysYK J39cq2A4RwWuWfdL/LObeCJx5GdZtti84BiSLyBWKga/Pn0t4H7YnK3ISkersrnAOf7e 47UxOcfijPpzHJBnROcTpQrayb8jCUP0d8h0VCy3lq7nBPEh3hGirJ66RxLC9wpUInC6 MuFrLpDhaJYcTKHG2COjC6htWVNrtdl1rw3jSlnYfqDYHbUJCX01Yv9MVMhJQ2VsQ5z5 zbRQ== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=redhat.com Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id m22-v6si14881778pls.147.2018.06.05.05.19.02; Tue, 05 Jun 2018 05:19:17 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=redhat.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751876AbeFEMSd (ORCPT + 99 others); Tue, 5 Jun 2018 08:18:33 -0400 Received: from mx3-rdu2.redhat.com ([66.187.233.73]:55886 "EHLO mx1.redhat.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1751742AbeFEMSb (ORCPT ); Tue, 5 Jun 2018 08:18:31 -0400 Received: from smtp.corp.redhat.com (int-mx05.intmail.prod.int.rdu2.redhat.com [10.11.54.5]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 2830C818BAEE; Tue, 5 Jun 2018 12:18:31 +0000 (UTC) Received: from gondolin (dhcp-192-222.str.redhat.com [10.33.192.222]) by smtp.corp.redhat.com (Postfix) with ESMTP id 166AC63535; Tue, 5 Jun 2018 12:18:29 +0000 (UTC) Date: Tue, 5 Jun 2018 14:18:27 +0200 From: Cornelia Huck To: Pierre Morel Cc: pasic@linux.vnet.ibm.com, bjsdjshi@linux.vnet.ibm.com, linux-s390@vger.kernel.org, linux-kernel@vger.kernel.org, kvm@vger.kernel.org Subject: Re: [PATCH v2 08/10] vfio: ccw: Handling reset and shutdown with states Message-ID: <20180605141827.6911fc74.cohuck@redhat.com> In-Reply-To: <1527243678-3140-9-git-send-email-pmorel@linux.vnet.ibm.com> References: <1527243678-3140-1-git-send-email-pmorel@linux.vnet.ibm.com> <1527243678-3140-9-git-send-email-pmorel@linux.vnet.ibm.com> Organization: Red Hat GmbH MIME-Version: 1.0 Content-Type: text/plain; charset=US-ASCII Content-Transfer-Encoding: 7bit X-Scanned-By: MIMEDefang 2.79 on 10.11.54.5 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.8]); Tue, 05 Jun 2018 12:18:31 +0000 (UTC) X-Greylist: inspected by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.8]); Tue, 05 Jun 2018 12:18:31 +0000 (UTC) for IP:'10.11.54.5' DOMAIN:'int-mx05.intmail.prod.int.rdu2.redhat.com' HELO:'smtp.corp.redhat.com' FROM:'cohuck@redhat.com' RCPT:'' Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org On Fri, 25 May 2018 12:21:16 +0200 Pierre Morel wrote: > Two new events, VFIO_CCW_EVENT_ONLINE and VFIO_CCW_EVENT_OFFLINE > allow to handle the enabling and disabling of a Sub Channel and > the init, shutdown, quiesce and reset operations are changed > accordingly. > > Signed-off-by: Pierre Morel > --- > drivers/s390/cio/vfio_ccw_drv.c | 44 ++++------------------ > drivers/s390/cio/vfio_ccw_fsm.c | 75 +++++++++++++++++++++++++++++++++---- > drivers/s390/cio/vfio_ccw_ops.c | 15 ++------ > drivers/s390/cio/vfio_ccw_private.h | 3 ++ > 4 files changed, 82 insertions(+), 55 deletions(-) > > diff --git a/drivers/s390/cio/vfio_ccw_drv.c b/drivers/s390/cio/vfio_ccw_drv.c > index 6fc7668..3e7b514 100644 > --- a/drivers/s390/cio/vfio_ccw_drv.c > +++ b/drivers/s390/cio/vfio_ccw_drv.c > @@ -30,41 +30,13 @@ int vfio_ccw_sch_quiesce(struct subchannel *sch) > { > struct vfio_ccw_private *private = dev_get_drvdata(&sch->dev); > DECLARE_COMPLETION_ONSTACK(completion); > - int iretry, ret = 0; > - > - spin_lock_irq(sch->lock); > - if (!sch->schib.pmcw.ena) > - goto out_unlock; > - ret = cio_disable_subchannel(sch); > - if (ret != -EBUSY) > - goto out_unlock; > - > - do { > - iretry = 255; > - > - ret = cio_cancel_halt_clear(sch, &iretry); > - while (ret == -EBUSY) { > - /* > - * Flush all I/O and wait for > - * cancel/halt/clear completion. > - */ > - private->completion = &completion; > - spin_unlock_irq(sch->lock); > - > - wait_for_completion_timeout(&completion, 3*HZ); > - > - spin_lock_irq(sch->lock); > - private->completion = NULL; > - flush_workqueue(vfio_ccw_work_q); > - ret = cio_cancel_halt_clear(sch, &iretry); > - }; > - > - ret = cio_disable_subchannel(sch); > - } while (ret == -EBUSY); > -out_unlock: > - private->state = VFIO_CCW_STATE_NOT_OPER; > - spin_unlock_irq(sch->lock); > - return ret; > + > + private->completion = &completion; > + vfio_ccw_fsm_event(private, VFIO_CCW_EVENT_OFFLINE); > + wait_for_completion_interruptible_timeout(&completion, jiffies + 3*HZ); > + if (private->state != VFIO_CCW_STATE_STANDBY) > + return -EFAULT; -EFAULT really looks like the wrong error here. -EIO? (I'm not sold on the whole concept here, though. See below.) > + return 0; > } > > static void vfio_ccw_sch_io_todo(struct work_struct *work) > @@ -95,8 +67,6 @@ static void vfio_ccw_sch_irq(struct subchannel *sch) > memcpy(&private->irb, irb, sizeof(*irb)); > > queue_work(vfio_ccw_work_q, &private->io_work); > - if (private->completion) > - complete(private->completion); > } > > static int vfio_ccw_sch_probe(struct subchannel *sch) > diff --git a/drivers/s390/cio/vfio_ccw_fsm.c b/drivers/s390/cio/vfio_ccw_fsm.c > index 20b909c..0acab2f 100644 > --- a/drivers/s390/cio/vfio_ccw_fsm.c > +++ b/drivers/s390/cio/vfio_ccw_fsm.c > @@ -73,6 +73,53 @@ static int fsm_notoper(struct vfio_ccw_private *private) > return VFIO_CCW_STATE_NOT_OPER; > } > > +static int fsm_online(struct vfio_ccw_private *private) > +{ > + struct subchannel *sch = private->sch; > + int ret = VFIO_CCW_STATE_IDLE; > + > + spin_lock_irq(sch->lock); > + if (cio_enable_subchannel(sch, (u32)(unsigned long)sch)) > + ret = VFIO_CCW_STATE_NOT_OPER; > + spin_unlock_irq(sch->lock); > + > + return ret; > +} > +static int fsm_offline(struct vfio_ccw_private *private) > +{ > + struct subchannel *sch = private->sch; > + int ret = VFIO_CCW_STATE_STANDBY; > + > + spin_lock_irq(sch->lock); > + if (cio_disable_subchannel(sch)) > + ret = VFIO_CCW_STATE_NOT_OPER; So, what about a subchannel that is busy? Why should it go to the not oper state? (And you should try to flush pending I/O and then try again in that case. Otherwise, you may have a still-enabled subchannel which may throw an interrupt.) > + spin_unlock_irq(sch->lock); > + if (private->completion) > + complete(private->completion); > + > + return ret; > +} > +static int fsm_quiescing(struct vfio_ccw_private *private) > +{ > + struct subchannel *sch = private->sch; > + int ret = VFIO_CCW_STATE_STANDBY; > + int iretry = 255; > + > + spin_lock_irq(sch->lock); > + ret = cio_cancel_halt_clear(sch, &iretry); > + if (ret == -EBUSY) > + ret = VFIO_CCW_STATE_QUIESCING; > + else if (private->completion) > + complete(private->completion); > + spin_unlock_irq(sch->lock); > + return ret; If I read this correctly, you're calling cio_cancel_halt_clear() only once. What happened to the retry loop? > +} > +static int fsm_quiescing_done(struct vfio_ccw_private *private) > +{ > + if (private->completion) > + complete(private->completion); > + return VFIO_CCW_STATE_STANDBY; > +} > /* > * No operation action. > */ > @@ -178,15 +225,10 @@ static int fsm_sch_event(struct vfio_ccw_private *private) > static int fsm_init(struct vfio_ccw_private *private) > { > struct subchannel *sch = private->sch; > - int ret = VFIO_CCW_STATE_STANDBY; > > - spin_lock_irq(sch->lock); > sch->isc = VFIO_CCW_ISC; > - if (cio_enable_subchannel(sch, (u32)(unsigned long)sch)) > - ret = VFIO_CCW_STATE_NOT_OPER; > - spin_unlock_irq(sch->lock); > > - return ret; > + return VFIO_CCW_STATE_STANDBY; Doesn't that change the semantic of the standby state? > } > > > @@ -196,6 +238,8 @@ static int fsm_init(struct vfio_ccw_private *private) > fsm_func_t *vfio_ccw_jumptable[NR_VFIO_CCW_STATES][NR_VFIO_CCW_EVENTS] = { > [VFIO_CCW_STATE_NOT_OPER] = { > [VFIO_CCW_EVENT_INIT] = fsm_init, > + [VFIO_CCW_EVENT_ONLINE] = fsm_nop, > + [VFIO_CCW_EVENT_OFFLINE] = fsm_nop, > [VFIO_CCW_EVENT_NOT_OPER] = fsm_nop, > [VFIO_CCW_EVENT_SSCH_REQ] = fsm_nop, > [VFIO_CCW_EVENT_INTERRUPT] = fsm_nop, > @@ -203,13 +247,17 @@ fsm_func_t *vfio_ccw_jumptable[NR_VFIO_CCW_STATES][NR_VFIO_CCW_EVENTS] = { > }, > [VFIO_CCW_STATE_STANDBY] = { > [VFIO_CCW_EVENT_INIT] = fsm_nop, > + [VFIO_CCW_EVENT_ONLINE] = fsm_online, > + [VFIO_CCW_EVENT_OFFLINE] = fsm_offline, > [VFIO_CCW_EVENT_NOT_OPER] = fsm_notoper, > [VFIO_CCW_EVENT_SSCH_REQ] = fsm_io_error, > - [VFIO_CCW_EVENT_INTERRUPT] = fsm_irq, > + [VFIO_CCW_EVENT_INTERRUPT] = fsm_disabled_irq, > [VFIO_CCW_EVENT_SCHIB_CHANGED] = fsm_sch_event, > }, > [VFIO_CCW_STATE_IDLE] = { > [VFIO_CCW_EVENT_INIT] = fsm_nop, > + [VFIO_CCW_EVENT_ONLINE] = fsm_nop, > + [VFIO_CCW_EVENT_OFFLINE] = fsm_offline, > [VFIO_CCW_EVENT_NOT_OPER] = fsm_notoper, > [VFIO_CCW_EVENT_SSCH_REQ] = fsm_io_request, > [VFIO_CCW_EVENT_INTERRUPT] = fsm_irq, > @@ -217,6 +265,8 @@ fsm_func_t *vfio_ccw_jumptable[NR_VFIO_CCW_STATES][NR_VFIO_CCW_EVENTS] = { > }, > [VFIO_CCW_STATE_BOXED] = { > [VFIO_CCW_EVENT_INIT] = fsm_nop, > + [VFIO_CCW_EVENT_ONLINE] = fsm_nop, > + [VFIO_CCW_EVENT_OFFLINE] = fsm_quiescing, > [VFIO_CCW_EVENT_NOT_OPER] = fsm_notoper, > [VFIO_CCW_EVENT_SSCH_REQ] = fsm_io_busy, > [VFIO_CCW_EVENT_INTERRUPT] = fsm_irq, > @@ -224,9 +274,20 @@ fsm_func_t *vfio_ccw_jumptable[NR_VFIO_CCW_STATES][NR_VFIO_CCW_EVENTS] = { > }, > [VFIO_CCW_STATE_BUSY] = { > [VFIO_CCW_EVENT_INIT] = fsm_nop, > + [VFIO_CCW_EVENT_ONLINE] = fsm_nop, > + [VFIO_CCW_EVENT_OFFLINE] = fsm_quiescing, > [VFIO_CCW_EVENT_NOT_OPER] = fsm_notoper, > [VFIO_CCW_EVENT_SSCH_REQ] = fsm_io_busy, > [VFIO_CCW_EVENT_INTERRUPT] = fsm_irq, > [VFIO_CCW_EVENT_SCHIB_CHANGED] = fsm_sch_event, > }, > + [VFIO_CCW_STATE_QUIESCING] = { > + [VFIO_CCW_EVENT_INIT] = fsm_nop, > + [VFIO_CCW_EVENT_ONLINE] = fsm_nop, > + [VFIO_CCW_EVENT_OFFLINE] = fsm_nop, > + [VFIO_CCW_EVENT_NOT_OPER] = fsm_notoper, > + [VFIO_CCW_EVENT_SSCH_REQ] = fsm_io_busy, > + [VFIO_CCW_EVENT_INTERRUPT] = fsm_quiescing_done, > + [VFIO_CCW_EVENT_SCHIB_CHANGED] = fsm_sch_event, > + }, Your idea here seems to be to go to either disabling the subchannel directly or flushing out I/O first, depending on the state you're in. The problem is that you may need retries in any case (the subchannel may be status pending if it is enabled; not necessarily by any I/O that had been started, but also from an unsolicited notification.) > }; > diff --git a/drivers/s390/cio/vfio_ccw_ops.c b/drivers/s390/cio/vfio_ccw_ops.c > index ea8fd64..b202e73 100644 > --- a/drivers/s390/cio/vfio_ccw_ops.c > +++ b/drivers/s390/cio/vfio_ccw_ops.c > @@ -21,21 +21,14 @@ static int vfio_ccw_mdev_reset(struct mdev_device *mdev) > > private = dev_get_drvdata(mdev_parent_dev(mdev)); > sch = private->sch; > - /* > - * TODO: > - * In the cureent stage, some things like "no I/O running" and "no > - * interrupt pending" are clear, but we are not sure what other state > - * we need to care about. > - * There are still a lot more instructions need to be handled. We > - * should come back here later. > - */ This is still true, no? I'm thinking about things like channel monitors and the like (even if we don't support them yet). > + > ret = vfio_ccw_sch_quiesce(sch); > if (ret) > return ret; > + vfio_ccw_fsm_event(private, VFIO_CCW_EVENT_ONLINE); > > - ret = cio_enable_subchannel(sch, (u32)(unsigned long)sch); > - if (!ret) > - private->state = VFIO_CCW_STATE_IDLE; > + if (!(private->state == VFIO_CCW_STATE_IDLE)) > + ret = -EFAULT; The -EFAULT looks wrong here as well. I'm also not sure whether we should conflate enabling/disabling a device and doing a reset. > > return ret; > } > diff --git a/drivers/s390/cio/vfio_ccw_private.h b/drivers/s390/cio/vfio_ccw_private.h > index c5455a9..ad59091 100644 > --- a/drivers/s390/cio/vfio_ccw_private.h > +++ b/drivers/s390/cio/vfio_ccw_private.h > @@ -68,6 +68,7 @@ enum vfio_ccw_state { > VFIO_CCW_STATE_IDLE, > VFIO_CCW_STATE_BOXED, > VFIO_CCW_STATE_BUSY, > + VFIO_CCW_STATE_QUIESCING, > /* last element! */ > NR_VFIO_CCW_STATES > }; > @@ -81,6 +82,8 @@ enum vfio_ccw_event { > VFIO_CCW_EVENT_SSCH_REQ, > VFIO_CCW_EVENT_INTERRUPT, > VFIO_CCW_EVENT_SCHIB_CHANGED, > + VFIO_CCW_EVENT_ONLINE, > + VFIO_CCW_EVENT_OFFLINE, > /* last element! */ > NR_VFIO_CCW_EVENTS > };