Update hyperkit vendoring

This includes using ftruncate for speedier disk creation

Signed-off-by: Rolf Neugebauer <rolf.neugebauer@docker.com>
This commit is contained in:
Rolf Neugebauer 2017-11-09 17:53:28 +00:00
parent a9e6f37958
commit 4b9bf071e5
7 changed files with 715 additions and 21 deletions

View File

@ -15,7 +15,7 @@ github.com/gophercloud/gophercloud 2804b72cf099b41d2e25c8afcca786f9f962ddee
github.com/jmespath/go-jmespath bd40a432e4c76585ef6b72d3fd96fb9b6dc7b68d
github.com/mitchellh/go-ps 4fdf99ab29366514c69ccccddab5dc58b8d84062
github.com/moby/datakit 97b3d230535397a813323902c23751e176481a86
github.com/moby/hyperkit 3e31617ae866c93925e2b3bc5d8006b60985e920
github.com/moby/hyperkit a12cd7250bcd8d689078e3e42ae4a7cf6a0cbaf3
github.com/moby/vpnkit 0e4293bb1058598c4b0a406ed171f52573ef414c
github.com/packethost/packngo 131798f2804a1b3e895ca98047d56f0d7e094e2a
github.com/pmezard/go-difflib v1.0.0

View File

@ -395,11 +395,7 @@ func CreateDiskImage(location string, sizeMB int) error {
}
defer f.Close()
buf := make([]byte, 1048676)
for i := 0; i < sizeMB; i++ {
f.Write(buf)
}
return nil
return f.Truncate(int64(sizeMB) * int64(1024) * int64(1024))
}
func intArrayToString(i []int, sep string) string {

View File

@ -4,5 +4,6 @@
#include <stdbool.h>
int bootrom_init(const char *bootrom_path);
const char *bootrom(void);
uint64_t bootrom_load(void);
bool bootrom_contains_gpa(uint64_t gpa);

View File

@ -0,0 +1,54 @@
/*-
* Copyright (c) 2015 Peter Grehan <grehan@freebsd.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $FreeBSD$
*/
#ifndef _FWCTL_H_
#define _FWCTL_H_
#include <xhyve/support/linker_set.h>
/*
* Linker set api for export of information to guest firmware via
* a sysctl-like OID interface
*/
struct ctl {
const char *c_oid;
const void *c_data;
const int c_len;
};
#define CTL_NODE(oid, data, len) \
static struct ctl __CONCAT(__ctl, __LINE__) = { \
oid, \
(data), \
(len), \
}; \
DATA_SET(ctl_set, __CONCAT(__ctl, __LINE__))
void fwctl_init(void);
#endif /* _FWCTL_H_ */

View File

@ -33,6 +33,7 @@
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <sys/disk.h>
#include <sys/mount.h>
#include <assert.h>
#include <fcntl.h>
@ -53,6 +54,14 @@
#define BLOCKIF_SIG 0xb109b109
#ifndef ALIGNUP
#define ALIGNUP(x, a) (((x - 1) & ~(a - 1)) + a)
#endif
#ifndef ALIGNDOWN
#define ALIGNDOWN(x, a) (-(a) & (x))
#endif
/* xhyve: FIXME
*
* // #define BLOCKIF_NUMTHR 8
@ -101,6 +110,8 @@ struct blockif_ctxt {
off_t bc_size;
int bc_sectsz;
int bc_psectsz;
size_t bc_delete_alignment; /* f_bsize always a power of 2 */
void* bc_delete_zero_buf;
int bc_psectoff;
int bc_closing;
pthread_t bc_btid[BLOCKIF_NUMTHR];
@ -211,6 +222,7 @@ static int
block_delete(struct blockif_ctxt *bc, off_t offset, off_t len)
{
int ret = -1;
#ifdef __FreeBSD__
off_t arg[2] = { offset, len };
#endif
@ -221,22 +233,52 @@ block_delete(struct blockif_ctxt *bc, off_t offset, off_t len)
errno = EOPNOTSUPP;
else if (bc->bc_rdonly)
errno = EROFS;
if (bc->bc_fd >= 0) {
if (bc->bc_ischr) {
#ifdef __FreeBSD__
ret = ioctl(bc->bc_fd, DIOCGDELETE, arg);
#else
errno = EOPNOTSUPP;
#endif
} else
errno = EOPNOTSUPP;
#ifdef HAVE_OCAML_QCOW
} else if (bc->bc_mbh >= 0) {
if (bc->bc_mbh >= 0) {
ret = mirage_block_delete(bc->bc_mbh, offset, len);
goto out;
}
#endif
} else
abort();
#ifdef __FreeBSD__
if ((bc->bc_fd >= 0) && (bc->bc_ischr)) {
ret = ioctl(bc->bc_fd, DIOCGDELETE, arg);
errno = EOPNOTSUPP;
goto out;
}
#elif __APPLE__
if (bc->bc_fd >= 0) {
/* PUNCHHOLE lengths and offsets have to be aligned so explicitly write zeroes
into the unaligned parts at the beginning and the end. This wouldn't be necessary
if the host and guest had the same sector size */
assert (offset >= 0);
assert (len >= 0);
size_t fp_offset = (size_t) offset;
size_t fp_length = (size_t) len;
size_t aligned_offset = ALIGNUP(fp_offset, bc->bc_delete_alignment);
if (aligned_offset != fp_offset) {
size_t len_to_zero = aligned_offset - fp_offset;
assert(len_to_zero <= bc->bc_delete_alignment);
ssize_t written = pwrite(bc->bc_fd, bc->bc_delete_zero_buf, len_to_zero, (off_t) fp_offset);
if (written == -1) goto out;
fp_offset += len_to_zero;
fp_length -= len_to_zero;
}
size_t aligned_length = ALIGNDOWN(fp_length, bc->bc_delete_alignment);
if (aligned_length != fp_length) {
size_t len_to_zero = fp_length - aligned_length;
assert(len_to_zero <= bc->bc_delete_alignment);
fp_length -= len_to_zero;
ssize_t written = pwrite(bc->bc_fd, bc->bc_delete_zero_buf, len_to_zero, (off_t) (fp_offset + fp_length));
if (written == -1) goto out;
}
struct fpunchhole arg = { .fp_flags = 0, .reserved = 0, .fp_offset = (off_t) fp_offset, .fp_length = (off_t) fp_length };
ret = fcntl(bc->bc_fd, F_PUNCHHOLE, &arg);
goto out;
}
#endif
errno = EOPNOTSUPP;
out:
HYPERKIT_BLOCK_DELETE_DONE(offset, ret);
return ret;
}
@ -554,9 +596,12 @@ blockif_open(const char *optstr, const char *ident)
char *nopt, *xopts, *cp;
struct blockif_ctxt *bc;
struct stat sbuf;
struct statfs fsbuf;
// struct diocgattr_arg arg;
off_t size, psectsz, psectoff, blocks;
int extra, fd, i, sectsz;
size_t delete_alignment;
void *delete_zero_buf;
int nocache, sync, ro, candelete, geom, ssopt, pssopt;
mirage_block_handle mbh;
int use_mirage = 0;
@ -621,6 +666,8 @@ blockif_open(const char *optstr, const char *ident)
extra |= O_SYNC;
candelete = 0;
sectsz = DEV_BSIZE;
delete_alignment = DEV_BSIZE;
if (use_mirage) {
#ifdef HAVE_OCAML_QCOW
@ -655,7 +702,33 @@ blockif_open(const char *optstr, const char *ident)
perror("Could not stat backing file");
goto err;
}
if (fstatfs(fd, &fsbuf) < 0) {
perror("Could not stat backfile file filesystem");
goto err;
}
delete_alignment = (size_t)fsbuf.f_bsize;
#ifdef __APPLE__
{
/* Check to see whether we can use F_PUNCHHOLE on this file */
struct fpunchhole arg = { .fp_flags = 0, .reserved = 0, .fp_offset = 0, .fp_length = 0 };
if (fcntl(fd, F_PUNCHHOLE, &arg) == 0) {
/* Sparse files are supported: enable TRIM */
candelete = 1;
} else {
perror("fcntl(F_PUNCHHOLE) failed: host filesystem does not support sparse files");
candelete = 0;
}
}
#endif
}
/* delete_alignment is a power of 2 allowing us to use ALIGNDOWN for rounding */
assert((delete_alignment & (delete_alignment - 1)) == 0);
if ((delete_zero_buf = malloc(delete_alignment)) == NULL){
perror("Failed to allocate zeroed buffer for unaligned deletes");
goto err;
}
bzero(delete_zero_buf, delete_alignment);
/* One and only one handle */
assert(mbh >= 0 || fd >= 0);
@ -664,7 +737,6 @@ blockif_open(const char *optstr, const char *ident)
* Deal with raw devices
*/
size = sbuf.st_size;
sectsz = DEV_BSIZE;
psectsz = psectoff = 0;
geom = 0;
if (S_ISCHR(sbuf.st_mode)) {
@ -749,6 +821,8 @@ blockif_open(const char *optstr, const char *ident)
bc->bc_sectsz = sectsz;
bc->bc_psectsz = (int)psectsz;
bc->bc_psectoff = (int)psectoff;
bc->bc_delete_alignment = delete_alignment;
bc->bc_delete_zero_buf = delete_zero_buf;
pthread_mutex_init(&bc->bc_mtx, NULL);
pthread_cond_init(&bc->bc_cond, NULL);
TAILQ_INIT(&bc->bc_freeq);

View File

@ -0,0 +1,560 @@
/*-
* Copyright (c) 2015 Peter Grehan <grehan@freebsd.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $FreeBSD$
*/
/*
* Guest firmware interface. Uses i/o ports x510/x511 as Qemu does,
* but with a request/response messaging protocol.
*/
#include <sys/cdefs.h>
#include <sys/param.h>
#include <sys/types.h>
#include <sys/errno.h>
#include <sys/uio.h>
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "xhyve/inout.h"
#include "xhyve/xhyve.h"
#include "xhyve/support/misc.h"
#include "xhyve/fwctl.h"
/*
* Messaging protocol base operations
*/
#define OP_NULL 1
#define OP_ECHO 2
#define OP_GET 3
#define OP_GET_LEN 4
#define OP_SET 5
#define OP_MAX OP_SET
/* I/O ports */
#define FWCTL_OUT 0x510
#define FWCTL_IN 0x511
/*
* Back-end state-machine
*/
static enum state {
DORMANT,
IDENT_WAIT,
IDENT_SEND,
REQ,
RESP
} be_state = DORMANT;
static uint8_t sig[] = { 'B', 'H', 'Y', 'V' };
static u_int ident_idx;
struct op_info {
int op;
int (*op_start)(size_t len);
void (*op_data)(uint32_t data, size_t len);
int (*op_result)(struct iovec **data);
void (*op_done)(struct iovec *data);
};
static struct op_info *ops[OP_MAX+1];
/* Return 0-padded uint32_t */
static uint32_t
fwctl_send_rest(uint8_t *data, size_t len)
{
union {
uint8_t c[4];
uint32_t w;
} u;
size_t i;
u.w = 0;
for (i = 0, u.w = 0; i < len; i++)
u.c[i] = *data++;
return (u.w);
}
/*
* error op dummy proto - drop all data sent and return an error
*/
static int errop_code;
static void
errop_set(int err)
{
errop_code = err;
}
static int
errop_start(UNUSED size_t len)
{
errop_code = ENOENT;
/* accept any length */
return (errop_code);
}
static void
errop_data(UNUSED uint32_t data, UNUSED size_t len)
{
/* ignore */
}
static int
errop_result(struct iovec **data)
{
/* no data to send back; always successful */
*data = NULL;
return (errop_code);
}
static void
errop_done(UNUSED struct iovec *data)
{
/* assert data is NULL */
}
static struct op_info errop_info = {
.op_start = errop_start,
.op_data = errop_data,
.op_result = errop_result,
.op_done = errop_done
};
/* OID search */
SET_DECLARE(ctl_set, struct ctl);
CTL_NODE("hw.ncpu", &guest_ncpus, sizeof(guest_ncpus));
static struct ctl *
ctl_locate(const char *str, size_t maxlen)
{
struct ctl *cp, **cpp;
SET_FOREACH(cpp, ctl_set) {
cp = *cpp;
if (!strncmp(str, cp->c_oid, maxlen))
return (cp);
}
return (NULL);
}
/* uefi-sysctl get-len */
#define FGET_STRSZ 80
static struct iovec fget_biov[2];
static char fget_str[FGET_STRSZ];
static struct {
size_t f_sz;
uint32_t f_data[1024];
} fget_buf;
static size_t fget_cnt;
static size_t fget_size;
static int
fget_start(size_t len)
{
if (len > FGET_STRSZ)
return(E2BIG);
fget_cnt = 0;
return (0);
}
static void
fget_data(uint32_t data, UNUSED size_t len)
{
memcpy(&fget_str[fget_cnt], &data, sizeof(data));
fget_cnt += sizeof(uint32_t);
}
static int
fget_result(struct iovec **data, int val)
{
struct ctl *cp;
int err;
err = 0;
/* Locate the OID */
cp = ctl_locate(fget_str, fget_cnt);
if (cp == NULL) {
*data = NULL;
err = ENOENT;
} else {
if (val) {
/* For now, copy the len/data into a buffer */
memset(&fget_buf, 0, sizeof(fget_buf));
fget_buf.f_sz = (size_t)cp->c_len;
memcpy(fget_buf.f_data, cp->c_data, cp->c_len);
fget_biov[0].iov_base = (char *)&fget_buf;
fget_biov[0].iov_len = sizeof(fget_buf.f_sz) +
(size_t)cp->c_len;
} else {
fget_size = (size_t)cp->c_len;
fget_biov[0].iov_base = (char *)&fget_size;
fget_biov[0].iov_len = sizeof(fget_size);
}
fget_biov[1].iov_base = NULL;
fget_biov[1].iov_len = 0;
*data = fget_biov;
}
return (err);
}
static void
fget_done(UNUSED struct iovec *data)
{
/* nothing needs to be freed */
}
static int
fget_len_result(struct iovec **data)
{
return (fget_result(data, 0));
}
static int
fget_val_result(struct iovec **data)
{
return (fget_result(data, 1));
}
static struct op_info fgetlen_info = {
.op_start = fget_start,
.op_data = fget_data,
.op_result = fget_len_result,
.op_done = fget_done
};
static struct op_info fgetval_info = {
.op_start = fget_start,
.op_data = fget_data,
.op_result = fget_val_result,
.op_done = fget_done
};
static struct req_info {
int req_error;
u_int req_count;
uint32_t req_size;
uint32_t req_type;
uint32_t req_txid;
struct op_info *req_op;
int resp_error;
int resp_count;
int resp_size;
int resp_off;
struct iovec *resp_biov;
} rinfo;
static void
fwctl_response_done(void)
{
(*rinfo.req_op->op_done)(rinfo.resp_biov);
/* reinit the req data struct */
memset(&rinfo, 0, sizeof(rinfo));
}
static void
fwctl_request_done(void)
{
rinfo.resp_error = (*rinfo.req_op->op_result)(&rinfo.resp_biov);
/* XXX only a single vector supported at the moment */
rinfo.resp_off = 0;
if (rinfo.resp_biov == NULL) {
rinfo.resp_size = 0;
} else {
assert(rinfo.resp_biov[0].iov_len < INT_MAX);
rinfo.resp_size = (int)rinfo.resp_biov[0].iov_len;
}
}
static int
fwctl_request_start(void)
{
int err;
/* Data size doesn't include header */
rinfo.req_size -= 12;
rinfo.req_op = &errop_info;
if (rinfo.req_type <= OP_MAX && ops[rinfo.req_type] != NULL)
rinfo.req_op = ops[rinfo.req_type];
err = (*rinfo.req_op->op_start)(rinfo.req_size);
if (err) {
errop_set(err);
rinfo.req_op = &errop_info;
}
/* Catch case of zero-length message here */
if (rinfo.req_size == 0) {
fwctl_request_done();
return (1);
}
return (0);
}
static int
fwctl_request_data(uint32_t value)
{
size_t remlen;
/* Make sure remaining size is >= 0 */
rinfo.req_size -= sizeof(uint32_t);
remlen = MAX(rinfo.req_size, 0);
(*rinfo.req_op->op_data)(value, remlen);
if (rinfo.req_size < sizeof(uint32_t)) {
fwctl_request_done();
return (1);
}
return (0);
}
static int
fwctl_request(uint32_t value)
{
int ret;
ret = 0;
switch (rinfo.req_count) {
case 0:
/* Verify size */
if (value < 12) {
printf("msg size error");
exit(1);
}
rinfo.req_size = value;
rinfo.req_count = 1;
break;
case 1:
rinfo.req_type = value;
rinfo.req_count++;
break;
case 2:
rinfo.req_txid = value;
rinfo.req_count++;
ret = fwctl_request_start();
break;
default:
ret = fwctl_request_data(value);
break;
}
return (ret);
}
static int
fwctl_response(uint32_t *retval)
{
uint8_t *dp;
size_t remlen;
switch(rinfo.resp_count) {
case 0:
/* 4 x u32 header len + data */
*retval = 4*sizeof(uint32_t) +
roundup((uint32_t)rinfo.resp_size, sizeof(uint32_t));
rinfo.resp_count++;
break;
case 1:
*retval = rinfo.req_type;
rinfo.resp_count++;
break;
case 2:
*retval = rinfo.req_txid;
rinfo.resp_count++;
break;
case 3:
*retval = (uint32_t)rinfo.resp_error;
rinfo.resp_count++;
break;
default:
remlen = (size_t)rinfo.resp_size - (size_t)rinfo.resp_off;
dp = ((uint8_t *)rinfo.resp_biov->iov_base + rinfo.resp_off);
if (remlen >= sizeof(uint32_t)) {
memcpy(retval, dp, sizeof(*retval));
} else if (remlen > 0) {
*retval = fwctl_send_rest(dp, remlen);
}
rinfo.resp_off += sizeof(uint32_t);
break;
}
if (rinfo.resp_count > 3 &&
rinfo.resp_size - rinfo.resp_off <= 0) {
fwctl_response_done();
return (1);
}
return (0);
}
/*
* i/o port handling.
*/
static uint8_t
fwctl_inb(void)
{
uint8_t retval;
retval = 0xff;
switch (be_state) {
case DORMANT:
case IDENT_WAIT:
break;
case IDENT_SEND:
retval = sig[ident_idx++];
if (ident_idx >= sizeof(sig))
be_state = REQ;
break;
case REQ:
case RESP:
break;
}
return (retval);
}
static void
fwctl_outw(uint16_t val)
{
switch (be_state) {
case DORMANT:
break;
case IDENT_WAIT:
if (val == 0) {
be_state = IDENT_SEND;
ident_idx = 0;
}
break;
case IDENT_SEND:
case REQ:
case RESP:
break;
}
}
static uint32_t
fwctl_inl(void)
{
uint32_t retval;
switch (be_state) {
case DORMANT:
case IDENT_WAIT:
case IDENT_SEND:
case REQ:
retval = 0xffffffff;
break;
case RESP:
if (fwctl_response(&retval))
be_state = REQ;
break;
}
return (retval);
}
static void
fwctl_outl(uint32_t val)
{
switch (be_state) {
case DORMANT:
case IDENT_WAIT:
case IDENT_SEND:
break;
case REQ:
if (fwctl_request(val))
be_state = RESP;
case RESP:
break;
}
}
static int
fwctl_handler(UNUSED int vcpu, int in, UNUSED int port, int bytes,
uint32_t *eax, UNUSED void *arg)
{
if (in) {
if (bytes == 1)
*eax = fwctl_inb();
else if (bytes == 4)
*eax = fwctl_inl();
else
*eax = 0xffff;
} else {
if (bytes == 2)
fwctl_outw((uint16_t)*eax);
else if (bytes == 4)
fwctl_outl(*eax);
}
return (0);
}
INOUT_PORT(fwctl_wreg, FWCTL_OUT, IOPORT_F_INOUT, fwctl_handler);
INOUT_PORT(fwctl_rreg, FWCTL_IN, IOPORT_F_IN, fwctl_handler);
void
fwctl_init(void)
{
ops[OP_GET_LEN] = &fgetlen_info;
ops[OP_GET] = &fgetval_info;
be_state = IDENT_WAIT;
}

View File

@ -797,7 +797,15 @@ next:
done += 8;
if (elen == 0) {
if (done >= len) {
ahci_write_fis_d2h(p, slot, cfis, ATA_S_READY | ATA_S_DSC);
if (ncq) {
if (first)
ahci_write_fis_d2h_ncq(p, slot);
ahci_write_fis_sdb(p, slot, cfis,
ATA_S_READY | ATA_S_DSC);
} else {
ahci_write_fis_d2h(p, slot, cfis,
ATA_S_READY | ATA_S_DSC);
}
p->pending &= ~(1 << slot);
ahci_check_stopped(p);
if (!first)
@ -977,6 +985,7 @@ handle_identify(struct ahci_port *p, int slot, uint8_t *cfis)
buf[88] = 0x7f;
if (p->xfermode & ATA_UDMA0)
buf[88] |= (1 << ((p->xfermode & 7) + 8));
buf[93] = (1 | 1 <<14);
buf[100] = (uint16_t) sectors;
buf[101] = (uint16_t) (sectors >> 16);
buf[102] = (uint16_t) (sectors >> 32);
@ -1725,7 +1734,7 @@ ahci_handle_cmd(struct ahci_port *p, int slot, uint8_t *cfis)
case ATA_SEND_FPDMA_QUEUED:
if ((cfis[13] & 0x1f) == ATA_SFPDMA_DSM &&
cfis[17] == 0 && cfis[16] == ATA_DSM_TRIM &&
cfis[11] == 0 && cfis[13] == 1) {
cfis[11] == 0 && cfis[3] == 1) {
ahci_handle_dsm_trim(p, slot, cfis, 0);
break;
}