/* * This routine is called when everything should be correctly set up * for the transfer (ie floppy motor is on and the correct floppy is * selected). */ static void transfer(void) { read_track = (command == FD_READ) && (CURRENT_ERRORS < 4) && (floppy->sect <= MAX_BUFFER_SECTORS); configure_fdc_mode(); if (reset) { redo_fd_request(); return; } if (!seek) { setup_rw_floppy(); return; } do_floppy = seek_interrupt; output_byte(FD_SEEK); if (read_track) output_byte(current_drive); else output_byte((head<<2) | current_drive); output_byte(seek_track); if (reset) redo_fd_request(); }
/* * This routine is called when everything should be correctly set up * for the transfer (ie floppy motor is on and the correct floppy is * selected). */ static void transfer(void) { read_track = (command == FD_READ) && (CURRENT_ERRORS < 4) && (floppy->sect <= MAX_BUFFER_SECTORS); if (cur_spec1 != floppy->spec1) { cur_spec1 = floppy->spec1; output_byte(FD_SPECIFY); output_byte(cur_spec1); /* hut etc */ output_byte(6); /* Head load time =6ms, DMA */ } if (cur_rate != floppy->rate) { /* use bit 6 of floppy->rate to indicate perpendicular mode */ perpendicular_mode(floppy->rate); outb_p(cur_rate = ((floppy->rate)) & ~0x40, FD_DCR); } if (reset) { redo_fd_request(); return; } if (!seek) { setup_rw_floppy(); return; } do_floppy = seek_interrupt; output_byte(FD_SEEK); if (read_track) output_byte(current_drive); else output_byte((head<<2) | current_drive); output_byte(seek_track); if (reset) redo_fd_request(); }
/** * We try to read tracks, but if we get too many errors, we * go back to reading just one sector at a time. * * This means we should be able to read a sector even if there * are other bad sectors on this track. * * @see rw_interrupt */ inline void setup_rw_floppy(void) { setup_DMA(); do_floppy = rw_interrupt; output_byte(command); if (command != FD_FORMAT) { if (read_track) { output_byte(current_drive); output_byte(track); output_byte(0); output_byte(1); } else { output_byte(head<<2 | current_drive); output_byte(track); output_byte(head); output_byte(sector); } output_byte(2); /* sector size = 512 */ output_byte(floppy->sect); output_byte(floppy->gap); output_byte(0xFF); /* sector size (0xff when n!=0 ?) */ } else { output_byte(head<<2 | current_drive); output_byte(2); output_byte(floppy->sect); output_byte(floppy->fmt_gap); output_byte(FD_FILL_BYTE); } if (reset) redo_fd_request(); }
static void shake_done(void) { current_track = NO_TRACK; if (inb(FD_DIR) & 0x80) request_done(0); redo_fd_request(); }
/* * Must do 4 FD_SENSEIs after reset because of ``drive polling''. */ static void reset_interrupt(void) { short i; for (i=0; i<4; i++) { output_byte(FD_SENSEI); (void) result(); } output_byte(FD_SPECIFY); output_byte(cur_spec1); /* hut etc */ output_byte(6); /* Head load time =6ms, DMA */ configure_fdc_mode(); /* reprogram fdc */ if (initial_reset_flag) { initial_reset_flag = 0; recalibrate = 1; reset = 0; return; } if (!recover) redo_fd_request(); else { recalibrate_floppy(); recover = 0; } }
static void floppy_shutdown(void) { cli(); do_floppy = NULL; request_done(0); recover = 1; reset_floppy(); sti(); redo_fd_request(); }
static void recalibrate_floppy(void) { recalibrate = 0; current_track = 0; do_floppy = recal_interrupt; output_byte(FD_RECALIBRATE); output_byte(head<<2 | current_drive); if (reset) redo_fd_request(); }
static void recal_interrupt(void) { output_byte(FD_SENSEI); current_track = NO_TRACK; if (result()!=2 || (ST0 & 0xE0) == 0x60) reset = 1; /* Recalibrate until track 0 is reached. Might help on some errors. */ if ((ST0 & 0x10) == 0x10) recalibrate_floppy(); else redo_fd_request(); }
/* * This is the routine called after every seek (or recalibrate) interrupt * from the floppy controller. Note that the "unexpected interrupt" routine * also does a recalibrate, but doesn't come here. */ static void seek_interrupt(void) { /* sense drive status */ output_byte(FD_SENSEI); if (result() != 2 || (ST0 & 0xF8) != 0x20 || ST1 != seek_track) { printk(DEVICE_NAME ": seek failed\n"); recalibrate = 1; bad_flp_intr(); redo_fd_request(); return; } current_track = ST1; setup_rw_floppy(); }
static void fd_error(void) { printk("FDC1772: fd_error\n"); /*panic("fd1772: fd_error"); *//* DAG tmp */ if (!CURRENT) return; CURRENT->errors++; if (CURRENT->errors >= MAX_ERRORS) { printk("fd%d: too many errors.\n", SelectedDrive); end_request(CURRENT, 0); } else if (CURRENT->errors == RECALIBRATE_ERRORS) { printk("fd%d: recalibrating\n", SelectedDrive); if (SelectedDrive != -1) unit[SelectedDrive].track = -1; } redo_fd_request(); }
static void do_fd_action(int drive) { struct request *req; DPRINT(("do_fd_action unit[drive].track=%d\n", unit[drive].track)); #ifdef TRACKBUFFER repeat: if (IS_BUFFERED( drive, ReqSide, ReqTrack )) { req = CURRENT; if (ReqCmd == READ) { copy_buffer( SECTOR_BUFFER(ReqSector), ReqData ); if (++ReqCnt < req->current_nr_sectors) { /* read next sector */ setup_req_params( drive ); goto repeat; } else { /* all sectors finished */ req->nr_sectors -= req->current_nr_sectors; req->sector += req->current_nr_sectors; end_request(req, 1); redo_fd_request(); return; } } else { /* cmd == WRITE, pay attention to track buffer * consistency! */ copy_buffer( ReqData, SECTOR_BUFFER(ReqSector) ); } } #endif if (SelectedDrive != drive) { /*unit[drive].track = -1; DAG */ fd_select_drive(drive); }; if (unit[drive].track == -1) fd_calibrate(); else if (unit[drive].track != ReqTrack << unit[drive].disktype->stretch) fd_seek(); else fd_rwsec(); }
/** * This interrupt is called after a DMA read/write has succeeded * or failed, so we check the results, and copy any buffers. * hhb: Added better error reporting. */ static void rw_interrupt(void) { char *buffer_area; int nr; char bad; nr = result(); /* check IC to find cause of interrupt */ switch ((ST0 & ST0_INTR)>>6) { case 1: /* error occured during command execution */ bad = 1; if (ST1 & ST1_WP) { printk(DEVICE_NAME ": Drive %d is write protected\n", current_drive); request_done(0); bad = 0; } else if (ST1 & ST1_OR) { if (ftd_msg[ST0 & ST0_DS]) printk(DEVICE_NAME ": Over/Underrun - retrying\n"); /* could continue from where we stopped, but ... */ bad = 0; } else if (CURRENT_ERRORS > min_report_error_cnt[ST0 & ST0_DS]) { printk(DEVICE_NAME " %d: ", ST0 & ST0_DS); if (ST0 & ST0_ECE) { printk("Recalibrate failed!"); } else if (ST2 & ST2_CRC) { printk("data CRC error"); tell_sector(nr); } else if (ST1 & ST1_CRC) { printk("CRC error"); tell_sector(nr); } else if ((ST1 & (ST1_MAM|ST1_ND)) || (ST2 & ST2_MAM)) { if (!probing) { printk("sector not found"); tell_sector(nr); } else printk("probe failed..."); } else if (ST2 & ST2_WC) { /* seek error */ printk("wrong cylinder"); } else if (ST2 & ST2_BC) { /* cylinder marked as bad */ printk("bad cylinder"); } else { printk("unknown error. ST[0..3] are: 0x%x 0x%x 0x%x 0x%x\n", ST0, ST1, ST2, ST3); } printk("\n"); } if (bad) { bad_flp_intr(); } redo_fd_request(); return; case 2: /* invalid command given */ printk(DEVICE_NAME ": Invalid FDC command given!\n"); request_done(0); return; case 3: printk(DEVICE_NAME ": Abnormal termination caused by polling\n"); bad_flp_intr(); redo_fd_request(); return; default: /* (0) Normal command termination */ break; } if (probing) { int drive = MINOR(CURRENT->dev); if (ftd_msg[drive]) printk("Auto-detected floppy type %s in fd%d\n", floppy->name,drive); current_type[drive] = floppy; floppy_sizes[drive] = floppy->size >> 1; probing = 0; } if (read_track) { buffer_track = seek_track; buffer_drive = current_drive; buffer_area = floppy_track_buffer + ((sector-1 + head*floppy->sect)<<9); copy_buffer(buffer_area,CURRENT->buffer); } else if (command == FD_READ && (unsigned long)(CURRENT->buffer) >= LAST_DMA_ADDR) copy_buffer(tmp_floppy_area,CURRENT->buffer); request_done(1); redo_fd_request(); }