# /* * RX02 floppy disk device driver * * Bill Shannon CWRU 05/29/79 * * Modified for Version 7 - 08/13/79 - Bill Shannon * * * Layout of logical devices: * * name min dev unit density * ---- ------- ---- ------- * rx0 0 0 single * rx1 1 1 single * rx2 2 0 double * rx3 3 1 double * * * Stty function call may be used to format a disk. * To enable this feature, define CTRL in this module. */ #include "../h/param.h" #include "../h/buf.h" #include "../h/dir.h" #include "../h/user.h" #include "../h/conf.h" #include "../h/tty.h" /* The following structure is used to access av_back as an integer */ struct { int dummy0; struct buf *dummy1; struct buf *dummy2; struct buf *dummy3; int seccnt; }; struct device { int rx2cs; int rx2db; }; /* * the following defines use some fundamental * constants of the RX02. */ #define RXADDR ((struct device *) 0177170) #define NSPB ((minor(bp->b_dev)&2) ? 2 : 4) /* Number of floppy sectors per unix block */ #define NBPS ((minor(bp->b_dev)&2) ? 256 : 128) /* Number of bytes per floppy sector */ #define NRXBLKS ((minor(bp->b_dev)&2) ? 1001 : 500) /* Number of unix blocks on a floppy */ #define DENSITY (minor(bp->b_dev)&2) /* Density: 0 = single, 2 = double */ #define UNIT (minor(bp->b_dev)&1) /* Unit Number: 0 = left, 1 = right */ #define CTRL CTRL /* define for control functions (formatting) */ #ifdef CTRL #define B_CTRL 020000 #endif #define TRWAIT while (ptcs->lobyte >= 0) struct { char lobyte; char hibyte; }; struct buf rx2tab; struct buf rrx2buf; #ifdef CTRL struct buf crx2buf; /* buffer header for control functions */ #endif #define GO 0000001 /* execute command function */ #define UNIT1 0000020 /* unit select (drive 0=0, 1=1) */ #define RXDONE 0000040 /* function complete */ #define INTENB 0000100 /* interrupt enable */ #define TRANREQ 0000200 /* transfer request (data only) */ #define RXINIT 0040000 /* rx211 initialize */ #define RXERROR 0100000 /* general error bit */ /* * rx211 control function bits 1-3 of rx2cs */ #define FILL 0000000 /* fill buffer */ #define EMPTY 0000002 /* empty buffer */ #define WRITE 0000004 /* write buffer to disk */ #define READ 0000006 /* read disk sector to buffer */ #define FORMAT 0000010 /* set media density (format) */ #define RSTAT 0000012 /* read disk status */ #define WSDD 0000014 /* write sector deleted data */ #define RDERR 0000016 /* read error register function */ /* * states of driver, kept in b_active */ #define SREAD 1 /* read started */ #define SEMPTY 2 /* empty started */ #define SFILL 3 /* fill started */ #define SWRITE 4 /* write started */ #define SINIT 5 /* init started */ #define SFORMAT 6 /* format started */ rx2open(dev, flag) { if(minor(dev) >= 4) u.u_error = ENXIO; } rx2strategy(bp) register struct buf *bp; { if(bp->b_flags & B_PHYS) mapalloc(bp); if(bp->b_blkno >= NRXBLKS) { if(bp->b_flags&B_READ) bp->b_resid = bp->b_bcount; else { bp->b_flags =| B_ERROR; bp->b_error = ENXIO; } iodone(bp); return; } bp->av_forw = (struct buf *) NULL; /* * seccnt is actually the number of floppy sectors transferred, * incremented by one after each successful transfer of a sector. */ bp->seccnt = 0; /* * We'll modify b_resid as each piece of the transfer * successfully completes. It will also tell us when * the transfer is complete. */ bp->b_resid = bp->b_bcount; spl5(); if(rx2tab.b_actf == NULL) rx2tab.b_actf = bp; else rx2tab.b_actl->av_forw = bp; rx2tab.b_actl = bp; if(rx2tab.b_active == NULL) rx2start(); spl0(); } rx2start() { register int *ptcs, *ptdb; register struct buf *bp; int sector, track; char *addr, *xmem; if((bp = rx2tab.b_actf) == NULL) { rx2tab.b_active = NULL; return; } ptcs = &RXADDR->rx2cs; ptdb = &RXADDR->rx2db; #ifdef CTRL if (bp->b_flags&B_CTRL) { /* is it a control request ? */ rx2tab.b_active = SFORMAT; *ptcs = FORMAT | GO | INTENB | (UNIT << 4) | (DENSITY << 7); TRWAIT; *ptdb = 'I'; } else #endif if(bp->b_flags&B_READ) { rx2tab.b_active = SREAD; rx2factr((int)bp->b_blkno * NSPB + bp->seccnt, §or, &track); *ptcs = READ | GO | INTENB | (UNIT << 4) | (DENSITY << 7); TRWAIT; *ptdb = sector; TRWAIT; *ptdb = track; } else { rx2tab.b_active = SFILL; rx2addr(bp, &addr, &xmem); *ptcs = FILL | GO | INTENB | (xmem << 12) | (DENSITY << 7); TRWAIT; *ptdb = (bp->b_resid >= NBPS ? NBPS : bp->b_resid) >> 1; TRWAIT; *ptdb = addr; } } rx2intr() { register int *ptcs, *ptdb; register struct buf *bp; int sector, track; char *addr, *xmem; /* fix for error recovery by duke!phs!dennis */ if (rx2tab.b_active == SINIT) { rx2start(); return; } if((bp = rx2tab.b_actf) == NULL) return; ptcs = &RXADDR->rx2cs; ptdb = &RXADDR->rx2db; if(*ptcs < 0) { if(rx2tab.b_errcnt++ > 10 || rx2tab.b_active == SFORMAT) { bp->b_flags =| B_ERROR; deverror(bp, *ptcs, *ptdb); rx2tab.b_errcnt = 0; rx2tab.b_actf = bp->av_forw; iodone(bp); } *ptcs = RXINIT; *ptcs = INTENB; rx2tab.b_active = SINIT; return; } switch (rx2tab.b_active) { case SREAD: /* read done, start empty */ rx2tab.b_active = SEMPTY; rx2addr(bp, &addr, &xmem); *ptcs = EMPTY | GO | INTENB | (xmem << 12) | (DENSITY << 7); TRWAIT; *ptdb = (bp->b_resid >= NBPS ? NBPS : bp->b_resid) >> 1; TRWAIT; *ptdb = addr; return; case SFILL: /* fill done, start write */ rx2tab.b_active = SWRITE; rx2factr((int)bp->b_blkno * NSPB + bp->seccnt, §or, &track); *ptcs = WRITE | GO | INTENB | (UNIT << 4) | (DENSITY << 7); TRWAIT; *ptdb = sector; TRWAIT; *ptdb = track; return; case SWRITE: /* write done, start next fill */ case SEMPTY: /* empty done, start next read */ /* * increment amount remaining to be transferred. * if it becomes positive, last transfer was a * partial sector and we're done, so set remaining * to zero. */ if (bp->b_resid <= NBPS) { done: bp->b_resid = 0; rx2tab.b_errcnt = 0; rx2tab.b_actf = bp->av_forw; iodone(bp); break; } bp->b_resid -= NBPS; bp->seccnt++; break; #ifdef CTRL case SFORMAT: /* format done (whew!!!) */ goto done; /* driver's getting too big... */ #endif } /* end up here from states SWRITE, SEMPTY, and SINIT */ rx2start(); } /* * rx2factr -- calculates the physical sector and physical * track on the disk for a given logical sector. * call: * rx2factr(logical_sector,&p_sector,&p_track); * the logical sector number (0 - 2001) is converted * to a physical sector number (1 - 26) and a physical * track number (0 - 76). * the logical sectors specify physical sectors that * are interleaved with a factor of 2. thus the sectors * are read in the following order for increasing * logical sector numbers (1,3, ... 23,25,2,4, ... 24,26) * There is also a 6 sector slew between tracks. * Logical sectors start at track 1, sector 1; go to * track 76 and then to track 0. Thus, for example, unix block number * 498 starts at track 0, sector 21 and runs thru track 0, sector 2. */ rx2factr(sectr, psectr, ptrck) register int sectr; int *psectr, *ptrck; { register int p1, p2; p1 = sectr/26; p2 = sectr%26; /* 2 to 1 interleave */ p2 = (2*p2 + (p2 >= 13 ? 1 : 0)) % 26; /* 6 sector per track slew */ *psectr = 1 + (p2 + 6*p1) % 26; if (++p1 >= 77) p1 = 0; *ptrck = p1; } /* * rx2addr -- compute core address where next sector * goes to / comes from based on bp->b_un.b_addr, bp->b_xmem, * and bp->seccnt. */ rx2addr(bp, addr, xmem) register struct buf *bp; register char **addr, **xmem; { *addr = bp->b_un.b_addr + bp->seccnt * NBPS; *xmem = bp->b_xmem; if (*addr < bp->b_un.b_addr) /* overflow, bump xmem */ (*xmem)++; } rx2read(dev) { physio(rx2strategy, &rrx2buf, dev, B_READ, minor(dev)&2 ? 1001 : 500); } rx2write(dev) { physio(rx2strategy, &rrx2buf, dev, B_WRITE, minor(dev)&2 ? 1001 : 500); } #ifdef CTRL /* * rx2sgtty -- format RX02 disk, single or double density. * stty with word 0 == 010 does format. density determined * by device opened. */ rx2ioctl(dev, cmd, addr, flag) { register struct buf *bp; struct rx2iocb { int ioc_cmd; /* command */ int ioc_res1; /* reserved */ int ioc_res2; /* reserved */ } iocb; if (cmd != TIOCSETP) { err: u.u_error = ENXIO; return(0); } if (copyin(addr, (caddr_t)&iocb, sizeof (iocb))) { u.u_error = EFAULT; return(1); } if (iocb.ioc_cmd != FORMAT) goto err; bp = &crx2buf; spl6(); while (bp->b_flags & B_BUSY) { bp->b_flags =| B_WANTED; sleep(bp, PRIBIO); } bp->b_flags = B_BUSY | B_CTRL; bp->b_dev = dev; bp->b_error = 0; rx2strategy(bp); iowait(bp); bp->b_flags = 0; } #endif