Subject: kern/8083: Short transfers from bulk ugen devices lose
To: None <gnats-bugs@gnats.netbsd.org>
From: Ed Gould <ed@pa.dec.com>
List: netbsd-bugs
Date: 07/26/1999 15:06:58
>Number:         8083
>Category:       kern
>Synopsis:       Short transfers from bulk ugen devices lose
>Confidential:   yes
>Severity:       serious
>Priority:       high
>Responsible:    kern-bug-people (Kernel Bug People)
>State:          open
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Mon Jul 26 15:05:00 1999
>Last-Modified:
>Originator:     Ed Gould
>Organization:
--
Ed Gould	 Palo Alto Advanced Development	 Compaq Computer Corp.
+1 650 853 2108	 ed@pa.dec.com			 130 Lytton Avenue
		 ed.gould@compaq.com		 Palo Alto, CA 94301
>Release:        20 July 1999 (but not changed in 26 July sources)
>Environment:
System: NetBSD toblerone.pa.dec.com 1.4G NetBSD 1.4G (TOBLERONE) #19: Mon Jul 26 14:25:04 PDT 1999 ed@toblerone.pa.dec.com:/usr/src/current/sys/arch/i386/compile/TOBLERONE i386


>Description:
	Reads from bulk-transfer USB devices using the ugen driver hang
	if the data offered is shorter than requested.  There is an
	ioctl to enable short transfers, but it doesn't do anything.

>How-To-Repeat:
	Attempt to read data from a ugen bulk device.

>Fix:
	It looked like the fix would be to propogate the flag set by
	USB_SET_SHORT_XFER down into the lower layers of the driver,
	but this doesn't quite work.  If the code in the UE_BULK
	branch within ugen_do_read()  that reads

		r = usbd_bulk_transfer(reqh, sce->pipeh, 0, buf,
				       &tn, "ugenrb");

	is changed to

		r = usbd_bulk_transfer(reqh, sce->pipeh,
			sce->state & UGEN_SHORT_OK ? USBD_SHORT_XFER_OK : 0,
			buf, &tn, "ugenrb");

	things get slightly better, but don't work right.  In
	particular, the first read completes, but the second read
	issued never sees its interrupt.

	If, instead, uhci_device_bulk_start() is kludged to always
	request that the short-transfer bit be set in the TD chain by
	changing the code that reads

		r = uhci_alloc_std_chain(upipe, sc, len, isread,
					 reqh->flags & USBD_SHORT_XFER_OK,
					 dmap, &xfer, &xferend);

	to


		r = uhci_alloc_std_chain(upipe, sc, len, isread,
					 1 || reqh->flags & USBD_SHORT_XFER_OK,
					 dmap, &xfer, &xferend);

	and ugen_do_read() is hacked to accept short transfers by
	changing

		if (r != USBD_NORMAL_COMPLETION) {
		    ...
		}

	to

		if ((r != USBD_NORMAL_COMPLETION) &&
		    (r != USBD_SHORT_XFER)) {
			...
		}

	then - modulo complaints about short transfers from
	uhbd_transfer_cb() - it works as expected.

	I have not spent enough time in this code to undersstand why
	the "correct" fix of passing the flag set by USB_SET_SHORT_XFER
	down to lower levels doesn't work.  Either it should be made
	to work, or the restriction on unsolicited short transfers
	removed.
>Audit-Trail:
>Unformatted: