From owner-p4-projects@FreeBSD.ORG Mon Sep 7 15:39:08 2009 Return-Path: Delivered-To: p4-projects@freebsd.org Received: by hub.freebsd.org (Postfix, from userid 32767) id E208C1065692; Mon, 7 Sep 2009 15:39:07 +0000 (UTC) Delivered-To: perforce@FreeBSD.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id A67B01065672 for ; Mon, 7 Sep 2009 15:39:07 +0000 (UTC) (envelope-from hselasky@FreeBSD.org) Received: from repoman.freebsd.org (repoman.freebsd.org [IPv6:2001:4f8:fff6::29]) by mx1.freebsd.org (Postfix) with ESMTP id 944478FC1E for ; Mon, 7 Sep 2009 15:39:07 +0000 (UTC) Received: from repoman.freebsd.org (localhost [127.0.0.1]) by repoman.freebsd.org (8.14.3/8.14.3) with ESMTP id n87Fd7nu074878 for ; Mon, 7 Sep 2009 15:39:07 GMT (envelope-from hselasky@FreeBSD.org) Received: (from perforce@localhost) by repoman.freebsd.org (8.14.3/8.14.3/Submit) id n87Fd7wB074876 for perforce@freebsd.org; Mon, 7 Sep 2009 15:39:07 GMT (envelope-from hselasky@FreeBSD.org) Date: Mon, 7 Sep 2009 15:39:07 GMT Message-Id: <200909071539.n87Fd7wB074876@repoman.freebsd.org> X-Authentication-Warning: repoman.freebsd.org: perforce set sender to hselasky@FreeBSD.org using -f From: Hans Petter Selasky To: Perforce Change Reviews Cc: Subject: PERFORCE change 168279 for review X-BeenThere: p4-projects@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: p4 projects tree changes List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 07 Sep 2009 15:39:08 -0000 http://perforce.freebsd.org/chv.cgi?CH=168279 Change 168279 by hselasky@hselasky_laptop001 on 2009/09/07 15:39:06 USB CORE: - add full featured fault injection system for control transfers. Affected files ... .. //depot/projects/usb/src/sys/dev/usb/usb_request.c#26 edit Differences ... ==== //depot/projects/usb/src/sys/dev/usb/usb_request.c#26 (text+ko) ==== @@ -71,14 +71,123 @@ #if USB_DEBUG static int usb_pr_poll_delay = USB_PORT_RESET_DELAY; static int usb_pr_recovery_delay = USB_PORT_RESET_RECOVERY; -static int usb_ss_delay = 0; SYSCTL_INT(_hw_usb, OID_AUTO, pr_poll_delay, CTLFLAG_RW, &usb_pr_poll_delay, 0, "USB port reset poll delay in ms"); SYSCTL_INT(_hw_usb, OID_AUTO, pr_recovery_delay, CTLFLAG_RW, &usb_pr_recovery_delay, 0, "USB port reset recovery delay in ms"); -SYSCTL_INT(_hw_usb, OID_AUTO, ss_delay, CTLFLAG_RW, - &usb_ss_delay, 0, "USB status stage delay in ms"); + +/* The following structures are used in connection to fault injection. */ + +struct usb_ctrl_debug { + int bus_index; /* target bus */ + int dev_index; /* target address */ + int ds_fail; /* fail data stage */ + int ss_fail; /* fail data stage */ + int ds_delay; /* data stage delay in ms */ + int ss_delay; /* status stage delay in ms */ + int bmRequestType_value; + int bRequest_value; +}; + +struct usb_ctrl_debug_bits { + uint16_t ds_delay; + uint16_t ss_delay; + uint8_t ds_fail:1; + uint8_t ss_fail:1; + uint8_t enabled:1; +}; + +/* The default is to disable fault injection. */ + +static struct usb_ctrl_debug usb_ctrl_debug = { + .bus_index = -1, + .dev_index = -1, + .bmRequestType_value = -1, + .bRequest_value = -1, +}; + +SYSCTL_INT(_hw_usb, OID_AUTO, ctrl_bus_fail, CTLFLAG_RW, + &usb_ctrl_debug.bus_index, 0, "USB controller index to fail"); +SYSCTL_INT(_hw_usb, OID_AUTO, ctrl_dev_fail, CTLFLAG_RW, + &usb_ctrl_debug.dev_index, 0, "USB device address to fail"); +SYSCTL_INT(_hw_usb, OID_AUTO, ctrl_ds_fail, CTLFLAG_RW, + &usb_ctrl_debug.ds_fail, 0, "USB fail data stage"); +SYSCTL_INT(_hw_usb, OID_AUTO, ctrl_ss_fail, CTLFLAG_RW, + &usb_ctrl_debug.ss_fail, 0, "USB fail status stage"); +SYSCTL_INT(_hw_usb, OID_AUTO, ctrl_ds_delay, CTLFLAG_RW, + &usb_ctrl_debug.ds_delay, 0, "USB data stage delay in ms"); +SYSCTL_INT(_hw_usb, OID_AUTO, ctrl_ss_delay, CTLFLAG_RW, + &usb_ctrl_debug.ss_delay, 0, "USB status stage delay in ms"); +SYSCTL_INT(_hw_usb, OID_AUTO, ctrl_rt_fail, CTLFLAG_RW, + &usb_ctrl_debug.bmRequestType_value, 0, "USB bmRequestType to fail"); +SYSCTL_INT(_hw_usb, OID_AUTO, ctrl_rv_fail, CTLFLAG_RW, + &usb_ctrl_debug.bRequest_value, 0, "USB bRequest to fail"); + +#endif + +#if USB_DEBUG +/*------------------------------------------------------------------------* + * usbd_get_debug_bits + * + * This function is only useful in USB host mode. + *------------------------------------------------------------------------*/ +static void +usbd_get_debug_bits(struct usb_device *udev, struct usb_device_request *req, + struct usb_ctrl_debug_bits *dbg) +{ + int temp; + + memset(dbg, 0, sizeof(*dbg)); + + /* Compute data stage delay */ + + temp = usb_ctrl_debug.ds_delay; + if (temp < 0) + temp = 0; + else if (temp > (16*1024)) + temp = (16*1024); + + dbg->ds_delay = temp; + + /* Compute status stage delay */ + + temp = usb_ctrl_debug.ss_delay; + if (temp < 0) + temp = 0; + else if (temp > (16*1024)) + temp = (16*1024); + + dbg->ss_delay = temp; + + /* Check if this control request should be failed */ + + if (usbd_get_bus_index(udev) != usb_ctrl_debug.bus_index) + return; + + if (usbd_get_device_index(udev) != usb_ctrl_debug.dev_index) + return; + + temp = usb_ctrl_debug.bmRequestType_value; + + if ((temp != req->bmRequestType) && (temp >= 0) && (temp <= 255)) + return; + + temp = usb_ctrl_debug.bRequest_value; + + if ((temp != req->bRequest) && (temp >= 0) && (temp <= 255)) + return; + + temp = usb_ctrl_debug.ds_fail; + if (temp) + dbg->ds_fail = 1; + + temp = usb_ctrl_debug.ss_fail; + if (temp) + dbg->ss_fail = 1; + + dbg->enabled = 1; +} #endif /*------------------------------------------------------------------------* @@ -264,6 +373,9 @@ struct usb_device_request *req, void *data, uint16_t flags, uint16_t *actlen, usb_timeout_t timeout) { +#if USB_DEBUG + struct usb_ctrl_debug_bits dbg; +#endif usb_handle_req_t *hr_func; struct usb_xfer *xfer; const void *desc; @@ -382,6 +494,15 @@ err = USB_ERR_NOMEM; goto done; } + +#if USB_DEBUG + /* Get debug bits */ + usbd_get_debug_bits(udev, req, &dbg); + + /* Check for fault injection */ + if (dbg.enabled) + flags |= USB_DELAY_STATUS_STAGE; +#endif USB_XFER_LOCK(xfer); if (flags & USB_DELAY_STATUS_STAGE) @@ -403,13 +524,32 @@ usbd_copy_in(xfer->frbuffers, 0, req, sizeof(*req)); usbd_xfer_set_frame_len(xfer, 0, sizeof(*req)); - xfer->nframes = 2; while (1) { temp = length; - if (temp > xfer->max_data_length) { + if (temp > usbd_xfer_max_len(xfer)) { temp = usbd_xfer_max_len(xfer); } +#if USB_DEBUG + if (xfer->flags.manual_status) { + if (usbd_xfer_frame_len(xfer, 0) != 0) { + /* Execute data stage separately */ + temp = 0; + } else if (temp > 0) { + if (dbg.ds_fail) { + err = USB_ERR_INVAL; + break; + } + if (dbg.ds_delay > 0) { + usb_pause_mtx( + xfer->xroot->xfer_mtx, + USB_MS_TO_TICKS(dbg.ds_delay)); + /* make sure we don't time out */ + start_ticks = ticks; + } + } + } +#endif usbd_xfer_set_frame_len(xfer, 1, temp); if (temp > 0) { @@ -429,21 +569,21 @@ usbd_copy_in(xfer->frbuffers + 1, 0, data, temp); } - xfer->nframes = 2; + usbd_xfer_set_frames(xfer, 2); } else { - if (xfer->frlengths[0] == 0) { + if (usbd_xfer_frame_len(xfer, 0) == 0) { if (xfer->flags.manual_status) { #if USB_DEBUG - int temp; - - temp = usb_ss_delay; - if (temp > 5000) { - temp = 5000; + if (dbg.ss_fail) { + err = USB_ERR_INVAL; + break; } - if (temp > 0) { + if (dbg.ss_delay > 0) { usb_pause_mtx( xfer->xroot->xfer_mtx, - USB_MS_TO_TICKS(temp)); + USB_MS_TO_TICKS(dbg.ss_delay)); + /* make sure we don't time out */ + start_ticks = ticks; } #endif xfer->flags.manual_status = 0; @@ -451,7 +591,7 @@ break; } } - xfer->nframes = 1; + usbd_xfer_set_frames(xfer, 1); } usbd_transfer_start(xfer); @@ -469,7 +609,7 @@ /* subtract length of SETUP packet, if any */ if (xfer->aframes > 0) { - xfer->actlen -= xfer->frlengths[0]; + xfer->actlen -= usbd_xfer_frame_len(xfer, 0); } else { xfer->actlen = 0; }