Subject: troubles with serial console support....
To: NetBSD/i386 Discussion List <port-i386@netbsd.org>
From: Greg A. Woods <woods@most.weird.com>
List: port-i386
Date: 01/02/1999 20:30:21
Well, as my recent PR on the subject of boot_console(8.i386) may have
hinted, I've been looking at the serial console support in -current.

Unfortunately since then I've been unable to make it work reliably, even
on fairly recent vintage Pentium and Pentium-II servers.

The primary problem is with handling input from the selected COM port.

With the DIRECT_SERIAL option I rarely get any success at even
interrupting the boot countdown, though if I do it seems to work A-OK
after that point.  So far I've found no pattern at all to the whys and
wherefores of this problem so I've left it for now and concentrated on
getting the hokey old BIOS interface to at least work.

With the default BIOS interface I can always interrupt the boot process,
but only through extreme hackery have I been able to convince it to
accept any characters.

Unfortunately I don't have a data scope, or even a working oscilloscope
at the moment, though my trusty RS-232 breakout box is hinting to me
that the PC is dropping RTS after accepting the first character of
input, and only by severely beating on the BIOS calls am I able to
convince it to one-by-one accept characters.  With debug output turned
on there's enough time during the printf()s at 9600bps to see the RTS
light on the breakout box change state.  I've tried every conceivable
null modem wiring plan (and some that no sane engineer would never
conceive of too!) to no avail.  The problem is most emphatically not
with my cable, but rather that the PC really doesn't want to receive any
more characters.

(FYI:  Once the kernel has booted the serial console works perfectly, as
did 'cu' sessions prior to trying to using serial boot blocks.)

I don't have a BIOS programming manual handy, though I did find some
fairly detailed information in an old FAQ, and was able to fix one bug
in the code only to be thwarted by unknown agents.

The motherboard I've been primarily testing on is an Intel TC430hx, and
on occasion I also give a try on an IBM PC Server 325 too.  Both systems
behave almost identically, though the 325 on occasion freezes after init
starts and is unfrozen by sending another character to the console port.

Here's the code I've ended up with in sys/arch/i386/stand/lib/pcio.c in
the guts of getchar():

	do {
		static int timeout_notify = 0;

		c = comgetc(SERIAL_DEV);
		if (c & 0x8000) {		/* XXX magic!!! */
			unsigned int s = comstatus(SERIAL_DEV);

			/*
			 * XXX!!! This is a very gross hack, but seems
			 * to be the only way to make the BOIS continue
			 * to receive characters after a timeout....
			 */
			if (!timeout_notify++) {
				printf("\nCOM%d: timeout! input LSR=0x%x, current: LSR=0x%x, MSR=0x%x: %s\n",
				       iodev - 1, (c >> 8) & 0xff, (s >> 8) & 0xff, s & 0xff,
				       (s & 0x20) ? "unknown cause!" : "DSR not asserted?");
			} else
				printf("_\b");
		}
	} while (c & 0x8000);		/* XXX magic!!! */
#  ifdef COMCONS_DEBUG
	{
		unsigned int s = comstatus(SERIAL_DEV);

		printf("\nCOM%d: input 0x%x, status LSR=0x%x, MSR=0x%x\n",
		       iodev - 1, c, (s >> 8) & 0xff, s & 0xff);
	}
#  endif /* COMCONS_DEBUG */

Here's a snip-it of a boot sequence with COMCONS_DEBUG enabled:

 |  COM0: status: LSR=0x60, MSR=0xb0
 |   

The above is the status returned by cominit() and clearly shows that
everything appears normal (DSR, CTS, and DCD are set and the transmitter
buffers are empty and ready).

 |  >> NetBSD/i386 BIOS Boot, Revision 2.2
 |  >> (woods@becoming, Sat Jan  2 14:34:40 EST 1999)
 |  >> Memory: 639/48128 k
 |  Use hd1a:netbsd to boot sd0 when wd0 is also installed
 |  Press return to boot now, any other key for boot menu
 |  booting wd0a:netbsd - starting in 3

Here I pressed the 'f' key on the terminal

 |  COM0: input 0xffff0066, status LSR=0x60, MSR=0xb0
 |  ... interrupted!
 |  type "?" or "help" for help.
 |  > 
 |  COM0: timeout! input LSR=0xe0, current: LSR=0x60, MSR=0xb0: (unknown cause!)
 |  _

and then I typed 'boot<CR>' with pauses between each character

 |  COM0: input 0xffff0062, status LSR=0x20, MSR=0xb0
 |  b
 |  COM0: input 0xffff006f, status LSR=0x20, MSR=0xb0
 |  o_
 |  COM0: input 0xffff006f, status LSR=0x20, MSR=0xb0
 |  o
 |  COM0: input 0xffff0074, status LSR=0x0, MSR=0xb0
 |  t_
 |  COM0: input 0xffff0015, status LSR=0x20, MSR=0xb0
 |  
 |  booting wd0a:netbsd


Note that DSR and CTS (i.e. MSR=0xB0) never waver....

If anyone can see what the problem is here, I'd very much appreciate a
hint!  ;-)

I'm very tempted to rip out the BIOS support and try to fix the problem
with the DIRECT_SERIAL code (just as FreeBSD seems to have done), but I
think at least some folks will appreciate having BIOS support for those
cases where they want to use a slightly non-standard port as a console.


If/when I get this tiny but very frustrating problem solved I'll send-pr
my changes which add another console selection policy, something that
IMNSHO is critical to successful use of serial consoles in production.

I think that with my changes it should even be possible to ship
NetBSD/i386 with boot blocks that always use my new policy algorithm,
though ideally some mechanism for non-volatile run-time configuration
(perhaps ala FreeBSD) is still *HIGHLY* desirable on i386.  (Oh, please,
*someone* create a *real* boot monitor program for PC's!!!!  I think
such firmware would be worth at least $100/copy and I for one don't give
a damn if it's totally incompatible with the original PC BIOS.)

While I'm at it, I wouldn't mind hearing from folks who have tried any
*BSD with the Phoenix Server-BIOS serial console (such as on the Intel
N440bx and T440bx boards), or with any other custom single-board
passive-backplane and embedded-PC computers that support serial port
consoles in their BIOS (as most SBCs should).

-- 
							Greg A. Woods

+1 416 218-0098      VE3TCP      <gwoods@acm.org>      <robohack!woods>
Planix, Inc. <woods@planix.com>; Secrets of the Weird <woods@weird.com>