Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 7 Sep 2009 15:39:07 GMT
From:      Hans Petter Selasky <hselasky@FreeBSD.org>
To:        Perforce Change Reviews <perforce@FreeBSD.org>
Subject:   PERFORCE change 168279 for review
Message-ID:  <200909071539.n87Fd7wB074876@repoman.freebsd.org>

next in thread | raw e-mail | index | archive | help
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;
 		}



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200909071539.n87Fd7wB074876>