summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorneel <neel@FreeBSD.org>2014-10-20 02:57:30 +0000
committerneel <neel@FreeBSD.org>2014-10-20 02:57:30 +0000
commitdd2febd6f26be95c4b3f1f67b23f53a28885082f (patch)
treeb2c78a90b3492af4d40dfeb9faedeb6bb82208c4
parent53c23ba9a2104ef3682a2b22cb1ab9269ca0745d (diff)
downloadFreeBSD-src-dd2febd6f26be95c4b3f1f67b23f53a28885082f.zip
FreeBSD-src-dd2febd6f26be95c4b3f1f67b23f53a28885082f.tar.gz
IFC @r273214
-rw-r--r--sbin/ping6/ping6.817
-rw-r--r--sbin/ping6/ping6.c55
-rw-r--r--sys/amd64/vmm/amd/svm_support.S2
-rw-r--r--sys/amd64/vmm/intel/vmx_support.S2
-rw-r--r--sys/conf/files5
-rw-r--r--sys/fs/autofs/autofs.c1
-rw-r--r--sys/geom/geom_dump.c5
-rw-r--r--sys/modules/vmm/Makefile24
-rw-r--r--sys/net/if_lagg.c88
-rw-r--r--usr.sbin/bhyve/block_if.c27
-rw-r--r--usr.sbin/bhyve/pci_ahci.c146
11 files changed, 272 insertions, 100 deletions
diff --git a/sbin/ping6/ping6.8 b/sbin/ping6/ping6.8
index 60a6980..99111e2 100644
--- a/sbin/ping6/ping6.8
+++ b/sbin/ping6/ping6.8
@@ -29,7 +29,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd May 5, 2013
+.Dd September 22, 2014
.Dt PING6 8
.Os
.Sh NAME
@@ -65,6 +65,12 @@ packets to network hosts
.Op Fl i Ar wait
.Ek
.Bk -words
+.Op Fl x Ar waittime
+.Ek
+.Bk -words
+.Op Fl X Ar timeout
+.Ek
+.Bk -words
.Op Fl l Ar preload
.Ek
.Bk -words
@@ -191,6 +197,15 @@ The default is to wait for one second between each packet.
This option is incompatible with the
.Fl f
option.
+.It Fl x Ar waittime
+Time in milliseconds to wait for a reply for each packet sent.
+If a reply arrives later,
+the packet is not printed as replied,
+but considered as replied when calculating statistics.
+.It Fl X Ar timeout
+Specify a timeout,
+in seconds,
+before ping exits regardless of how many packets have been received.
.It Fl l Ar preload
If
.Ar preload
diff --git a/sbin/ping6/ping6.c b/sbin/ping6/ping6.c
index 14f689d..9ad285c 100644
--- a/sbin/ping6/ping6.c
+++ b/sbin/ping6/ping6.c
@@ -152,6 +152,8 @@ struct tv32 {
#define DEFDATALEN ICMP6ECHOTMLEN
#define MAXDATALEN MAXPACKETLEN - IP6LEN - ICMP6ECHOLEN
#define NROUTES 9 /* number of record route slots */
+#define MAXWAIT 10000 /* max ms to wait for response */
+#define MAXALARM (60 * 60) /* max seconds for alarm timeout */
#define A(bit) rcvd_tbl[(bit)>>3] /* identify byte in array */
#define B(bit) (1 << ((bit) & 0x07)) /* identify bit in byte */
@@ -188,6 +190,7 @@ struct tv32 {
#define F_MISSED 0x800000
#define F_DONTFRAG 0x1000000
#define F_NOUSERDATA (F_NODEADDR | F_FQDN | F_FQDNOLD | F_SUPTYPES)
+#define F_WAITTIME 0x2000000
u_int options;
#define IN6LEN sizeof(struct in6_addr)
@@ -228,6 +231,8 @@ long nreceived; /* # of packets we got back */
long nrepeats; /* number of duplicates */
long ntransmitted; /* sequence # for outbound packets = #sent */
int interval = 1000; /* interval between packets in ms */
+int waittime = MAXWAIT; /* timeout for each packet */
+long nrcvtimeout = 0; /* # of packets we got back after waittime */
/* timing */
int timing; /* flag to do timing */
@@ -312,6 +317,7 @@ main(int argc, char *argv[])
char *policy_out = NULL;
#endif
double t;
+ u_long alarmtimeout;
size_t rthlen;
#ifdef IPV6_USE_MIN_MTU
int mflag = 0;
@@ -321,7 +327,7 @@ main(int argc, char *argv[])
memset(&smsghdr, 0, sizeof(smsghdr));
memset(&smsgiov, 0, sizeof(smsgiov));
- preload = 0;
+ alarmtimeout = preload = 0;
datap = &outpack[ICMP6ECHOLEN + ICMP6ECHOTMLEN];
#ifndef IPSEC
#define ADDOPTS
@@ -333,7 +339,7 @@ main(int argc, char *argv[])
#endif /*IPSEC_POLICY_IPSEC*/
#endif
while ((ch = getopt(argc, argv,
- "a:b:c:DdfHg:h:I:i:l:mnNop:qrRS:s:tvwW" ADDOPTS)) != -1) {
+ "a:b:c:DdfHg:h:I:i:l:mnNop:qrRS:s:tvwWx:X:" ADDOPTS)) != -1) {
#undef ADDOPTS
switch (ch) {
case 'a':
@@ -541,6 +547,24 @@ main(int argc, char *argv[])
options &= ~F_NOUSERDATA;
options |= F_FQDNOLD;
break;
+ case 'x':
+ t = strtod(optarg, &e);
+ if (*e || e == optarg || t > (double)INT_MAX)
+ err(EX_USAGE, "invalid timing interval: `%s'",
+ optarg);
+ options |= F_WAITTIME;
+ waittime = (int)t;
+ break;
+ case 'X':
+ alarmtimeout = strtoul(optarg, &e, 0);
+ if ((alarmtimeout < 1) || (alarmtimeout == ULONG_MAX))
+ errx(EX_USAGE, "invalid timeout: `%s'",
+ optarg);
+ if (alarmtimeout > MAXALARM)
+ errx(EX_USAGE, "invalid timeout: `%s' > %d",
+ optarg, MAXALARM);
+ alarm((int)alarmtimeout);
+ break;
#ifdef IPSEC
#ifdef IPSEC_POLICY_IPSEC
case 'P':
@@ -1057,6 +1081,10 @@ main(int argc, char *argv[])
err(EX_OSERR, "sigaction SIGINFO");
seeninfo = 0;
#endif
+ if (alarmtimeout > 0) {
+ if (sigaction(SIGALRM, &si_sa, 0) == -1)
+ err(EX_OSERR, "sigaction SIGALRM");
+ }
if (options & F_FLOOD) {
intvl.tv_sec = 0;
intvl.tv_usec = 10000;
@@ -1157,17 +1185,18 @@ main(int argc, char *argv[])
/*
* If we're not transmitting any more packets,
* change the timer to wait two round-trip times
- * if we've received any packets or ten seconds
- * if we haven't.
+ * if we've received any packets or (waittime)
+ * milliseconds if we haven't.
*/
-#define MAXWAIT 10
intvl.tv_usec = 0;
if (nreceived) {
intvl.tv_sec = 2 * tmax / 1000;
if (intvl.tv_sec == 0)
intvl.tv_sec = 1;
- } else
- intvl.tv_sec = MAXWAIT;
+ } else {
+ intvl.tv_sec = waittime / 1000;
+ intvl.tv_usec = waittime % 1000 * 1000;
+ }
}
gettimeofday(&last, NULL);
if (ntransmitted - nreceived - 1 > nmissedmax) {
@@ -1181,6 +1210,7 @@ main(int argc, char *argv[])
si_sa.sa_flags = 0;
si_sa.sa_handler = SIG_IGN;
sigaction(SIGINT, &si_sa, 0);
+ sigaction(SIGALRM, &si_sa, 0);
summary();
if (res != NULL)
@@ -1198,6 +1228,7 @@ onsignal(int sig)
switch (sig) {
case SIGINT:
+ case SIGALRM:
seenint++;
break;
#ifdef SIGINFO
@@ -1521,6 +1552,11 @@ pr_pack(u_char *buf, int cc, struct msghdr *mhdr)
if (options & F_QUIET)
return;
+ if (options & F_WAITTIME && triptime > waittime) {
+ ++nrcvtimeout;
+ return;
+ }
+
if (options & F_FLOOD)
(void)write(STDOUT_FILENO, &BSPACE, 1);
else {
@@ -2216,6 +2252,8 @@ summary(void)
((((double)ntransmitted - nreceived) * 100.0) /
ntransmitted));
}
+ if (nrcvtimeout)
+ printf(", %ld packets out of wait time", nrcvtimeout);
(void)putchar('\n');
if (nreceived && timing) {
/* Only display average to microseconds */
@@ -2741,6 +2779,7 @@ usage(void)
#endif
"\n"
" [-p pattern] [-S sourceaddr] [-s packetsize] "
- "[hops ...] host\n");
+ "[-x waittime]\n"
+ " [-X timeout] [hops ...] host\n");
exit(1);
}
diff --git a/sys/amd64/vmm/amd/svm_support.S b/sys/amd64/vmm/amd/svm_support.S
index 11da759..72327bd 100644
--- a/sys/amd64/vmm/amd/svm_support.S
+++ b/sys/amd64/vmm/amd/svm_support.S
@@ -25,7 +25,7 @@
*/
#include <machine/asmacros.h>
-#include "svm_assym.s"
+#include "svm_assym.h"
/*
* Be friendly to DTrace FBT's prologue/epilogue pattern matching.
diff --git a/sys/amd64/vmm/intel/vmx_support.S b/sys/amd64/vmm/intel/vmx_support.S
index 840b7e0..84fb5b0 100644
--- a/sys/amd64/vmm/intel/vmx_support.S
+++ b/sys/amd64/vmm/intel/vmx_support.S
@@ -29,7 +29,7 @@
#include <machine/asmacros.h>
-#include "vmx_assym.s"
+#include "vmx_assym.h"
#ifdef SMP
#define LK lock ;
diff --git a/sys/conf/files b/sys/conf/files
index 13150f4..80755fc 100644
--- a/sys/conf/files
+++ b/sys/conf/files
@@ -3231,7 +3231,8 @@ net/if_ethersubr.c optional ether
net/if_faith.c optional faith
net/if_fddisubr.c optional fddi
net/if_fwsubr.c optional fwip
-net/if_gif.c optional gif inet | gif inet6 | netgraph_gif
+net/if_gif.c optional gif inet | gif inet6 | \
+ netgraph_gif inet | netgraph_gif inet6
net/if_gre.c optional gre inet
net/if_iso88025subr.c optional token
net/if_lagg.c optional lagg
@@ -3357,7 +3358,7 @@ netgraph/ng_eiface.c optional netgraph_eiface
netgraph/ng_ether.c optional netgraph_ether
netgraph/ng_ether_echo.c optional netgraph_ether_echo
netgraph/ng_frame_relay.c optional netgraph_frame_relay
-netgraph/ng_gif.c optional netgraph_gif
+netgraph/ng_gif.c optional netgraph_gif inet6 | netgraph_gif inet
netgraph/ng_gif_demux.c optional netgraph_gif_demux
netgraph/ng_hole.c optional netgraph_hole
netgraph/ng_iface.c optional netgraph_iface
diff --git a/sys/fs/autofs/autofs.c b/sys/fs/autofs/autofs.c
index 029d254..6a9c0bf 100644
--- a/sys/fs/autofs/autofs.c
+++ b/sys/fs/autofs/autofs.c
@@ -550,7 +550,6 @@ autofs_ioctl_request(struct autofs_daemon_request *adr)
&autofs_softc->sc_lock);
if (error != 0) {
sx_xunlock(&autofs_softc->sc_lock);
- AUTOFS_DEBUG("failed with error %d", error);
return (error);
}
}
diff --git a/sys/geom/geom_dump.c b/sys/geom/geom_dump.c
index 8aaab0f..8ce237f 100644
--- a/sys/geom/geom_dump.c
+++ b/sys/geom/geom_dump.c
@@ -61,8 +61,9 @@ static void
g_confdot_provider(struct sbuf *sb, struct g_provider *pp)
{
- sbuf_printf(sb, "z%p [shape=hexagon,label=\"%s\\nr%dw%de%d\\nerr#%d\"];\n",
- pp, pp->name, pp->acr, pp->acw, pp->ace, pp->error);
+ sbuf_printf(sb, "z%p [shape=hexagon,label=\"%s\\nr%dw%de%d\\nerr#%d\\n"
+ "sector=%u\\nstripe=%u\"];\n", pp, pp->name, pp->acr, pp->acw,
+ pp->ace, pp->error, pp->sectorsize, pp->stripesize);
}
static void
diff --git a/sys/modules/vmm/Makefile b/sys/modules/vmm/Makefile
index 5bb31f5..45025a8 100644
--- a/sys/modules/vmm/Makefile
+++ b/sys/modules/vmm/Makefile
@@ -3,6 +3,7 @@
KMOD= vmm
SRCS= opt_acpi.h opt_ddb.h device_if.h bus_if.h pci_if.h
+SRCS+= vmx_assym.h svm_assym.h
CFLAGS+= -DVMM_KEEP_STATS -DSMP
CFLAGS+= -I${.CURDIR}/../../amd64/vmm
@@ -39,6 +40,7 @@ SRCS+= iommu.c \
SRCS+= ept.c \
vmcs.c \
vmx_msr.c \
+ vmx_support.S \
vmx.c \
vtd.c
@@ -46,37 +48,37 @@ SRCS+= ept.c \
.PATH: ${.CURDIR}/../../amd64/vmm/amd
SRCS+= vmcb.c \
svm.c \
+ svm_support.S \
npt.c \
amdv.c \
svm_msr.c
-OBJS= vmx_support.o svm_support.o
+CLEANFILES= vmx_assym.h vmx_genassym.o svm_assym.h svm_genassym.o
-CLEANFILES= vmx_assym.s vmx_genassym.o svm_assym.s svm_genassym.o
-
-vmx_assym.s: vmx_genassym.o
+vmx_assym.h: vmx_genassym.o
.if exists(@)
-vmx_assym.s: @/kern/genassym.sh
+vmx_assym.h: @/kern/genassym.sh
.endif
sh @/kern/genassym.sh vmx_genassym.o > ${.TARGET}
-svm_assym.s: svm_genassym.o
+svm_assym.h: svm_genassym.o
.if exists(@)
-svm_assym.s: @/kern/genassym.sh
+svm_assym.h: @/kern/genassym.sh
.endif
sh @/kern/genassym.sh svm_genassym.o > ${.TARGET}
-vmx_support.o: vmx_support.S vmx_assym.s
+vmx_support.o:
${CC} -c -x assembler-with-cpp -DLOCORE ${CFLAGS} \
${.IMPSRC} -o ${.TARGET}
-svm_support.o: svm_support.S svm_assym.s
+svm_support.o:
${CC} -c -x assembler-with-cpp -DLOCORE ${CFLAGS} \
${.IMPSRC} -o ${.TARGET}
-vmx_genassym.o: vmx_genassym.c @ machine x86
+vmx_genassym.o:
${CC} -c ${CFLAGS:N-fno-common} ${.IMPSRC}
-svm_genassym.o: svm_genassym.c @ machine x86
+svm_genassym.o:
${CC} -c ${CFLAGS:N-fno-common} ${.IMPSRC}
+
.include <bsd.kmod.mk>
diff --git a/sys/net/if_lagg.c b/sys/net/if_lagg.c
index 7f7e4b5..5c8b2e1 100644
--- a/sys/net/if_lagg.c
+++ b/sys/net/if_lagg.c
@@ -569,9 +569,22 @@ lagg_clone_destroy(struct ifnet *ifp)
static void
lagg_lladdr(struct lagg_softc *sc, uint8_t *lladdr)
{
+ struct ifnet *ifp = sc->sc_ifp;
struct lagg_port lp;
+ if (memcmp(lladdr, IF_LLADDR(ifp), ETHER_ADDR_LEN) == 0)
+ return;
+
LAGG_WLOCK_ASSERT(sc);
+ /*
+ * Set the link layer address on the lagg interface.
+ * lagg_proto_lladdr() notifies the MAC change to
+ * the aggregation protocol. iflladdr_event handler which
+ * may trigger gratuitous ARPs for INET will be handled in
+ * a taskqueue.
+ */
+ bcopy(lladdr, IF_LLADDR(ifp), ETHER_ADDR_LEN);
+ lagg_proto_lladdr(sc);
bzero(&lp, sizeof(lp));
lp.lp_ifp = sc->sc_ifp;
@@ -625,11 +638,13 @@ lagg_port_lladdr(struct lagg_port *lp, uint8_t *lladdr)
struct ifnet *ifp = lp->lp_ifp;
struct lagg_llq *llq;
int pending = 0;
+ int primary;
LAGG_WLOCK_ASSERT(sc);
- if (lp->lp_detaching ||
- memcmp(lladdr, IF_LLADDR(ifp), ETHER_ADDR_LEN) == 0)
+ primary = (sc->sc_primary->lp_ifp == ifp) ? 1 : 0;
+ if (primary == 0 && (lp->lp_detaching ||
+ memcmp(lladdr, IF_LLADDR(ifp), ETHER_ADDR_LEN) == 0))
return;
/* Check to make sure its not already queued to be changed */
@@ -648,7 +663,7 @@ lagg_port_lladdr(struct lagg_port *lp, uint8_t *lladdr)
/* Update the lladdr even if pending, it may have changed */
llq->llq_ifp = ifp;
- llq->llq_primary = (sc->sc_primary->lp_ifp == ifp) ? 1 : 0;
+ llq->llq_primary = primary;
bcopy(lladdr, llq->llq_lladdr, ETHER_ADDR_LEN);
if (!pending)
@@ -692,23 +707,8 @@ lagg_port_setlladdr(void *arg, int pending)
if (error)
printf("%s: setlladdr failed on %s\n", __func__,
ifp->if_xname);
- } else {
- /*
- * Set the link layer address on the lagg interface.
- * lagg_proto_lladdr() notifies the MAC change to
- * the aggregation protocol. iflladdr_event handler
- * may trigger gratuitous ARPs for INET.
- */
- if (memcmp(llq->llq_lladdr, IF_LLADDR(ifp),
- ETHER_ADDR_LEN) != 0) {
- bcopy(llq->llq_lladdr, IF_LLADDR(ifp),
- ETHER_ADDR_LEN);
- LAGG_WLOCK(sc);
- lagg_proto_lladdr(sc);
- LAGG_WUNLOCK(sc);
- EVENTHANDLER_INVOKE(iflladdr_event, ifp);
- }
- }
+ } else
+ EVENTHANDLER_INVOKE(iflladdr_event, ifp);
CURVNET_RESTORE();
head = SLIST_NEXT(llq, llq_entries);
free(llq, M_DEVBUF);
@@ -742,34 +742,6 @@ lagg_port_create(struct lagg_softc *sc, struct ifnet *ifp)
if (ifp->if_type != IFT_ETHER)
return (EPROTONOSUPPORT);
-#ifdef INET6
- /*
- * The member interface should not have inet6 address because
- * two interfaces with a valid link-local scope zone must not be
- * merged in any form. This restriction is needed to
- * prevent violation of link-local scope zone. Attempts to
- * add a member interface which has inet6 addresses triggers
- * removal of all inet6 addresses on the member interface.
- */
- SLIST_FOREACH(lp, &sc->sc_ports, lp_entries) {
- if (in6ifa_llaonifp(lp->lp_ifp)) {
- in6_ifdetach(lp->lp_ifp);
- if_printf(sc->sc_ifp,
- "IPv6 addresses on %s have been removed "
- "before adding it as a member to prevent "
- "IPv6 address scope violation.\n",
- lp->lp_ifp->if_xname);
- }
- }
- if (in6ifa_llaonifp(ifp)) {
- in6_ifdetach(ifp);
- if_printf(sc->sc_ifp,
- "IPv6 addresses on %s have been removed "
- "before adding it as a member to prevent "
- "IPv6 address scope violation.\n",
- ifp->if_xname);
- }
-#endif
/* Allow the first Ethernet member to define the MTU */
if (SLIST_EMPTY(&sc->sc_ports))
sc->sc_ifp->if_mtu = ifp->if_mtu;
@@ -1414,6 +1386,26 @@ lagg_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
error = EINVAL;
break;
}
+#ifdef INET6
+ /*
+ * A laggport interface should not have inet6 address
+ * because two interfaces with a valid link-local
+ * scope zone must not be merged in any form. This
+ * restriction is needed to prevent violation of
+ * link-local scope zone. Attempts to add a laggport
+ * interface which has inet6 addresses triggers
+ * removal of all inet6 addresses on the member
+ * interface.
+ */
+ if (in6ifa_llaonifp(tpif)) {
+ in6_ifdetach(tpif);
+ if_printf(sc->sc_ifp,
+ "IPv6 addresses on %s have been removed "
+ "before adding it as a member to prevent "
+ "IPv6 address scope violation.\n",
+ tpif->if_xname);
+ }
+#endif
LAGG_WLOCK(sc);
error = lagg_port_create(sc, tpif);
LAGG_WUNLOCK(sc);
diff --git a/usr.sbin/bhyve/block_if.c b/usr.sbin/bhyve/block_if.c
index b038228..cbe5ac3 100644
--- a/usr.sbin/bhyve/block_if.c
+++ b/usr.sbin/bhyve/block_if.c
@@ -55,8 +55,7 @@ __FBSDID("$FreeBSD$");
enum blockop {
BOP_READ,
BOP_WRITE,
- BOP_FLUSH,
- BOP_CANCEL
+ BOP_FLUSH
};
enum blockstat {
@@ -159,9 +158,6 @@ blockif_proc(struct blockif_ctxt *bc, struct blockif_elem *be)
break;
case BOP_FLUSH:
break;
- case BOP_CANCEL:
- err = EINTR;
- break;
default:
err = EINVAL;
break;
@@ -356,9 +352,28 @@ blockif_flush(struct blockif_ctxt *bc, struct blockif_req *breq)
int
blockif_cancel(struct blockif_ctxt *bc, struct blockif_req *breq)
{
+ struct blockif_elem *be;
assert(bc->bc_magic == BLOCKIF_SIG);
- return (blockif_request(bc, breq, BOP_CANCEL));
+
+ pthread_mutex_lock(&bc->bc_mtx);
+ TAILQ_FOREACH(be, &bc->bc_inuseq, be_link) {
+ if (be->be_req == breq)
+ break;
+ }
+ if (be == NULL) {
+ pthread_mutex_unlock(&bc->bc_mtx);
+ return (EINVAL);
+ }
+
+ TAILQ_REMOVE(&bc->bc_inuseq, be, be_link);
+ be->be_status = BST_FREE;
+ be->be_req = NULL;
+ TAILQ_INSERT_TAIL(&bc->bc_freeq, be, be_link);
+ bc->bc_req_count--;
+ pthread_mutex_unlock(&bc->bc_mtx);
+
+ return (0);
}
int
diff --git a/usr.sbin/bhyve/pci_ahci.c b/usr.sbin/bhyve/pci_ahci.c
index 214237d..42aa0b3 100644
--- a/usr.sbin/bhyve/pci_ahci.c
+++ b/usr.sbin/bhyve/pci_ahci.c
@@ -48,6 +48,7 @@ __FBSDID("$FreeBSD$");
#include <unistd.h>
#include <assert.h>
#include <pthread.h>
+#include <pthread_np.h>
#include <inttypes.h>
#include "bhyverun.h"
@@ -115,7 +116,8 @@ static FILE *dbg;
struct ahci_ioreq {
struct blockif_req io_req;
struct ahci_port *io_pr;
- STAILQ_ENTRY(ahci_ioreq) io_list;
+ STAILQ_ENTRY(ahci_ioreq) io_flist;
+ TAILQ_ENTRY(ahci_ioreq) io_blist;
uint8_t *cfis;
uint32_t len;
uint32_t done;
@@ -160,6 +162,7 @@ struct ahci_port {
struct ahci_ioreq *ioreq;
int ioqsz;
STAILQ_HEAD(ahci_fhead, ahci_ioreq) iofhd;
+ TAILQ_HEAD(ahci_bhead, ahci_ioreq) iobhd;
};
struct ahci_cmd_hdr {
@@ -360,6 +363,68 @@ ahci_write_reset_fis_d2h(struct ahci_port *p)
}
static void
+ahci_check_stopped(struct ahci_port *p)
+{
+ /*
+ * If we are no longer processing the command list and nothing
+ * is in-flight, clear the running bit.
+ */
+ if (!(p->cmd & AHCI_P_CMD_ST)) {
+ if (p->pending == 0)
+ p->cmd &= ~(AHCI_P_CMD_CR | AHCI_P_CMD_CCS_MASK);
+ }
+}
+
+static void
+ahci_port_stop(struct ahci_port *p)
+{
+ struct ahci_ioreq *aior;
+ uint8_t *cfis;
+ int slot;
+ int ncq;
+ int error;
+
+ assert(pthread_mutex_isowned_np(&p->pr_sc->mtx));
+
+ TAILQ_FOREACH(aior, &p->iobhd, io_blist) {
+ /*
+ * Try to cancel the outstanding blockif request.
+ */
+ error = blockif_cancel(p->bctx, &aior->io_req);
+ if (error != 0)
+ continue;
+
+ slot = aior->slot;
+ cfis = aior->cfis;
+ if (cfis[2] == ATA_WRITE_FPDMA_QUEUED ||
+ cfis[2] == ATA_READ_FPDMA_QUEUED)
+ ncq = 1;
+
+ if (ncq)
+ p->sact &= ~(1 << slot);
+ else
+ p->ci &= ~(1 << slot);
+
+ /*
+ * This command is now done.
+ */
+ p->pending &= ~(1 << slot);
+
+ /*
+ * Delete the blockif request from the busy list
+ */
+ TAILQ_REMOVE(&p->iobhd, aior, io_blist);
+
+ /*
+ * Move the blockif request back to the free list
+ */
+ STAILQ_INSERT_TAIL(&p->iofhd, aior, io_flist);
+ }
+
+ ahci_check_stopped(p);
+}
+
+static void
ahci_port_reset(struct ahci_port *pr)
{
pr->sctl = 0;
@@ -492,7 +557,7 @@ ahci_handle_dma(struct ahci_port *p, int slot, uint8_t *cfis, uint32_t done,
*/
aior = STAILQ_FIRST(&p->iofhd);
assert(aior != NULL);
- STAILQ_REMOVE_HEAD(&p->iofhd, io_list);
+ STAILQ_REMOVE_HEAD(&p->iofhd, io_flist);
aior->cfis = cfis;
aior->slot = slot;
aior->len = len;
@@ -503,15 +568,21 @@ ahci_handle_dma(struct ahci_port *p, int slot, uint8_t *cfis, uint32_t done,
if (iovcnt > BLOCKIF_IOV_MAX) {
aior->prdtl = iovcnt - BLOCKIF_IOV_MAX;
iovcnt = BLOCKIF_IOV_MAX;
- /*
- * Mark this command in-flight.
- */
- p->pending |= 1 << slot;
} else
aior->prdtl = 0;
breq->br_iovcnt = iovcnt;
/*
+ * Mark this command in-flight.
+ */
+ p->pending |= 1 << slot;
+
+ /*
+ * Stuff request onto busy list
+ */
+ TAILQ_INSERT_HEAD(&p->iobhd, aior, io_blist);
+
+ /*
* Build up the iovec based on the prdt
*/
for (i = 0; i < iovcnt; i++) {
@@ -546,7 +617,7 @@ ahci_handle_flush(struct ahci_port *p, int slot, uint8_t *cfis)
*/
aior = STAILQ_FIRST(&p->iofhd);
assert(aior != NULL);
- STAILQ_REMOVE_HEAD(&p->iofhd, io_list);
+ STAILQ_REMOVE_HEAD(&p->iofhd, io_flist);
aior->cfis = cfis;
aior->slot = slot;
aior->len = 0;
@@ -554,6 +625,16 @@ ahci_handle_flush(struct ahci_port *p, int slot, uint8_t *cfis)
aior->prdtl = 0;
breq = &aior->io_req;
+ /*
+ * Mark this command in-flight.
+ */
+ p->pending |= 1 << slot;
+
+ /*
+ * Stuff request onto busy list
+ */
+ TAILQ_INSERT_HEAD(&p->iobhd, aior, io_blist);
+
err = blockif_flush(p->bctx, breq);
assert(err == 0);
}
@@ -961,7 +1042,7 @@ atapi_read(struct ahci_port *p, int slot, uint8_t *cfis,
*/
aior = STAILQ_FIRST(&p->iofhd);
assert(aior != NULL);
- STAILQ_REMOVE_HEAD(&p->iofhd, io_list);
+ STAILQ_REMOVE_HEAD(&p->iofhd, io_flist);
aior->cfis = cfis;
aior->slot = slot;
aior->len = len;
@@ -977,6 +1058,16 @@ atapi_read(struct ahci_port *p, int slot, uint8_t *cfis,
breq->br_iovcnt = iovcnt;
/*
+ * Mark this command in-flight.
+ */
+ p->pending |= 1 << slot;
+
+ /*
+ * Stuff request onto busy list
+ */
+ TAILQ_INSERT_HEAD(&p->iobhd, aior, io_blist);
+
+ /*
* Build up the iovec based on the prdt
*/
for (i = 0; i < iovcnt; i++) {
@@ -1415,9 +1506,14 @@ ata_ioreq_cb(struct blockif_req *br, int err)
pthread_mutex_lock(&sc->mtx);
/*
+ * Delete the blockif request from the busy list
+ */
+ TAILQ_REMOVE(&p->iobhd, aior, io_blist);
+
+ /*
* Move the blockif request back to the free list
*/
- STAILQ_INSERT_TAIL(&p->iofhd, aior, io_list);
+ STAILQ_INSERT_TAIL(&p->iofhd, aior, io_flist);
if (pending && !err) {
ahci_handle_dma(p, slot, cfis, aior->done,
@@ -1438,17 +1534,18 @@ ata_ioreq_cb(struct blockif_req *br, int err)
p->serr |= (1 << slot);
}
- /*
- * This command is now complete.
- */
- p->pending &= ~(1 << slot);
-
if (ncq) {
p->sact &= ~(1 << slot);
ahci_write_fis_sdb(p, slot, tfd);
} else
ahci_write_fis_d2h(p, slot, cfis, tfd);
+ /*
+ * This command is now complete.
+ */
+ p->pending &= ~(1 << slot);
+
+ ahci_check_stopped(p);
out:
pthread_mutex_unlock(&sc->mtx);
DPRINTF("%s exit\n", __func__);
@@ -1478,9 +1575,14 @@ atapi_ioreq_cb(struct blockif_req *br, int err)
pthread_mutex_lock(&sc->mtx);
/*
+ * Delete the blockif request from the busy list
+ */
+ TAILQ_REMOVE(&p->iobhd, aior, io_blist);
+
+ /*
* Move the blockif request back to the free list
*/
- STAILQ_INSERT_TAIL(&p->iofhd, aior, io_list);
+ STAILQ_INSERT_TAIL(&p->iofhd, aior, io_flist);
if (pending && !err) {
atapi_read(p, slot, cfis, aior->done, hdr->prdtl - pending);
@@ -1500,6 +1602,12 @@ atapi_ioreq_cb(struct blockif_req *br, int err)
cfis[4] = (cfis[4] & ~7) | ATA_I_CMD | ATA_I_IN;
ahci_write_fis_d2h(p, slot, cfis, tfd);
+ /*
+ * This command is now complete.
+ */
+ p->pending &= ~(1 << slot);
+
+ ahci_check_stopped(p);
out:
pthread_mutex_unlock(&sc->mtx);
DPRINTF("%s exit\n", __func__);
@@ -1526,8 +1634,10 @@ pci_ahci_ioreq_init(struct ahci_port *pr)
else
vr->io_req.br_callback = atapi_ioreq_cb;
vr->io_req.br_param = vr;
- STAILQ_INSERT_TAIL(&pr->iofhd, vr, io_list);
+ STAILQ_INSERT_TAIL(&pr->iofhd, vr, io_flist);
}
+
+ TAILQ_INIT(&pr->iobhd);
}
static void
@@ -1565,9 +1675,7 @@ pci_ahci_port_write(struct pci_ahci_softc *sc, uint64_t offset, uint64_t value)
p->cmd = value;
if (!(value & AHCI_P_CMD_ST)) {
- p->cmd &= ~(AHCI_P_CMD_CR | AHCI_P_CMD_CCS_MASK);
- p->ci = 0;
- p->sact = 0;
+ ahci_port_stop(p);
} else {
uint64_t clb;
OpenPOWER on IntegriCloud