00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025 #include "floppy.h"
00026 #include <timers.h>
00027 #include <ibm/diskparm.h>
00028 #include <minix/sysutil.h>
00029 #include <minix/syslib.h>
00030
00031
00032 #define DOR 0x3F2
00033 #define FDC_STATUS 0x3F4
00034 #define FDC_DATA 0x3F5
00035 #define FDC_RATE 0x3F7
00036 #define DMA_ADDR 0x004
00037 #define DMA_TOP 0x081
00038 #define DMA_COUNT 0x005
00039 #define DMA_FLIPFLOP 0x00C
00040 #define DMA_MODE 0x00B
00041 #define DMA_INIT 0x00A
00042 #define DMA_RESET_VAL 0x006
00043
00044 #define DMA_ADDR_MASK 0xFFFFFF
00045
00046
00047 #define ST0 0x00
00048 #define ST1 0x01
00049 #define ST2 0x02
00050 #define ST3 0x00
00051 #define ST_CYL 0x03
00052 #define ST_HEAD 0x04
00053 #define ST_SEC 0x05
00054 #define ST_PCN 0x01
00055
00056
00057
00058 #define CTL_BUSY 0x10
00059 #define DIRECTION 0x40
00060 #define MASTER 0x80
00061
00062
00063 #define MOTOR_SHIFT 4
00064 #define ENABLE_INT 0x0C
00065
00066
00067 #define ST0_BITS_TRANS 0xD8
00068 #define TRANS_ST0 0x00
00069 #define ST0_BITS_SEEK 0xF8
00070 #define SEEK_ST0 0x20
00071
00072
00073 #define BAD_SECTOR 0x05
00074 #define WRITE_PROTECT 0x02
00075
00076
00077 #define BAD_CYL 0x1F
00078
00079
00080 #define ST3_FAULT 0x80
00081 #define ST3_WR_PROTECT 0x40
00082 #define ST3_READY 0x20
00083
00084
00085 #define FDC_SEEK 0x0F
00086 #define FDC_READ 0xE6
00087 #define FDC_WRITE 0xC5
00088 #define FDC_SENSE 0x08
00089 #define FDC_RECALIBRATE 0x07
00090 #define FDC_SPECIFY 0x03
00091 #define FDC_READ_ID 0x4A
00092 #define FDC_FORMAT 0x4D
00093
00094
00095 #define DMA_READ 0x46
00096 #define DMA_WRITE 0x4A
00097
00098
00099 #define HC_SIZE 2880
00100 #define NR_HEADS 0x02
00101 #define MAX_SECTORS 18
00102 #define DTL 0xFF
00103 #define SPEC2 0x02
00104 #define MOTOR_OFF (3*HZ)
00105 #define WAKEUP (2*HZ)
00106
00107
00108 #define ERR_SEEK (-1)
00109 #define ERR_TRANSFER (-2)
00110 #define ERR_STATUS (-3)
00111 #define ERR_READ_ID (-4)
00112 #define ERR_RECALIBRATE (-5)
00113 #define ERR_DRIVE (-6)
00114 #define ERR_WR_PROTECT (-7)
00115 #define ERR_TIMEOUT (-8)
00116
00117
00118 #define err_no_retry(err) ((err) <= ERR_WR_PROTECT)
00119
00120
00121 #define DEV_TYPE_BITS 0x7C
00122 #define DEV_TYPE_SHIFT 2
00123 #define FORMAT_DEV_BIT 0x80
00124
00125
00126 #define MAX_ERRORS 6
00127 #define MAX_RESULTS 7
00128 #define NR_DRIVES 2
00129 #define DIVISOR 128
00130 #define SECTOR_SIZE_CODE 2
00131 #define TIMEOUT_MICROS 500000L
00132 #define TIMEOUT_TICKS 30
00133 #define NT 7
00134 #define UNCALIBRATED 0
00135 #define CALIBRATED 1
00136 #define BASE_SECTOR 1
00137 #define NO_SECTOR (-1)
00138 #define NO_CYL (-1)
00139 #define NO_DENS 100
00140 #define BSY_IDLE 0
00141 #define BSY_IO 1
00142 #define BSY_WAKEN 2
00143
00144
00145
00146
00147
00148
00149
00150
00151
00152
00153
00154
00155
00156
00157
00158
00159
00160 PRIVATE struct density {
00161 u8_t secpt;
00162 u8_t cyls;
00163 u8_t steps;
00164 u8_t test;
00165 u8_t rate;
00166 u8_t start;
00167 u8_t gap;
00168 u8_t spec1;
00169 } fdensity[NT] = {
00170 { 9, 40, 1, 4*9, 2, 4*HZ/8, 0x2A, 0xDF },
00171 { 15, 80, 1, 14, 0, 4*HZ/8, 0x1B, 0xDF },
00172 { 9, 40, 2, 2*9, 2, 4*HZ/8, 0x2A, 0xDF },
00173 { 9, 80, 1, 4*9, 2, 6*HZ/8, 0x2A, 0xDF },
00174 { 9, 40, 2, 2*9, 1, 4*HZ/8, 0x23, 0xDF },
00175 { 9, 80, 1, 4*9, 1, 4*HZ/8, 0x23, 0xDF },
00176 { 18, 80, 1, 17, 0, 6*HZ/8, 0x1B, 0xCF },
00177 };
00178
00179
00180
00181
00182
00183
00184
00185
00186
00187 #define b(d) (1 << (d))
00188
00189 PRIVATE struct test_order {
00190 u8_t t_density;
00191 u8_t t_class;
00192 } test_order[NT-1] = {
00193 { 6, b(3) | b(6) },
00194 { 1, b(1) | b(4) | b(5) },
00195 { 3, b(2) | b(3) | b(6) },
00196 { 4, b(1) | b(4) | b(5) },
00197 { 5, b(1) | b(4) | b(5) },
00198 { 2, b(2) | b(3) },
00199
00200
00201
00202 };
00203
00204
00205 PRIVATE struct floppy {
00206 unsigned fl_curcyl;
00207 unsigned fl_hardcyl;
00208 unsigned fl_cylinder;
00209 unsigned fl_sector;
00210 unsigned fl_head;
00211 char fl_calibration;
00212 u8_t fl_density;
00213 u8_t fl_class;
00214 timer_t fl_tmr_stop;
00215 struct device fl_geom;
00216 struct device fl_part[NR_PARTITIONS];
00217 } floppy[NR_DRIVES];
00218
00219 PRIVATE int irq_hook_id;
00220 PRIVATE int motor_status;
00221 PRIVATE int need_reset;
00222 PRIVATE unsigned f_drive;
00223 PRIVATE unsigned f_device;
00224 PRIVATE struct floppy *f_fp;
00225 PRIVATE struct density *f_dp;
00226 PRIVATE struct density *prev_dp;
00227 PRIVATE unsigned f_sectors;
00228 PRIVATE u16_t f_busy;
00229 PRIVATE struct device *f_dv;
00230 PRIVATE struct disk_parameter_s fmt_param;
00231 PRIVATE u8_t f_results[MAX_RESULTS];
00232
00233
00234
00235
00236
00237
00238 PRIVATE timer_t f_tmr_timeout;
00239 PRIVATE timer_t *f_timers;
00240 PRIVATE clock_t f_next_timeout;
00241 FORWARD _PROTOTYPE( void f_expire_tmrs, (struct driver *dp, message *m_ptr) );
00242 FORWARD _PROTOTYPE( void f_set_timer, (timer_t *tp, clock_t delta,
00243 tmr_func_t watchdog) );
00244 FORWARD _PROTOTYPE( void stop_motor, (timer_t *tp) );
00245 FORWARD _PROTOTYPE( void f_timeout, (timer_t *tp) );
00246
00247 FORWARD _PROTOTYPE( struct device *f_prepare, (int device) );
00248 FORWARD _PROTOTYPE( char *f_name, (void) );
00249 FORWARD _PROTOTYPE( void f_cleanup, (void) );
00250 FORWARD _PROTOTYPE( int f_transfer, (int proc_nr, int opcode, off_t position,
00251 iovec_t *iov, unsigned nr_req) );
00252 FORWARD _PROTOTYPE( int dma_setup, (int opcode) );
00253 FORWARD _PROTOTYPE( void start_motor, (void) );
00254 FORWARD _PROTOTYPE( int seek, (void) );
00255 FORWARD _PROTOTYPE( int fdc_transfer, (int opcode) );
00256 FORWARD _PROTOTYPE( int fdc_results, (void) );
00257 FORWARD _PROTOTYPE( int fdc_command, (u8_t *cmd, int len) );
00258 FORWARD _PROTOTYPE( void fdc_out, (int val) );
00259 FORWARD _PROTOTYPE( int recalibrate, (void) );
00260 FORWARD _PROTOTYPE( void f_reset, (void) );
00261 FORWARD _PROTOTYPE( int f_intr_wait, (void) );
00262 FORWARD _PROTOTYPE( int read_id, (void) );
00263 FORWARD _PROTOTYPE( int f_do_open, (struct driver *dp, message *m_ptr) );
00264 FORWARD _PROTOTYPE( void floppy_stop, (struct driver *dp, message *m_ptr));
00265 FORWARD _PROTOTYPE( int test_read, (int density) );
00266 FORWARD _PROTOTYPE( void f_geometry, (struct partition *entry) );
00267
00268
00269 PRIVATE struct driver f_dtab = {
00270 f_name,
00271 f_do_open,
00272 do_nop,
00273 do_diocntl,
00274 f_prepare,
00275 f_transfer,
00276 f_cleanup,
00277 f_geometry,
00278 floppy_stop,
00279 f_expire_tmrs,
00280 nop_cancel,
00281 nop_select,
00282 NULL,
00283 NULL
00284 };
00285
00286
00287
00288
00289 PUBLIC void main()
00290 {
00291
00292
00293 struct floppy *fp;
00294 int s;
00295
00296 f_next_timeout = TMR_NEVER;
00297 tmr_inittimer(&f_tmr_timeout);
00298
00299 for (fp = &floppy[0]; fp < &floppy[NR_DRIVES]; fp++) {
00300 fp->fl_curcyl = NO_CYL;
00301 fp->fl_density = NO_DENS;
00302 fp->fl_class = ~0;
00303 tmr_inittimer(&fp->fl_tmr_stop);
00304 }
00305
00306
00307
00308
00309 irq_hook_id = FLOPPY_IRQ;
00310 if ((s=sys_irqsetpolicy(FLOPPY_IRQ, 0, &irq_hook_id )) != OK)
00311 panic("FLOPPY", "Couldn't set IRQ policy", s);
00312 if ((s=sys_irqenable(&irq_hook_id)) != OK)
00313 panic("FLOPPY", "Couldn't enable IRQs", s);
00314
00315 driver_task(&f_dtab);
00316 }
00317
00318
00319
00320
00321 PRIVATE void f_expire_tmrs(struct driver *dp, message *m_ptr)
00322 {
00323
00324
00325
00326 clock_t now;
00327 timer_t *tp;
00328 int s;
00329
00330
00331 if ((s=getuptime(&now)) != OK)
00332 panic("FLOPPY","Couldn't get uptime from clock.", s);
00333
00334
00335
00336
00337
00338 tmrs_exptimers(&f_timers, now, NULL);
00339 if (f_timers == NULL) {
00340 f_next_timeout = TMR_NEVER;
00341 } else {
00342 f_next_timeout = f_timers->tmr_exp_time;
00343 if ((s=sys_setalarm(f_next_timeout, 1)) != OK)
00344 panic("FLOPPY","Couldn't set synchronous alarm.", s);
00345 }
00346 }
00347
00348
00349
00350
00351 PRIVATE void f_set_timer(tp, delta, watchdog)
00352 timer_t *tp;
00353 clock_t delta;
00354 tmr_func_t watchdog;
00355 {
00356 clock_t now;
00357 int s;
00358
00359
00360 if ((s=getuptime(&now)) != OK)
00361 panic("FLOPPY","Couldn't get uptime from clock.", s);
00362
00363
00364 tmrs_settimer(&f_timers, tp, now + delta, watchdog, NULL);
00365
00366
00367
00368
00369
00370 if (f_timers->tmr_exp_time != f_next_timeout) {
00371 f_next_timeout = f_timers->tmr_exp_time;
00372 if ((s=sys_setalarm(f_next_timeout, 1)) != OK)
00373 panic("FLOPPY","Couldn't set synchronous alarm.", s);
00374 }
00375 }
00376
00377
00378
00379
00380 PRIVATE struct device *f_prepare(device)
00381 int device;
00382 {
00383
00384
00385 f_device = device;
00386 f_drive = device & ~(DEV_TYPE_BITS | FORMAT_DEV_BIT);
00387 if (f_drive < 0 || f_drive >= NR_DRIVES) return(NIL_DEV);
00388
00389 f_fp = &floppy[f_drive];
00390 f_dv = &f_fp->fl_geom;
00391 if (f_fp->fl_density < NT) {
00392 f_dp = &fdensity[f_fp->fl_density];
00393 f_sectors = f_dp->secpt;
00394 f_fp->fl_geom.dv_size = mul64u((long) (NR_HEADS * f_sectors
00395 * f_dp->cyls), SECTOR_SIZE);
00396 }
00397
00398
00399 if ((device &= DEV_TYPE_BITS) >= MINOR_fd0p0)
00400 f_dv = &f_fp->fl_part[(device - MINOR_fd0p0) >> DEV_TYPE_SHIFT];
00401
00402 return f_dv;
00403 }
00404
00405
00406
00407
00408 PRIVATE char *f_name()
00409 {
00410
00411 static char name[] = "fd0";
00412
00413 name[2] = '0' + f_drive;
00414 return name;
00415 }
00416
00417
00418
00419
00420 PRIVATE void f_cleanup()
00421 {
00422
00423 tmr_arg(&f_fp->fl_tmr_stop)->ta_int = f_drive;
00424 f_set_timer(&f_fp->fl_tmr_stop, MOTOR_OFF, stop_motor);
00425
00426
00427 f_fp->fl_sector = NO_SECTOR;
00428 }
00429
00430
00431
00432
00433 PRIVATE int f_transfer(proc_nr, opcode, position, iov, nr_req)
00434 int proc_nr;
00435 int opcode;
00436 off_t position;
00437 iovec_t *iov;
00438 unsigned nr_req;
00439 {
00440 struct floppy *fp = f_fp;
00441 iovec_t *iop, *iov_end = iov + nr_req;
00442 int s, r, errors;
00443 unsigned block;
00444 unsigned nbytes, count, chunk, sector;
00445 unsigned long dv_size = cv64ul(f_dv->dv_size);
00446 vir_bytes user_addr;
00447 vir_bytes uaddrs[MAX_SECTORS], *up;
00448 u8_t cmd[3];
00449
00450
00451 if ((position & SECTOR_MASK) != 0) return(EINVAL);
00452
00453 errors = 0;
00454 while (nr_req > 0) {
00455
00456 nbytes = 0;
00457 for (iop = iov; iop < iov_end; iop++) nbytes += iop->iov_size;
00458
00459
00460 if (position >= dv_size) return(OK);
00461 if (position + nbytes > dv_size) nbytes = dv_size - position;
00462 block = div64u(add64ul(f_dv->dv_base, position), SECTOR_SIZE);
00463
00464 if ((nbytes & SECTOR_MASK) != 0) return(EINVAL);
00465
00466
00467 if (f_device & FORMAT_DEV_BIT) {
00468 if (opcode != DEV_SCATTER) return(EIO);
00469 if (iov->iov_size < SECTOR_SIZE + sizeof(fmt_param))
00470 return(EINVAL);
00471
00472 if ((s=sys_datacopy(proc_nr, iov->iov_addr + SECTOR_SIZE,
00473 SELF, (vir_bytes) &fmt_param,
00474 (phys_bytes) sizeof(fmt_param))) != OK)
00475 panic("FLOPPY", "Sys_vircopy failed", s);
00476
00477
00478
00479
00480
00481 if (fmt_param.sectors_per_cylinder == 0) return(EIO);
00482
00483
00484 iov->iov_size = nbytes = SECTOR_SIZE;
00485 }
00486
00487
00488 if (errors > 0) nbytes = SECTOR_SIZE;
00489
00490
00491 fp->fl_cylinder = block / (NR_HEADS * f_sectors);
00492 fp->fl_hardcyl = fp->fl_cylinder * f_dp->steps;
00493 fp->fl_head = (block % (NR_HEADS * f_sectors)) / f_sectors;
00494
00495
00496
00497
00498 for (up = uaddrs; up < uaddrs + MAX_SECTORS; up++) *up = 0;
00499 count = 0;
00500 iop = iov;
00501 sector = block % f_sectors;
00502 for (;;) {
00503 user_addr = iop->iov_addr;
00504 chunk = iop->iov_size;
00505 if ((chunk & SECTOR_MASK) != 0) return(EINVAL);
00506
00507 while (chunk > 0) {
00508 uaddrs[sector++] = user_addr;
00509 chunk -= SECTOR_SIZE;
00510 user_addr += SECTOR_SIZE;
00511 count += SECTOR_SIZE;
00512 if (sector == f_sectors || count == nbytes)
00513 goto track_set_up;
00514 }
00515 iop++;
00516 }
00517 track_set_up:
00518
00519
00520 if (need_reset) f_reset();
00521
00522
00523 start_motor();
00524
00525
00526 if (f_dp != prev_dp) {
00527 cmd[0] = FDC_SPECIFY;
00528 cmd[1] = f_dp->spec1;
00529 cmd[2] = SPEC2;
00530 (void) fdc_command(cmd, 3);
00531 if ((s=sys_outb(FDC_RATE, f_dp->rate)) != OK)
00532 panic("FLOPPY","Sys_outb failed", s);
00533 prev_dp = f_dp;
00534 }
00535
00536
00537 r = seek();
00538
00539
00540 if (fp->fl_sector == NO_SECTOR && count < (6 * SECTOR_SIZE))
00541 fp->fl_sector = 0;
00542
00543 for (nbytes = 0; nbytes < count; nbytes += SECTOR_SIZE) {
00544 if (fp->fl_sector == NO_SECTOR) {
00545
00546
00547
00548 if (r == OK && read_id() != OK) r = read_id();
00549 }
00550
00551
00552 if (r == OK) {
00553 for (;;) {
00554 if (fp->fl_sector >= f_sectors)
00555 fp->fl_sector = 0;
00556
00557 up = &uaddrs[fp->fl_sector];
00558 if (*up != 0) break;
00559 fp->fl_sector++;
00560 }
00561 }
00562
00563 if (r == OK && opcode == DEV_SCATTER) {
00564
00565 if ((s=sys_datacopy(proc_nr, *up, SELF,
00566 (vir_bytes) tmp_buf,
00567 (phys_bytes) SECTOR_SIZE)) != OK)
00568 panic("FLOPPY", "Sys_vircopy failed", s);
00569 }
00570
00571
00572 if (r == OK) {
00573 if (dma_setup(opcode) != OK) {
00574
00575
00576
00577
00578 return(EIO);
00579 }
00580 r = fdc_transfer(opcode);
00581 }
00582
00583 if (r == OK && opcode == DEV_GATHER) {
00584
00585 if ((s=sys_datacopy(SELF, (vir_bytes) tmp_buf,
00586 proc_nr, *up,
00587 (phys_bytes) SECTOR_SIZE)) != OK)
00588 panic("FLOPPY", "Sys_vircopy failed", s);
00589 }
00590
00591 if (r != OK) {
00592
00593 if (err_no_retry(r) || ++errors == MAX_ERRORS) {
00594 return(EIO);
00595 }
00596
00597
00598 if (errors == MAX_ERRORS / 2)
00599 fp->fl_calibration = UNCALIBRATED;
00600
00601 nbytes = 0;
00602 break;
00603 }
00604 }
00605
00606
00607 position += nbytes;
00608 for (;;) {
00609 if (nbytes < iov->iov_size) {
00610
00611 iov->iov_addr += nbytes;
00612 iov->iov_size -= nbytes;
00613 break;
00614 }
00615 nbytes -= iov->iov_size;
00616 iov->iov_addr += iov->iov_size;
00617 iov->iov_size = 0;
00618 if (nbytes == 0) {
00619
00620
00621
00622 return(OK);
00623 }
00624 iov++;
00625 nr_req--;
00626 }
00627 }
00628 return(OK);
00629 }
00630
00631
00632
00633
00634 PRIVATE int dma_setup(opcode)
00635 int opcode;
00636 {
00637
00638
00639
00640
00641
00642
00643
00644
00645
00646
00647
00648
00649 pvb_pair_t byte_out[9];
00650 int s;
00651
00652
00653 if (tmp_phys != (tmp_phys & DMA_ADDR_MASK)) {
00654 report("FLOPPY", "DMA denied because address out of range", NO_NUM);
00655 return(EIO);
00656 }
00657
00658
00659
00660
00661 pv_set(byte_out[0], DMA_INIT, DMA_RESET_VAL);
00662 pv_set(byte_out[1], DMA_FLIPFLOP, 0);
00663 pv_set(byte_out[2], DMA_MODE, opcode == DEV_SCATTER ? DMA_WRITE : DMA_READ);
00664 pv_set(byte_out[3], DMA_ADDR, (unsigned) tmp_phys >> 0);
00665 pv_set(byte_out[4], DMA_ADDR, (unsigned) tmp_phys >> 8);
00666 pv_set(byte_out[5], DMA_TOP, (unsigned) (tmp_phys >> 16));
00667 pv_set(byte_out[6], DMA_COUNT, (((SECTOR_SIZE - 1) >> 0) & 0xff));
00668 pv_set(byte_out[7], DMA_COUNT, (SECTOR_SIZE - 1) >> 8);
00669 pv_set(byte_out[8], DMA_INIT, 2);
00670
00671 if ((s=sys_voutb(byte_out, 9)) != OK)
00672 panic("FLOPPY","Sys_voutb in dma_setup() failed", s);
00673 return(OK);
00674 }
00675
00676
00677
00678
00679 PRIVATE void start_motor()
00680 {
00681
00682
00683
00684
00685
00686
00687
00688
00689
00690
00691 int s, motor_bit, running;
00692 message mess;
00693
00694 motor_bit = 1 << f_drive;
00695 running = motor_status & motor_bit;
00696 motor_status |= motor_bit;
00697
00698 if ((s=sys_outb(DOR,
00699 (motor_status << MOTOR_SHIFT) | ENABLE_INT | f_drive)) != OK)
00700 panic("FLOPPY","Sys_outb in start_motor() failed", s);
00701
00702
00703 if (running) return;
00704
00705
00706
00707
00708 f_set_timer(&f_tmr_timeout, f_dp->start, f_timeout);
00709 f_busy = BSY_IO;
00710 do {
00711 receive(ANY, &mess);
00712 if (mess.m_type == SYN_ALARM) {
00713 f_expire_tmrs(NULL, NULL);
00714 } else if(mess.m_type == DEV_PING) {
00715 notify(mess.m_source);
00716 } else {
00717 f_busy = BSY_IDLE;
00718 }
00719 } while (f_busy == BSY_IO);
00720 f_fp->fl_sector = NO_SECTOR;
00721 }
00722
00723
00724
00725
00726 PRIVATE void stop_motor(tp)
00727 timer_t *tp;
00728 {
00729
00730
00731
00732 int s;
00733 motor_status &= ~(1 << tmr_arg(tp)->ta_int);
00734 if ((s=sys_outb(DOR, (motor_status << MOTOR_SHIFT) | ENABLE_INT)) != OK)
00735 panic("FLOPPY","Sys_outb in stop_motor() failed", s);
00736 }
00737
00738
00739
00740
00741 PRIVATE void floppy_stop(struct driver *dp, message *m_ptr)
00742 {
00743
00744 int s;
00745 sigset_t sigset = m_ptr->NOTIFY_ARG;
00746 if (sigismember(&sigset, SIGTERM) || sigismember(&sigset, SIGKSTOP)) {
00747 if ((s=sys_outb(DOR, ENABLE_INT)) != OK)
00748 panic("FLOPPY","Sys_outb in floppy_stop() failed", s);
00749 exit(0);
00750 }
00751 }
00752
00753
00754
00755
00756 PRIVATE int seek()
00757 {
00758
00759
00760
00761
00762 struct floppy *fp = f_fp;
00763 int r;
00764 message mess;
00765 u8_t cmd[3];
00766
00767
00768 if (fp->fl_calibration == UNCALIBRATED)
00769 if (recalibrate() != OK) return(ERR_SEEK);
00770 if (fp->fl_curcyl == fp->fl_hardcyl) return(OK);
00771
00772
00773 cmd[0] = FDC_SEEK;
00774 cmd[1] = (fp->fl_head << 2) | f_drive;
00775 cmd[2] = fp->fl_hardcyl;
00776 if (fdc_command(cmd, 3) != OK) return(ERR_SEEK);
00777 if (f_intr_wait() != OK) return(ERR_TIMEOUT);
00778
00779
00780 fdc_out(FDC_SENSE);
00781 r = fdc_results();
00782 if (r != OK || (f_results[ST0] & ST0_BITS_SEEK) != SEEK_ST0
00783 || f_results[ST1] != fp->fl_hardcyl) {
00784
00785 return(ERR_SEEK);
00786 }
00787
00788 if (f_device & FORMAT_DEV_BIT) {
00789
00790
00791
00792 f_set_timer(&f_tmr_timeout, HZ/30, f_timeout);
00793 f_busy = BSY_IO;
00794 do {
00795 receive(ANY, &mess);
00796 if (mess.m_type == SYN_ALARM) {
00797 f_expire_tmrs(NULL, NULL);
00798 } else if(mess.m_type == DEV_PING) {
00799 notify(mess.m_source);
00800 } else {
00801 f_busy = BSY_IDLE;
00802 }
00803 } while (f_busy == BSY_IO);
00804 }
00805 fp->fl_curcyl = fp->fl_hardcyl;
00806 fp->fl_sector = NO_SECTOR;
00807 return(OK);
00808 }
00809
00810
00811
00812
00813 PRIVATE int fdc_transfer(opcode)
00814 int opcode;
00815 {
00816
00817
00818 struct floppy *fp = f_fp;
00819 int r, s;
00820 u8_t cmd[9];
00821
00822
00823 if (fp->fl_calibration == UNCALIBRATED) return(ERR_TRANSFER);
00824 if ((motor_status & (1 << f_drive)) == 0) return(ERR_TRANSFER);
00825
00826
00827
00828 if (f_device & FORMAT_DEV_BIT) {
00829 cmd[0] = FDC_FORMAT;
00830 cmd[1] = (fp->fl_head << 2) | f_drive;
00831 cmd[2] = fmt_param.sector_size_code;
00832 cmd[3] = fmt_param.sectors_per_cylinder;
00833 cmd[4] = fmt_param.gap_length_for_format;
00834 cmd[5] = fmt_param.fill_byte_for_format;
00835 if (fdc_command(cmd, 6) != OK) return(ERR_TRANSFER);
00836 } else {
00837 cmd[0] = opcode == DEV_SCATTER ? FDC_WRITE : FDC_READ;
00838 cmd[1] = (fp->fl_head << 2) | f_drive;
00839 cmd[2] = fp->fl_cylinder;
00840 cmd[3] = fp->fl_head;
00841 cmd[4] = BASE_SECTOR + fp->fl_sector;
00842 cmd[5] = SECTOR_SIZE_CODE;
00843 cmd[6] = f_sectors;
00844 cmd[7] = f_dp->gap;
00845 cmd[8] = DTL;
00846 if (fdc_command(cmd, 9) != OK) return(ERR_TRANSFER);
00847 }
00848
00849
00850 if (f_intr_wait() != OK) {
00851 printf("%s: disk interrupt timed out.\n", f_name());
00852 return(ERR_TIMEOUT);
00853 }
00854
00855
00856 r = fdc_results();
00857 if (r != OK) return(r);
00858
00859 if (f_results[ST1] & WRITE_PROTECT) {
00860 printf("%s: diskette is write protected.\n", f_name());
00861 return(ERR_WR_PROTECT);
00862 }
00863
00864 if ((f_results[ST0] & ST0_BITS_TRANS) != TRANS_ST0) return(ERR_TRANSFER);
00865 if (f_results[ST1] | f_results[ST2]) return(ERR_TRANSFER);
00866
00867 if (f_device & FORMAT_DEV_BIT) return(OK);
00868
00869
00870 s = (f_results[ST_CYL] - fp->fl_cylinder) * NR_HEADS * f_sectors;
00871 s += (f_results[ST_HEAD] - fp->fl_head) * f_sectors;
00872 s += (f_results[ST_SEC] - BASE_SECTOR - fp->fl_sector);
00873 if (s != 1) return(ERR_TRANSFER);
00874
00875
00876 fp->fl_sector = f_results[ST_SEC] - BASE_SECTOR;
00877 #if 0
00878 if (processor < 386) fp->fl_sector++;
00879 #endif
00880 return(OK);
00881 }
00882
00883
00884
00885
00886 PRIVATE int fdc_results()
00887 {
00888
00889
00890
00891
00892 int s, result_nr;
00893 unsigned long status;
00894 clock_t t0,t1;
00895
00896
00897
00898
00899
00900 result_nr = 0;
00901 getuptime(&t0);
00902 do {
00903
00904
00905
00906
00907 if ((s=sys_inb(FDC_STATUS, &status)) != OK)
00908 panic("FLOPPY","Sys_inb in fdc_results() failed", s);
00909 status &= (MASTER | DIRECTION | CTL_BUSY);
00910 if (status == (MASTER | DIRECTION | CTL_BUSY)) {
00911 unsigned long tmp_r;
00912 if (result_nr >= MAX_RESULTS) break;
00913 if ((s=sys_inb(FDC_DATA, &tmp_r)) != OK)
00914 panic("FLOPPY","Sys_inb in fdc_results() failed", s);
00915 f_results[result_nr] = tmp_r;
00916 result_nr ++;
00917 continue;
00918 }
00919 if (status == MASTER) {
00920 if ((s=sys_irqenable(&irq_hook_id)) != OK)
00921 panic("FLOPPY", "Couldn't enable IRQs", s);
00922
00923 return(OK);
00924 }
00925 } while ( (s=getuptime(&t1))==OK && (t1-t0) < TIMEOUT_TICKS );
00926 if (OK!=s) printf("FLOPPY: warning, getuptime failed: %d\n", s);
00927 need_reset = TRUE;
00928
00929 if ((s=sys_irqenable(&irq_hook_id)) != OK)
00930 panic("FLOPPY", "Couldn't enable IRQs", s);
00931 return(ERR_STATUS);
00932 }
00933
00934
00935
00936
00937 PRIVATE int fdc_command(cmd, len)
00938 u8_t *cmd;
00939 int len;
00940 {
00941
00942
00943
00944
00945
00946
00947
00948 f_set_timer(&f_tmr_timeout, WAKEUP, f_timeout);
00949
00950 f_busy = BSY_IO;
00951 while (len > 0) {
00952 fdc_out(*cmd++);
00953 len--;
00954 }
00955 return(need_reset ? ERR_DRIVE : OK);
00956 }
00957
00958
00959
00960
00961 PRIVATE void fdc_out(val)
00962 int val;
00963 {
00964
00965
00966
00967
00968 clock_t t0, t1;
00969 int s;
00970 unsigned long status;
00971
00972 if (need_reset) return;
00973
00974
00975 getuptime(&t0);
00976 do {
00977 if ( (s=getuptime(&t1))==OK && (t1-t0) > TIMEOUT_TICKS ) {
00978 if (OK!=s) printf("FLOPPY: warning, getuptime failed: %d\n", s);
00979 need_reset = TRUE;
00980 return;
00981 }
00982 if ((s=sys_inb(FDC_STATUS, &status)) != OK)
00983 panic("FLOPPY","Sys_inb in fdc_out() failed", s);
00984 }
00985 while ((status & (MASTER | DIRECTION)) != (MASTER | 0));
00986
00987 if ((s=sys_outb(FDC_DATA, val)) != OK)
00988 panic("FLOPPY","Sys_outb in fdc_out() failed", s);
00989 }
00990
00991
00992
00993
00994 PRIVATE int recalibrate()
00995 {
00996
00997
00998
00999
01000
01001
01002
01003
01004
01005 struct floppy *fp = f_fp;
01006 int r;
01007 u8_t cmd[2];
01008
01009
01010 cmd[0] = FDC_RECALIBRATE;
01011 cmd[1] = f_drive;
01012 if (fdc_command(cmd, 2) != OK) return(ERR_SEEK);
01013 if (f_intr_wait() != OK) return(ERR_TIMEOUT);
01014
01015
01016 fdc_out(FDC_SENSE);
01017 r = fdc_results();
01018 fp->fl_curcyl = NO_CYL;
01019 fp->fl_sector = NO_SECTOR;
01020 if (r != OK ||
01021 (f_results[ST0] & ST0_BITS_SEEK) != SEEK_ST0 || f_results[ST_PCN] != 0) {
01022
01023 need_reset = TRUE;
01024 return(ERR_RECALIBRATE);
01025 } else {
01026
01027 fp->fl_calibration = CALIBRATED;
01028 fp->fl_curcyl = f_results[ST_PCN];
01029 return(OK);
01030 }
01031 }
01032
01033
01034
01035
01036 PRIVATE void f_reset()
01037 {
01038
01039
01040
01041 pvb_pair_t byte_out[2];
01042 int s,i;
01043 message mess;
01044
01045
01046 need_reset = FALSE;
01047
01048
01049
01050
01051
01052
01053
01054
01055
01056
01057 (void) fdc_command((u8_t *) 0, 0);
01058 motor_status = 0;
01059 pv_set(byte_out[0], DOR, 0);
01060 pv_set(byte_out[1], DOR, ENABLE_INT);
01061 if ((s=sys_voutb(byte_out, 2)) != OK)
01062 panic("FLOPPY", "Sys_voutb in f_reset() failed", s);
01063
01064
01065
01066
01067
01068 do {
01069 receive(ANY, &mess);
01070 if (mess.m_type == SYN_ALARM) {
01071 f_expire_tmrs(NULL, NULL);
01072 } else if(mess.m_type == DEV_PING) {
01073 notify(mess.m_source);
01074 } else {
01075 f_busy = BSY_IDLE;
01076 }
01077 } while (f_busy == BSY_IO);
01078
01079
01080
01081
01082
01083
01084
01085
01086
01087
01088
01089
01090 for (i = 0; i < 4; i++) {
01091 fdc_out(FDC_SENSE);
01092 (void) fdc_results();
01093 }
01094 for (i = 0; i < NR_DRIVES; i++)
01095 floppy[i].fl_calibration = UNCALIBRATED;
01096
01097
01098 prev_dp = NULL;
01099 }
01100
01101
01102
01103
01104 PRIVATE int f_intr_wait()
01105 {
01106
01107
01108
01109 message mess;
01110
01111
01112
01113
01114
01115 do {
01116 receive(ANY, &mess);
01117 if (mess.m_type == SYN_ALARM) {
01118 f_expire_tmrs(NULL, NULL);
01119 } else if(mess.m_type == DEV_PING) {
01120 notify(mess.m_source);
01121 } else {
01122 f_busy = BSY_IDLE;
01123 }
01124 } while (f_busy == BSY_IO);
01125
01126 if (f_busy == BSY_WAKEN) {
01127
01128
01129
01130
01131 need_reset = TRUE;
01132 return(ERR_TIMEOUT);
01133 }
01134 return(OK);
01135 }
01136
01137
01138
01139
01140 PRIVATE void f_timeout(tp)
01141 timer_t *tp;
01142 {
01143
01144
01145
01146
01147
01148 if (f_busy == BSY_IO) {
01149 f_busy = BSY_WAKEN;
01150 }
01151 }
01152
01153
01154
01155
01156 PRIVATE int read_id()
01157 {
01158
01159
01160 struct floppy *fp = f_fp;
01161 int result;
01162 u8_t cmd[2];
01163
01164
01165 if (fp->fl_calibration == UNCALIBRATED) return(ERR_READ_ID);
01166 if ((motor_status & (1 << f_drive)) == 0) return(ERR_READ_ID);
01167
01168
01169 cmd[0] = FDC_READ_ID;
01170 cmd[1] = (fp->fl_head << 2) | f_drive;
01171 if (fdc_command(cmd, 2) != OK) return(ERR_READ_ID);
01172 if (f_intr_wait() != OK) return(ERR_TIMEOUT);
01173
01174
01175 result = fdc_results();
01176 if (result != OK) return(result);
01177
01178 if ((f_results[ST0] & ST0_BITS_TRANS) != TRANS_ST0) return(ERR_READ_ID);
01179 if (f_results[ST1] | f_results[ST2]) return(ERR_READ_ID);
01180
01181
01182 fp->fl_sector = f_results[ST_SEC] - BASE_SECTOR + 1;
01183 return(OK);
01184 }
01185
01186
01187
01188
01189 PRIVATE int f_do_open(dp, m_ptr)
01190 struct driver *dp;
01191 message *m_ptr;
01192 {
01193
01194
01195 int dtype;
01196 struct test_order *top;
01197
01198
01199 if (f_prepare(m_ptr->DEVICE) == NIL_DEV) return(ENXIO);
01200
01201 dtype = f_device & DEV_TYPE_BITS;
01202 if (dtype >= MINOR_fd0p0) dtype = 0;
01203
01204 if (dtype != 0) {
01205
01206 dtype = (dtype >> DEV_TYPE_SHIFT) - 1;
01207 if (dtype >= NT) return(ENXIO);
01208 f_fp->fl_density = dtype;
01209 (void) f_prepare(f_device);
01210 return(OK);
01211 }
01212 if (f_device & FORMAT_DEV_BIT) return(EIO);
01213
01214
01215
01216
01217
01218
01219 if (f_fp->fl_density != NO_DENS) {
01220 if (motor_status & (1 << f_drive)) return(OK);
01221 if (test_read(f_fp->fl_density) == OK) return(OK);
01222 }
01223
01224
01225
01226
01227 for (top = &test_order[0]; top < &test_order[NT-1]; top++) {
01228 dtype = top->t_density;
01229
01230
01231 if (!(f_fp->fl_class & (1 << dtype))) continue;
01232
01233 if (test_read(dtype) == OK) {
01234
01235
01236
01237 f_fp->fl_class &= top->t_class;
01238 return(OK);
01239 }
01240
01241 if (f_busy == BSY_WAKEN) break;
01242 }
01243 f_fp->fl_density = NO_DENS;
01244 return(EIO);
01245 }
01246
01247
01248
01249
01250 PRIVATE int test_read(density)
01251 int density;
01252 {
01253
01254
01255
01256
01257 int device;
01258 off_t position;
01259 iovec_t iovec1;
01260 int result;
01261
01262 f_fp->fl_density = density;
01263 device = ((density + 1) << DEV_TYPE_SHIFT) + f_drive;
01264
01265 (void) f_prepare(device);
01266 position = (off_t) f_dp->test << SECTOR_SHIFT;
01267 iovec1.iov_addr = (vir_bytes) tmp_buf;
01268 iovec1.iov_size = SECTOR_SIZE;
01269 result = f_transfer(SELF, DEV_GATHER, position, &iovec1, 1);
01270
01271 if (iovec1.iov_size != 0) return(EIO);
01272
01273 partition(&f_dtab, f_drive, P_FLOPPY, 0);
01274 return(OK);
01275 }
01276
01277
01278
01279
01280 PRIVATE void f_geometry(entry)
01281 struct partition *entry;
01282 {
01283 entry->cylinders = f_dp->cyls;
01284 entry->heads = NR_HEADS;
01285 entry->sectors = f_sectors;
01286 }
01287