1 /* flp.c 3.3 06/07/80 */ 2 3 #include "../h/flp.h" 4 #include "../h/param.h" 5 #include "../h/systm.h" 6 #include "../h/conf.h" 7 #include "../h/dir.h" 8 #include "../h/user.h" 9 #include "../h/mtpr.h" 10 #include "../h/buf.h" 11 #include "../h/cons.h" 12 13 struct { 14 short fl_state; /* open and busy flags */ 15 short fl_active; /* driver state flag */ 16 struct buf *fl_buf; /* buffer we're using */ 17 unsigned char *fl_xaddr; /* transfer address */ 18 short fl_errcnt; 19 } fltab; 20 21 /*ARGSUSED*/ 22 flopen(dev, flag) 23 dev_t dev; 24 int flag; 25 { 26 struct buf *geteblk(); 27 28 if (fltab.fl_state != 0) { 29 u.u_error = ENXIO; 30 return; 31 } 32 fltab.fl_state = FL_OPEN; 33 fltab.fl_buf = geteblk(); 34 fltab.fl_active = FL_IDLE; 35 } 36 37 /*ARGSUSED*/ 38 flclose(dev, flag) 39 dev_t dev; 40 int flag; 41 { 42 43 brelse(fltab.fl_buf); 44 fltab.fl_state = 0; 45 } 46 47 flstrategy(rw) 48 int rw; 49 { 50 register struct buf *bp; 51 register unsigned i; 52 53 /* 54 * Assume one block read/written for each call - 55 * and enforce this by checking for block size of 128. 56 * Use the b_blkno field to address 57 * physical, 128-byte blocks (u.u_offset/128). 58 * This is checked for validity, and is further interpreted as: 59 * 60 * track# * (sectors/track) + sector # 61 */ 62 if (u.u_count == 0) 63 return; 64 (void) spl4(); 65 while (fltab.fl_state & FL_BUSY) 66 sleep((caddr_t)&fltab, PRIBIO); 67 fltab.fl_state |= FL_BUSY; 68 (void) spl0(); 69 70 bp = fltab.fl_buf; 71 while ((i = min(RXBYSEC, u.u_count)) != 0) { 72 bp->b_blkno = u.u_offset>>7; 73 if (bp->b_blkno >= MAXSEC || (u.u_offset & 0177) != 0) { 74 /* block number out of range */ 75 /* or offset in middle of block */ 76 u.u_error = ENXIO; 77 break; 78 } 79 if (rw == B_WRITE) { 80 iomove(bp->b_un.b_addr, i, B_WRITE); 81 if (u.u_error != 0) 82 break; 83 } 84 bp->b_flags = rw; 85 (void) spl4(); 86 flstart(); 87 while ((bp->b_flags & B_DONE) == 0) 88 sleep((caddr_t)bp, PRIBIO); 89 (void) spl0(); 90 if (bp->b_flags & B_ERROR) { 91 u.u_error = EIO; 92 break; 93 } 94 if (rw == B_READ) { 95 iomove(bp->b_un.b_addr, i, B_READ); 96 if (u.u_error != 0) 97 break; 98 } 99 } 100 u.u_count = bp->b_resid; 101 fltab.fl_state &= ~FL_BUSY; 102 wakeup((caddr_t)&fltab); 103 } 104 105 /*ARGSUSED*/ 106 flread(dev) 107 dev_t dev; 108 { 109 110 flstrategy(B_READ); 111 } 112 113 /*ARGSUSED*/ 114 flwrite(dev) 115 dev_t dev; 116 { 117 118 flstrategy(B_WRITE); 119 } 120 121 flstart() 122 { 123 register struct buf *bp; 124 125 bp = fltab.fl_buf; 126 fltab.fl_active = FL_MAND; 127 fltab.fl_errcnt = 0; 128 fltab.fl_xaddr = (unsigned char *) bp->b_un.b_addr; 129 bp->b_resid = 0; 130 bp->b_bcount = RXBYSEC; /* always transfer a full sector */ 131 132 if ((mfpr(TXCS) & TXCS_RDY) == 0) 133 /* not ready to receive order */ 134 return; 135 /* 136 * Wake up floppy LSI software with command 137 */ 138 fltab.fl_active = FL_SEC; 139 if ((bp->b_flags&B_READ) == B_READ) 140 mtpr(TXDB, FL_RS); 141 else 142 mtpr(TXDB, FL_WS); 143 } 144 145 /* 146 * See if we want to transmit something 147 * to the floppy - and do it 148 */ 149 conxfl() 150 { 151 register int databyte; 152 register struct buf *bp; 153 154 bp = fltab.fl_buf; 155 switch (fltab.fl_active) { 156 157 case FL_MAND: /* send command */ 158 if ((bp->b_flags&B_READ) == B_READ) 159 mtpr(TXDB,FL_RS); 160 else 161 mtpr(TXDB, FL_WS); 162 fltab.fl_active = FL_SEC; 163 break; 164 165 case FL_SEC: /* send sector address */ 166 databyte = (int)bp->b_blkno % RXSTRK + 1; 167 mtpr(TXDB, FL_DATA | databyte); 168 fltab.fl_active = FL_TRACK; 169 break; 170 171 case FL_TRACK: /* send track address */ 172 databyte = (int)bp->b_blkno / RXSTRK; 173 mtpr(TXDB , FL_DATA | databyte); 174 if ((bp->b_flags&B_READ) == B_READ) 175 /* prepare to receive complete */ 176 fltab.fl_active = FL_COM; 177 else 178 /* prepare to send data */ 179 fltab.fl_active = FL_DAX; 180 break; 181 182 case FL_DAX: 183 databyte = *(fltab.fl_xaddr++); 184 mtpr(TXDB, FL_DATA | databyte); 185 if (--bp->b_bcount == 0) 186 fltab.fl_active = FL_COM; 187 break; 188 189 case FL_CAN: /* give cancel order */ 190 mtpr(TXDB, FL_CANCEL); 191 if (++fltab.fl_errcnt <= FLERRS) { 192 /* If error count permits, retry order */ 193 fltab.fl_active = FL_MAND; 194 bp->b_bcount = RXBYSEC; 195 fltab.fl_xaddr = (unsigned char *) bp->b_un.b_addr; 196 } else { 197 /* 198 * We're really stupid today - call it an 199 * error and give up 200 */ 201 bp->b_flags |= B_ERROR | B_DONE; 202 bp->b_resid = -RXBYSEC; 203 fltab.fl_active = FL_IDLE; 204 wakeup((caddr_t)bp); 205 } 206 } 207 } 208 209 cnrfl(c) 210 int c; 211 { 212 register int datum; 213 register struct buf *bp; 214 215 datum = c; 216 bp = fltab.fl_buf; 217 if (datum == FL_PERR) { 218 /* 219 * Got a protocol error - cancel the 220 * current function and try again if error count isn't 221 * too great. First, though, make sure that an actual 222 * transaction is in progress (so a spurious error from 223 * the LSI won't screw us up too much! 224 */ 225 if (fltab.fl_active != FL_IDLE) 226 fltab.fl_active = FL_CAN; 227 } else switch(fltab.fl_active ) { 228 229 case FL_DAR: /* expecting a datum */ 230 if ((c&RXDB_ID) != FL_DATA) 231 goto error; 232 *(fltab.fl_xaddr++) = (c & RXDB_DATA); 233 if (--bp->b_bcount==0) { 234 fltab.fl_active = FL_IDLE; 235 bp->b_flags |= B_DONE; 236 wakeup((caddr_t)bp); 237 } 238 break; 239 240 case FL_COM: /* expecting a "function complete" */ 241 if ((c&RXDB_ID)!= FL_FFC || (c&FL_ERR) == FL_ERR){ 242 error: 243 bp->b_flags |= B_ERROR | B_DONE; 244 bp->b_resid = -bp->b_bcount; 245 fltab.fl_active = FL_IDLE; 246 wakeup((caddr_t)bp); 247 } else if ((bp->b_flags&B_READ) == B_READ) 248 /* got function complete, now get data */ 249 fltab.fl_active = FL_DAR; 250 else { 251 /* got function complete on write - finish up */ 252 fltab.fl_active = FL_IDLE; 253 bp->b_flags |= B_DONE; 254 wakeup((caddr_t)bp); 255 } 256 break; 257 } 258 } 259