1 /*- 2 * Copyright (c) 1993, 1994 Charles Hannum. 3 * Copyright (c) 1990 The Regents of the University of California. 4 * All rights reserved. 5 * 6 * This code is derived from software contributed to Berkeley by 7 * Don Ahn. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 3. All advertising materials mentioning features or use of this software 18 * must display the following acknowledgement: 19 * This product includes software developed by the University of 20 * California, Berkeley and its contributors. 21 * 4. Neither the name of the University nor the names of its contributors 22 * may be used to endorse or promote products derived from this software 23 * without specific prior written permission. 24 * 25 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 27 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 28 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 29 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 30 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 31 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 32 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 33 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 34 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 35 * SUCH DAMAGE. 36 * 37 * from: @(#)fd.c 7.4 (Berkeley) 5/25/91 38 */ 39 /* 40 * Copyright (c) 1994 Brad Pepers 41 * All rights reserved. 42 * 43 * Redistribution and use in source and binary forms, with or without 44 * modification, are permitted provided that the following conditions 45 * are met: 46 * 1. Redistributions of source code must retain the above copyright 47 * notice, this list of conditions and the following disclaimer. 48 * 2. Redistributions in binary form must reproduce the above copyright 49 * notice, this list of conditions and the following disclaimer in the 50 * documentation and/or other materials provided with the distribution. 51 * 3. All advertising materials mentioning features or use of this software 52 * must display the following acknowledgement: 53 * This product includes software developed by Brad Pepers 54 * 4. The name of the author may not be used to endorse or promote products 55 * derived from this software without specific prior written permission 56 * 57 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 58 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 59 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 60 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 61 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 62 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 63 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 64 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 65 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 66 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 67 * 68 * $Id: fd.c,v 1.4 1994/04/22 02:20:48 chopps Exp $ 69 * 70 * 71 */ 72 73 /* 74 * floppy interface 75 */ 76 77 #include "fd.h" 78 #if NFD > 0 79 80 #include <sys/param.h> 81 #include <sys/systm.h> 82 #include <sys/buf.h> 83 #include <sys/dkstat.h> 84 #include <sys/disklabel.h> 85 #include <sys/malloc.h> 86 #include <sys/proc.h> 87 #include <sys/reboot.h> 88 #include <sys/file.h> 89 #include <sys/ioctl.h> 90 91 #include <amiga/dev/device.h> 92 #include <amiga/amiga/cia.h> 93 #include <amiga/amiga/custom.h> 94 95 #define UNIT(x) (minor(x) & 3) 96 #define b_cylin b_resid 97 #define FDBLK 512 98 #define MAX_SECTS 22 99 #define IMMED_WRITE 0 100 101 int fdattach(); 102 struct driver fddriver = { 103 fdattach, "fd", 104 }; 105 106 /* defines */ 107 #define MFM_SYNC 0x4489 108 #define DSKLEN_DMAEN (1<<15) 109 #define DSKLEN_WRITE (1<<14) 110 111 /* drive type values */ 112 #define FD_NONE 0xffffffff 113 #define FD_DD_3 0x00000000 /* double-density 3.5" (880K) */ 114 #define FD_HD_3 0xaaaaaaaa /* high-density 3.5" (1760K) */ 115 #define FD_DD_5 0x55555555 /* double-density 5.25" (440K) */ 116 117 struct fd_type { 118 int id; 119 char *name; 120 int tracks; 121 int heads; 122 int read_size; 123 int write_size; 124 int gap_size; 125 int sect_mult; 126 int precomp1; 127 int precomp2; 128 int step_delay; 129 int side_time; 130 int settle_time; 131 }; 132 133 struct fd_type drive_types[] = { 134 /* id name tr he rdsz wrsz gap sm pc1 pc2 sd st st */ 135 { FD_DD_3, "DD 3.5\"", 80, 2, 14716, 13630, 414, 1, 80, 161, 3, 2, 18 }, 136 { FD_HD_3, "HD 3.5\"", 80, 2, 29432, 27260, 828, 2, 80, 161, 3, 2, 18 }, 137 { FD_DD_5, "DD 5.25\"",40, 2, 14716, 13630, 414, 1, 40, 80, 3, 2, 18 }, 138 { FD_NONE, "No Drive", 0, } 139 }; 140 int num_dr_types = sizeof(drive_types) / sizeof(drive_types[0]); 141 142 /* 143 * Per drive structure. 144 * N per controller (presently 4) (DRVS_PER_CTLR) 145 */ 146 #define DRVS_PER_CTLR 4 147 struct fd_data { 148 int fdu; /* This unit number */ 149 struct buf head; /* Head of buf chain */ 150 struct buf rhead; /* Raw head of buf chain */ 151 int type; /* Drive type */ 152 struct fd_type *ft; /* Pointer to type descriptor */ 153 int flags; 154 #define FDF_OPEN 0x01 /* it's open */ 155 int skip; 156 int sects; /* number of sectors in a track */ 157 int size; /* size of disk in sectors */ 158 int side; /* current side disk is on */ 159 int dir; /* current direction of stepping */ 160 int cyl; /* current cylinder disk is on */ 161 int buf_track; 162 int buf_dirty; 163 char *buf_data; 164 char *buf_labels; 165 int write_cnt; 166 }; 167 168 /* 169 * Per controller structure. 170 */ 171 struct fdc_data 172 { 173 int fdcu; /* our unit number */ 174 struct fd_data *fd; /* drive we are currently doing work for */ 175 int motor_fdu; /* drive that has its motor on */ 176 int state; 177 int saved; 178 int retry; 179 struct fd_data fd_data[DRVS_PER_CTLR]; 180 }; 181 struct fdc_data fdc_data[NFD]; 182 183 /* 184 * Throughout this file the following conventions will be used: 185 * 186 * fd is a pointer to the fd_data struct for the drive in question 187 * fdc is a pointer to the fdc_data struct for the controller 188 * fdu is the floppy drive unit number 189 * fdcu is the floppy controller unit number 190 * fdsu is the floppy drive unit number on that controller. (sub-unit) 191 */ 192 typedef int fdu_t; 193 typedef int fdcu_t; 194 typedef int fdsu_t; 195 typedef struct fd_data *fd_p; 196 typedef struct fdc_data *fdc_p; 197 198 /* 199 * protos. 200 */ 201 static int delay __P((int)); 202 void encode __P((u_long, u_long *, u_long *)); 203 void fd_step __P((void)); 204 void fd_seek __P((fd_p, int)); 205 void correct __P((u_long *)); 206 void fd_probe __P((fd_p)); 207 void fd_turnon __P((fdc_p, fdu_t)); 208 void fd_turnoff __P((fdc_p)); 209 void track_read __P((fdc_p, fd_p, int)); 210 void fd_timeout __P((fdc_p)); 211 void fd_motor_to __P((fdcu_t)); 212 void fd_motor_on __P((fdc_p, fdu_t)); 213 void track_write __P((fdc_p, fd_p)); 214 void amiga_write __P((fd_p)); 215 void fd_calibrate __P((fd_p)); 216 void encode_block __P((u_long *, u_char *, int, u_long *)); 217 void fd_select_dir __P((fd_p, int)); 218 void fd_pseudointr __P((fdc_p)); 219 void fd_select_side __P((fd_p, int)); 220 221 u_long scan_sync __P((u_long, u_long, int)); 222 u_long encode_long __P((u_long, u_long *)); 223 u_long loop_read_id __P((int)); 224 u_long get_drive_id __P((int)); 225 226 int fdstate __P((fdc_p)); 227 int retrier __P((fdc_p)); 228 int amiga_read __P((fd_p)); 229 int get_drive_type __P((u_long)); 230 231 /* device routines */ 232 int Fdopen __P((dev_t, int)); 233 int fdsize __P((dev_t)); 234 int fdioctl __P((dev_t, int, caddr_t, int, struct proc *)); 235 int fdclose __P((dev_t, int)); 236 int fdattach __P((struct amiga_device *)); 237 238 void fdintr __P((fdcu_t)); 239 void fdstart __P((fdc_p)); 240 void fdstrategy __P((struct buf *bp)); 241 242 #define DEVIDLE 0 243 #define FINDWORK 1 244 #define DOSEEK 2 245 #define DO_IO 3 246 #define DONE_IO 4 247 #define WAIT_READ 5 248 #define WAIT_WRITE 6 249 #define DELAY_WRITE 7 250 #define RECALCOMPLETE 8 251 #define STARTRECAL 9 252 #define RESETCTLR 10 253 #define SEEKWAIT 11 254 #define RECALWAIT 12 255 #define MOTORWAIT 13 256 257 #undef DEBUG 258 259 #ifdef DEBUG 260 261 char *fdstates[] = 262 { 263 "DEVIDLE", 264 "FINDWORK", 265 "DOSEEK", 266 "DO_IO", 267 "DONE_IO", 268 "WAIT_READ", 269 "WAIT_WRITE", 270 "DELAY_WRITE", 271 "RECALCOMPLETE", 272 "STARTRECAL", 273 "RESETCTLR", 274 "SEEKWAIT", 275 "RECALWAIT", 276 "MOTORWAIT", 277 }; 278 279 #define TRACE0(arg) if (fd_debug == 1) printf(arg) 280 #define TRACE1(arg1,arg2) if (fd_debug == 1) printf(arg1,arg2) 281 282 #else /* !DEBUG */ 283 284 #define TRACE0(arg) 285 #define TRACE1(arg1,arg2) 286 287 #endif /* !DEBUG */ 288 289 extern int hz; 290 291 unsigned char *raw_buf = NULL; 292 #ifdef DEBUG 293 int fd_debug = 1; 294 #else 295 int fd_debug = 0; 296 #endif 297 298 /* 299 * Floppy Support Routines 300 */ 301 #define MOTOR_ON (ciab.prb &= ~CIAB_PRB_MTR) 302 #define MOTOR_OFF (ciab.prb |= CIAB_PRB_MTR) 303 #define SELECT(mask) (ciab.prb &= ~mask) 304 #define DESELECT(mask) (ciab.prb |= mask) 305 #define SELMASK(drive) (1 << (3 + (drive & 3))) 306 307 /* 308 * Delay for a number of milliseconds 309 * - tried ciab.tod but seems to miss values and screw up 310 * - stupid busy loop for now 311 */ 312 static int 313 delay(delay_ms) 314 int delay_ms; 315 { 316 long cnt, inner; 317 int val; 318 319 DELAY (delay_ms * 1000 * 25); /* NOTE: DELAY seems to run too fast */ 320 return(val); 321 } 322 323 /* 324 * motor control stuff 325 */ 326 void 327 fd_motor_to(fdcu) 328 fdcu_t fdcu; 329 { 330 printf("timeout starting motor\n"); /* XXXX */ 331 fdc_data[fdcu].motor_fdu = -2; 332 } 333 334 void 335 fd_motor_on(fdc, fdu) 336 fdc_p fdc; 337 fdu_t fdu; 338 { 339 int i; 340 341 /* deselect all drives */ 342 for (i = 0; i < DRVS_PER_CTLR; i++) 343 DESELECT(SELMASK(i)); 344 345 /* turn on the unit's motor */ 346 MOTOR_ON; 347 SELECT(SELMASK(fdu)); 348 349 timeout((timeout_t)fd_motor_to, (caddr_t)fdc->fdcu, hz); 350 while (ciaa.pra & CIAA_PRA_RDY) 351 ; 352 untimeout((timeout_t)fd_motor_to, (caddr_t)fdc->fdcu); 353 fdc->motor_fdu = fdu; 354 } 355 356 void 357 fd_turnoff(fdc) 358 fdc_p fdc; 359 { 360 int i; 361 362 if (fdc->motor_fdu != -1) { 363 /* deselect all drives */ 364 for (i = 0; i < DRVS_PER_CTLR; i++) 365 DESELECT(SELMASK(i)); 366 367 /* turn off the unit's motor */ 368 MOTOR_OFF; 369 SELECT(SELMASK(fdc->motor_fdu)); 370 MOTOR_ON; 371 DESELECT(SELMASK(fdc->motor_fdu)); 372 } 373 374 fdc->motor_fdu = -1; 375 } 376 377 void 378 fd_turnon(fdc, fdu) 379 fdc_p fdc; 380 fdu_t fdu; 381 { 382 if (fdc->motor_fdu == fdu) 383 return; 384 385 fd_turnoff(fdc); 386 fd_motor_on(fdc, fdu); 387 } 388 389 /* 390 * Step the drive once in its current direction 391 */ 392 void 393 fd_step() 394 { 395 ciab.prb &= ~CIAB_PRB_STEP; 396 ciab.prb |= CIAB_PRB_STEP; 397 } 398 399 /* 400 * Select the side to use for a particular drive. 401 * The drive must have been calibrated at some point before this. 402 * The drive must also be active and the motor must be running. 403 */ 404 void 405 fd_select_side(fd, side) 406 fd_p fd; 407 int side; 408 { 409 if (fd->side == side) 410 return; 411 412 /* select the requested side */ 413 if (side == 0) 414 ciab.prb &= ~CIAB_PRB_SIDE; 415 else 416 ciab.prb |= CIAB_PRB_SIDE; 417 delay(fd->ft->side_time); 418 fd->side = side; 419 } 420 421 /* 422 * Select the direction to use for the current particular drive. 423 */ 424 void 425 fd_select_dir(fd, dir) 426 fd_p fd; 427 int dir; 428 { 429 if (fd->dir == dir) 430 return; 431 432 /* select the requested direction */ 433 if (dir == 0) 434 ciab.prb &= ~CIAB_PRB_DIR; 435 else 436 ciab.prb |= CIAB_PRB_DIR; 437 delay(fd->ft->settle_time); 438 fd->dir = dir; 439 } 440 441 /* 442 * Seek the drive to track 0. 443 * The drive must be active and the motor must be running. 444 * Returns standard floppy error code. /* XXXX doesn't return anything 445 */ 446 void 447 fd_calibrate(fd) 448 fd_p fd; 449 { 450 fd_select_dir(fd, 1); 451 452 /* loop until we hit track 0 */ 453 while (ciaa.pra & CIAA_PRA_TK0) { 454 fd_step(); 455 delay(4); 456 } 457 458 /* set known values */ 459 fd->cyl = 0; 460 461 delay (fd->ft->settle_time); 462 } 463 464 /* 465 * Seek the drive to the requested track. 466 * The drive must be active and the motor must be running. 467 */ 468 void 469 fd_seek(fd, track) 470 fd_p fd; 471 int track; 472 { 473 int cyl, side; 474 int dir, cnt; 475 476 cyl = track >> 1; 477 side = (track % 2) ^ 1; 478 479 if (fd->cyl == -1) 480 fd_calibrate(fd); 481 482 fd_select_side(fd, side); 483 484 if (cyl < fd->cyl) { 485 dir = 1; 486 cnt = fd->cyl - cyl; 487 } else { 488 dir = 0; 489 cnt = cyl - fd->cyl; 490 } 491 492 fd_select_dir(fd, dir); 493 494 if (cnt) { 495 while (cnt) { 496 fd_step(); 497 delay(fd->ft->step_delay); 498 --cnt; 499 } 500 delay(fd->ft->settle_time); 501 } 502 503 fd->cyl = cyl; 504 } 505 506 void 507 encode(data, dest, csum) 508 u_long data; 509 u_long *dest, *csum; 510 { 511 u_long data2; 512 513 data &= 0x55555555; 514 data2 = data ^ 0x55555555; 515 data |= ((data2 >> 1) | 0x80000000) & (data2 << 1); 516 517 if (*(dest - 1) & 0x00000001) 518 data &= 0x7FFFFFFF; 519 520 *csum ^= data; 521 *dest = data; 522 } 523 524 u_long 525 encode_long(data, dest) 526 u_long data; 527 u_long *dest; 528 { 529 u_long csum; 530 531 csum = 0; 532 533 encode(data >> 1, dest, &csum); 534 encode(data, dest + 1, &csum); 535 536 return(csum & 0x55555555); 537 } 538 539 void 540 encode_block(dest, from, len, csum) 541 u_long *dest, *csum; 542 u_char *from; 543 int len; 544 { 545 int cnt, to_cnt = 0; 546 u_long data, *src; 547 548 to_cnt = 0; 549 src = (u_long *)from; 550 551 /* odd bits */ 552 for (cnt = 0; cnt < len / 4; cnt++) { 553 data = src[cnt] >> 1; 554 encode(data, dest + to_cnt++, csum); 555 } 556 557 /* even bits */ 558 for (cnt = 0; cnt < len / 4; cnt++) { 559 data = src[cnt]; 560 encode(data, dest + to_cnt++, csum); 561 } 562 563 *csum &= 0x55555555; 564 } 565 566 void 567 correct(raw) 568 u_long *raw; 569 { 570 u_char data, *ptr; 571 572 ptr = (u_char *)raw; 573 574 data = *ptr; 575 if (*(ptr - 1) & 0x01) { /* XXXX will choke on old GVP's */ 576 *ptr = data & 0x7f; 577 return; 578 } 579 580 if (data & 0x40) 581 return; 582 583 *ptr |= 0x80; 584 } 585 586 /* 587 * amiga_write converts track/labels data to raw track data 588 */ 589 void 590 amiga_write(fd) 591 fd_p fd; 592 { 593 u_long *raw, csum, format; 594 u_char *data, *labels; 595 int cnt, track; 596 597 raw = (u_long *)raw_buf; /* XXXX never used while intr? */ 598 /* XXXX never waits after here? */ 599 data = fd->buf_data; 600 labels = fd->buf_labels; 601 track = fd->buf_track; 602 603 /* gap space */ 604 for (cnt = fd->ft->gap_size; cnt; cnt--) 605 *raw++ = 0xaaaaaaaa; 606 607 /* sectors */ 608 for (cnt = 0; cnt < fd->sects; cnt++) { 609 *raw = 0xaaaaaaaa; 610 correct(raw); 611 ++raw; 612 613 *raw++ = 0x44894489; 614 615 format = 0xff000000 | (track << 16) | (cnt << 8) | (fd->sects - cnt); 616 csum = encode_long(format,raw); 617 raw += 2; 618 619 encode_block(raw, labels + cnt * 16, 16, &csum); 620 raw += 8; 621 csum = encode_long(csum, raw); 622 raw += 2; 623 624 csum = 0; 625 encode_block(raw+2, data + cnt * 512, 512, &csum); 626 csum = encode_long(csum, raw); 627 correct (raw+2); 628 raw += 256 + 2; 629 } 630 *raw = 0xaaa80000; 631 correct(raw); 632 633 } 634 635 #define get_word(raw) (*(u_short *)(raw)) 636 #define get_long(raw) (*(u_long *)(raw)) 637 638 #define decode_long(raw) \ 639 (((get_long(raw) & 0x55555555) << 1) | \ 640 (get_long((raw)+4) & 0x55555555)) 641 642 #define MFM_NOSYNC 1 643 #define MFM_HEADER 2 644 #define MFM_DATA 3 645 #define MFM_TRACK 4 646 647 /* 648 * scan_sync - looks for the next start of sector marked by a sync. When 649 * sect != 0, can't be certain of a starting sync. 650 */ 651 u_long 652 scan_sync(raw, end, sect) 653 u_long raw, end; 654 int sect; 655 { 656 u_short data; 657 658 if (sect == 0) { 659 while (raw < end) { 660 data = get_word(raw); 661 if (data == 0x4489) 662 break; 663 raw += 2; 664 } 665 if (raw > end) 666 return(0); 667 } 668 669 while (raw < end) { 670 data = get_word(raw); 671 if (data != 0x4489) 672 break; 673 raw += 2; 674 } 675 if (raw > end) 676 return(0); 677 return(raw); 678 } 679 680 /* 681 * amiga_read reads a raw track of data into a track buffer 682 */ 683 int 684 amiga_read(fd) 685 fd_p fd; 686 { 687 u_char *track_data, *label_data; 688 u_long raw, end, val1, val2, csum, data_csum; 689 u_long *data, *labels; 690 int scnt, cnt, format, tnum, sect, snext; 691 692 track_data = fd->buf_data; 693 label_data = fd->buf_labels; 694 raw = (u_long)raw_buf; /* XXXX see above about glb */ 695 696 end = raw + fd->ft->read_size; 697 698 for (scnt = fd->sects-1; scnt >= 0; scnt--) { 699 if ((raw = scan_sync(raw, end, scnt == fd->sects-1)) == 0) { 700 /* XXXX */ 701 printf("can't find sync for sector %d\n", scnt); 702 return(1); 703 } 704 705 val1 = decode_long(raw); 706 707 format = (val1 >> 24) & 0xFF; 708 tnum = (val1 >> 16) & 0xFF; 709 sect = (val1 >> 8) & 0xFF; 710 snext = (val1) & 0xFF; 711 712 labels = (u_long *)(label_data + (sect << 4)); 713 714 csum = 0; 715 val1 = get_long(raw); 716 raw += 4; 717 csum ^= val1; 718 val1 = get_long(raw); 719 raw += 4; 720 csum ^= val1; 721 722 for (cnt = 0; cnt < 4; cnt++) { 723 val1 = get_long(raw+16); 724 csum ^= val1; 725 val1 &= 0x55555555; 726 val2 = get_long(raw); 727 raw += 4; 728 csum ^= val2; 729 val2 &= 0x55555555; 730 val2 = val2 << 1; 731 val1 |= val2; 732 *labels++ = val1; 733 } 734 735 csum &= 0x55555555; 736 raw += 16; 737 val1 = decode_long(raw); 738 raw += 8; 739 if (val1 != csum) { 740 /* XXXX */ 741 printf("MFM_HEADER %d: %08x,%08x\n", scnt, 742 val1, csum); 743 return(MFM_HEADER); 744 } 745 746 /* verify track */ 747 if (tnum != fd->buf_track) { 748 /* XXXX */ 749 printf("MFM_TRACK %d: %d, %d\n", scnt, tnum, 750 fd->buf_track); 751 return(MFM_TRACK); 752 } 753 754 data_csum = decode_long(raw); 755 raw += 8; 756 data = (u_long *)(track_data + (sect << 9)); 757 758 csum = 0; 759 for (cnt = 0; cnt < 128; cnt++) { 760 val1 = get_long(raw + 512); 761 csum ^= val1; 762 val1 &= 0x55555555; 763 val2 = get_long(raw); 764 raw += 4; 765 csum ^= val2; 766 val2 &= 0x55555555; 767 val2 = val2 << 1; 768 val1 |= val2; 769 *data++ = val1; 770 } 771 772 csum &= 0x55555555; 773 raw += 512; 774 775 if (data_csum != csum) { 776 printf( 777 "MFM_DATA: f=%d t=%d s=%d sn=%d sc=%d %lx, %lx\n", 778 format, tnum, sect, snext, scnt, data_csum, csum); 779 return(MFM_DATA); 780 } 781 } 782 return(0); 783 } 784 785 /* 786 * Return unit ID number of given disk 787 * XXXX This function doesn't return anything. 788 */ 789 u_long 790 loop_read_id(unit) 791 int unit; 792 { 793 u_long id; 794 u_long id_bit; 795 796 id = 0; 797 798 /* loop and read disk ID */ 799 for (id_bit = 0x80000000; id_bit; id_bit >>= 1) { 800 SELECT(SELMASK(unit)); 801 802 /* read and store value of DSKRDY */ 803 if (ciaa.pra & CIAA_PRA_RDY) 804 id |= id_bit; 805 806 DESELECT(SELMASK(unit)); 807 } 808 } 809 810 u_long 811 get_drive_id(unit) 812 int unit; 813 { 814 int t; 815 u_long id, id_bit; 816 u_char mask1, mask2; 817 volatile u_char *a_ptr; 818 volatile u_char *b_ptr; 819 820 id = 0; 821 a_ptr = &ciaa.pra; 822 b_ptr = &ciab.prb; 823 mask1 = ~(1 << (3 + unit)); 824 mask2 = 1 << (3 + unit); 825 826 *b_ptr &= ~CIAB_PRB_MTR; 827 *b_ptr &= mask1; 828 *b_ptr |= mask2; 829 *b_ptr |= CIAB_PRB_MTR; 830 *b_ptr &= mask1; 831 *b_ptr |= mask2; 832 833 for (id_bit = 0x80000000; id_bit; id_bit >>= 1) { 834 *b_ptr &= mask1; 835 if ((*a_ptr) & CIAA_PRA_RDY) 836 id |= id_bit; 837 *b_ptr |= mask2; 838 } 839 840 /* all amigas have internal drives at 0. */ 841 if (unit == 0 && id == FD_NONE) 842 return(FD_DD_3); 843 return(id); 844 #if 0 845 /* set up for ID */ 846 MOTOR_ON; 847 SELECT(SELMASK(unit)); 848 DESELECT(SELMASK(unit)); 849 MOTOR_OFF; 850 SELECT(SELMASK(unit)); 851 DESELECT(SELMASK(unit)); 852 853 return loop_read_id(unit); /* XXXX gotta fix loop_read_id() if use */ 854 #endif 855 } 856 857 int 858 get_drive_type(u_long id) 859 { 860 int type; 861 862 for (type = 0; type < num_dr_types; type++) 863 if (drive_types[type].id == id) 864 return(type); 865 return(-1); 866 } 867 868 void 869 fd_probe(fd) 870 fd_p fd; 871 { 872 u_long id; 873 int type, data; 874 875 fd->ft = NULL; 876 877 id = get_drive_id(fd->fdu); 878 type = get_drive_type(id); 879 880 /* get_drive_id shuts off the motor */ 881 /* XXXX fdc_data[0] only as long as there is one controller */ 882 if (fd->fdu == fdc_data[0].motor_fdu) 883 fdc_data[0].motor_fdu = -1; 884 885 if (type == -1) { 886 /* XXXX */ 887 printf("fd_probe: unsupported drive type %08x found\n", id); 888 return; 889 } 890 891 fd->type = type; 892 fd->ft = &drive_types[type]; 893 if (fd->ft->tracks == 0) { 894 /* XXXX */ 895 printf("no drive type %d\n", type); 896 } 897 fd->side = -1; 898 fd->dir = -1; 899 fd->cyl = -1; 900 901 fd->sects = 11 * drive_types[type].sect_mult; 902 fd->size = fd->sects * 903 drive_types[type].tracks * 904 drive_types[type].heads; 905 fd->flags = 0; 906 } 907 908 void 909 track_read(fdc, fd, track) 910 fdc_p fdc; 911 fd_p fd; 912 int track; 913 { 914 u_long len; 915 916 fd->buf_track = track; 917 fdc->state = WAIT_READ; 918 919 fd_seek(fd, track); 920 921 len = fd->ft->read_size >> 1; 922 923 /* setup adkcon bits correctly */ 924 custom.adkcon = ADKF_MSBSYNC; 925 custom.adkcon = ADKF_SETCLR | ADKF_WORDSYNC | ADKF_FAST; 926 927 custom.dsksync = MFM_SYNC; 928 929 custom.dsklen = 0; 930 delay(fd->ft->side_time); 931 timeout((timeout_t)fd_timeout, (caddr_t)fdc, 2 * hz); 932 933 custom.dskpt = (u_char *)kvtop(raw_buf); 934 custom.dsklen = len | DSKLEN_DMAEN; 935 custom.dsklen = len | DSKLEN_DMAEN; 936 } 937 938 void 939 track_write(fdc, fd) 940 fdc_p fdc; 941 fd_p fd; 942 { 943 int track; 944 u_long len; 945 u_short adk; 946 947 amiga_write(fd); 948 949 track = fd->buf_track; 950 fd->write_cnt += 1; 951 952 fdc->saved = fdc->state; 953 fdc->state = WAIT_WRITE; 954 955 fd_seek(fd, track); 956 957 len = fd->ft->write_size >> 1; 958 959 if ((ciaa.pra & CIAA_PRA_WPRO) == 0) 960 return; 961 962 /* clear adkcon bits */ 963 custom.adkcon = ADKF_PRECOMP1 | ADKF_PRECOMP0 | ADKF_WORDSYNC | 964 ADKF_MSBSYNC; 965 966 /* set appropriate adkcon bits */ 967 adk = ADKF_SETCLR | ADKF_FAST | ADKF_MFMPREC; 968 if (track >= fd->ft->precomp2) 969 adk |= ADKF_PRECOMP1; 970 else if (track >= fd->ft->precomp1) 971 adk |= ADKF_PRECOMP0; 972 custom.adkcon = adk; 973 974 custom.dsklen = DSKLEN_WRITE; 975 delay(fd->ft->side_time); 976 timeout((timeout_t)fd_timeout, (caddr_t)fdc, 2 * hz); 977 978 custom.dskpt = (u_char *)kvtop(raw_buf); /* XXXX again raw */ 979 custom.dsklen = len | DSKLEN_DMAEN | DSKLEN_WRITE; 980 custom.dsklen = len | DSKLEN_DMAEN | DSKLEN_WRITE; 981 } 982 983 /* 984 * Floppy Device Code 985 */ 986 int 987 fdattach(ad) 988 struct amiga_device *ad; 989 { 990 int fdcu = 0; 991 fdc_p fdc = fdc_data + fdcu; 992 int i; 993 unsigned long id; 994 int type; 995 996 fdc->fdcu = fdcu; 997 fdc->state = FINDWORK; 998 fdc->fd = NULL; 999 fdc->motor_fdu = -1; 1000 1001 for (i = 0; i < DRVS_PER_CTLR; i++) { 1002 fdc->fd_data[i].fdu = i; 1003 fdc->fd_data[i].flags = 0; 1004 1005 fdc->fd_data[i].buf_track = -1; 1006 fdc->fd_data[i].buf_dirty = 0; 1007 fdc->fd_data[i].buf_data = 1008 malloc(MAX_SECTS * 512, M_DEVBUF, 0); 1009 fdc->fd_data[i].buf_labels = 1010 malloc(MAX_SECTS * 16, M_DEVBUF, 0); 1011 1012 if (fdc->fd_data[i].buf_data == NULL || 1013 fdc->fd_data[i].buf_labels == NULL) { 1014 printf("Cannot alloc buffer memory for fd device\n"); 1015 return(0); 1016 } 1017 1018 id = get_drive_id(i); 1019 type = get_drive_type(id); 1020 1021 if (type != -1 && drive_types[type].tracks != 0) { 1022 printf("floppy drive %d: %s\n", i, 1023 drive_types[type].name); 1024 } 1025 } 1026 1027 raw_buf = (char *)alloc_chipmem(30000); 1028 if (raw_buf == NULL) { 1029 printf("Cannot alloc chipmem for fd device\n"); 1030 return 0; 1031 } 1032 1033 /* enable disk DMA */ 1034 custom.dmacon = DMAF_SETCLR | DMAF_DISK; 1035 1036 /* enable interrupts for IRQ_DSKBLK */ 1037 ciaa.icr = CIA_ICR_IR_SC | CIA_ICR_FLG; 1038 custom.intena = INTF_SETCLR | INTF_SOFTINT; 1039 1040 /* enable disk block interrupts */ 1041 custom.intena = INTF_SETCLR | INTF_DSKBLK; 1042 1043 return(1); 1044 } 1045 1046 int 1047 Fdopen(dev, flags) 1048 dev_t dev; 1049 int flags; 1050 { 1051 fdcu_t fdcu; 1052 fdc_p fdc; 1053 fdu_t fdu; 1054 fd_p fd; 1055 1056 fdcu = 0; 1057 fdc = fdc_data + fdcu; 1058 fdu = UNIT(dev); 1059 fd = fdc->fd_data + fdu; 1060 1061 /* check bounds */ 1062 if (fdu >= DRVS_PER_CTLR) 1063 return(ENXIO); 1064 1065 /* 1066 * XXXX don't probe if device is currently selected 1067 * it may be in the middle of a DMA transfer and fd_probe 1068 * will deselect all drives 1069 */ 1070 if (fdc->motor_fdu < 0) 1071 fd_probe(fd); 1072 #if 0 1073 else 1074 printf ("fd: Fdopen called with a drive selected\n"); 1075 #endif 1076 1077 1078 if (fd->ft == NULL || fd->ft->tracks == 0) 1079 return(ENXIO); 1080 1081 fd->flags |= FDF_OPEN; 1082 fd->write_cnt = 0; 1083 1084 return(0); 1085 } 1086 1087 int 1088 fdclose(dev, flags) 1089 dev_t dev; 1090 int flags; 1091 { 1092 struct buf *dp,*bp; 1093 fdcu_t fdcu; 1094 fdc_p fdc; 1095 fdu_t fdu; 1096 fd_p fd; 1097 1098 fdcu = 0; 1099 fdc = fdc_data + fdcu; 1100 fdu = UNIT(dev); 1101 fd = fdc->fd_data + fdu; 1102 1103 1104 /* wait until activity is done for this drive */ 1105 /* XXXX ACK! sleep.. */ 1106 do { 1107 dp = &(fd->head); 1108 bp = dp->b_actf; 1109 } while (bp); 1110 1111 /* XXXX */ 1112 printf("wrote %d tracks (%d)\n", fd->write_cnt, fd->buf_dirty); 1113 1114 fd->buf_track = -1; 1115 fd->buf_dirty = 0; 1116 fd->flags &= ~FDF_OPEN; 1117 1118 return(0); 1119 } 1120 1121 int 1122 fdioctl(dev, cmd, data, flag, p) 1123 dev_t dev; 1124 int cmd, flag; 1125 caddr_t data; 1126 struct proc *p; 1127 { 1128 struct disklabel *fd_label; 1129 fdcu_t fdcu; 1130 fdc_p fdc; 1131 fdu_t fdu; 1132 fd_p fd; 1133 int error; 1134 1135 fdcu = 0; 1136 fdc = fdc_data + fdcu; 1137 fdu = UNIT(dev); 1138 fd = fdc->fd_data + fdu; 1139 error = 0; 1140 1141 if (cmd != DIOCGDINFO) 1142 return (EINVAL); 1143 1144 fd_label = (struct disklabel *)data; 1145 1146 bzero(fd_label, sizeof(fd_label)); 1147 fd_label->d_magic = DISKMAGIC; 1148 fd_label->d_type = DTYPE_FLOPPY; 1149 strncpy(fd_label->d_typename, "fd", sizeof(fd_label->d_typename) - 1); 1150 strcpy(fd_label->d_packname, fd->ft->name); 1151 1152 fd_label->d_rpm = 300 / fd->ft->sect_mult; 1153 fd_label->d_secsize = 512; 1154 fd_label->d_nsectors = fd->sects; 1155 fd_label->d_ntracks = fd->ft->heads; 1156 fd_label->d_ncylinders = fd->ft->tracks; 1157 fd_label->d_secpercyl = fd_label->d_nsectors * fd_label->d_ntracks; 1158 fd_label->d_secperunit= fd_label->d_ncylinders * fd_label->d_secpercyl; 1159 1160 fd_label->d_magic2 = DISKMAGIC; 1161 fd_label->d_partitions[0].p_offset = 0; 1162 fd_label->d_partitions[0].p_size = fd_label->d_secperunit; 1163 fd_label->d_partitions[0].p_fstype = FS_UNUSED; 1164 fd_label->d_npartitions = 1; 1165 1166 fd_label->d_checksum = 0; 1167 fd_label->d_checksum = dkcksum(fd_label); 1168 1169 return(0); 1170 } 1171 1172 int 1173 fdsize(dev) 1174 dev_t dev; 1175 { 1176 /* check UNIT? */ 1177 return((fdc_data + 0)->fd_data[UNIT(dev)].size); 1178 } 1179 1180 void 1181 fdstrategy(bp) 1182 struct buf *bp; 1183 { 1184 fdcu_t fdcu; 1185 fdc_p fdc; 1186 fdu_t fdu; 1187 fd_p fd; 1188 long nblocks, blknum; 1189 struct buf *dp; 1190 int s; 1191 1192 fdcu = 0; 1193 fdc = fdc_data + fdcu; 1194 fdu = UNIT(bp->b_dev); 1195 fd = fdc->fd_data + fdu; 1196 1197 if (bp->b_blkno < 0) { 1198 /* XXXX */ 1199 printf("fdstrat error: fdu = %d, blkno = %d, bcount = %d\n", 1200 fdu, bp->b_blkno, bp->b_bcount); 1201 bp->b_error = EINVAL; 1202 bp->b_flags |= B_ERROR; 1203 biodone(bp); 1204 return; 1205 } 1206 1207 /* 1208 * Set up block calculations. 1209 */ 1210 blknum = (unsigned long) bp->b_blkno * DEV_BSIZE / FDBLK; 1211 nblocks = fd->sects * fd->ft->tracks * fd->ft->heads; 1212 if (blknum + (bp->b_bcount / FDBLK) > nblocks) { 1213 nblocks -= blknum; 1214 if (nblocks == 0) { 1215 bp->b_resid = bp->b_bcount; 1216 goto done; 1217 } 1218 if (nblocks < 0) { 1219 bp->b_error = EINVAL; 1220 bp->b_flags |= B_ERROR; 1221 done: 1222 biodone(bp); 1223 return; 1224 } 1225 bp->b_bcount = dbtob(nblocks); 1226 } 1227 1228 bp->b_cylin = blknum; /* set here for disksort */ 1229 dp = &(fd->head); 1230 1231 s = splbio(); 1232 disksort(dp, bp); 1233 untimeout((timeout_t)fd_turnoff, (caddr_t)fdc); /* a good idea */ 1234 fdstart(fdc); 1235 splx(s); 1236 } 1237 1238 /* 1239 * We have just queued something.. if the controller is not busy 1240 * then simulate the case where it has just finished a command 1241 * So that it (the interrupt routine) looks on the queue for more 1242 * work to do and picks up what we just added. 1243 * If the controller is already busy, we need do nothing, as it 1244 * will pick up our work when the present work completes 1245 */ 1246 void 1247 fdstart(fdc) 1248 fdc_p fdc; 1249 { 1250 int s; 1251 1252 s = splbio(); 1253 if (fdc->state == FINDWORK) 1254 fdintr(fdc->fdcu); 1255 splx(s); 1256 } 1257 1258 /* 1259 * just ensure it has the right spl 1260 */ 1261 void 1262 fd_pseudointr(fdc) 1263 fdc_p fdc; 1264 { 1265 int s; 1266 1267 s = splbio(); 1268 fdintr(fdc->fdcu); 1269 splx(s); 1270 } 1271 1272 void 1273 fd_timeout(fdc) 1274 fdc_p fdc; 1275 { 1276 struct buf *dp,*bp; 1277 fd_p fd; 1278 1279 fd = fdc->fd; 1280 dp = &fd->head; 1281 bp = dp->b_actf; 1282 1283 if (fd == NULL) { 1284 printf ("fd_timeout called with no active drive?\n"); 1285 return; 1286 } 1287 1288 /* XXXX */ 1289 printf("fd%d: Operation timeout; state %d\n", fd->fdu, fdc->state); 1290 if (bp) { 1291 retrier(fdc); 1292 #if 0 /* XXX retrier already set fdc->state? */ 1293 fdc->state = DONE_IO; 1294 #endif 1295 if (fdc->retry < 6) 1296 fdc->retry = 6; 1297 } else { 1298 fdc->fd = NULL; 1299 fdc->state = FINDWORK; 1300 } 1301 1302 fd_pseudointr(fdc); 1303 } 1304 1305 /* 1306 * keep calling the state machine until it returns a 0 1307 * ALWAYS called at SPLBIO 1308 */ 1309 void 1310 fdintr(fdcu) 1311 fdcu_t fdcu; 1312 { 1313 fdc_p fdc; 1314 1315 fdc = fdc_data + fdcu; 1316 while (fdstate(fdc)) 1317 ; 1318 } 1319 1320 /* 1321 * The controller state machine. 1322 * if it returns a non zero value, it should be called again immediatly 1323 */ 1324 int 1325 fdstate(fdc) 1326 fdc_p fdc; 1327 { 1328 struct buf *dp,*bp; 1329 int track, read, sec, i; 1330 u_long blknum; 1331 fd_p fd; 1332 1333 fd = fdc->fd; 1334 1335 if (fd == NULL) { 1336 /* search for a unit do work with */ 1337 for (i = 0; i < DRVS_PER_CTLR; i++) { 1338 fd = fdc->fd_data + i; 1339 dp = &(fd->head); 1340 bp = dp->b_actf; 1341 if (bp) { 1342 fdc->fd = fd; 1343 break; 1344 } 1345 } 1346 1347 if (fdc->fd) 1348 return(1); 1349 1350 fdc->state = FINDWORK; 1351 TRACE1("[fdc%d IDLE]\n", fdc->fdcu); 1352 return(0); 1353 } 1354 1355 dp = &(fd->head); 1356 bp = dp->b_actf; 1357 1358 blknum = (u_long)bp->b_blkno * DEV_BSIZE / FDBLK + fd->skip / FDBLK; 1359 track = blknum / fd->sects; 1360 sec = blknum % fd->sects; 1361 1362 read = bp->b_flags & B_READ; 1363 TRACE1("fd%d", fd->fdu); 1364 TRACE1("[%s]", fdstates[fdc->state]); 1365 TRACE1("(0x%x) ", fd->flags); 1366 TRACE1("%d\n", fd->buf_track); 1367 1368 untimeout((timeout_t)fd_turnoff, (caddr_t)fdc); 1369 timeout((timeout_t)fd_turnoff, (caddr_t)fdc, 4 * hz); 1370 1371 switch (fdc->state) { 1372 case FINDWORK: 1373 if (!bp) { 1374 if (fd->buf_dirty) { 1375 track_write(fdc, fd); 1376 return(0); 1377 } 1378 fdc->fd = NULL; 1379 return(1); 1380 } 1381 1382 fdc->state = DOSEEK; 1383 fdc->retry = 0; 1384 fd->skip = 0; 1385 return(1); 1386 case DOSEEK: 1387 fd_turnon(fdc, fd->fdu); 1388 1389 /* 1390 * If not started, error starting it 1391 */ 1392 if (fdc->motor_fdu != fd->fdu) { 1393 /* XXXX */ 1394 printf("motor not on!\n"); 1395 } 1396 1397 /* 1398 * If track not in buffer, read it in 1399 */ 1400 if (fd->buf_track != track) { 1401 TRACE1("do track %d\n", track); 1402 1403 if (fd->buf_dirty) { 1404 track_write(fdc, fd); 1405 return (0); 1406 } else { 1407 if (read || sec != 0 || 1408 ((bp->b_bcount - fd->skip)/FDBLK) % fd->sects) { 1409 track_read(fdc, fd, track); 1410 return(0); 1411 } 1412 /* 1413 * if writing a full track, don't bother reading 1414 * in the old track - we're just going to overwrite 1415 * it all anyway. 1416 */ 1417 fd_seek (fd, track); 1418 fd->buf_track = track; 1419 /* clear sector labels */ 1420 bzero(fd->buf_labels, MAX_SECTS * 16); 1421 } 1422 } 1423 1424 fdc->state = DO_IO; 1425 return(1); 1426 case DO_IO: 1427 if (read) 1428 bcopy(&fd->buf_data[sec * FDBLK], 1429 bp->b_un.b_addr + fd->skip, FDBLK); 1430 else { 1431 bcopy(bp->b_un.b_addr + fd->skip, 1432 &fd->buf_data[sec * FDBLK], FDBLK); 1433 fd->buf_dirty = 1; 1434 if (IMMED_WRITE) { 1435 fdc->state = DONE_IO; 1436 track_write(fdc, fd); 1437 return(0); 1438 } 1439 } 1440 case DONE_IO: 1441 fd->skip += FDBLK; 1442 if (fd->skip < bp->b_bcount) 1443 fdc->state = DOSEEK; 1444 else { 1445 fd->skip = 0; 1446 if (bp == NULL) 1447 printf ("fd: fdstate DONE_IO bp == NULL\n"); 1448 else { 1449 bp->b_resid = 0; 1450 dp->b_actf = bp->b_actf; 1451 biodone(bp); 1452 } 1453 fdc->state = FINDWORK; 1454 } 1455 return(1); 1456 case WAIT_READ: 1457 untimeout((timeout_t)fd_timeout, (caddr_t)fdc); 1458 custom.dsklen = 0; 1459 if (amiga_read(fd) == 0) { 1460 fdc->retry = 0; 1461 fdc->state = DO_IO; 1462 return(1); 1463 } 1464 if (fdc->retry++ < 6) { 1465 track_read(fdc, fd, track); 1466 return(0); 1467 } 1468 if (bp) { 1469 bp->b_flags |= B_ERROR; 1470 bp->b_error = EIO; 1471 bp->b_resid = bp->b_bcount - fd->skip; 1472 dp->b_actf = bp->b_actf; 1473 fd->skip = 0; 1474 biodone(bp); 1475 } 1476 fdc->state = FINDWORK; 1477 return (1); 1478 case WAIT_WRITE: 1479 untimeout((timeout_t)fd_timeout, (caddr_t)fdc); 1480 custom.dsklen = 0; 1481 fdc->state = fdc->saved; 1482 fd->buf_dirty = 0; 1483 /* 1484 * post-write delay - should delay only if changing sides 1485 * after a write? 1486 */ 1487 delay (4); 1488 return(1); 1489 default: 1490 /* XXXX */ 1491 printf("Unexpected FD int->%d\n", fdc->state); 1492 return 0; 1493 } 1494 1495 /* Come back immediatly to new state */ 1496 return(1); 1497 } 1498 1499 int 1500 retrier(fdc) 1501 fdc_p fdc; 1502 { 1503 struct buf *dp,*bp; 1504 fd_p fd; 1505 1506 fd = fdc->fd; 1507 dp = &(fd->head); 1508 bp = dp->b_actf; 1509 1510 #if 0 1511 switch(fdc->retry) { 1512 case 0: 1513 case 1: 1514 case 2: 1515 fdc->state = SEEKCOMPLETE; 1516 break; 1517 case 3: 1518 case 4: 1519 case 5: 1520 fdc->state = STARTRECAL; 1521 break; 1522 case 6: 1523 fdc->state = RESETCTLR; 1524 break; 1525 case 7: 1526 break; 1527 default: 1528 #endif 1529 /* XXXX */ 1530 printf("fd%d: hard error\n", fd->fdu); 1531 1532 if (bp == NULL) 1533 printf ("fd: retrier bp == NULL\n"); 1534 else { 1535 bp->b_flags |= B_ERROR; 1536 bp->b_error = EIO; 1537 bp->b_resid = bp->b_bcount - fd->skip; 1538 dp->b_actf = bp->b_actf; 1539 fd->skip = 0; 1540 biodone(bp); 1541 } 1542 fdc->state = FINDWORK; 1543 return(1); 1544 #if 0 1545 fdc->retry++; 1546 return(1); 1547 #endif 1548 } 1549 1550 #endif 1551