Indeed, it should be checked. There was a disk_change call
missing. The patch at the end of this mail should fix this (along with
several unrelated problems)
>
>If you change the above situation to one that uses reads, things are
>done in a sane fashion via DCL, and the driver moans loudly with a:
>
> floppy0: disk absent or changed during operation
Disk_change is tested at several places, that's why in most common
cases it works.
>
>and then returns an IO error, which seems sensible enough.
>My other minor query is why doesn't the floppy driver support:
>
> fd = open("/dev/fd0", O_RDONLY);
> ioctl(fd, BLKFLSBUF, NULL);
>
>The other common block devices (such as SCSI disk, IDE disk and even RAM
>disk) support BLKFLSBUF via invalidate_buffers().
Indeed. No technical reason. I simply didn't know about these
"generic" bloc device ioctls. The following patch adds these.
(In case the patch gets garbled on its way through the mailing list, you may find
it also on ftp.imag.fr:pub/Linux/ZLIBC/floppy/BETA/fdp-pre2.0.14-0806.diff.gz)
Alain
diff -ur pre2.0.14/linux/drivers/block/floppy.c linux/drivers/block/floppy.c
--- pre2.0.14/linux/drivers/block/floppy.c Mon Jun 3 09:27:17 1996
+++ linux/drivers/block/floppy.c Sun Jun 9 15:48:24 1996
@@ -130,6 +130,7 @@
#include <linux/fd.h>
+#include <linux/hdreg.h>
#define OLDFDRAWCMD 0x020d /* send a raw command to the FDC */
@@ -1039,6 +1040,7 @@
INT_OFF;
fd_disable_dma();
fd_clear_dma_ff();
+ fd_cacheflush(raw_cmd->kernel_data, raw_cmd->length);
fd_set_dma_mode((raw_cmd->flags & FD_RAW_READ)?
DMA_MODE_READ : DMA_MODE_WRITE);
fd_set_dma_addr(virt_to_bus(raw_cmd->kernel_data));
@@ -2385,13 +2387,10 @@
if (((unsigned long)buffer) % 512)
DPRINT("%p buffer not aligned\n", buffer);
#endif
- if (CT(COMMAND) == FD_READ) {
- fd_cacheflush(dma_buffer, size);
+ if (CT(COMMAND) == FD_READ)
memcpy(buffer, dma_buffer, size);
- } else {
+ else
memcpy(dma_buffer, buffer, size);
- fd_cacheflush(dma_buffer, size);
- }
remaining -= size;
if (!remaining)
break;
@@ -2708,6 +2707,7 @@
raw_cmd = & default_raw_cmd;
raw_cmd->flags = 0;
if (start_motor(redo_fd_request)) return;
+ disk_change(current_drive);
if (test_bit(current_drive, &fake_change) ||
TESTF(FD_DISK_CHANGED)){
DPRINT("disk absent or changed during operation\n");
@@ -2839,9 +2839,6 @@
int ret;
ECALL(verify_area(VERIFY_WRITE,param,size));
- fd_cacheflush(address, size); /* is this necessary ??? */
- /* Ralf: Yes; only the l2 cache is completely chipset
- controlled */
memcpy_tofs(param,(void *) address, size);
return 0;
}
@@ -2855,6 +2852,14 @@
return 0;
}
+static int write_fs_long(unsigned long useraddr, long value)
+{
+ int ret;
+ ECALL(verify_area(VERIFY_WRITE, (long *)useraddr, sizeof(long)));
+ put_user((unsigned)value, (long *) useraddr);
+ return 0;
+}
+
#define COPYOUT(x) ECALL(fd_copyout((void *)param, &(x), sizeof(x)))
#define COPYIN(x) ECALL(fd_copyin((void *)param, &(x), sizeof(x)))
@@ -2883,7 +2888,7 @@
int i;
if (!flag) {
- raw_cmd->flags = FD_RAW_FAILURE;
+ raw_cmd->flags |= FD_RAW_FAILURE;
raw_cmd->flags |= FD_RAW_HARDFAILURE;
} else {
raw_cmd->reply_count = inr;
@@ -3257,6 +3262,21 @@
return -EINVAL;
}
+static int get_floppy_geometry(int drive, int type, struct floppy_struct **g)
+{
+ if (type)
+ *g = &floppy_type[type];
+ else {
+ LOCK_FDC(drive,1);
+ CALL(poll_drive(1,0));
+ process_fd_request();
+ *g = current_type[drive];
+ }
+ if(!*g)
+ return -ENODEV;
+ return 0;
+}
+
static int fd_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
unsigned long param)
{
@@ -3295,6 +3315,42 @@
cmd = FDEJECT;
}
+ /* generic block device ioctls */
+ switch(cmd) {
+ /* the following have been inspired by the corresponding
+ * code for other block devices. */
+ struct floppy_struct *g;
+ struct hd_geometry *loc;
+
+ case HDIO_GETGEO:
+ loc = (struct hd_geometry *) param;
+ ECALL(get_floppy_geometry(drive, type, &g));
+ ECALL(verify_area(VERIFY_WRITE, loc, sizeof(*loc)));
+ put_user(g->head, &loc->heads);
+ put_user(g->sect, &loc->sectors);
+ put_user(g->track, &loc->cylinders);
+ put_user(0,&loc->start);
+ return 0;
+ case BLKRASET:
+ if(!suser()) return -EACCES;
+ if(param > 0xff) return -EINVAL;
+ read_ahead[MAJOR(inode->i_rdev)] = param;
+ return 0;
+ case BLKRAGET:
+ return write_fs_long(param,
+ read_ahead[MAJOR(inode->i_rdev)]);
+ case BLKFLSBUF:
+ if(!suser()) return -EACCES;
+ fsync_dev(inode->i_rdev);
+ cmd = FDFLUSH; /* flush it */
+ break;
+ case BLKGETSIZE:
+ ECALL(get_floppy_geometry(drive, type, &g));
+ return write_fs_long(param, g->size);
+ /* BLKRRPART is not defined as floppies don't have
+ * partition tables */
+ }
+
/* convert the old style command into a new style command */
if ((cmd & 0xff00) == 0x0200) {
ECALL(normalize_0x02xx_ioctl(&cmd, &size));
@@ -3343,17 +3399,10 @@
return set_geometry(cmd, & inparam.g,
drive, type, device);
case FDGETPRM:
- LOCK_FDC(drive,1);
- CALL(poll_drive(1,0));
- process_fd_request();
- if (type)
- outparam = (char *) &floppy_type[type];
- else
- outparam = (char *) current_type[drive];
- if(!outparam)
- return -ENODEV;
+ ECALL(get_floppy_geometry(drive, type,
+ (struct floppy_struct**)
+ &outparam));
break;
-
case FDMSGON:
UDP->flags |= FTD_MSG;
return 0;