Subject: TS-11 alignment problems plus a few other changes
From: [email-masked] (Steven M. Schultz)
Newsgroups: comp.bugs.2bsd

Subject: TS-11 alignment problems plus a few other changes
Index	sys/pdpuba/ts.c 2.11BSD

Description:

	The command structure has to be aligned on a 4 byte boundary,
	for UNIBUS systems this means that the UNIBUS virtual address
	must be properly aligned rather than the physical address.
	
	The UMR allocation was moved from the tsinit() routine to
	the tsattach() routine.  Only 1 UMR is required to map the
	structures for all TS-11 controllers in the system instead of
	a UMR per controller.  Virtual addresses are calculated from 
	the base of the ts_softc structure now.  The sc_mapped element 
	has been removed from the softc structure since it is no longer 
	needed.

	Almost all of the UNIBUS_MAP conditionals have been removed, the
	address fields in ts_softc are calculated once at attach time just
	as they are for the UNIBUS case.

Repeat-By:
	Examine the sources and the enclosed patch.
	
Fix:

	Apply the following patch to ts.c and recompile the kernel
	if a TS-11 is configured.

*** /usr/src/sys/pdpuba/ts.c.old	Fri May 24 20:46:13 1991
--- /usr/src/sys/pdpuba/ts.c	Mon Jun  3 18:53:16 1991
***************
*** 3,9 ****
   * All rights reserved.  The Berkeley software License Agreement
   * specifies the terms and conditions for redistribution.
   *
!  *	@(#)ts.c	2.0 (2.11BSD) 5/23/91
   */
  
  /*
--- 3,9 ----
   * All rights reserved.  The Berkeley software License Agreement
   * specifies the terms and conditions for redistribution.
   *
!  *	@(#)ts.c	2.1 (2.11BSD) 5/31/91
   */
  
  /*
***************
*** 21,26 ****
--- 21,28 ----
  #include "fs.h"
  #include "tsreg.h"
  #include "mtio.h"
+ #include "map.h"
+ #include "uba.h"
  
  /*
   * Software state per tape transport:
***************
*** 45,57 ****
  	struct	ts_cmd	sc_cmd;	/* the command packet */
  	struct	ts_char	sc_char;/* status packet, for returned status */
  	struct	ts_sts	sc_sts; /* characteristics packet */
- #ifdef UNIBUS_MAP
  	u_short	sc_uba;		/* Unibus addr of cmd pkt for tsdb */
  	ubadr_t	sc_uadr;	/* actual unibus address */
! 	short	sc_mapped;	/* is sc_cmd mapped in Unibus space? */
! #endif
  } *ts_softc[NTS];
  
  struct	buf	tstab[NTS];
  
  /*
--- 47,59 ----
  	struct	ts_cmd	sc_cmd;	/* the command packet */
  	struct	ts_char	sc_char;/* status packet, for returned status */
  	struct	ts_sts	sc_sts; /* characteristics packet */
  	u_short	sc_uba;		/* Unibus addr of cmd pkt for tsdb */
  	ubadr_t	sc_uadr;	/* actual unibus address */
! 	struct	tty *sc_ttyp;	/* record user's tty for errors */
  } *ts_softc[NTS];
  
+ static	ubadr_t	TS_ubadr;
+ 
  struct	buf	tstab[NTS];
  
  /*
***************
*** 80,93 ****
  #define	SCOM		3	/* sending a control command */
  #define	SREW		4	/* sending a drive rewind */
  
