static void start_request(struct floppy_state *fs) { struct request *req; unsigned long x; if (fs->state == idle && fs->wanted) { fs->state = available; wake_up(&fs->wait); return; } while (fs->state == idle) { if (!fd_req) { fd_req = blk_fetch_request(swim3_queue); if (!fd_req) break; } req = fd_req; #if 0 printk("do_fd_req: dev=%s cmd=%d sec=%ld nr_sec=%u buf=%p\n", req->rq_disk->disk_name, req->cmd, (long)blk_rq_pos(req), blk_rq_sectors(req), req->buffer); printk(" errors=%d current_nr_sectors=%u\n", req->errors, blk_rq_cur_sectors(req)); #endif if (blk_rq_pos(req) >= fs->total_secs) { swim3_end_request_cur(-EIO); continue; } if (fs->ejected) { swim3_end_request_cur(-EIO); continue; } if (rq_data_dir(req) == WRITE) { if (fs->write_prot < 0) fs->write_prot = swim3_readbit(fs, WRITE_PROT); if (fs->write_prot) { swim3_end_request_cur(-EIO); continue; } } /* Do not remove the cast. blk_rq_pos(req) is now a * sector_t and can be 64 bits, but it will never go * past 32 bits for this driver anyway, so we can * safely cast it down and not have to do a 64/32 * division */ fs->req_cyl = ((long)blk_rq_pos(req)) / fs->secpercyl; x = ((long)blk_rq_pos(req)) % fs->secpercyl; fs->head = x / fs->secpertrack; fs->req_sector = x % fs->secpertrack + 1; fd_req = req; fs->state = do_transfer; fs->retries = 0; act(fs); } }
static void settle_timeout(struct timer_list *t) { struct floppy_state *fs = from_timer(fs, t, timeout); struct swim3 __iomem *sw = fs->swim3; unsigned long flags; swim3_dbg("* settle timeout, state=%d\n", fs->state); spin_lock_irqsave(&swim3_lock, flags); fs->timeout_pending = 0; if (swim3_readbit(fs, SEEK_COMPLETE)) { out_8(&sw->select, RELAX); fs->state = locating; act(fs); goto unlock; } out_8(&sw->select, RELAX); if (fs->settle_time < 2*HZ) { ++fs->settle_time; set_timeout(fs, 1, settle_timeout); goto unlock; } swim3_err("%s", "Seek settle timeout\n"); swim3_end_request(fs, BLK_STS_IOERR, 0); fs->state = idle; start_request(fs); unlock: spin_unlock_irqrestore(&swim3_lock, flags); }
static void start_request(struct floppy_state *fs) { struct request *req; unsigned long x; if (fs->state == idle && fs->wanted) { fs->state = available; wake_up(&fs->wait); return; } while (fs->state == idle && (req = elv_next_request(swim3_queue))) { #if 0 printk("do_fd_req: dev=%s cmd=%d sec=%ld nr_sec=%ld buf=%p\n", req->rq_disk->disk_name, req->cmd, (long)req->sector, req->nr_sectors, req->buffer); printk(" rq_status=%d errors=%d current_nr_sectors=%ld\n", req->rq_status, req->errors, req->current_nr_sectors); #endif if (req->sector < 0 || req->sector >= fs->total_secs) { end_request(req, 0); continue; } if (req->current_nr_sectors == 0) { end_request(req, 1); continue; } if (fs->ejected) { end_request(req, 0); continue; } if (rq_data_dir(req) == WRITE) { if (fs->write_prot < 0) fs->write_prot = swim3_readbit(fs, WRITE_PROT); if (fs->write_prot) { end_request(req, 0); continue; } } /* Do not remove the cast. req->sector is now a sector_t and * can be 64 bits, but it will never go past 32 bits for this * driver anyway, so we can safely cast it down and not have * to do a 64/32 division */ fs->req_cyl = ((long)req->sector) / fs->secpercyl; x = ((long)req->sector) % fs->secpercyl; fs->head = x / fs->secpertrack; fs->req_sector = x % fs->secpertrack + 1; fd_req = req; fs->state = do_transfer; fs->retries = 0; act(fs); } }
static void start_request(struct floppy_state *fs) { struct request *req; unsigned long x; if (fs->state == idle && fs->wanted) { fs->state = available; wake_up(&fs->wait); return; } while (fs->state == idle && (req = elv_next_request(swim3_queue))) { #if 0 printk("do_fd_req: dev=%s cmd=%d sec=%ld nr_sec=%ld buf=%p\n", req->rq_disk->disk_name, req->cmd, req->sector, req->nr_sectors, req->buffer); printk(" rq_status=%d errors=%d current_nr_sectors=%ld\n", req->rq_status, req->errors, req->current_nr_sectors); #endif if (req->sector < 0 || req->sector >= fs->total_secs) { end_request(req, 0); continue; } if (req->current_nr_sectors == 0) { end_request(req, 1); continue; } if (fs->ejected) { end_request(req, 0); continue; } if (rq_data_dir(req) == WRITE) { if (fs->write_prot < 0) fs->write_prot = swim3_readbit(fs, WRITE_PROT); if (fs->write_prot) { end_request(req, 0); continue; } } fs->req_cyl = req->sector / fs->secpercyl; x = req->sector % fs->secpercyl; fs->head = x / fs->secpertrack; fs->req_sector = x % fs->secpertrack + 1; fd_req = req; fs->state = do_transfer; fs->retries = 0; act(fs); } }
static int floppy_revalidate(struct gendisk *disk) { struct floppy_state *fs = disk->private_data; struct swim3 __iomem *sw; int ret, n; if (fs->mdev->media_bay && check_media_bay(fs->mdev->media_bay) != MB_FD) return -ENXIO; sw = fs->swim3; grab_drive(fs, revalidating, 0); out_8(&sw->intr_enable, 0); out_8(&sw->control_bis, DRIVE_ENABLE); swim3_action(fs, MOTOR_ON); /* necessary? */ fs->write_prot = -1; fs->cur_cyl = -1; mdelay(1); for (n = HZ; n > 0; --n) { if (swim3_readbit(fs, SEEK_COMPLETE)) break; if (signal_pending(current)) break; swim3_select(fs, RELAX); schedule_timeout_interruptible(1); } ret = swim3_readbit(fs, SEEK_COMPLETE) == 0 || swim3_readbit(fs, DISK_IN) == 0; if (ret) swim3_action(fs, MOTOR_OFF); else { fs->ejected = 0; swim3_action(fs, SETMFM); } swim3_select(fs, RELAX); release_drive(fs); return ret; }
static void settle_timeout(unsigned long data) { struct floppy_state *fs = (struct floppy_state *) data; struct swim3 __iomem *sw = fs->swim3; fs->timeout_pending = 0; if (swim3_readbit(fs, SEEK_COMPLETE)) { out_8(&sw->select, RELAX); fs->state = locating; act(fs); return; } out_8(&sw->select, RELAX); if (fs->settle_time < 2*HZ) { ++fs->settle_time; set_timeout(fs, 1, settle_timeout); return; } printk(KERN_ERR "swim3: seek settle timeout\n"); swim3_end_request_cur(-EIO); fs->state = idle; start_request(fs); }
static int fd_eject(struct floppy_state *fs) { int err, n; err = grab_drive(fs, ejecting, 1); if (err) return err; swim3_action(fs, EJECT); for (n = 20; n > 0; --n) { if (signal_pending(current)) { err = -EINTR; break; } swim3_select(fs, RELAX); schedule_timeout_interruptible(1); if (swim3_readbit(fs, DISK_IN) == 0) break; } swim3_select(fs, RELAX); udelay(150); fs->ejected = 1; release_drive(fs); return err; }
static void seek_timeout(unsigned long data) { struct floppy_state *fs = (struct floppy_state *) data; volatile struct swim3 *sw = fs->swim3; fs->timeout_pending = 0; if (fs->state == settling) { printk(KERN_ERR "swim3: MSI sel=%x ctrl=%x stat=%x intr=%x ie=%x\n", sw->select, sw->control, sw->status, sw->intr, sw->intr_enable); } out_8(&sw->control_bic, DO_SEEK); out_8(&sw->select, RELAX); out_8(&sw->intr_enable, 0); if (fs->state == settling && swim3_readbit(fs, SEEK_COMPLETE)) { /* printk(KERN_DEBUG "swim3: missed settling interrupt\n"); */ fs->state = locating; act(fs); return; } printk(KERN_ERR "swim3: seek timeout\n"); end_request(fd_req, 0); fs->state = idle; start_request(fs); }
static int floppy_open(struct block_device *bdev, fmode_t mode) { struct floppy_state *fs = bdev->bd_disk->private_data; struct swim3 __iomem *sw = fs->swim3; int n, err = 0; if (fs->ref_count == 0) { if (fs->mdev->media_bay && check_media_bay(fs->mdev->media_bay) != MB_FD) return -ENXIO; out_8(&sw->setup, S_IBM_DRIVE | S_FCLK_DIV2); out_8(&sw->control_bic, 0xff); out_8(&sw->mode, 0x95); udelay(10); out_8(&sw->intr_enable, 0); out_8(&sw->control_bis, DRIVE_ENABLE | INTR_ENABLE); swim3_action(fs, MOTOR_ON); fs->write_prot = -1; fs->cur_cyl = -1; for (n = 0; n < 2 * HZ; ++n) { if (n >= HZ/30 && swim3_readbit(fs, SEEK_COMPLETE)) break; if (signal_pending(current)) { err = -EINTR; break; } swim3_select(fs, RELAX); schedule_timeout_interruptible(1); } if (err == 0 && (swim3_readbit(fs, SEEK_COMPLETE) == 0 || swim3_readbit(fs, DISK_IN) == 0)) err = -ENXIO; swim3_action(fs, SETMFM); swim3_select(fs, RELAX); } else if (fs->ref_count == -1 || mode & FMODE_EXCL) return -EBUSY; if (err == 0 && (mode & FMODE_NDELAY) == 0 && (mode & (FMODE_READ|FMODE_WRITE))) { check_disk_change(bdev); if (fs->ejected) err = -ENXIO; } if (err == 0 && (mode & FMODE_WRITE)) { if (fs->write_prot < 0) fs->write_prot = swim3_readbit(fs, WRITE_PROT); if (fs->write_prot) err = -EROFS; } if (err) { if (fs->ref_count == 0) { swim3_action(fs, MOTOR_OFF); out_8(&sw->control_bic, DRIVE_ENABLE | INTR_ENABLE); swim3_select(fs, RELAX); } return err; } if (mode & FMODE_EXCL) fs->ref_count = -1; else ++fs->ref_count; return 0; }
static void act(struct floppy_state *fs) { for (;;) { switch (fs->state) { case idle: return; /* XXX shouldn't get here */ case locating: if (swim3_readbit(fs, TRACK_ZERO)) { fs->cur_cyl = 0; if (fs->req_cyl == 0) fs->state = do_transfer; else fs->state = seeking; break; } scan_track(fs); return; case seeking: if (fs->cur_cyl < 0) { fs->expect_cyl = -1; fs->state = locating; break; } if (fs->req_cyl == fs->cur_cyl) { printk("whoops, seeking 0\n"); fs->state = do_transfer; break; } seek_track(fs, fs->req_cyl - fs->cur_cyl); return; case settling: /* check for SEEK_COMPLETE after 30ms */ fs->settle_time = (HZ + 32) / 33; set_timeout(fs, fs->settle_time, settle_timeout); return; case do_transfer: if (fs->cur_cyl != fs->req_cyl) { if (fs->retries > 5) { swim3_end_request_cur(-EIO); fs->state = idle; return; } fs->state = seeking; break; } setup_transfer(fs); return; case jogging: seek_track(fs, -5); return; default: printk(KERN_ERR"swim3: unknown state %d\n", fs->state); return; } } }
static void act(struct floppy_state *fs) { volatile struct swim3 *sw = fs->swim3; for (;;) { switch (fs->state) { case idle: return; /* XXX shouldn't get here */ case locating: if (swim3_readbit(fs, TRACK_ZERO)) { fs->cur_cyl = 0; if (fs->req_cyl == 0) fs->state = do_transfer; else fs->state = seeking; break; } scan_track(fs); return; case seeking: if (fs->cur_cyl < 0) { fs->expect_cyl = -1; fs->state = locating; break; } if (fs->req_cyl == fs->cur_cyl) { printk("whoops, seeking 0\n"); fs->state = do_transfer; break; } seek_track(fs, fs->req_cyl - fs->cur_cyl); return; case settling: /* wait for SEEK_COMPLETE to become true */ swim3_select(fs, SEEK_COMPLETE); udelay(10); out_8(&sw->intr_enable, ERROR_INTR | DATA_CHANGED); in_8(&sw->intr); /* clear DATA_CHANGED */ if (in_8(&sw->status) & DATA) { /* seek_complete is not yet true */ set_timeout(fs, HZ/2, seek_timeout); return; } out_8(&sw->intr_enable, 0); in_8(&sw->intr); fs->state = locating; break; case do_transfer: if (fs->cur_cyl != fs->req_cyl) { if (fs->retries > 5) { end_request(fd_req, 0); fs->state = idle; return; } fs->state = seeking; break; } setup_transfer(fs); return; case jogging: seek_track(fs, -5); return; default: printk(KERN_ERR"swim3: unknown state %d\n", fs->state); return; } } }
static void act(struct floppy_state *fs) { for (;;) { swim3_dbg(" act loop, state=%d, req_cyl=%d, cur_cyl=%d\n", fs->state, fs->req_cyl, fs->cur_cyl); switch (fs->state) { case idle: return; /* XXX shouldn't get here */ case locating: if (swim3_readbit(fs, TRACK_ZERO)) { swim3_dbg("%s", " locate track 0\n"); fs->cur_cyl = 0; if (fs->req_cyl == 0) fs->state = do_transfer; else fs->state = seeking; break; } scan_track(fs); return; case seeking: if (fs->cur_cyl < 0) { fs->expect_cyl = -1; fs->state = locating; break; } if (fs->req_cyl == fs->cur_cyl) { swim3_warn("%s", "Whoops, seeking 0\n"); fs->state = do_transfer; break; } seek_track(fs, fs->req_cyl - fs->cur_cyl); return; case settling: /* check for SEEK_COMPLETE after 30ms */ fs->settle_time = (HZ + 32) / 33; set_timeout(fs, fs->settle_time, settle_timeout); return; case do_transfer: if (fs->cur_cyl != fs->req_cyl) { if (fs->retries > 5) { swim3_err("Wrong cylinder in transfer, want: %d got %d\n", fs->req_cyl, fs->cur_cyl); swim3_end_request(fs, BLK_STS_IOERR, 0); fs->state = idle; return; } fs->state = seeking; break; } setup_transfer(fs); return; case jogging: seek_track(fs, -5); return; default: swim3_err("Unknown state %d\n", fs->state); return; } } }
static void start_request(struct floppy_state *fs) { struct request *req; unsigned long x; swim3_dbg("start request, initial state=%d\n", fs->state); if (fs->state == idle && fs->wanted) { fs->state = available; wake_up(&fs->wait); return; } while (fs->state == idle) { swim3_dbg("start request, idle loop, cur_req=%p\n", fs->cur_req); if (!fs->cur_req) { fs->cur_req = blk_fetch_request(disks[fs->index]->queue); swim3_dbg(" fetched request %p\n", fs->cur_req); if (!fs->cur_req) break; } req = fs->cur_req; if (fs->mdev->media_bay && check_media_bay(fs->mdev->media_bay) != MB_FD) { swim3_dbg("%s", " media bay absent, dropping req\n"); swim3_end_request(fs, BLK_STS_IOERR, 0); continue; } #if 0 /* This is really too verbose */ swim3_dbg("do_fd_req: dev=%s cmd=%d sec=%ld nr_sec=%u buf=%p\n", req->rq_disk->disk_name, req->cmd, (long)blk_rq_pos(req), blk_rq_sectors(req), bio_data(req->bio)); swim3_dbg(" current_nr_sectors=%u\n", blk_rq_cur_sectors(req)); #endif if (blk_rq_pos(req) >= fs->total_secs) { swim3_dbg(" pos out of bounds (%ld, max is %ld)\n", (long)blk_rq_pos(req), (long)fs->total_secs); swim3_end_request(fs, BLK_STS_IOERR, 0); continue; } if (fs->ejected) { swim3_dbg("%s", " disk ejected\n"); swim3_end_request(fs, BLK_STS_IOERR, 0); continue; } if (rq_data_dir(req) == WRITE) { if (fs->write_prot < 0) fs->write_prot = swim3_readbit(fs, WRITE_PROT); if (fs->write_prot) { swim3_dbg("%s", " try to write, disk write protected\n"); swim3_end_request(fs, BLK_STS_IOERR, 0); continue; } } /* Do not remove the cast. blk_rq_pos(req) is now a * sector_t and can be 64 bits, but it will never go * past 32 bits for this driver anyway, so we can * safely cast it down and not have to do a 64/32 * division */ fs->req_cyl = ((long)blk_rq_pos(req)) / fs->secpercyl; x = ((long)blk_rq_pos(req)) % fs->secpercyl; fs->head = x / fs->secpertrack; fs->req_sector = x % fs->secpertrack + 1; fs->state = do_transfer; fs->retries = 0; act(fs); } }