/* * 02.12.91 - Changed to static variables to indicate need for reset * and recalibrate. This makes some things easier (output_byte reset * checking etc), and means less interrupt jumping in case of errors, * so the code is hopefully easier to understand.
*/
/* * This file is certainly a mess. I've tried my best to get it working, * but I don't like programming floppies, and I have only one anyway. * Urgel. I should check for more errors, and do more graceful error * recovery. Seems there are problems with several drives. I've tried to * correct them. No promises.
*/
/* * As with hd.c, all routines within this file can (and will) be called * by interrupts, so extreme caution is needed. A hardware interrupt * handler may not sleep, or a kernel panic will happen. Thus I cannot * call "floppy-on" directly, but have to set a special timer interrupt * etc.
*/
/* * 28.02.92 - made track-buffering routines, based on the routines written * by entropy@wintermute.wpi.edu (Lawrence Foard). Linus.
*/
/* * Automatic floppy-detection and formatting written by Werner Almesberger * (almesber@nessie.cs.id.ethz.ch), who also corrected some problems with * the floppy-change signal detection.
*/
/* * 1992/7/22 -- Hennus Bergman: Added better error reporting, fixed * FDC data overrun bug, added some preliminary stuff for vertical * recording support. * * 1992/9/17: Added DMA allocation & DMA functions. -- hhb. * * TODO: Errors are still not counted properly.
*/
/* 1992/9/20 * Modifications for ``Sector Shifting'' by Rob Hooft (hooft@chem.ruu.nl) * modeled after the freeware MS-DOS program fdformat/88 V1.8 by * Christoph H. Hochst\"atter. * I have fixed the shift values to the ones I always use. Maybe a new * ioctl() should be created to be able to modify them. * There is a bug in the driver that makes it impossible to format a * floppy as the first thing after bootup.
*/
/* * 1993/4/29 -- Linus -- cleaned up the timer handling in the kernel, and * this helped the floppy driver as well. Much cleaner, and still seems to * work.
*/
/* 1994/6/24 --bbroad-- added the floppy table entries and made * minor modifications to allow 2.88 floppies to be run.
*/
/* 1994/7/13 -- Paul Vojta -- modified the probing code to allow three or more * disk types.
*/
/* * 1994/8/8 -- Alain Knaff -- Switched to fdpatch driver: Support for bigger * format bug fixes, but unfortunately some new bugs too...
*/
/* 1994/9/17 -- Koen Holtman -- added logging of physical floppy write * errors to allow safe writing by specialized programs.
*/
/* 1995/4/24 -- Dan Fandrich -- added support for Commodore 1581 3.5" disks * by defining bit 1 of the "stretch" parameter to mean put sectors on the * opposite side of the disk, leaving the sector IDs alone (i.e. Commodore's * drives are "upside-down").
*/
/* * 1995/10/18 -- Ralf Baechle -- Portability cleanup; move machine dependent * features to asm/floppy.h.
*/
/* * 1998/1/21 -- Richard Gooch <rgooch@atnf.csiro.au> -- devfs support
*/
/* * 1998/05/07 -- Russell King -- More portability cleanups; moved definition of * interrupt and dma channel to asm/floppy.h. Cleaned up some formatting & * use of '0' for NULL.
*/
/* * 1998/06/07 -- Alan Cox -- Merged the 2.0.34 fixes for resource allocation * failures.
*/
/* * 1998/09/20 -- David Weinehall -- Added slow-down code for buggy PS/2-drives.
*/
/* * 1999/08/13 -- Paul Slootman -- floppy stopped working on Alpha after 24 * days, 6 hours, 32 minutes and 32 seconds (i.e. MAXINT jiffies; ints were * being used to store jiffies, which are unsigned longs).
*/
/* * 2000/08/28 -- Arnaldo Carvalho de Melo <acme@conectiva.com.br> * - get rid of check_region * - s/suser/capable/
*/
/* * 2001/08/26 -- Paul Gortmaker - fix insmod oops on machines with no * floppy controller (lingering task on list after module is gone... boom.)
*/
/* * 2002/02/07 -- Anton Altaparmakov - Fix io ports reservation to correct range * (0x3f2-0x3f5, 0x3f7). This fix is a bit of a hack but the proper fix * requires many non-obvious changes in arch dependent code.
*/
/* * PS/2 floppies have much slower step rates than regular floppies. * It's been recommended that take about 1/4 of the default speed * in some more extreme cases.
*/ static DEFINE_MUTEX(floppy_mutex); staticint slow_floppy;
#include <asm/dma.h> #include <asm/irq.h>
staticint FLOPPY_IRQ = 6; staticint FLOPPY_DMA = 2; staticint can_use_virtual_dma = 2; /* ======= * can use virtual DMA: * 0 = use of virtual DMA disallowed by config * 1 = use of virtual DMA prescribed by config * 2 = no virtual DMA preference configured. By default try hard DMA, * but fall back on virtual DMA when not enough memory available
*/
staticint use_virtual_dma; /* ======= * use virtual DMA * 0 using hard DMA * 1 using virtual DMA * This variable is set to virtual when a DMA mem problem arises, and * reset back in floppy_grab_irq_and_dma. * It is not safe to reset it in other circumstances, because the floppy * driver may have several buffers in use at once, and we do currently not * record each buffers capabilities
*/
/* the following is the mask of allowed drives. By default units 2 and * 3 of both floppy controllers are disabled, because switching on the * motor of these drives causes system hangs on some PCI computers. drive * 0 is the low bit (0x1), and drive 7 is the high bit (0x80). Bits are on if * a drive is allowed. * * NOTE: This must come before we include the arch floppy header because * some ports reference this variable from there. -DaveM
*/
staticint allowed_drive_mask = 0x33;
#include <asm/floppy.h>
staticint irqdma_allocated;
#include <linux/blk-mq.h> #include <linux/blkpg.h> #include <linux/cdrom.h> /* for the compatibility eject ioctl */ #include <linux/completion.h>
/* * Maximum disk size (in kilobytes). * This default is used whenever the current disk size is unknown. * [Now it is rather a minimum]
*/ #define MAX_DISK_SIZE 4 /* 3984 */
/* * globals used by 'result()'
*/ staticunsignedchar reply_buffer[FD_RAW_REPLY_SIZE]; staticint inr; /* size of reply buffer, when called from interrupt */ #define ST0 0 #define ST1 1 #define ST2 2 #define ST3 0 /* result of GETSTATUS */ #define R_TRACK 3 #define R_HEAD 4 #define R_SECTOR 5 #define R_SIZECODE 6
#define SEL_DLY (2 * HZ / 100)
/* * this struct defines the different floppy drive types.
*/ staticstruct { struct floppy_drive_params params; constchar *name; /* name printed while booting */
} default_drive_params[] = { /* NOTE: the time values in jiffies should be in msec! CMOS drive type | Maximum data rate supported by drive type | | Head load time, msec | | | Head unload time, msec (not used) | | | | Step rate interval, usec | | | | | Time needed for spinup time (jiffies) | | | | | | Timeout for spinning down (jiffies) | | | | | | | Spindown offset (where disk stops) | | | | | | | | Select delay | | | | | | | | | RPS | | | | | | | | | | Max number of tracks | | | | | | | | | | | Interrupt timeout | | | | | | | | | | | | Max nonintlv. sectors
| | | | | | | | | | | | | -Max Errors- flags */
{{0, 500, 16, 16, 8000, 1*HZ, 3*HZ, 0, SEL_DLY, 5, 80, 3*HZ, 20, {3,1,2,0,2}, 0,
0, { 7, 4, 8, 2, 1, 5, 3,10}, 3*HZ/2, 0 }, "unknown" },
/* * This struct defines the different floppy types. * * Bit 0 of 'stretch' tells if the tracks need to be doubled for some * types (e.g. 360kB diskette in 1.2MB drive, etc.). Bit 1 of 'stretch' * tells if the disk is in Commodore 1581 format, which means side 0 sectors * are located on side 1 of the disk but with a side 0 ID, and vice-versa. * This is the same as the Sharp MZ-80 5.25" CP/M disk format, except that the * 1581's logical side 0 is on physical side 1, whereas the Sharp's logical * side 0 is on physical side 0 (but with the misnamed sector IDs). * 'stretch' should probably be renamed to something more general, like * 'options'. * * Bits 2 through 9 of 'stretch' tell the number of the first sector. * The LSB (bit 2) is flipped. For most disks, the first sector * is 1 (represented by 0x00<<2). For some CP/M and music sampler * disks (such as Ensoniq EPS 16plus) it is 0 (represented as 0x01<<2). * For Amstrad CPC disks it is 0xC1 (represented as 0xC0<<2). * * Other parameters should be self-explanatory (see also setfdprm(8)).
*/ /* Size | Sectors per track | | Head | | | Tracks | | | | Stretch | | | | | Gap 1 size | | | | | | Data rate, | 0x40 for perp | | | | | | | Spec1 (stepping rate, head unload
| | | | | | | | /fmt gap (gap2) */ staticstruct floppy_struct floppy_type[32] = {
{ 0, 0,0, 0,0,0x00,0x00,0x00,0x00,NULL }, /* 0 no testing */
{ 720, 9,2,40,0,0x2A,0x02,0xDF,0x50,"d360" }, /* 1 360KB PC */
{ 2400,15,2,80,0,0x1B,0x00,0xDF,0x54,"h1200" }, /* 2 1.2MB AT */
{ 720, 9,1,80,0,0x2A,0x02,0xDF,0x50,"D360" }, /* 3 360KB SS 3.5" */
{ 1440, 9,2,80,0,0x2A,0x02,0xDF,0x50,"D720" }, /* 4 720KB 3.5" */
{ 720, 9,2,40,1,0x23,0x01,0xDF,0x50,"h360" }, /* 5 360KB AT */
{ 1440, 9,2,80,0,0x23,0x01,0xDF,0x50,"h720" }, /* 6 720KB AT */
{ 2880,18,2,80,0,0x1B,0x00,0xCF,0x6C,"H1440" }, /* 7 1.44MB 3.5" */
{ 5760,36,2,80,0,0x1B,0x43,0xAF,0x54,"E2880" }, /* 8 2.88MB 3.5" */
{ 6240,39,2,80,0,0x1B,0x43,0xAF,0x28,"E3120" }, /* 9 3.12MB 3.5" */
/* Auto-detection: Disk type used until the next media change occurs. */ staticstruct floppy_struct *current_type[N_DRIVE];
/* * User-provided type information. current_type points to * the respective entry of this array.
*/ staticstruct floppy_struct user_params[N_DRIVE];
static sector_t floppy_sizes[256];
staticchar floppy_device_name[] = "floppy";
/* * The driver is trying to determine the correct media format * while probing is set. rw_interrupt() clears it after a * successful access.
*/ staticint probing;
/* errors encountered on the current (or last) request */ staticint floppy_errors;
/* Format request descriptor. */ staticstruct format_descr format_req;
/* * Rate is 0 for 500kb/s, 1 for 300kbps, 2 for 250kbps * Spec1 is 0xSH, where S is stepping rate (F=1ms, E=2ms, D=3ms etc), * H is head unload time (1=16ms, 2=32ms, etc)
*/
/* * Track buffer * Because these are written to by the DMA controller, they must * not contain a 64k byte boundary crossing, or data will be * corrupted/lost.
*/ staticchar *floppy_track_buffer; staticint max_buffer_sectors;
staticconststruct cont_t { void (*interrupt)(void); /* this is called after the interrupt of the
* main command */ void (*redo)(void); /* this is called to retry the operation */ void (*error)(void); /* this is called to tally an error */ void (*done)(int); /* this is called to say if the operation has
* succeeded/failed */
} *cont;
/* * The "reset" variable should be tested whenever an interrupt is scheduled, * after the commands have been sent. This is to ensure that the driver doesn't * get wedged when the interrupt doesn't come because of a failed command. * reset doesn't need to be tested before sending commands, because * output_byte is automatically disabled when reset is set.
*/ staticvoid reset_fdc(void); staticint floppy_revalidate(struct gendisk *disk);
/* * These are global variables, as that's the easiest way to give * information to interrupts. They are the data used for the current * request.
*/ #define NO_TRACK -1 #define NEED_1_RECAL -2 #define NEED_2_RECAL -3
#define INFBOUND(a, b) (a) = max_t(int, a, b) #define SUPBOUND(a, b) (a) = min_t(int, a, b)
/* * Bottom half floppy driver. * ========================== * * This part of the file contains the code talking directly to the hardware, * and also the main service loop (seek-configure-spinup-command)
*/
/* * disk change. * This routine is responsible for maintaining the FD_DISK_CHANGE flag, * and the last_checked date. * * last_checked is the date of the last check which showed 'no disk change' * FD_DISK_CHANGE is set under two conditions: * 1. The floppy has been changed after some i/o to that floppy already * took place. * 2. No floppy disk is in the drive. This is done in order to ensure that * requests are quickly flushed in case there is no disk in the drive. It * follows that FD_DISK_CHANGE can only be cleared if there is a disk in * the drive. * * For 1., maxblock is observed. Maxblock is 0 if no i/o has taken place yet. * For 2., FD_DISK_NEWCHANGE is watched. FD_DISK_NEWCHANGE is cleared on * each seek. If a disk is present, the disk change line should also be * cleared on each seek. Thus, if FD_DISK_NEWCHANGE is clear, but the disk * change line is set, this means either that no disk is in the drive, or * that it has been removed since the last seek. * * This means that we really have a third possibility too: * The floppy has been changed after the last seek.
*/
staticint disk_change(int drive)
{ int fdc = FDC(drive);
if (time_before(jiffies, drive_state[drive].select_date + drive_params[drive].select_delay))
DPRINT("WARNING disk change called early\n"); if (!(fdc_state[fdc].dor & (0x10 << UNIT(drive))) ||
(fdc_state[fdc].dor & 3) != UNIT(drive) || fdc != FDC(drive)) {
DPRINT("probing disk change on unselected drive\n");
DPRINT("drive=%d fdc=%d dor=%x\n", drive, FDC(drive),
(unsignedint)fdc_state[fdc].dor);
}
debug_dcl(drive_params[drive].flags, "checking disk change line for drive %d\n", drive);
debug_dcl(drive_params[drive].flags, "jiffies=%lu\n", jiffies);
debug_dcl(drive_params[drive].flags, "disk change line=%x\n",
fdc_inb(fdc, FD_DIR) & 0x80);
debug_dcl(drive_params[drive].flags, "flags=%lx\n",
drive_state[drive].flags);
if (drive_state[drive].maxblock) /* mark it changed */
set_bit(FD_DISK_CHANGED_BIT,
&drive_state[drive].flags);
/* invalidate its geometry */ if (drive_state[drive].keep_data >= 0) { if ((drive_params[drive].flags & FTD_MSG) &&
current_type[drive] != NULL)
DPRINT("Disk type is undefined after disk change\n");
current_type[drive] = NULL;
floppy_sizes[TOMINOR(drive)] = MAX_DISK_SIZE << 1;
}
/* * Reset all driver information about the specified fdc. * This is needed after a reset, and after a raw command.
*/ staticvoid reset_fdc_info(int fdc, int mode)
{ int drive;
/* * selects the fdc and drive, and enables the fdc's input/dma. * Both current_drive and current_fdc are changed to match the new drive.
*/ staticvoid set_fdc(int drive)
{ unsignedint fdc;
if (drive < 0 || drive >= N_DRIVE) {
pr_info("bad drive value %d\n", drive); return;
}
/* * locks the driver. * Both current_drive and current_fdc are changed to match the new drive.
*/ staticint lock_fdc(int drive)
{ if (WARN(atomic_read(&usage_count) == 0, "Trying to lock fdc while usage count=0\n")) return -1;
if (wait_event_interruptible(fdc_wait, !test_and_set_bit(0, &fdc_busy))) return -EINTR;
/* switches the motor off after a given timeout */ staticvoid motor_off_callback(struct timer_list *t)
{ unsignedlong nr = t - motor_off_timer; unsignedchar mask = ~(0x10 << UNIT(nr));
if (WARN_ON_ONCE(nr >= N_DRIVE)) return;
set_dor(FDC(nr), mask, 0);
}
/* schedules motor off */ staticvoid floppy_off(unsignedint drive)
{ unsignedlongvolatile delta; int fdc = FDC(drive);
if (!(fdc_state[fdc].dor & (0x10 << UNIT(drive)))) return;
timer_delete(motor_off_timer + drive);
/* make spindle stop in a position which minimizes spinup time
* next time */ if (drive_params[drive].rps) {
delta = jiffies - drive_state[drive].first_read_date + HZ -
drive_params[drive].spindown_offset;
delta = ((delta * drive_params[drive].rps) % HZ) / drive_params[drive].rps;
motor_off_timer[drive].expires =
jiffies + drive_params[drive].spindown - delta;
}
add_timer(motor_off_timer + drive);
}
/* * cycle through all N_DRIVE floppy drives, for disk change testing. * stopping at current drive. This is done before any long operation, to * be sure to have up to date disk change information.
*/ staticvoid scandrives(void)
{ int i; int drive; int saved_drive;
if (drive_params[current_drive].select_delay) return;
saved_drive = current_drive; for (i = 0; i < N_DRIVE; i++) {
drive = (saved_drive + i + 1) % N_DRIVE; if (drive_state[drive].fd_ref == 0 || drive_params[drive].select_delay != 0) continue; /* skip closed drives */
set_fdc(drive); if (!(set_dor(current_fdc, ~3, UNIT(drive) | (0x10 << UNIT(drive))) &
(0x10 << UNIT(drive)))) /* switch the motor off again, if it was off to
* begin with */
set_dor(current_fdc, ~(0x10 << UNIT(drive)), 0);
}
set_fdc(saved_drive);
}
/* this function makes sure that the disk stays in the drive during the
* transfer */ staticvoid fd_watchdog(void)
{
debug_dcl(drive_params[current_drive].flags, "calling disk change from watchdog\n");
/* waits for a delay (spinup or select) to pass */ staticint fd_wait_for_completion(unsignedlong expires, void (*function)(void))
{ if (fdc_state[current_fdc].reset) {
reset_fdc(); /* do the reset during sleep to win time * if we don't need to sleep, it's a good
* occasion anyways */ return 1;
}
/* gets the response from the fdc */ staticint result(int fdc)
{ int i; int status = 0;
for (i = 0; i < FD_RAW_REPLY_SIZE; i++) {
status = wait_til_ready(fdc); if (status < 0) break;
status &= STATUS_DIR | STATUS_READY | STATUS_BUSY | STATUS_DMA; if ((status & ~STATUS_BUSY) == STATUS_READY) {
resultjiffies = jiffies;
resultsize = i; return i;
} if (status == (STATUS_DIR | STATUS_READY | STATUS_BUSY))
reply_buffer[i] = fdc_inb(fdc, FD_DATA); else break;
} if (initialized) {
DPRINT("get result error. Fdc=%d Last status=%x Read bytes=%d\n",
fdc, status, i);
show_floppy(fdc);
}
fdc_state[fdc].reset = 1; return -1;
}
#define MORE_OUTPUT -2 /* does the fdc need more output? */ staticint need_more_output(int fdc)
{ int status = wait_til_ready(fdc);
if (status < 0) return -1;
if (is_ready_state(status)) return MORE_OUTPUT;
return result(fdc);
}
/* Set perpendicular mode as required, based on data rate, if supported. * 82077 Now tested. 1Mbps data rate only possible with 82077-1.
*/ staticvoid perpendicular_mode(int fdc)
{ unsignedchar perp_mode;
if (raw_cmd->rate & 0x40) { switch (raw_cmd->rate & 3) { case 0:
perp_mode = 2; break; case 3:
perp_mode = 3; break; default:
DPRINT("Invalid data rate for perpendicular mode!\n");
cont->done(0);
fdc_state[fdc].reset = 1; /* * convenient way to return to * redo without too much hassle * (deep stack et al.)
*/ return;
}
} else
perp_mode = 0;
if (fdc_state[fdc].perp_mode == perp_mode) return; if (fdc_state[fdc].version >= FDC_82077_ORIG) {
output_byte(fdc, FD_PERPENDICULAR);
output_byte(fdc, perp_mode);
fdc_state[fdc].perp_mode = perp_mode;
} elseif (perp_mode) {
DPRINT("perpendicular mode not supported by this FDC.\n");
}
} /* perpendicular_mode */
/* Issue a "SPECIFY" command to set the step rate time, head unload time, * head load time, and DMA disable flag to values needed by floppy. * * The value "dtr" is the data transfer rate in Kbps. It is needed * to account for the data rate-based scaling done by the 82072 and 82077 * FDC types. This parameter is ignored for other types of FDCs (i.e. * 8272a). * * Note that changing the data transfer rate has a (probably deleterious) * effect on the parameters subject to scaling for 82072/82077 FDCs, so * fdc_specify is called again after each data transfer rate * change. * * srt: 1000 to 16000 in microseconds * hut: 16 to 240 milliseconds * hlt: 2 to 254 milliseconds * * These values are rounded up to the next highest available delay time.
*/ staticvoid fdc_specify(int fdc, int drive)
{ unsignedchar spec1; unsignedchar spec2; unsignedlong srt; unsignedlong hlt; unsignedlong hut; unsignedlong dtr = NOMINAL_DTR; unsignedlong scale_dtr = NOMINAL_DTR; int hlt_max_code = 0x7f; int hut_max_code = 0xf;
/* If these parameters did not change, just return with success */ if (fdc_state[fdc].spec1 != spec1 ||
fdc_state[fdc].spec2 != spec2) { /* Go ahead and set spec1 and spec2 */
output_byte(fdc, FD_SPECIFY);
output_byte(fdc, fdc_state[fdc].spec1 = spec1);
output_byte(fdc, fdc_state[fdc].spec2 = spec2);
}
} /* fdc_specify */
/* Set the FDC's data transfer rate on behalf of the specified drive. * NOTE: with 82072/82077 FDCs, changing the data rate requires a reissue * of the specify command (i.e. using the fdc_specify function).
*/ staticint fdc_dtr(void)
{ /* If data rate not already set to desired value, set it. */ if ((raw_cmd->rate & 3) == fdc_state[current_fdc].dtr) return 0;
/* Set dtr */
fdc_outb(raw_cmd->rate & 3, current_fdc, FD_DCR);
/* TODO: some FDC/drive combinations (C&T 82C711 with TEAC 1.2MB) * need a stabilization period of several milliseconds to be * enforced after data rate changes before R/W operations. * Pause 5 msec to avoid trouble. (Needs to be 2 jiffies)
*/
fdc_state[current_fdc].dtr = raw_cmd->rate & 3; return fd_wait_for_completion(jiffies + 2UL * HZ / 100, floppy_ready);
} /* fdc_dtr */
/* * OK, this error interpreting routine 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. * ak: Made this into a separate routine.
*/ staticint interpret_errors(void)
{ char bad;
/* check IC to find cause of interrupt */ switch (reply_buffer[ST0] & ST0_INTR) { case 0x40: /* error occurred during command execution */ if (reply_buffer[ST1] & ST1_EOC) return 0; /* occurs with pseudo-DMA */
bad = 1; if (reply_buffer[ST1] & ST1_WP) {
DPRINT("Drive is write protected\n");
clear_bit(FD_DISK_WRITABLE_BIT,
&drive_state[current_drive].flags);
cont->done(0);
bad = 2;
} elseif (reply_buffer[ST1] & ST1_ND) {
set_bit(FD_NEED_TWADDLE_BIT,
&drive_state[current_drive].flags);
} elseif (reply_buffer[ST1] & ST1_OR) { if (drive_params[current_drive].flags & FTD_MSG)
DPRINT("Over/Underrun - retrying\n");
bad = 0;
} elseif (floppy_errors >= drive_params[current_drive].max_errors.reporting) {
print_errors();
} if (reply_buffer[ST2] & ST2_WC || reply_buffer[ST2] & ST2_BC) /* wrong cylinder => recal */
drive_state[current_drive].track = NEED_2_RECAL; return bad; case 0x80: /* invalid command given */
DPRINT("Invalid FDC command given!\n");
cont->done(0); return 2; case 0xc0:
DPRINT("Abnormal termination caused by polling\n");
cont->error(); return 2; default: /* (0) Normal command termination */ return 0;
}
}
/* * This routine is called when everything should be correctly set up * for the transfer (i.e. floppy motor is on, the correct floppy is * selected, and the head is sitting on the right track).
*/ staticvoid setup_rw_floppy(void)
{ int i; int r; int flags; unsignedlong ready_date; void (*function)(void);
if ((flags & FD_RAW_SPIN) && !(flags & FD_RAW_NO_MOTOR)) {
ready_date = drive_state[current_drive].spinup_date + drive_params[current_drive].spinup; /* If spinup will take a long time, rerun scandrives * again just before spinup completion. Beware that * after scandrives, we must again wait for selection.
*/ if (time_after(ready_date, jiffies + drive_params[current_drive].select_delay)) {
ready_date -= drive_params[current_drive].select_delay;
function = floppy_start;
} else
function = setup_rw_floppy;
/* wait until the floppy is spinning fast enough */ if (fd_wait_for_completion(ready_date, function)) return;
} if ((flags & FD_RAW_READ) || (flags & FD_RAW_WRITE))
setup_DMA();
if (flags & FD_RAW_INTR)
do_floppy = main_command_interrupt;
r = 0; for (i = 0; i < raw_cmd->cmd_count; i++)
r |= output_byte(current_fdc, raw_cmd->fullcmd[i]);
/* * This is the routine called after every seek (or recalibrate) interrupt * from the floppy controller.
*/ staticvoid seek_interrupt(void)
{
debugt(__func__, ""); if (inr != 2 || (reply_buffer[ST0] & 0xF8) != 0x20) {
DPRINT("seek failed\n");
drive_state[current_drive].track = NEED_2_RECAL;
cont->error();
cont->redo(); return;
} if (drive_state[current_drive].track >= 0 &&
drive_state[current_drive].track != reply_buffer[ST1] &&
!blind_seek) {
debug_dcl(drive_params[current_drive].flags, "clearing NEWCHANGE flag because of effective seek\n");
debug_dcl(drive_params[current_drive].flags, "jiffies=%lu\n",
jiffies);
clear_bit(FD_DISK_NEWCHANGE_BIT,
&drive_state[current_drive].flags); /* effective seek */
drive_state[current_drive].select_date = jiffies;
}
drive_state[current_drive].track = reply_buffer[ST1];
floppy_ready();
}
staticvoid check_wp(int fdc, int drive)
{ if (test_bit(FD_VERIFY_BIT, &drive_state[drive].flags)) { /* check write protection */
output_byte(fdc, FD_GETSTATUS);
output_byte(fdc, UNIT(drive)); if (result(fdc) != 1) {
fdc_state[fdc].reset = 1; return;
}
clear_bit(FD_VERIFY_BIT, &drive_state[drive].flags);
clear_bit(FD_NEED_TWADDLE_BIT,
&drive_state[drive].flags);
debug_dcl(drive_params[drive].flags, "checking whether disk is write protected\n");
debug_dcl(drive_params[drive].flags, "wp=%x\n",
reply_buffer[ST3] & 0x40); if (!(reply_buffer[ST3] & 0x40))
set_bit(FD_DISK_WRITABLE_BIT,
&drive_state[drive].flags); else
clear_bit(FD_DISK_WRITABLE_BIT,
&drive_state[drive].flags);
}
}
staticvoid seek_floppy(void)
{ int track;
blind_seek = 0;
debug_dcl(drive_params[current_drive].flags, "calling disk change from %s\n", __func__);
if (!test_bit(FD_DISK_NEWCHANGE_BIT, &drive_state[current_drive].flags) &&
disk_change(current_drive) && (raw_cmd->flags & FD_RAW_NEED_DISK)) { /* the media changed flag should be cleared after the seek. * If it isn't, this means that there is really no disk in * the drive.
*/
set_bit(FD_DISK_CHANGED_BIT,
&drive_state[current_drive].flags);
cont->done(0);
cont->redo(); return;
} if (drive_state[current_drive].track <= NEED_1_RECAL) {
recalibrate_floppy(); return;
} elseif (test_bit(FD_DISK_NEWCHANGE_BIT, &drive_state[current_drive].flags) &&
(raw_cmd->flags & FD_RAW_NEED_DISK) &&
(drive_state[current_drive].track <= NO_TRACK || drive_state[current_drive].track == raw_cmd->track)) { /* we seek to clear the media-changed condition. Does anybody
* know a more elegant way, which works on all drives? */ if (raw_cmd->track)
track = raw_cmd->track - 1; else { if (drive_params[current_drive].flags & FD_SILENT_DCL_CLEAR) {
set_dor(current_fdc, ~(0x10 << UNIT(current_drive)), 0);
blind_seek = 1;
raw_cmd->flags |= FD_RAW_NEED_SEEK;
}
track = 1;
}
} else {
check_wp(current_fdc, current_drive); if (raw_cmd->track != drive_state[current_drive].track &&
(raw_cmd->flags & FD_RAW_NEED_SEEK))
track = raw_cmd->track; else {
setup_rw_floppy(); return;
}
}
staticvoid recal_interrupt(void)
{
debugt(__func__, ""); if (inr != 2)
fdc_state[current_fdc].reset = 1; elseif (reply_buffer[ST0] & ST0_ECE) { switch (drive_state[current_drive].track) { case NEED_1_RECAL:
debugt(__func__, "need 1 recal"); /* after a second recalibrate, we still haven't * reached track 0. Probably no drive. Raise an * error, as failing immediately might upset
* computers possessed by the Devil :-) */
cont->error();
cont->redo(); return; case NEED_2_RECAL:
debugt(__func__, "need 2 recal"); /* If we already did a recalibrate, * and we are not at track 0, this * means we have moved. (The only way * not to move at recalibration is to * be already at track 0.) Clear the
* new change flag */
debug_dcl(drive_params[current_drive].flags, "clearing NEWCHANGE flag because of second recalibrate\n");
clear_bit(FD_DISK_NEWCHANGE_BIT,
&drive_state[current_drive].flags);
drive_state[current_drive].select_date = jiffies;
fallthrough; default:
debugt(__func__, "default"); /* Recalibrate moves the head by at * most 80 steps. If after one * recalibrate we don't have reached * track 0, this might mean that we * started beyond track 80. Try
* again. */
drive_state[current_drive].track = NEED_1_RECAL; break;
}
} else
drive_state[current_drive].track = reply_buffer[ST1];
floppy_ready();
}
staticvoid print_result(char *message, int inr)
{ int i;
DPRINT("%s ", message); if (inr >= 0) for (i = 0; i < inr; i++)
pr_cont("repl[%d]=%x ", i, reply_buffer[i]);
pr_cont("\n");
}
/* interrupt handler. Note that this can be called externally on the Sparc */
irqreturn_t floppy_interrupt(int irq, void *dev_id)
{ int do_print; unsignedlong f; void (*handler)(void) = do_floppy;
f = claim_dma_lock();
fd_disable_dma();
release_dma_lock(f);
do_floppy = NULL; if (current_fdc >= N_FDC || fdc_state[current_fdc].address == -1) { /* we don't even know which FDC is the culprit */
pr_info("DOR0=%x\n", fdc_state[0].dor);
pr_info("floppy interrupt on bizarre fdc %d\n", current_fdc);
pr_info("handler=%ps\n", handler);
is_alive(__func__, "bizarre fdc"); return IRQ_NONE;
}
fdc_state[current_fdc].reset = 0; /* We have to clear the reset flag here, because apparently on boxes * with level triggered interrupts (PS/2, Sparc, ...), it is needed to * emit SENSEI's to clear the interrupt line. And fdc_state[fdc].reset * blocks the emission of the SENSEI's. * It is OK to emit floppy commands because we are in an interrupt * handler here, and thus we have to fear no interference of other * activity.
*/
do_print = !handler && print_unex && initialized;
inr = result(current_fdc); if (do_print)
print_result("unexpected interrupt", inr); if (inr == 0) { int max_sensei = 4; do {
output_byte(current_fdc, FD_SENSEI);
inr = result(current_fdc); if (do_print)
print_result("sensei", inr);
max_sensei--;
} while ((reply_buffer[ST0] & 0x83) != UNIT(current_drive) &&
inr == 2 && max_sensei);
} if (!handler) {
fdc_state[current_fdc].reset = 1; return IRQ_NONE;
}
schedule_bh(handler);
is_alive(__func__, "normal interrupt end");
/* FIXME! Was it really for us? */ return IRQ_HANDLED;
}
/* * Must do 4 FD_SENSEIs after reset because of ``drive polling''.
*/ staticvoid reset_interrupt(void)
{
debugt(__func__, "");
result(current_fdc); /* get the status ready for set_fdc */ if (fdc_state[current_fdc].reset) {
pr_info("reset set in interrupt, calling %ps\n", cont->error);
cont->error(); /* a reset just after a reset. BAD! */
}
cont->redo();
}
/* * reset is done by pulling bit 2 of DOR low for a while (old FDCs), * or by setting the self clearing bit 7 of STATUS (newer FDCs). * This WILL trigger an interrupt, causing the handlers in the current * cont's ->redo() to be called via reset_interrupt().
*/ staticvoid reset_fdc(void)
{ unsignedlong flags;
/* avoid dma going to a random drive after shutdown */
if (initialized)
DPRINT("floppy timeout called\n");
fdc_state[current_fdc].reset = 1; if (cont) {
cont->done(0);
cont->redo(); /* this will recall reset when needed */
} else {
pr_info("no cont in shutdown!\n");
process_fd_request();
}
is_alive(__func__, "");
}
/* start motor, check media-changed condition and write protection */ staticint start_motor(void (*function)(void))
{ int mask; int data;
mask = 0xfc;
data = UNIT(current_drive); if (!(raw_cmd->flags & FD_RAW_NO_MOTOR)) { if (!(fdc_state[current_fdc].dor & (0x10 << UNIT(current_drive)))) {
set_debugt(); /* no read since this drive is running */
drive_state[current_drive].first_read_date = 0; /* note motor start time if motor is not yet running */
drive_state[current_drive].spinup_date = jiffies;
data |= (0x10 << UNIT(current_drive));
}
} elseif (fdc_state[current_fdc].dor & (0x10 << UNIT(current_drive)))
mask &= ~(0x10 << UNIT(current_drive));
/* starts motor and selects floppy */
timer_delete(motor_off_timer + current_drive);
set_dor(current_fdc, mask, data);
/* wait_for_completion also schedules reset if needed. */ return fd_wait_for_completion(drive_state[current_drive].select_date + drive_params[current_drive].select_delay,
function);
}
staticvoid floppy_ready(void)
{ if (fdc_state[current_fdc].reset) {
reset_fdc(); return;
} if (start_motor(floppy_ready)) return; if (fdc_dtr()) return;
debug_dcl(drive_params[current_drive].flags, "calling disk change from floppy_ready\n"); if (!(raw_cmd->flags & FD_RAW_NO_MOTOR) &&
disk_change(current_drive) && !drive_params[current_drive].select_delay)
twaddle(current_fdc, current_drive); /* this clears the dcl on certain
* drive/controller combinations */
/* schedules handler, waiting for completion. May be interrupted, will then * return -EINTR, in which case the driver will automatically be unlocked.
*/ staticint wait_til_done(void (*handler)(void), bool interruptible)
{ int ret;
/* current_count_sectors can be zero if transfer failed */ if (error)
nr_sectors = blk_rq_cur_sectors(req); if (blk_update_request(req, error, nr_sectors << 9)) return;
__blk_mq_end_request(req, error);
/* We're done with the request */
floppy_off(drive);
current_req = NULL;
}
/* new request_done. Can handle physical sectors which are smaller than a
* logical buffer */ staticvoid request_done(int uptodate)
{ struct request *req = current_req; int block; char msg[sizeof("request done ") + sizeof(int) * 3];
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.