! char softspace[sizeof(struct ts_softc)*NTS + 3];
  
  tsattach(addr, unit)
  struct tsdevice *addr;
  register int unit;
  {
! 	register u_short sp = ((u_short)softspace + 3) & ~3;
  	register struct ts_softc *sc;
  
  	if (unit >= NTS)
  		return(0);
--- 82,96 ----
  #define	SCOM		3	/* sending a control command */
  #define	SREW		4	/* sending a drive rewind */
  
! u_short softspace[NTS][(sizeof(struct ts_softc)/2) + 1];
  
  tsattach(addr, unit)
  struct tsdevice *addr;
  register int unit;
  {
! 	register u_short sp = (u_short)softspace[unit];
  	register struct ts_softc *sc;
+ 	struct buf tbuf;
  
  	if (unit >= NTS)
  		return(0);
***************
*** 97,107 ****
  	 * core address is a 4-byte multiple.  The compiler only
  	 * guarantees word alignment.  We reserve and extra 3 bytes
  	 * so that we can slide the array down by 2 if the compiler
! 	 * gets it wrong.
  	 */
! 	sp += (unit * sizeof (struct ts_softc));
! 	sc = ts_softc[unit] = (struct ts_softc *)sp;
  	sc->sc_addr = addr;
  	return(1);
  }
  
--- 100,135 ----
  	 * core address is a 4-byte multiple.  The compiler only
  	 * guarantees word alignment.  We reserve and extra 3 bytes
  	 * so that we can slide the array down by 2 if the compiler
! 	 * gets it wrong.  Only allocate 1 UMR to map all of the
! 	 * communication area instead of a UMR per controller.
! 	 *
! 	 * On a UNIBUS system the ts_softc structure is aligned so
! 	 * that the UNIBUS virtual address of sc_cmd falls on a 4
! 	 * byte boundary - the physical address may be on a 2 byte bound.
! 	 *
! 	 * On non-UNIBUS systems the ts_softc structure is aligned so
! 	 * that sc_cmd falls on a physical 4 byte boundary.
  	 */
! 	sc = (struct ts_softc *)sp;
! 	if (((u_short)&sc->sc_cmd  - (ubmap ? (u_short)softspace : 0)) & 3)
! 		sp += 2;
! 	if (ubmap && TS_ubadr == 0) {
! 		tbuf.b_xmem = 0;	/* won't work above 64k any way */
! 		tbuf.b_un.b_addr = (caddr_t) softspace;
! 		tbuf.b_flags = B_PHYS;
! 		tbuf.b_bcount = sizeof (softspace);
! #ifdef	UNIBUS_MAP
! 		mapalloc(&tbuf);
! #endif
! 		TS_ubadr = ((long)((unsigned)tbuf.b_xmem)) << 16
! 				| ((long)((unsigned)tbuf.b_un.b_addr));
! 	}
! 	sc = ts_softc[unit] = (struct ts_softc *) sp;
  	sc->sc_addr = addr;
+ 	sc->sc_uadr = TS_ubadr + ((u_short)&sc->sc_cmd - 
+ 				(ubmap ? (u_short)softspace : 0));
+ 	sc->sc_uba = loint(sc->sc_uadr) 
+ 		   | hiint(sc->sc_uadr);	/* register format */
  	return(1);
  }
  
***************
*** 141,146 ****
--- 169,175 ----
  	sc->sc_blkno = (daddr_t) 0;
  	sc->sc_nxrec = INF;
  	sc->sc_lastiow = 0;
+ 	sc->sc_ttyp = u.u_ttyp;
  	return(0);
  }
  
***************
*** 335,345 ****
  		if (um->b_errcnt)
  			cmd |= TS_RETRY;
  		tc->c_cmd = TS_ACK | TS_CVC | TS_IE | cmd;
- #ifdef UNIBUS_MAP
  		sc->sc_addr->tsdb = sc->sc_uba;
- #else
- 		sc->sc_addr->tsdb = (u_short)&sc->sc_cmd.c_cmd;
- #endif
  		return;
  	}
  	/*
--- 364,370 ----
***************
*** 362,372 ****
  	 * Do the command in bp.
  	 */
  	tc->c_cmd = TS_ACK | TS_CVC | TS_IE | bp->b_command;
- #ifdef UNIBUS_MAP
  	sc->sc_addr->tsdb = sc->sc_uba;
- #else
- 	sc->sc_addr->tsdb = (u_short)&sc->sc_cmd.c_cmd;
- #endif
  	return;
  
  next:
