1: /* 2: * SCCS id @(#)rx3.c 2.1 (Berkeley) 8/5/83 3: */ 4: 5: /* 6: * 7: * Data Systems Design (DSD480) floppy disk drive 8: * 9: * Lauri Rathmann 10: * Tektronix 11: * 12: * 13: * Notes: 14: * The drive is being used in MODE 3 (Extended IBM) 15: * The ioctl mechanism is being used to determine 16: * format, density, number of sectors, bytes per 17: * sector and number of sides. 18: * 19: * History: 20: * August 1981 21: * Written (for 2.8BSD UNIX) 22: * 23: * January 1982 Modified slightly to work for standard V7 UNIX 24: * S. McGeady 25: * 26: * NOTE: 27: * This is a block rx3device: the 'c.c' file should contain 28: * lines that look like: 29: * 30: * int rx3open(), rx3close(), rx3strategy(); 31: * struct buf rx3tab; 32: * ... 33: * in bdevsw: 34: * rx3open, rx3close, rx3strategy, &rx3tab, 35: * 36: * ... 37: * int rx3ioctl(); 38: * ... 39: * in cdevsw: 40: * nulldev, nulldev, nodev, nodev, rx3ioctl, nulldev, 0, 41: * 42: * The block rx3device is used for all I/O, and the character rx3device 43: * is used only for the IOCTL to set up the rx3device format parameters 44: */ 45: 46: #include "rx3.h" 47: #if NRX3 > 0 48: #include "param.h" 49: #include <sys/systm.h> 50: #include <sys/buf.h> 51: #include <sys/conf.h> 52: #include <sys/dir.h> 53: #include <sys/user.h> 54: #include <sys/map.h> 55: #include <sys/rx2reg.h> 56: 57: extern struct rx3device *RX3ADDR; 58: 59: #define RXUNIT(dev) (minor(dev)&07) 60: 61: #define NSEC 4 /* Number of logical sections on a disk */ 62: #define MSEC 5 /* Maximum number of retrys */ 63: #define TTIME (2 * hz)/* Timeout time in HZ */ 64: #define trwait() while((rx3r->rx2cs & RX2_XREQ) == 0) 65: 66: /* 67: * type of disk information. The floppy is logically divided 68: * into four sections. 1) Track 0, side 0 69: * 2) Track 1-76, side 0 70: * 3) Track 0, side 1 71: * 4) Track 1-76, side 1 72: */ 73: struct rx3info { 74: long first_byte; /* first byte of section */ 75: long no_bytes; /* number of bytes in section */ 76: char first_track; /* track offset for section */ 77: char no_track; /* number of tracks in section */ 78: char sector_code; /* Information about sectors */ 79: char interleave; /* interleave factor */ 80: char secperrot; /* sectors per rotation for track */ 81: u_short skew; /* skew factor */ 82: char side_code; /* 0=side 0, 1=side 1; 2=either side */ 83: } rx3info[NRX3][NSEC] = { 84: 0L, 252928L, 0, 77, 0, 2, 13, 6, 0, 85: 0L, 0L, 0, 0, 0, 1, 0, 0, 0, 86: 0L, 0L, 0, 0, 0, 1, 0, 0, 0, 87: 0L, 252928L, 0, 77, 0, 1, 26, 0, 0 88: }; 89: 90: struct secinfo { 91: char no_sect; /* number of sectors per cyclinder */ 92: short bytpersec; /* number of bytes per sector */ 93: char density; /* 0=single, 1=double */ 94: short bytpertrk; /* number of bytes per track */ 95: short sect_size; /* coded sector size */ 96: } secinfo[] = { 97: 26, 128, 0, 26*128, 0, /* 26 128 byte sect/trk */ 98: 26, 256, 1, 26*256, 0, 99: 15, 256, 1, 15*256, 2, /* 15 512 byte sectors/track */ 100: 15, 512, 1, 15*512, 2, 101: 8, 512, 1, 8*512, 4, /* 8 512 byte sectors/trakc */ 102: 8, 1024, 1, 8*1024, 4 103: }; 104: 105: struct rx3stat { 106: char rx3open; /* open/closed status */ 107: short bytect; /* remaining bytes */ 108: char com; /* save current command */ 109: char sec_code; /* pointer to sector data */ 110: caddr_t addr; /* address in memory */ 111: short xmem; /* high order bits of memory */ 112: off_t seek; /* current byte to begin operation */ 113: short uid; /* current user's uid */ 114: } rx3stat[NRX3]; 115: 116: struct rx3errs { 117: short retries; /* number of retries */ 118: short errs; /* number of hard errors */ 119: short errreg; /* Last error register */ 120: short stat1; /* extended status location 1 */ 121: short stat2; /* extended status location 2 */ 122: short stat3; /* extended status location 3 */ 123: short stat4; /* extended status location 4 */ 124: } rx3errs[NRX3]; 125: 126: struct buf rx3tab; /* driver info */ 127: 128: /* 129: * ioctl commands for 130: * rx03 floppy 131: */ 132: #define RX3SET ((('r') << 8) | 2) /* set up parameters */ 133: #define RX3RD ((('r') << 8) | 3) /* read parameters */ 134: #define RX3STAT ((('r') << 8) | 4) /* read status */ 135: #define RX3ERR ((('r') << 8) | 5) /* give error information */ 136: 137: /* 138: * Commands. 139: */ 140: #define XINIT 01 141: #define XREAD 02 142: #define XWRITE 04 143: #define XFILL 010 144: #define XEMPTY 020 145: #define XERR 040 146: 147: /* 148: * States. 149: */ 150: #define NCRC 10 /* number of crc retries */ 151: #define NDEN 2 /* number of density retries */ 152: 153: #ifdef RX3_TIMEOUT 154: int rx3_wticks; /* used to keep track of lost interrupts */ 155: int rx3wstart; 156: int rx3watch(); 157: #endif RX3_TIMEOUT 158: 159: /* 160: * Open drive for use. 161: * 162: */ 163: /*ARGSUSED*/ 164: rx3open(dev, flag) 165: register dev_t dev; 166: { 167: register drv, result; 168: 169: drv = RXUNIT(dev); 170: 171: 172: /* Make sure drive is a valid one */ 173: if (drv >= NRX3) { 174: u.u_error = ENXIO; 175: return; 176: }; 177: 178: #ifdef RX3_TIMEOUT 179: /* Start timing for timeouts. Set status to open */ 180: if (rx3wstart==0) 181: timeout(rx3watch, (caddr_t) 0, TTIME); 182: rx3wstart++; 183: #endif 184: 185: rx3stat[drv].rx3open++; 186: rx3stat[drv].uid = u.u_uid; 187: rx3errs[drv].retries = 0; 188: rx3errs[drv].errs = 0; 189: } 190: 191: /* 192: * Close drive. Simply need to turn off timeouts and 193: * set drive status to closed. 194: */ 195: /*ARGSUSED*/ 196: rx3close(dev, flag) 197: register dev_t dev; 198: { 199: register drv = RXUNIT(dev); 200: 201: #ifdef RX3_TIMEOUT 202: rx3wstart--; 203: #endif RX3_TIMEOUT 204: rx3stat[drv].rx3open--; 205: if (rx3stat[drv].rx3open < 0) 206: rx3stat[drv].rx3open = 0; 207: } 208: 209: rx3strategy(bp) 210: register struct buf *bp; 211: { 212: register opl; 213: int mdev,okay,i; 214: off_t seek; 215: 216: #ifdef UNIBUS_MAP 217: if (bp->b_flags & B_PHYS) 218: mapalloc(bp); 219: #endif 220: /* 221: * Make sure block number is within range. 222: */ 223: okay = 0; 224: mdev = RXUNIT(bp->b_dev); 225: seek = (dbtofsb(bp->b_blkno) << BSHIFT) + bp->b_bcount; 226: for (i=0; i<NSEC; i++) 227: if ((rx3info[mdev][i].no_bytes+rx3info[mdev][i].first_byte) > 228: seek) okay = 1; 229: if (!okay) { 230: bp->b_flags |= B_ERROR; 231: iodone(bp); 232: return; 233: }; 234: 235: /* 236: * Link buffer into rx3device queue 237: */ 238: bp->av_forw = (struct buf *) NULL; 239: opl = spl5(); 240: if (rx3tab.b_actf == (struct buf *) NULL) 241: rx3tab.b_actf = bp; 242: else 243: rx3tab.b_actl->av_forw = bp; 244: rx3tab.b_actl = bp; 245: if (rx3tab.b_active == 0) 246: rx3start(); 247: splx(opl); 248: } 249: 250: /* 251: * Start processing command. 252: */ 253: rx3start() 254: { 255: register struct buf *bp; 256: register int mdev; 257: 258: 259: if ((bp = rx3tab.b_actf) == (struct buf *) NULL) 260: return; 261: rx3tab.b_active++; 262: 263: /* 264: * get minor rx3device number from buffer 265: */ 266: mdev = RXUNIT(bp->b_dev); 267: 268: /* 269: * Set up status for current buffer 270: */ 271: rx3stat[mdev].addr = bp->b_un.b_addr; 272: rx3stat[mdev].xmem = bp->b_xmem; 273: rx3stat[mdev].seek = dbtofsb(bp->b_blkno) << BSHIFT; 274: rx3stat[mdev].bytect = bp->b_bcount; 275: 276: /* 277: * if command is read, initiate the command 278: * if command is write, fill the rx3device buffer, 279: * then initiate the write 280: */ 281: if (bp->b_flags & B_READ) 282: rx3io(bp, XREAD); 283: else 284: rx3io(bp, XFILL); 285: } 286: 287: /* 288: * Do actual IO command. 289: */ 290: rx3io(bp, cmd) 291: register struct buf *bp; 292: register short cmd; 293: { 294: register struct rx3device *rx3r; 295: int sect, code, trk, side, drv; 296: 297: 298: rx3r = RX3ADDR; 299: drv = RXUNIT(bp->b_dev); 300: rx3stat[drv].com = cmd; 301: rx3leave(bp,drv,&code,§,&trk,&side); 302: rx3stat[drv].sec_code = code; 303: 304: switch (cmd) { 305: case XINIT: /* Read status */ 306: cmd = RX2_GO|RX2_RDSTAT|RX2_IE|drv<<4; 307: rx3r->rx2cs = cmd; 308: break; 309: 310: case XREAD: /* Read Sector */ 311: cmd = RX2_GO|RX2_RSECT|RX2_IE|(drv<<4)|(secinfo[code].density<<8)| 312: (side<<9); 313: rx3r->rx2cs = cmd; 314: trwait(); 315: rx3r->rx2sa = sect|(secinfo[code].sect_size<<5); 316: trwait(); 317: rx3r->rx2ta = trk; 318: break; 319: 320: case XEMPTY: /* Empty buffer */ 321: /* no disk i/o; unit not needed */ 322: cmd = RX2_GO|RX2_EMPTY|RX2_IE|(side<<9)|(secinfo[code].density<<8)| 323: (drv<<4)|(rx3stat[drv].xmem<<12); 324: rx3r->rx2cs = cmd; 325: trwait(); 326: /* NOT 2's complement */ 327: if (rx3stat[drv].bytect <= secinfo[code].bytpersec) 328: rx3r->rx2wc = rx3stat[drv].bytect>>1; 329: else 330: rx3r->rx2wc = secinfo[code].bytpersec>>1; 331: trwait(); 332: rx3r->rx2ba = (int) rx3stat[drv].addr; 333: break; 334: 335: case XWRITE: /* Write buffer to disk */ 336: cmd = RX2_GO|RX2_WSECT|RX2_IE|(drv<<4)|(secinfo[code].density<<8)| 337: (side<<9); 338: rx3r->rx2cs = cmd; 339: trwait(); 340: rx3r->rx2sa = sect|(secinfo[code].sect_size<<5); 341: trwait(); 342: rx3r->rx2ta = trk; 343: break; 344: 345: case XFILL: /* Fill disk buffer */ 346: /* no disk i/o; unit not needed */ 347: cmd = RX2_GO|RX2_FILL|RX2_IE|(side<<9)|(secinfo[code].density<<8)| 348: (drv<<4)|(rx3stat[drv].xmem<<12); 349: rx3r->rx2cs = cmd; 350: trwait(); 351: /* NOT 2's complement */ 352: if (rx3stat[drv].bytect <= secinfo[code].bytpersec) 353: rx3r->rx2wc = rx3stat[drv].bytect>>1; 354: else 355: rx3r->rx2wc = secinfo[code].bytpersec>>1; 356: trwait(); 357: rx3r->rx2ba = (int) rx3stat[drv].addr; 358: break; 359: 360: case XERR: /* Read extended error status */ 361: cmd = RX2_IE|RX2_RDEC; 362: rx3r->rx2cs = cmd; 363: trwait(); 364: rx3r->rx2ba = (int) &rx3errs[drv].stat1; 365: break; 366: 367: default: 368: panic("rx3io"); 369: break; 370: } 371: } 372: 373: /* 374: * Process interrupt. 375: */ 376: rx3intr() 377: { 378: register struct buf *bp; 379: register struct rx3device *rx3r; 380: int drv, code; 381: long paddr; 382: 383: 384: if (rx3tab.b_active == 0) { 385: printf("rx3: stray interrupt\n"); 386: return; 387: } 388: 389: bp = rx3tab.b_actf; 390: rx3r = RX3ADDR; 391: #ifdef RX3_TIMEOUT 392: rx3_wticks = 0; 393: #endif RX3_TIMEOUT 394: 395: if (rx3r->rx2cs < 0) { 396: rx3err(bp); 397: return; 398: } 399: 400: drv = RXUNIT(bp->b_dev); 401: 402: switch (rx3stat[drv].com) { 403: case XINIT: 404: rx3errs[drv].errreg = rx3r->rx2es; 405: rx3tab.b_active = 0; 406: rx3tab.b_errcnt = 0; 407: rx3stat[drv].bytect = 0; 408: iodone(bp); 409: break; 410: case XREAD: 411: rx3io(bp, XEMPTY); 412: break; 413: case XFILL: 414: rx3io(bp, XWRITE); 415: break; 416: case XWRITE: /* Go on to next sector if should */ 417: case XEMPTY: 418: code = rx3stat[drv].sec_code; 419: if (rx3stat[drv].bytect <= secinfo[code].bytpersec) { 420: rx3stat[drv].bytect = 0; 421: rx3tab.b_errcnt = 0; 422: rx3tab.b_active = 0; 423: rx3tab.b_actf = bp->av_forw; 424: iodone(bp); 425: rx3start(); 426: } 427: else { 428: rx3stat[drv].bytect -= secinfo[code].bytpersec; 429: paddr = (long) rx3stat[drv].addr + 430: (long) secinfo[code].bytpersec; 431: rx3stat[drv].addr = (caddr_t) paddr; 432: rx3stat[drv].xmem = rx3stat[drv].xmem + 433: (int) (paddr>>16); 434: rx3stat[drv].seek += secinfo[code].bytpersec; 435: if (rx3stat[drv].com==XWRITE) 436: rx3stat[drv].com=XFILL; 437: else rx3stat[drv].com=XREAD; 438: rx3io(bp,rx3stat[drv].com); 439: } 440: break; 441: case XERR: 442: break; 443: 444: default: 445: printf("rx3: command %o\n", rx3stat[drv].com); 446: break; 447: } 448: } 449: 450: /* 451: * Handle an error condition. 452: * Crc errors and density errors get retries, 453: * only NDEN for density errors and NCRC for crc errors. 454: * All other errors are considered hard errors. 455: */ 456: rx3err(bp) 457: register struct buf *bp; 458: { 459: register struct rx3device *rx3r; 460: register int drv; 461: register int cmd; 462: 463: drv = minor(bp->b_dev); 464: 465: 466: rx3tab.b_active = 0; 467: rx3r = RX3ADDR; 468: rx3errs[drv].errreg = rx3r->rx2es; 469: 470: /* 471: * Crc error. 472: */ 473: if (rx3r->rx2es & RX2ES_CRC) { 474: rx3errs[drv].retries++; 475: if (rx3tab.b_errcnt < NCRC) { 476: rx3tab.b_errcnt++; 477: rx3reset(); 478: return; 479: } 480: } 481: 482: /* 483: * Density error. 484: */ 485: if (rx3r->rx2es & RX2ES_DENSERR) { 486: rx3errs[drv].retries++; 487: if (rx3tab.b_errcnt < NDEN) { 488: rx3tab.b_errcnt++; 489: rx3reset(); 490: return; 491: } 492: } 493: 494: rx3errs[drv].errs++; 495: bp->b_flags |= B_ERROR; 496: #ifdef UCB_DEVERR 497: harderr(bp, "rx3"); 498: printf("cs=%b er=%b\n", rx3r->rx2cs, RX2_BITS, rx3r->rx2es, RX2ES_BITS); 499: #else 500: deverror(bp, (rx3r->rx2es&0377), (rx3r->rx2cs)); 501: #endif UCB_DEVERR 502: 503: rx3tab.b_active = 0; 504: rx3tab.b_errcnt = 0; 505: rx3tab.b_actf = bp->av_forw; 506: 507: iodone(bp); 508: rx3reset(); 509: } 510: 511: /* 512: * Calculate the physical sector and physical track on the 513: * disk for a given logical sector. 514: * 515: */ 516: rx3leave(bp,drv,code,sect,trk,side) 517: int *code,*sect,*trk,*side; 518: register struct buf *bp; 519: { 520: off_t seek, t0; 521: int t1,t2,t3; 522: int section; 523: 524: 525: /* 526: * Determine track by searching the rx3info table 527: * looking at first_byte and no_bytes. 528: * first_byte <= seek < first_byte + no_bytes 529: */ 530: seek = rx3stat[drv].seek; 531: section = 0; 532: *trk = 0; 533: while (section<NSEC && *trk==0) { 534: if (rx3info[drv][section].first_byte <= rx3stat[drv].seek) { 535: t0 = rx3info[drv][section].first_byte + 536: rx3info[drv][section].no_bytes; 537: if (rx3stat[drv].seek < t0) *trk = 1; 538: } 539: if (!*trk) { 540: seek -= rx3info[drv][section].no_bytes; 541: section++; 542: } 543: } 544: if (!*trk) { 545: bp->b_flags |= B_ERROR; 546: rx3tab.b_active = 0; 547: iodone(bp); 548: return(1); 549: }; 550: *code = rx3info[drv][section].sector_code; 551: t1 = secinfo[*code].bytpertrk; 552: t2 = t1 * (rx3info[drv][section].side_code==2 ? 2 : 1 ); 553: *trk = seek/t2; /* track offset */ 554: 555: /* 556: * Determine side of disk. Use section code. 557: */ 558: t3 = seek % t2; /* sector offset in track */ 559: if (rx3info[drv][section].side_code==0) *side = 0; 560: else if (rx3info[drv][section].side_code==1) *side = 1; 561: else { 562: if (t3 < t1) *side = 0; 563: else { 564: t3 -= t1; 565: *side = 1; 566: } 567: }; 568: 569: /* 570: * Determine physical sector. 571: */ 572: t1 = t3 / secinfo[*code].bytpersec; /* logical sector */ 573: t1 = t1 % secinfo[*code].no_sect; 574: t2 = t1 / rx3info[drv][section].secperrot; /* logical rotation */ 575: t3 = t1 % rx3info[drv][section].secperrot; /* sector offset */ 576: t3 = t3 * rx3info[drv][section].interleave; 577: t3 = t3 + (rx3info[drv][section].skew * *trk); 578: /* sector count begins with 1 */ 579: *sect = (t3 + t2) % secinfo[*code].no_sect + 1; 580: *trk += rx3info[drv][section].first_track; /* physical track */ 581: return(0); 582: } 583: 584: rx3ioctl(dev, cmd, addr, flag) 585: caddr_t addr; 586: { 587: int drv; 588: register struct rx3device *rx3r; 589: 590: drv = RXUNIT(dev); 591: 592: 593: switch (cmd) { 594: case RX3SET: /* Setup parameters for disk */ 595: if (copyin(addr, (caddr_t)rx3info[drv], 596: sizeof(struct rx3info)*NSEC)) { 597: u.u_error = EFAULT; 598: return; 599: }; 600: break; 601: case RX3RD: /* return disk parameters */ 602: if (copyout((caddr_t)rx3info[drv], addr, 603: sizeof(struct rx3info)*NSEC)) { 604: u.u_error = EFAULT; 605: return; 606: } 607: break; 608: case RX3STAT: 609: break; 610: case RX3ERR: 611: if (copyout( (caddr_t)&rx3errs[drv], addr, 612: sizeof(struct rx3errs))) { 613: u.u_error = EFAULT; 614: return; 615: } 616: break; 617: default: 618: u.u_error = ENOTTY; 619: break; 620: } 621: } 622: 623: /* 624: * reset drives and restart controller. 625: */ 626: rx3reset() { 627: register struct rx3device *rx3r; 628: register int i; 629: register short cmd; 630: 631: 632: rx3r = RX3ADDR; 633: 634: /* 635: * If any drive is in use 636: * then do an init. 637: */ 638: for (i = 0; i < NRX3; i++) { 639: if (rx3stat[i].rx3open) { 640: rx3r->rx2cs = RX2_INIT; 641: while ((rx3r->rx2cs & RX2_DONE) == 0); 642: break; 643: } 644: } 645: 646: rx3start(); 647: } 648: 649: #ifdef RX3_TIMEOUT 650: /* 651: * Wake up every second and if an interrupt is pending 652: * but nothing has happened increment wticks. If nothing 653: * happens for 60 seconds, reset the controller and begin 654: * anew. 655: */ 656: rx3watch() 657: { 658: if (rx3wstart) 659: timeout(rx3watch, (caddr_t) 0, TTIME); 660: 661: if (rx3tab.b_active == 0) { 662: rx3_wticks = 0; /* idling */ 663: return; 664: } 665: 666: rx3_wticks++; 667: 668: if (rx3_wticks >= 60) { 669: rx3_wticks = 0; 670: printf("rx3: lost interrupt\n"); 671: rx3reset(); 672: } 673: } 674: #endif RX3_TIMEOUT 675: #endif NRX3