예제 #1
0
파일: swim3.c 프로젝트: ANFS/ANFS-kernel
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);
	}
}
예제 #2
0
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);
}
예제 #3
0
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);
	}
}
예제 #4
0
파일: swim3.c 프로젝트: sarnobat/knoppix
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);
	}
}
예제 #5
0
파일: swim3.c 프로젝트: ANFS/ANFS-kernel
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;
}
예제 #6
0
파일: swim3.c 프로젝트: ANFS/ANFS-kernel
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);
}
예제 #7
0
파일: swim3.c 프로젝트: ANFS/ANFS-kernel
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;
}
예제 #8
0
파일: swim3.c 프로젝트: sarnobat/knoppix
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);
}
예제 #9
0
파일: swim3.c 프로젝트: ANFS/ANFS-kernel
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;
}
예제 #10
0
파일: swim3.c 프로젝트: ANFS/ANFS-kernel
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;
		}
	}
}
예제 #11
0
파일: swim3.c 프로젝트: sarnobat/knoppix
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;
		}
	}
}
예제 #12
0
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;
		}
	}
}
예제 #13
0
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);
	}
}