--- 387,393 ----
***************
*** 389,395 ****
  {
  	int state;
  	register struct buf *bp, *um = &tstab[dev];
! 	register struct ts_softc *sc;
  
  	if ((bp = um->b_actf) == NULL)
  		return;
--- 410,416 ----
  {
  	int state;
  	register struct buf *bp, *um = &tstab[dev];
! 	register struct ts_softc *sc = ts_softc[dev];
  
  	if ((bp = um->b_actf) == NULL)
  		return;
***************
*** 398,404 ****
  	 * If last command was a rewind, and tape is still
  	 * rewinding, wait for the rewind complete interrupt.
  	 *
! 	 * SHOULD NEVER GET AN INTERRUPT IN THIS STATE.
  	 */
  	if (um->b_active == SREW) {
  		um->b_active = SCOM;
--- 419,426 ----
  	 * If last command was a rewind, and tape is still
  	 * rewinding, wait for the rewind complete interrupt.
  	 *
! 	 * SHOULD NEVER GET AN INTERRUPT IN THIS STATE, but it
! 	 * happens when a rewind completes.
  	 */
  	if (um->b_active == SREW) {
  		um->b_active = SCOM;
***************
*** 408,414 ****
  	/*
  	 * An operation completed... record status
  	 */
- 	sc = ts_softc[dev];
  	if ((bp->b_flags & B_READ) == 0)
  		sc->sc_lastiow = 1;
  	state = um->b_active;
--- 430,435 ----
***************
*** 478,500 ****
  
  			case TS_REJECT:
  				if (state == SIO && sc->sc_sts.s_xs0 & TS_WLE)
! 					printf("ts%d: no write ring\n", dev);
  				if ((sc->sc_sts.s_xs0 & TS_ONL) == 0)
! 					printf("ts%d: not online\n", dev);
  				break;
  		}
  		/*
  		 * Couldn't recover error.
  		 */
! 		printf("ts%d: hard error bn%D xs0=%b", dev,
  		     bp->b_blkno, sc->sc_sts.s_xs0, TSXS0_BITS);
  		if (sc->sc_sts.s_xs1)
! 			printf(" xs1=%b", sc->sc_sts.s_xs1, TSXS1_BITS);
  		if (sc->sc_sts.s_xs2)
! 			printf(" xs2=%b", sc->sc_sts.s_xs2, TSXS2_BITS);
  		if (sc->sc_sts.s_xs3)
! 			printf(" xs3=%b", sc->sc_sts.s_xs3, TSXS3_BITS);
! 		printf("\n");
  		bp->b_flags |= B_ERROR;
  		goto opdone;
  		/*NOTREACHED*/
--- 499,521 ----
  
  			case TS_REJECT:
  				if (state == SIO && sc->sc_sts.s_xs0 & TS_WLE)
! 					tprintf(sc->sc_ttyp,"ts%d: no write ring\n", dev);
  				if ((sc->sc_sts.s_xs0 & TS_ONL) == 0)
! 					tprintf(sc->sc_ttyp,"ts%d: not online\n", dev);
  				break;
  		}
  		/*
  		 * Couldn't recover error.
  		 */
! 		tprintf(sc->sc_ttyp,"ts%d: hard error bn%D xs0=%b", dev,
  		     bp->b_blkno, sc->sc_sts.s_xs0, TSXS0_BITS);
  		if (sc->sc_sts.s_xs1)
! 			tprintf(sc->sc_ttyp," xs1=%b", sc->sc_sts.s_xs1, TSXS1_BITS);
  		if (sc->sc_sts.s_xs2)
! 			tprintf(sc->sc_ttyp," xs2=%b", sc->sc_sts.s_xs2, TSXS2_BITS);
  		if (sc->sc_sts.s_xs3)
! 			tprintf(sc->sc_ttyp," xs3=%b", sc->sc_sts.s_xs3, TSXS3_BITS);
! 		tprintf(sc->sc_ttyp,"\n");
  		bp->b_flags |= B_ERROR;
  		goto opdone;
  		/*NOTREACHED*/
***************
*** 584,660 ****
   */
  tsinit(ts11)
  {
! 	struct	ts_softc *sc = ts_softc[ts11];
  	register struct ts_cmd *tcmd = &sc->sc_cmd;
  	register struct ts_char *tchar = &sc->sc_char;
  	int cnt;
- #ifdef	UNIBUS_MAP
- 	struct buf tbuf;
- 
  	/*
- 	 * Map the command and message packets into Unibus
- 	 * address space.  We do all the command and message
- 	 * packets at once to minimize the amount of Unibus
- 	 * mapping necessary.
- 	 */
- 	if (!sc->sc_mapped) {
- 		tbuf.b_xmem = 0;	/* won't work past 64k any way */
- 		tbuf.b_un.b_addr = (caddr_t)tcmd;
- 		tbuf.b_flags = B_PHYS;	/* want map to point to phys. addr. */
- 		tbuf.b_bcount = sizeof(struct ts_cmd);
- 		mapalloc(&tbuf);
- 		sc->sc_uadr = ((long)((unsigned)tbuf.b_xmem)) << 16
- 			 | ((long) ((unsigned)tbuf.b_un.b_addr));
- 		sc->sc_mapped++;
- 	}
- #endif	UNIBUS_MAP
- 
- 	/*
  	 * Now initialize the TS11 controller.
  	 * Set the characteristics.
  	 */
  	if (sc->sc_addr->tssr & (TS_NBA | TS_OFL)) {
  		tcmd->c_cmd = TS_ACK | TS_CVC | TS_INIT;
- #ifdef	UNIBUS_MAP
- 		sc->sc_uba = loint(sc->sc_uadr)
- 			   | hiint(sc->sc_uadr); /*register format*/
  		sc->sc_addr->tsdb = sc->sc_uba;
- #else
- 		sc->sc_addr->tsdb = (u_short) tcmd;
- #endif
  		for (cnt = 0; cnt < 10000; cnt++) {
  			if (sc->sc_addr->tssr & TS_SSR)
  				break;
  		}
! 		if (cnt >= 10000) {
! 			printf("ts%d: subsystem init. failure\n", ts11);
  			return (1);
- 		}
- #ifdef	UNIBUS_MAP
  		tchar->char_bptr = (u_short)loint(sc->sc_uadr)+
  			((u_short)&sc->sc_sts-(u_short)tcmd);
  		tchar->char_bae = hiint(sc->sc_uadr);
- #else	UNIBUS_MAP
- 		tchar->char_bptr = (u_short) &sc->sc_sts;
- 		tchar->char_bae = 0;
- #endif
  		tchar->char_size = sizeof(struct ts_sts);
  		tchar->char_mode = TS_ESS;
  		tcmd->c_cmd = TS_ACK | TS_CVC | TS_SETCHR;
- #ifdef	UNIBUS_MAP
  		tcmd->c_loba = (u_short)loint(sc->sc_uadr)+
  			((u_short)tchar-(u_short)tcmd);
  		tcmd->c_hiba = hiint(sc->sc_uadr);
- #else	UNIBUS_MAP
- 		tcmd->c_loba = (u_short) tchar;
- 		tcmd->c_hiba = 0;
- #endif
  		tcmd->c_size = sizeof(struct ts_char);
- #ifdef	UNIBUS_MAP
  		sc->sc_addr->tsdb = sc->sc_uba;
- #else	UNIBUS_MAP
- 		sc->sc_addr->tsdb = (u_short) tcmd;
- #endif
  		for (cnt = 0; cnt < 10000; cnt++) {
  			if (sc->sc_addr->tssr & TS_SSR)
  				break;
--- 605,638 ----
   */
  tsinit(ts11)
  {
! 	register struct	ts_softc *sc = ts_softc[ts11];
  	register struct ts_cmd *tcmd = &sc->sc_cmd;
  	register struct ts_char *tchar = &sc->sc_char;
  	int cnt;
  	/*
  	 * Now initialize the TS11 controller.
  	 * Set the characteristics.
  	 */
  	if (sc->sc_addr->tssr & (TS_NBA | TS_OFL)) {
  		tcmd->c_cmd = TS_ACK | TS_CVC | TS_INIT;
  		sc->sc_addr->tsdb = sc->sc_uba;
  		for (cnt = 0; cnt < 10000; cnt++) {
  			if (sc->sc_addr->tssr & TS_SSR)
  				break;
  		}
! 		if (cnt >= 10000)
  			return (1);
  		tchar->char_bptr = (u_short)loint(sc->sc_uadr)+
  			((u_short)&sc->sc_sts-(u_short)tcmd);
  		tchar->char_bae = hiint(sc->sc_uadr);
  		tchar->char_size = sizeof(struct ts_sts);
  		tchar->char_mode = TS_ESS;
  		tcmd->c_cmd = TS_ACK | TS_CVC | TS_SETCHR;
  		tcmd->c_loba = (u_short)loint(sc->sc_uadr)+
  			((u_short)tchar-(u_short)tcmd);
  		tcmd->c_hiba = hiint(sc->sc_uadr);
  		tcmd->c_size = sizeof(struct ts_char);
  		sc->sc_addr->tsdb = sc->sc_uba;
  		for (cnt = 0; cnt < 10000; cnt++) {
  			if (sc->sc_addr->tssr & TS_SSR)
  				break;