1132103Snyan/*- 216359Sasami * Copyright (c) 1990 The Regents of the University of California. 316359Sasami * All rights reserved. 416359Sasami * 516359Sasami * This code is derived from software contributed to Berkeley by 616359Sasami * Don Ahn. 716359Sasami * 841779Skato * Libretto PCMCIA floppy support by David Horwitt (dhorwitt@ucsd.edu) 941779Skato * aided by the Linux floppy driver modifications from David Bateman 1041779Skato * (dbateman@eng.uts.edu.au). 1141779Skato * 1216359Sasami * Copyright (c) 1993, 1994 by 1316359Sasami * jc@irbs.UUCP (John Capo) 1416359Sasami * vak@zebub.msk.su (Serge Vakulenko) 1516359Sasami * ache@astral.msk.su (Andrew A. Chernov) 1616359Sasami * 1716359Sasami * Copyright (c) 1993, 1994, 1995 by 1816359Sasami * joerg_wunsch@uriah.sax.de (Joerg Wunsch) 1916359Sasami * dufault@hda.com (Peter Dufault) 2016359Sasami * 2176615Skato * Copyright (c) 2001 Joerg Wunsch, 2278809Snyan * joerg_wunsch@uriah.heep.sax.de (Joerg Wunsch) 2376615Skato * 2416359Sasami * Redistribution and use in source and binary forms, with or without 2516359Sasami * modification, are permitted provided that the following conditions 2616359Sasami * are met: 2716359Sasami * 1. Redistributions of source code must retain the above copyright 2816359Sasami * notice, this list of conditions and the following disclaimer. 2916359Sasami * 2. Redistributions in binary form must reproduce the above copyright 3016359Sasami * notice, this list of conditions and the following disclaimer in the 3116359Sasami * documentation and/or other materials provided with the distribution. 3283548Snyan * 3. All advertising materials mentioning features or use of this software 3383548Snyan * must display the following acknowledgement: 3483548Snyan * This product includes software developed by the University of 3583548Snyan * California, Berkeley and its contributors. 3683548Snyan * 4. Neither the name of the University nor the names of its contributors 3783548Snyan * may be used to endorse or promote products derived from this software 3883548Snyan * without specific prior written permission. 3916359Sasami * 4016359Sasami * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 4116359Sasami * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 4216359Sasami * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 4316359Sasami * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 4416359Sasami * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 4516359Sasami * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 4616359Sasami * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 4716359Sasami * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 4816359Sasami * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 4916359Sasami * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 5016359Sasami * SUCH DAMAGE. 5116359Sasami * 5216359Sasami * from: @(#)fd.c 7.4 (Berkeley) 5/25/91 5350477Speter * $FreeBSD$ 5416359Sasami */ 5516359Sasami 5629533Skato#include "opt_fdc.h" 5716359Sasami 5816359Sasami#include <sys/param.h> 5960041Sphk#include <sys/bio.h> 6045783Skato#include <sys/bus.h> 6178809Snyan#include <sys/devicestat.h> 62103701Sphk#include <sys/disk.h> 6345783Skato#include <sys/fcntl.h> 6477800Sjoerg#include <sys/fdcio.h> 6588011Snyan#include <sys/filio.h> 6678809Snyan#include <sys/kernel.h> 6776211Skato#include <sys/lock.h> 6816359Sasami#include <sys/malloc.h> 6945783Skato#include <sys/module.h> 7076211Skato#include <sys/mutex.h> 71164033Srwatson#include <sys/priv.h> 7216359Sasami#include <sys/proc.h> 7345783Skato#include <sys/rman.h> 74131819Snyan#include <sys/systm.h> 7545783Skato 76132103Snyan#include <machine/bus.h> 7745783Skato#include <machine/stdarg.h> 7845783Skato 79131819Snyan#ifdef PC98 8045783Skato#include <isa/isavar.h> 81146049Snyan#include <pc98/cbus/fdcreg.h> 82146049Snyan#include <pc98/cbus/fdcvar.h> 8322407Skato#include <pc98/pc98/pc98_machdep.h> 8416359Sasami#else 85131819Snyan#include <isa/isavar.h> 8651613Snyan#include <isa/isareg.h> 87131819Snyan#include <dev/fdc/fdcreg.h> 88131819Snyan#include <dev/fdc/fdcvar.h> 8947669Skato#include <isa/rtc.h> 9016359Sasami#endif 9116359Sasami 92104515Sphk#define FDBIO_FORMAT BIO_CMD2 9396576Snyan 9488011Snyan/* configuration flags for fdc */ 9555652Snyan#define FDC_NO_FIFO (1 << 2) /* do not enable FIFO */ 9630625Skato 9783548Snyan/* 9883548Snyan * Stop retrying after this many DMA overruns. Since each retry takes 9983548Snyan * one revolution, with 300 rpm., 25 retries take approximately 5 10083548Snyan * seconds which the read attempt will block in case the DMA overrun 10183548Snyan * is persistent. 10283548Snyan */ 10383548Snyan#define FDC_DMAOV_MAX 25 10416359Sasami 10588011Snyan/* 10696576Snyan * Timeout value for the PIO loops to wait until the FDC main status 10796576Snyan * register matches our expectations (request for master, direction 10896576Snyan * bit). This is supposed to be a number of microseconds, although 10996576Snyan * timing might actually not be very accurate. 11096576Snyan * 11196576Snyan * Timeouts of 100 msec are believed to be required for some broken 11296576Snyan * (old) hardware. 11396576Snyan */ 11496576Snyan#define FDSTS_TIMEOUT 100000 11596576Snyan 11696576Snyan/* 11788011Snyan * Number of subdevices that can be used for different density types. 11888011Snyan */ 11916359Sasami#ifdef PC98 12088011Snyan#define NUMDENS 12 12116359Sasami#else 12288011Snyan#define NUMDENS 16 12316359Sasami#endif 12416359Sasami 125104515Sphk#define FDBIO_RDSECTID BIO_CMD1 12616359Sasami 12788011Snyan/* 12888011Snyan * List of native drive densities. Order must match enum fd_drivetype 12988011Snyan * in <sys/fdcio.h>. Upon attaching the drive, each of the 13088011Snyan * programmable subdevices is initialized with the native density 13188011Snyan * definition. 13288011Snyan */ 13351613Snyan#ifdef PC98 13488011Snyanstatic struct fd_type fd_native_types[] = 13588011Snyan{ 13688011Snyan{ 0 }, /* FDT_NONE */ 13788011Snyan{ 0 }, /* FDT_360K */ 138137458Snyan{ 15,2,0xFF,0x1B,80,2400,0,2,0x54,1,0,FL_MFM }, /* FDT_12M */ 13988011Snyan{ 0 }, /* FDT_720K */ 140137458Snyan{ 18,2,0xFF,0x1B,80,2880,2,2,0x54,1,0,FL_MFM }, /* FDT_144M */ 14188011Snyan{ 0 }, /* FDT_288M */ 14288011Snyan}; 14351613Snyan 14488011Snyanstatic struct fd_type fd_searchlist_12m[] = { 145127521Snyan{ 15,2,0xFF,0x1B,80,2400,0,2,0x54,1,0,FL_MFM }, /* 1.2M */ 146127521Snyan#if 0 147127521Snyan{ 10,2,0xFF,0x10,82,1640,1,2,0x30,1,0,FL_MFM }, /* 820K */ 148127521Snyan{ 10,2,0xFF,0x10,80,1600,1,2,0x30,1,0,FL_MFM }, /* 800K */ 149127521Snyan#endif 150127521Snyan{ 9,2,0xFF,0x20,80,1440,1,2,0x50,1,0,FL_MFM }, /* 720K */ 151127521Snyan{ 9,2,0xFF,0x20,40, 720,1,2,0x50,1,0,FL_MFM|FL_2STEP },/* 360K */ 152127521Snyan{ 8,2,0xFF,0x2A,80,1280,1,2,0x50,1,0,FL_MFM }, /* 640K */ 153127521Snyan{ 8,3,0xFF,0x35,77,1232,0,2,0x74,1,0,FL_MFM }, /* 1.23M 1024/sec */ 154127521Snyan#if 0 155127521Snyan{ 8,3,0xFF,0x35,80,1280,0,2,0x74,1,0,FL_MFM }, /* 1.28M 1024/sec */ 156127521Snyan#endif 15788011Snyan}; 15888011Snyanstatic struct fd_type fd_searchlist_144m[] = { 15951613Snyan#if 0 160127521Snyan{ 21,2,0xFF,0x04,82,3444,2,2,0x0C,2,0,FL_MFM }, /* 1.72M in 3mode */ 161127521Snyan{ 18,2,0xFF,0x1B,82,2952,2,2,0x54,1,0,FL_MFM }, /* 1.48M in 3mode */ 16251613Snyan#endif 163127521Snyan{ 18,2,0xFF,0x1B,80,2880,2,2,0x54,1,0,FL_MFM }, /* 1.44M in 3mode */ 164127521Snyan{ 15,2,0xFF,0x1B,80,2400,0,2,0x54,1,0,FL_MFM }, /* 1.2M */ 165127521Snyan#if 0 166127521Snyan{ 10,2,0xFF,0x10,82,1640,1,2,0x30,1,0,FL_MFM }, /* 820K */ 167127521Snyan{ 10,2,0xFF,0x10,80,1600,1,2,0x30,1,0,FL_MFM }, /* 800K */ 168127521Snyan#endif 169127521Snyan{ 9,2,0xFF,0x20,80,1440,1,2,0x50,1,0,FL_MFM }, /* 720K */ 170127521Snyan{ 9,2,0xFF,0x20,40, 720,1,2,0x50,1,0,FL_MFM|FL_2STEP },/* 360K */ 171127521Snyan{ 8,2,0xFF,0x2A,80,1280,1,2,0x50,1,0,FL_MFM }, /* 640K */ 172127521Snyan{ 8,3,0xFF,0x35,77,1232,0,2,0x74,1,0,FL_MFM }, /* 1.23M 1024/sec */ 173127521Snyan#if 0 174127521Snyan{ 8,3,0xFF,0x35,80,1280,0,2,0x74,1,0,FL_MFM }, /* 1.28M 1024/sec */ 175127521Snyan{ 9,3,0xFF,0x35,82,1476,0,2,0x47,1,0,FL_MFM }, /* 1.48M 1024/sec 9sec */ 176127521Snyan{ 10,3,0xFF,0x1B,82,1640,2,2,0x54,1,0,FL_MFM }, /* 1.64M in 3mode - Reserve */ 177127521Snyan#endif 17888011Snyan}; 17988011Snyan#else /* PC98 */ 18088011Snyanstatic struct fd_type fd_native_types[] = 18188011Snyan{ 18288011Snyan{ 0 }, /* FDT_NONE */ 18388011Snyan{ 9,2,0xFF,0x2A,40, 720,FDC_250KBPS,2,0x50,1,0,FL_MFM }, /* FDT_360K */ 18488011Snyan{ 15,2,0xFF,0x1B,80,2400,FDC_500KBPS,2,0x54,1,0,FL_MFM }, /* FDT_12M */ 18588011Snyan{ 9,2,0xFF,0x20,80,1440,FDC_250KBPS,2,0x50,1,0,FL_MFM }, /* FDT_720K */ 18688011Snyan{ 18,2,0xFF,0x1B,80,2880,FDC_500KBPS,2,0x6C,1,0,FL_MFM }, /* FDT_144M */ 18788011Snyan#if 0 /* we currently don't handle 2.88 MB */ 18888011Snyan{ 36,2,0xFF,0x1B,80,5760,FDC_1MBPS, 2,0x4C,1,1,FL_MFM|FL_PERPND } /*FDT_288M*/ 18916359Sasami#else 19088011Snyan{ 18,2,0xFF,0x1B,80,2880,FDC_500KBPS,2,0x6C,1,0,FL_MFM }, /* FDT_144M */ 19116359Sasami#endif 19216359Sasami}; 19316359Sasami 19488011Snyan/* 19588011Snyan * 360 KB 5.25" and 720 KB 3.5" drives don't have automatic density 19688011Snyan * selection, they just start out with their native density (or lose). 19788011Snyan * So 1.2 MB 5.25", 1.44 MB 3.5", and 2.88 MB 3.5" drives have their 19888011Snyan * respective lists of densities to search for. 19988011Snyan */ 20088011Snyanstatic struct fd_type fd_searchlist_12m[] = { 20188011Snyan{ 15,2,0xFF,0x1B,80,2400,FDC_500KBPS,2,0x54,1,0,FL_MFM }, /* 1.2M */ 20288011Snyan{ 9,2,0xFF,0x23,40, 720,FDC_300KBPS,2,0x50,1,0,FL_MFM|FL_2STEP }, /* 360K */ 20388011Snyan{ 9,2,0xFF,0x20,80,1440,FDC_300KBPS,2,0x50,1,0,FL_MFM }, /* 720K */ 20488011Snyan}; 20579704Snyan 20688011Snyanstatic struct fd_type fd_searchlist_144m[] = { 20788011Snyan{ 18,2,0xFF,0x1B,80,2880,FDC_500KBPS,2,0x6C,1,0,FL_MFM }, /* 1.44M */ 20888011Snyan{ 9,2,0xFF,0x20,80,1440,FDC_250KBPS,2,0x50,1,0,FL_MFM }, /* 720K */ 20988011Snyan}; 21088011Snyan 21188011Snyan/* We search for 1.44M first since this is the most common case. */ 21288011Snyanstatic struct fd_type fd_searchlist_288m[] = { 21388011Snyan{ 18,2,0xFF,0x1B,80,2880,FDC_500KBPS,2,0x6C,1,0,FL_MFM }, /* 1.44M */ 21488011Snyan#if 0 21588011Snyan{ 36,2,0xFF,0x1B,80,5760,FDC_1MBPS, 2,0x4C,1,1,FL_MFM|FL_PERPND } /* 2.88M */ 21616359Sasami#endif 21788011Snyan{ 9,2,0xFF,0x20,80,1440,FDC_250KBPS,2,0x50,1,0,FL_MFM }, /* 720K */ 21888011Snyan}; 21988011Snyan#endif /* PC98 */ 22016359Sasami 22178809Snyan#define MAX_SEC_SIZE (128 << 3) 22283548Snyan#define MAX_CYLINDER 85 /* some people really stress their drives 22383548Snyan * up to cyl 82 */ 22483548Snyan#define MAX_HEAD 1 22578809Snyan 226131819Snyandevclass_t fdc_devclass; 22716359Sasami 22883548Snyan/* 22983548Snyan * Per drive structure (softc). 23083548Snyan */ 23145783Skatostruct fd_data { 23216359Sasami struct fdc_data *fdc; /* pointer to controller structure */ 23316359Sasami int fdsu; /* this units number on this controller */ 23488011Snyan enum fd_drivetype type; /* drive type */ 23588011Snyan struct fd_type *ft; /* pointer to current type descriptor */ 23688011Snyan struct fd_type fts[NUMDENS]; /* type descriptors */ 23716359Sasami int flags; 23816359Sasami#define FD_OPEN 0x01 /* it's open */ 23988011Snyan#define FD_NONBLOCK 0x02 /* O_NONBLOCK set */ 24088011Snyan#define FD_ACTIVE 0x04 /* it's active */ 24188011Snyan#define FD_MOTOR 0x08 /* motor should be on */ 24288011Snyan#define FD_MOTOR_WAIT 0x10 /* motor coming up */ 24388011Snyan#define FD_UA 0x20 /* force unit attention */ 24416359Sasami int skip; 24516359Sasami int hddrv; 24616359Sasami#define FD_NO_TRACK -2 24716359Sasami int track; /* where we think the head is */ 24888011Snyan int options; /* user configurable options, see fdcio.h */ 24929715Skato struct callout_handle toffhandle; 25029715Skato struct callout_handle tohandle; 251112006Sphk struct devstat *device_stats; 252130585Sphk struct cdev *masterdev; 25345783Skato device_t dev; 25445783Skato fdu_t fdu; 25588011Snyan#ifdef PC98 25688011Snyan int pc98_trans; 25788011Snyan#endif 25845783Skato}; 25955652Snyan 26055652Snyanstruct fdc_ivars { 26155652Snyan int fdunit; 262132103Snyan int fdtype; 26355652Snyan}; 264132103Snyan 26545783Skatostatic devclass_t fd_devclass; 26616359Sasami 26788011Snyan/* configuration flags for fd */ 26888011Snyan#define FD_TYPEMASK 0x0f /* drive type, matches enum 26988011Snyan * fd_drivetype; on i386 machines, if 27088011Snyan * given as 0, use RTC type for fd0 27188011Snyan * and fd1 */ 27288011Snyan#define FD_DTYPE(flags) ((flags) & FD_TYPEMASK) 27388011Snyan#define FD_NO_CHLINE 0x10 /* drive does not support changeline 27488011Snyan * aka. unit attention */ 27588011Snyan#define FD_NO_PROBE 0x20 /* don't probe drive (seek test), just 27688011Snyan * assume it is there */ 27788011Snyan 27883548Snyan/* 27983548Snyan * Throughout this file the following conventions will be used: 28083548Snyan * 28183548Snyan * fd is a pointer to the fd_data struct for the drive in question 28283548Snyan * fdc is a pointer to the fdc_data struct for the controller 28383548Snyan * fdu is the floppy drive unit number 28483548Snyan * fdcu is the floppy controller unit number 28583548Snyan * fdsu is the floppy drive unit number on that controller. (sub-unit) 28683548Snyan */ 28716359Sasami 28883548Snyan/* 28983548Snyan * Function declarations, same (chaotic) order as they appear in the 29083548Snyan * file. Re-ordering is too late now, it would only obfuscate the 29183548Snyan * diffs against old and offspring versions (like the PC98 one). 29283548Snyan * 29383548Snyan * Anyone adding functions here, please keep this sequence the same 29483548Snyan * as below -- makes locating a particular function in the body much 29583548Snyan * easier. 29683548Snyan */ 29783548Snyanstatic u_int8_t fdsts_rd(fdc_p); 29883548Snyanstatic void fddata_wr(fdc_p, u_int8_t); 29983548Snyanstatic u_int8_t fddata_rd(fdc_p); 30083548Snyanstatic int fdc_err(struct fdc_data *, const char *); 30183548Snyanstatic int enable_fifo(fdc_p fdc); 30283548Snyanstatic int fd_sense_drive_status(fdc_p, int *); 30383548Snyanstatic int fd_sense_int(fdc_p, int *, int *); 30483548Snyanstatic int fd_read_status(fdc_p); 30583548Snyanstatic int fd_probe(device_t); 30683548Snyanstatic int fd_attach(device_t); 30783548Snyanstatic int fd_detach(device_t); 30845783Skatostatic void set_motor(struct fdc_data *, int, int); 30916359Sasami# define TURNON 1 31016359Sasami# define TURNOFF 0 31116359Sasamistatic timeout_t fd_turnoff; 31216359Sasamistatic timeout_t fd_motor_on; 31345783Skatostatic void fd_turnon(struct fd_data *); 31416359Sasamistatic void fdc_reset(fdc_p); 31545783Skatostatic int fd_in(struct fdc_data *, int *); 31678809Snyanstatic int out_fdc(struct fdc_data *, int); 317120194Snyanstatic d_open_t fdopen; 31883548Snyanstatic d_close_t fdclose; 31983548Snyanstatic d_strategy_t fdstrategy; 32045783Skatostatic void fdstart(struct fdc_data *); 32137971Skatostatic timeout_t fd_iotimeout; 32216359Sasamistatic timeout_t fd_pseudointr; 32383548Snyanstatic driver_intr_t fdc_intr; 32483548Snyanstatic int fdcpio(fdc_p, long, caddr_t, u_int); 325130585Sphkstatic int fdautoselect(struct cdev *); 32645783Skatostatic int fdstate(struct fdc_data *); 32745783Skatostatic int retrier(struct fdc_data *); 32883548Snyanstatic void fdbiodone(struct bio *); 329130585Sphkstatic int fdmisccmd(struct cdev *, u_int, void *); 33083548Snyanstatic d_ioctl_t fdioctl; 33116359Sasami 33229568Skatostatic int fifo_threshold = 8; /* XXX: should be accessible via sysctl */ 33329568Skato 33429533Skato#ifdef FDC_DEBUG 33516359Sasami/* CAUTION: fd_debug causes huge amounts of logging output */ 33617256Sasamistatic int volatile fd_debug = 0; 33783548Snyan#define TRACE0(arg) do { if (fd_debug) printf(arg); } while (0) 33883548Snyan#define TRACE1(arg1, arg2) do { if (fd_debug) printf(arg1, arg2); } while (0) 33929533Skato#else /* FDC_DEBUG */ 34083548Snyan#define TRACE0(arg) do { } while (0) 34183548Snyan#define TRACE1(arg1, arg2) do { } while (0) 34229533Skato#endif /* FDC_DEBUG */ 34316359Sasami 34483548Snyan/* 34583548Snyan * Bus space handling (access to low-level IO). 34683548Snyan */ 34779704Snyan#ifndef PC98 348131819Snyanvoid 34953093Snyanfdout_wr(fdc_p fdc, u_int8_t v) 35053093Snyan{ 35153093Snyan bus_space_write_1(fdc->portt, fdc->porth, FDOUT+fdc->port_off, v); 35253093Snyan} 35379704Snyan#endif 35453093Snyan 35553093Snyanstatic u_int8_t 35653093Snyanfdsts_rd(fdc_p fdc) 35753093Snyan{ 35853093Snyan return bus_space_read_1(fdc->portt, fdc->porth, FDSTS+fdc->port_off); 35953093Snyan} 36053093Snyan 36153093Snyanstatic void 36253093Snyanfddata_wr(fdc_p fdc, u_int8_t v) 36353093Snyan{ 36453093Snyan bus_space_write_1(fdc->portt, fdc->porth, FDDATA+fdc->port_off, v); 36553093Snyan} 36653093Snyan 36753093Snyanstatic u_int8_t 36853093Snyanfddata_rd(fdc_p fdc) 36953093Snyan{ 37053093Snyan return bus_space_read_1(fdc->portt, fdc->porth, FDDATA+fdc->port_off); 37153093Snyan} 37253093Snyan 37379704Snyan#ifdef PC98 37479704Snyanstatic void 37579704Snyanfdctl_wr(fdc_p fdc, u_int8_t v) 37679704Snyan{ 37779704Snyan bus_space_write_1(fdc->portt, fdc->porth, FDCTL, v); 37879704Snyan} 37979704Snyan#endif 38079704Snyan 38153093Snyan#ifndef PC98 38253093Snyanstatic u_int8_t 38353093Snyanfdin_rd(fdc_p fdc) 38453093Snyan{ 38553093Snyan return bus_space_read_1(fdc->portt, fdc->porth, FDIN); 38653093Snyan} 38788011Snyan#endif /* PC98 */ 38853093Snyan 38947625Sphkstatic struct cdevsw fd_cdevsw = { 390126080Sphk .d_version = D_VERSION, 391120194Snyan .d_open = fdopen, 392111815Sphk .d_close = fdclose, 393111815Sphk .d_read = physread, 394111815Sphk .d_write = physwrite, 395111815Sphk .d_ioctl = fdioctl, 396111815Sphk .d_strategy = fdstrategy, 397111815Sphk .d_name = "fd", 398126080Sphk .d_flags = D_DISK | D_NEEDGIANT, 39947625Sphk}; 40047625Sphk 40183548Snyan/* 40283548Snyan * Auxiliary functions. Well, some only. Others are scattered 40383548Snyan * throughout the entire file. 40483548Snyan */ 40516359Sasamistatic int 40645783Skatofdc_err(struct fdc_data *fdc, const char *s) 40716359Sasami{ 40845783Skato fdc->fdc_errs++; 40945783Skato if (s) { 41055652Snyan if (fdc->fdc_errs < FDC_ERRMAX) 41155652Snyan device_printf(fdc->fdc_dev, "%s", s); 41255652Snyan else if (fdc->fdc_errs == FDC_ERRMAX) 41355652Snyan device_printf(fdc->fdc_dev, "too many errors, not " 41455652Snyan "logging any more\n"); 41516359Sasami } 41616359Sasami 41716359Sasami return FD_FAILED; 41816359Sasami} 41916359Sasami 42016359Sasami/* 42116359Sasami * fd_cmd: Send a command to the chip. Takes a varargs with this structure: 42216359Sasami * Unit number, 42316359Sasami * # of output bytes, output bytes as ints ..., 42416359Sasami * # of input bytes, input bytes as ints ... 42516359Sasami */ 426131819Snyanint 42745783Skatofd_cmd(struct fdc_data *fdc, int n_out, ...) 42816359Sasami{ 42916359Sasami u_char cmd; 43016359Sasami int n_in; 43116359Sasami int n; 43216359Sasami va_list ap; 43316359Sasami 43416359Sasami va_start(ap, n_out); 43516359Sasami cmd = (u_char)(va_arg(ap, int)); 43616359Sasami va_end(ap); 43716359Sasami va_start(ap, n_out); 43816359Sasami for (n = 0; n < n_out; n++) 43916359Sasami { 44045783Skato if (out_fdc(fdc, va_arg(ap, int)) < 0) 44116359Sasami { 44216359Sasami char msg[50]; 44341536Skato snprintf(msg, sizeof(msg), 44416359Sasami "cmd %x failed at out byte %d of %d\n", 44516359Sasami cmd, n + 1, n_out); 44645783Skato return fdc_err(fdc, msg); 44716359Sasami } 44816359Sasami } 44916359Sasami n_in = va_arg(ap, int); 45016359Sasami for (n = 0; n < n_in; n++) 45116359Sasami { 45216359Sasami int *ptr = va_arg(ap, int *); 45345783Skato if (fd_in(fdc, ptr) < 0) 45416359Sasami { 45516359Sasami char msg[50]; 45641536Skato snprintf(msg, sizeof(msg), 45716359Sasami "cmd %02x failed at in byte %d of %d\n", 45816359Sasami cmd, n + 1, n_in); 45945783Skato return fdc_err(fdc, msg); 46016359Sasami } 46116359Sasami } 46216359Sasami 46316359Sasami return 0; 46416359Sasami} 46516359Sasami 46629568Skatostatic int 46729568Skatoenable_fifo(fdc_p fdc) 46829568Skato{ 46929568Skato int i, j; 47029568Skato 47129568Skato if ((fdc->flags & FDC_HAS_FIFO) == 0) { 47229568Skato 47329568Skato /* 47429568Skato * Cannot use fd_cmd the normal way here, since 47529568Skato * this might be an invalid command. Thus we send the 47629568Skato * first byte, and check for an early turn of data directon. 47729568Skato */ 47829568Skato 479162165Sjkim if (out_fdc(fdc, I8207X_CONFIG) < 0) 48045783Skato return fdc_err(fdc, "Enable FIFO failed\n"); 48129568Skato 48229568Skato /* If command is invalid, return */ 48396576Snyan j = FDSTS_TIMEOUT; 48453093Snyan while ((i = fdsts_rd(fdc) & (NE7_DIO | NE7_RQM)) 48596576Snyan != NE7_RQM && j-- > 0) { 48629568Skato if (i == (NE7_DIO | NE7_RQM)) { 48729568Skato fdc_reset(fdc); 48829568Skato return FD_FAILED; 48929568Skato } 49096576Snyan DELAY(1); 49196576Snyan } 49229568Skato if (j<0 || 49345783Skato fd_cmd(fdc, 3, 49429568Skato 0, (fifo_threshold - 1) & 0xf, 0, 0) < 0) { 49529568Skato fdc_reset(fdc); 49645783Skato return fdc_err(fdc, "Enable FIFO failed\n"); 49729568Skato } 49829568Skato fdc->flags |= FDC_HAS_FIFO; 49929568Skato return 0; 50029568Skato } 50145783Skato if (fd_cmd(fdc, 4, 502162165Sjkim I8207X_CONFIG, 0, (fifo_threshold - 1) & 0xf, 0, 0) < 0) 50345783Skato return fdc_err(fdc, "Re-enable FIFO failed\n"); 50429568Skato return 0; 50529568Skato} 50629568Skato 50716359Sasamistatic int 50816359Sasamifd_sense_drive_status(fdc_p fdc, int *st3p) 50916359Sasami{ 51016359Sasami int st3; 51116359Sasami 51245783Skato if (fd_cmd(fdc, 2, NE7CMD_SENSED, fdc->fdu, 1, &st3)) 51316359Sasami { 51445783Skato return fdc_err(fdc, "Sense Drive Status failed\n"); 51516359Sasami } 51616359Sasami if (st3p) 51716359Sasami *st3p = st3; 51816359Sasami 51916359Sasami return 0; 52016359Sasami} 52116359Sasami 52216359Sasamistatic int 52316359Sasamifd_sense_int(fdc_p fdc, int *st0p, int *cylp) 52416359Sasami{ 52545783Skato int cyl, st0, ret; 52616359Sasami 52745783Skato ret = fd_cmd(fdc, 1, NE7CMD_SENSEI, 1, &st0); 52845783Skato if (ret) { 52945783Skato (void)fdc_err(fdc, 53016359Sasami "sense intr err reading stat reg 0\n"); 53116359Sasami return ret; 53216359Sasami } 53316359Sasami 53416359Sasami if (st0p) 53516359Sasami *st0p = st0; 53616359Sasami 53745783Skato if ((st0 & NE7_ST0_IC) == NE7_ST0_IC_IV) { 53816359Sasami /* 53916359Sasami * There doesn't seem to have been an interrupt. 54016359Sasami */ 54116359Sasami return FD_NOT_VALID; 54216359Sasami } 54316359Sasami 54445783Skato if (fd_in(fdc, &cyl) < 0) { 54545783Skato return fdc_err(fdc, "can't get cyl num\n"); 54616359Sasami } 54716359Sasami 54816359Sasami if (cylp) 54916359Sasami *cylp = cyl; 55016359Sasami 55116359Sasami return 0; 55216359Sasami} 55316359Sasami 55416359Sasami 55516359Sasamistatic int 55683548Snyanfd_read_status(fdc_p fdc) 55716359Sasami{ 55816359Sasami int i, ret; 55916359Sasami 56083548Snyan for (i = ret = 0; i < 7; i++) { 56116359Sasami /* 56283548Snyan * XXX types are poorly chosen. Only bytes can be read 56337569Skato * from the hardware, but fdc->status[] wants u_ints and 56416359Sasami * fd_in() gives ints. 56516359Sasami */ 56616359Sasami int status; 56716359Sasami 56845783Skato ret = fd_in(fdc, &status); 56916359Sasami fdc->status[i] = status; 57016359Sasami if (ret != 0) 57116359Sasami break; 57216359Sasami } 57316359Sasami 57416359Sasami if (ret == 0) 57516359Sasami fdc->flags |= FDC_STAT_VALID; 57616359Sasami else 57716359Sasami fdc->flags &= ~FDC_STAT_VALID; 57816359Sasami 57916359Sasami return ret; 58016359Sasami} 58116359Sasami 58216359Sasami#ifdef PC98 58316359Sasamistatic int pc98_trans = 0; /* 0 : HD , 1 : DD , 2 : 1.44 */ 584127521Snyanstatic int pc98_trans_prev = -1; 58516359Sasami 58645783Skatostatic void set_density(fdc_p fdc) 58716359Sasami{ 58816359Sasami /* always motor on */ 58979704Snyan bus_space_write_1(fdc->sc_fdsiot, fdc->sc_fdsioh, 0, 59079704Snyan (pc98_trans != 1 ? FDP_FDDEXC : 0) | FDP_PORTEXC); 59116359Sasami DELAY(100); 59279704Snyan fdctl_wr(fdc, FDC_RST | FDC_DMAE); 59316359Sasami /* in the case of note W, always inhibit 100ms timer */ 59416359Sasami} 59516359Sasami 59645783Skatostatic int pc98_fd_check_ready(fdu_t fdu) 59716359Sasami{ 59845783Skato fd_p fd = devclass_get_softc(fd_devclass, fdu); 59945783Skato struct fdc_data *fdc = fd->fdc; 60078809Snyan int retry = 0, status; 60116359Sasami 60216359Sasami while (retry++ < 30000) { 60345783Skato set_motor(fdc, fd->fdsu, TURNON); 60445783Skato out_fdc(fdc, NE7CMD_SENSED); /* Sense Drive Status */ 60516359Sasami DELAY(100); 60645783Skato out_fdc(fdc, fdu); /* Drive number */ 60716359Sasami DELAY(100); 608100172Snyan if ((fd_in(fdc, &status) == 0) && (status & NE7_ST3_RD)) { 60979704Snyan fdctl_wr(fdc, FDC_DMAE | FDC_MTON); 61016359Sasami DELAY(10); 61116359Sasami return 0; 61216359Sasami } 61316359Sasami } 61416359Sasami return -1; 61516359Sasami} 616132103Snyan 617132103Snyanstatic void pc98_fd_check_type(struct fd_data *fd) 618132103Snyan{ 619132103Snyan struct fdc_data *fdc; 620132103Snyan 621132103Snyan if (fd->type != FDT_NONE || fd->fdu < 0 || fd->fdu > 3) 622132103Snyan return; 623132103Snyan 624132103Snyan fdc = fd->fdc; 625132103Snyan 626132103Snyan /* Look up what the BIOS thinks we have. */ 627132103Snyan if (!((PC98_SYSTEM_PARAMETER(0x55c) >> fd->fdu) & 0x01)) { 628132103Snyan fd->type = FDT_NONE; 629132103Snyan return; 630132103Snyan } 631132103Snyan if ((PC98_SYSTEM_PARAMETER(0x5ae) >> fd->fdu) & 0x01) { 632132103Snyan /* Check 3mode I/F */ 633132103Snyan fd->pc98_trans = 0; 634132103Snyan bus_space_write_1(fdc->sc_fdemsiot, fdc->sc_fdemsioh, 0, 635132103Snyan (fd->fdu << 5) | 0x10); 636132103Snyan if (!(bus_space_read_1(fdc->sc_fdemsiot, fdc->sc_fdemsioh, 0) & 637132103Snyan 0x01)) { 638132103Snyan fd->type = FDT_144M; 639132103Snyan return; 640132103Snyan } 641132103Snyan device_printf(fd->dev, 642132103Snyan "Warning: can't control 3mode I/F, fallback to 2mode.\n"); 643132103Snyan } 644132103Snyan 645132103Snyan fd->type = FDT_12M; 646132103Snyan} 64788011Snyan#endif /* PC98 */ 64816359Sasami 649131819Snyanvoid 65055652Snyanfdc_release_resources(struct fdc_data *fdc) 65155652Snyan{ 65255652Snyan device_t dev; 65355652Snyan 65455652Snyan dev = fdc->fdc_dev; 655132286Snyan if (fdc->fdc_intr) { 656155921Sjhb bus_teardown_intr(dev, fdc->res_irq, fdc->fdc_intr); 657132286Snyan fdc->fdc_intr = NULL; 658132286Snyan } 65955652Snyan if (fdc->res_irq != 0) { 66055652Snyan bus_release_resource(dev, SYS_RES_IRQ, fdc->rid_irq, 66155652Snyan fdc->res_irq); 662132286Snyan fdc->res_irq = NULL; 66355652Snyan } 66416359Sasami#ifndef PC98 66555652Snyan if (fdc->res_ctl != 0) { 66655652Snyan bus_release_resource(dev, SYS_RES_IOPORT, fdc->rid_ctl, 66755652Snyan fdc->res_ctl); 668132286Snyan fdc->res_ctl = NULL; 66955652Snyan } 67055652Snyan#endif 67179704Snyan#ifdef PC98 67279704Snyan if (fdc->res_fdsio != 0) { 67379704Snyan bus_release_resource(dev, SYS_RES_IOPORT, 3, fdc->res_fdsio); 674132286Snyan fdc->res_fdsio = NULL; 67579704Snyan } 67679704Snyan if (fdc->res_fdemsio != 0) { 67779704Snyan bus_release_resource(dev, SYS_RES_IOPORT, 4, fdc->res_fdemsio); 678132286Snyan fdc->res_fdemsio = NULL; 67979704Snyan } 68079704Snyan#endif 68155652Snyan if (fdc->res_ioport != 0) { 68255652Snyan bus_release_resource(dev, SYS_RES_IOPORT, fdc->rid_ioport, 68355652Snyan fdc->res_ioport); 684132286Snyan fdc->res_ioport = NULL; 68555652Snyan } 68655652Snyan if (fdc->res_drq != 0) { 68755652Snyan bus_release_resource(dev, SYS_RES_DRQ, fdc->rid_drq, 68855652Snyan fdc->res_drq); 689132286Snyan fdc->res_drq = NULL; 69055652Snyan } 69155652Snyan} 69255652Snyan 69383548Snyan/* 69483548Snyan * Configuration/initialization stuff, per controller. 69583548Snyan */ 69655652Snyan 697131819Snyanint 69862952Snyanfdc_read_ivar(device_t dev, device_t child, int which, uintptr_t *result) 69955652Snyan{ 70055652Snyan struct fdc_ivars *ivars = device_get_ivars(child); 70155652Snyan 70255652Snyan switch (which) { 70355652Snyan case FDC_IVAR_FDUNIT: 70455652Snyan *result = ivars->fdunit; 70555652Snyan break; 706132103Snyan case FDC_IVAR_FDTYPE: 707132103Snyan *result = ivars->fdtype; 708132103Snyan break; 70955652Snyan default: 710132103Snyan return (ENOENT); 71155652Snyan } 712132103Snyan return (0); 71355652Snyan} 71455652Snyan 715131819Snyanint 716132103Snyanfdc_write_ivar(device_t dev, device_t child, int which, uintptr_t value) 717132103Snyan{ 718132103Snyan struct fdc_ivars *ivars = device_get_ivars(child); 719132103Snyan 720132103Snyan switch (which) { 721132103Snyan case FDC_IVAR_FDUNIT: 722132103Snyan ivars->fdunit = value; 723132103Snyan break; 724132103Snyan case FDC_IVAR_FDTYPE: 725132103Snyan ivars->fdtype = value; 726132103Snyan break; 727132103Snyan default: 728132103Snyan return (ENOENT); 729132103Snyan } 730132103Snyan return (0); 731132103Snyan} 732132103Snyan 733132103Snyanint 734132103Snyanfdc_initial_reset(struct fdc_data *fdc) 735132103Snyan{ 736132103Snyan#ifdef PC98 737132103Snyan /* see if it can handle a command */ 738132103Snyan if (fd_cmd(fdc, 3, NE7CMD_SPECIFY, NE7_SPEC_1(4, 240), 739132103Snyan NE7_SPEC_2(2, 0), 0)) 740132103Snyan return (ENXIO); 741132103Snyan#else 742132103Snyan /* First, reset the floppy controller. */ 743132103Snyan fdout_wr(fdc, 0); 744132103Snyan DELAY(100); 745132103Snyan fdout_wr(fdc, FDO_FRST); 746132103Snyan 747132103Snyan /* Then, see if it can handle a command. */ 748132103Snyan if (fd_cmd(fdc, 3, NE7CMD_SPECIFY, NE7_SPEC_1(3, 240), 749132103Snyan NE7_SPEC_2(2, 0), 0)) 750132103Snyan return (ENXIO); 751132103Snyan#endif 752132103Snyan return (0); 753132103Snyan} 754132103Snyan 755132103Snyanint 75683548Snyanfdc_detach(device_t dev) 75758299Skato{ 75858299Skato struct fdc_data *fdc; 75958299Skato int error; 76058299Skato 76158299Skato fdc = device_get_softc(dev); 76258299Skato 76358299Skato /* have our children detached first */ 76458299Skato if ((error = bus_generic_detach(dev))) 76558299Skato return (error); 76658299Skato 76783548Snyan#ifdef PC98 76883548Snyan /* reset controller, turn motor off */ 76983548Snyan fdc_reset(fdc); 77083548Snyan#else 77183548Snyan /* reset controller, turn motor off */ 77283548Snyan fdout_wr(fdc, 0); 77383548Snyan#endif 77483548Snyan 77558299Skato fdc_release_resources(fdc); 77658299Skato return (0); 77758299Skato} 77858299Skato 77916359Sasami/* 78055652Snyan * Add a child device to the fdc controller. It will then be probed etc. 78116359Sasami */ 782132286Snyandevice_t 78355652Snyanfdc_add_child(device_t dev, const char *name, int unit) 78445783Skato{ 78555652Snyan struct fdc_ivars *ivar; 78645783Skato device_t child; 78745783Skato 78869781Sdwmalone ivar = malloc(sizeof *ivar, M_DEVBUF /* XXX */, M_NOWAIT | M_ZERO); 78955652Snyan if (ivar == NULL) 790132286Snyan return (NULL); 79154073Smdodd child = device_add_child(dev, name, unit); 792104619Snyan if (child == NULL) { 793104619Snyan free(ivar, M_DEVBUF); 794132286Snyan return (NULL); 795104619Snyan } 79654073Smdodd device_set_ivars(child, ivar); 797132286Snyan ivar->fdunit = unit; 798132286Snyan ivar->fdtype = FDT_NONE; 799117167Sjhb if (resource_disabled(name, unit)) 80045783Skato device_disable(child); 801132286Snyan return (child); 80245783Skato} 80345783Skato 804131819Snyanint 80545783Skatofdc_attach(device_t dev) 80616359Sasami{ 80755652Snyan struct fdc_data *fdc; 808132286Snyan int error; 80916359Sasami 81055652Snyan fdc = device_get_softc(dev); 811132103Snyan fdc->fdc_dev = dev; 812155921Sjhb error = bus_setup_intr(dev, fdc->res_irq, 813166901Spiso INTR_TYPE_BIO | INTR_ENTROPY, NULL, fdc_intr, fdc, 81476303Snyan &fdc->fdc_intr); 81555652Snyan if (error) { 81655652Snyan device_printf(dev, "cannot setup interrupt\n"); 81755652Snyan return error; 81855652Snyan } 81955652Snyan fdc->fdcu = device_get_unit(dev); 820132286Snyan fdc->flags |= FDC_NEEDS_RESET; 82145783Skato 82216359Sasami fdc->state = DEVIDLE; 82345783Skato 82445783Skato#ifdef PC98 82545783Skato /* reset controller, turn motor off, clear fdout mirror reg */ 82616359Sasami fdc_reset(fdc); 82716359Sasami#else 82816359Sasami /* reset controller, turn motor off, clear fdout mirror reg */ 82983548Snyan fdout_wr(fdc, fdc->fdout = 0); 83016359Sasami#endif 83159249Sphk bioq_init(&fdc->head); 83216359Sasami 833132286Snyan return (0); 834132286Snyan} 835132286Snyan 836132286Snyanint 837132286Snyanfdc_hints_probe(device_t dev) 838132286Snyan{ 839132286Snyan const char *name, *dname; 840132286Snyan int i, error, dunit; 841132286Snyan 84245783Skato /* 84355652Snyan * Probe and attach any children. We should probably detect 84455652Snyan * devices from the BIOS unless overridden. 84545783Skato */ 84667156Speter name = device_get_nameunit(dev); 84778135Speter i = 0; 848132286Snyan while ((resource_find_match(&i, &dname, &dunit, "at", name)) == 0) { 849132286Snyan resource_int_value(dname, dunit, "drive", &dunit); 85078135Speter fdc_add_child(dev, dname, dunit); 851132286Snyan } 85255652Snyan 85383548Snyan if ((error = bus_generic_attach(dev)) != 0) 85483548Snyan return (error); 85583548Snyan return (0); 85645783Skato} 85745783Skato 858131819Snyanint 85945783Skatofdc_print_child(device_t me, device_t child) 86045783Skato{ 86188011Snyan int retval = 0, flags; 86249195Smdodd 86349195Smdodd retval += bus_print_child_header(me, child); 86488011Snyan retval += printf(" on %s drive %d", device_get_nameunit(me), 86555652Snyan fdc_get_fdunit(child)); 86688011Snyan if ((flags = device_get_flags(me)) != 0) 86788011Snyan retval += printf(" flags %#x", flags); 86888011Snyan retval += printf("\n"); 86951613Snyan 87049195Smdodd return (retval); 87145783Skato} 87245783Skato 87351719Snyan/* 87483548Snyan * Configuration/initialization, per drive. 87551719Snyan */ 87645783Skatostatic int 87745783Skatofd_probe(device_t dev) 87845783Skato{ 87945783Skato int i; 88088011Snyan#ifndef PC98 88188011Snyan u_int st0, st3; 88267142Snyan#endif 88345783Skato struct fd_data *fd; 88445783Skato struct fdc_data *fdc; 88545783Skato fdsu_t fdsu; 886132103Snyan int flags, type; 88745783Skato 888132103Snyan fdsu = fdc_get_fdunit(dev); 88945783Skato fd = device_get_softc(dev); 89045783Skato fdc = device_get_softc(device_get_parent(dev)); 89188011Snyan flags = device_get_flags(dev); 89245783Skato 89345783Skato fd->dev = dev; 89445783Skato fd->fdc = fdc; 89545783Skato fd->fdsu = fdsu; 89645783Skato fd->fdu = device_get_unit(dev); 89745783Skato 898132286Snyan /* Auto-probe if fdinfo is present, but always allow override. */ 899132103Snyan type = FD_DTYPE(flags); 900132103Snyan if (type == FDT_NONE && (type = fdc_get_fdtype(dev)) != FDT_NONE) { 901132103Snyan fd->type = type; 902132103Snyan goto done; 903132103Snyan } else { 904132103Snyan /* make sure fdautoselect() will be called */ 905132103Snyan fd->flags = FD_UA; 906132103Snyan fd->type = type; 907132103Snyan } 908132103Snyan 90916359Sasami#ifdef PC98 910132103Snyan pc98_fd_check_type(fd); 911132103Snyan#else 912104619Snyan/* 913104619Snyan * XXX I think using __i386__ is wrong here since we actually want to probe 914104619Snyan * for the machine type, not the CPU type (so non-PC arch's like the PC98 will 915153167Sru * fail the probe). 916104619Snyan */ 917104619Snyan#ifdef __i386__ 91888011Snyan if (fd->type == FDT_NONE && (fd->fdu == 0 || fd->fdu == 1)) { 91988011Snyan /* Look up what the BIOS thinks we have. */ 92088011Snyan if (fd->fdu == 0) { 92188011Snyan if ((fdc->flags & FDC_ISPCMCIA)) 92288011Snyan /* 92388011Snyan * Somewhat special. No need to force the 92488011Snyan * user to set device flags, since the Y-E 92588011Snyan * Data PCMCIA floppy is always a 1.44 MB 92688011Snyan * device. 92788011Snyan */ 92888011Snyan fd->type = FDT_144M; 92988011Snyan else 93088011Snyan fd->type = (rtcin(RTC_FDISKETTE) & 0xf0) >> 4; 93188011Snyan } else { 93288011Snyan fd->type = rtcin(RTC_FDISKETTE) & 0x0f; 93388011Snyan } 93488011Snyan if (fd->type == FDT_288M_1) 93588011Snyan fd->type = FDT_288M; 93645783Skato } 937104619Snyan#endif /* __i386__ */ 93888011Snyan#endif /* PC98 */ 93945783Skato 94045783Skato /* is there a unit? */ 94188011Snyan if (fd->type == FDT_NONE) 94245783Skato return (ENXIO); 94316359Sasami 94418208Sasami#ifndef PC98 94545783Skato /* select it */ 94645783Skato set_motor(fdc, fdsu, TURNON); 94783548Snyan fdc_reset(fdc); /* XXX reset, then unreset, etc. */ 94845783Skato DELAY(1000000); /* 1 sec */ 94916359Sasami 95088011Snyan if ((flags & FD_NO_PROBE) == 0) { 95188011Snyan /* If we're at track 0 first seek inwards. */ 95288011Snyan if ((fd_sense_drive_status(fdc, &st3) == 0) && 95388011Snyan (st3 & NE7_ST3_T0)) { 95488011Snyan /* Seek some steps... */ 95588011Snyan if (fd_cmd(fdc, 3, NE7CMD_SEEK, fdsu, 10, 0) == 0) { 95688011Snyan /* ...wait a moment... */ 95788011Snyan DELAY(300000); 95888011Snyan /* make ctrlr happy: */ 95988011Snyan fd_sense_int(fdc, 0, 0); 96088011Snyan } 96116359Sasami } 96216359Sasami 96388011Snyan for (i = 0; i < 2; i++) { 96488011Snyan /* 96588011Snyan * we must recalibrate twice, just in case the 96688011Snyan * heads have been beyond cylinder 76, since 96788011Snyan * most FDCs still barf when attempting to 96888011Snyan * recalibrate more than 77 steps 96988011Snyan */ 97088011Snyan /* go back to 0: */ 97188011Snyan if (fd_cmd(fdc, 2, NE7CMD_RECAL, fdsu, 0) == 0) { 97288011Snyan /* a second being enough for full stroke seek*/ 97388011Snyan DELAY(i == 0 ? 1000000 : 300000); 97416359Sasami 97588011Snyan /* anything responding? */ 97688011Snyan if (fd_sense_int(fdc, &st0, 0) == 0 && 97788011Snyan (st0 & NE7_ST0_EC) == 0) 97888011Snyan break; /* already probed succesfully */ 97988011Snyan } 98016359Sasami } 98145783Skato } 98216359Sasami 98345783Skato set_motor(fdc, fdsu, TURNOFF); 98416359Sasami 98588011Snyan if ((flags & FD_NO_PROBE) == 0 && 98688011Snyan (st0 & NE7_ST0_EC) != 0) /* no track 0 -> no drive present */ 98745783Skato return (ENXIO); 98845783Skato#endif /* PC98 */ 98945783Skato 990132103Snyandone: 991132103Snyan#ifndef PC98 992132286Snyan /* This doesn't work before the first reset. */ 993132103Snyan if ((fdc->flags & FDC_HAS_FIFO) == 0 && 994132103Snyan fdc->fdct == FDC_ENHANCED && 995132103Snyan (device_get_flags(fdc->fdc_dev) & FDC_NO_FIFO) == 0 && 996132103Snyan enable_fifo(fdc) == 0) { 997132103Snyan device_printf(device_get_parent(dev), 998132103Snyan "FIFO enabled, %d bytes threshold\n", fifo_threshold); 999132103Snyan } 1000132103Snyan#endif /* PC98 */ 1001132103Snyan 100245783Skato#ifdef PC98 100388011Snyan switch (fd->type) { 100451613Snyan case FDT_144M: 1005132103Snyan device_set_desc(dev, "1.44M FDD"); 1006132103Snyan break; 100745783Skato case FDT_12M: 100888011Snyan device_set_desc(dev, "1M/640K FDD"); 100945783Skato break; 101045783Skato default: 101145783Skato return (ENXIO); 101245783Skato } 101345783Skato#else 101488011Snyan switch (fd->type) { 101588011Snyan case FDT_12M: 101645783Skato device_set_desc(dev, "1200-KB 5.25\" drive"); 101745783Skato break; 101888011Snyan case FDT_144M: 101945783Skato device_set_desc(dev, "1440-KB 3.5\" drive"); 102045783Skato break; 102188011Snyan case FDT_288M: 102245783Skato device_set_desc(dev, "2880-KB 3.5\" drive (in 1440-KB mode)"); 102345783Skato break; 102488011Snyan case FDT_360K: 102545783Skato device_set_desc(dev, "360-KB 5.25\" drive"); 102645783Skato break; 102788011Snyan case FDT_720K: 102888011Snyan device_set_desc(dev, "720-KB 3.5\" drive"); 102945783Skato break; 103045783Skato default: 103145783Skato return (ENXIO); 103245783Skato } 103345783Skato#endif 103488011Snyan fd->track = FD_NO_TRACK; 103588011Snyan fd->fdc = fdc; 103688011Snyan fd->fdsu = fdsu; 103788011Snyan fd->options = 0; 103888011Snyan#ifdef PC98 103988011Snyan fd->pc98_trans = 0; 104088011Snyan#endif 104188011Snyan callout_handle_init(&fd->toffhandle); 104288011Snyan callout_handle_init(&fd->tohandle); 104388011Snyan 104488011Snyan /* initialize densities for subdevices */ 104588011Snyan#ifdef PC98 104688011Snyan for (i = 0; i < NUMDENS; i++) 104788011Snyan memcpy(fd->fts + i, fd_searchlist_144m + i, 104888011Snyan sizeof(struct fd_type)); 104988011Snyan#else 105088011Snyan for (i = 0; i < NUMDENS; i++) 105188011Snyan memcpy(fd->fts + i, fd_native_types + fd->type, 105288011Snyan sizeof(struct fd_type)); 105388011Snyan#endif 105445783Skato return (0); 105545783Skato} 105616359Sasami 105745783Skatostatic int 105845783Skatofd_attach(device_t dev) 105945783Skato{ 106045783Skato struct fd_data *fd; 106116359Sasami 106283548Snyan fd = device_get_softc(dev); 1063126289Snyan fd->masterdev = make_dev(&fd_cdevsw, fd->fdu, 106483548Snyan UID_ROOT, GID_OPERATOR, 0640, "fd%d", fd->fdu); 1065120194Snyan fd->masterdev->si_drv1 = fd; 1066112006Sphk fd->device_stats = devstat_new_entry(device_get_name(dev), 106778809Snyan device_get_unit(dev), 0, DEVSTAT_NO_ORDERED_TAGS, 106845783Skato DEVSTAT_TYPE_FLOPPY | DEVSTAT_TYPE_IF_OTHER, 106945783Skato DEVSTAT_PRIORITY_FD); 107045783Skato return (0); 107116359Sasami} 107216359Sasami 107358299Skatostatic int 107458299Skatofd_detach(device_t dev) 107558299Skato{ 107658299Skato struct fd_data *fd; 107758299Skato 107858299Skato fd = device_get_softc(dev); 107958299Skato untimeout(fd_turnoff, fd, fd->toffhandle); 1080112006Sphk devstat_remove_entry(fd->device_stats); 108183548Snyan destroy_dev(fd->masterdev); 108258299Skato 108358299Skato return (0); 108458299Skato} 108558299Skato 108651719Snyanstatic device_method_t fd_methods[] = { 108751719Snyan /* Device interface */ 108851719Snyan DEVMETHOD(device_probe, fd_probe), 108951719Snyan DEVMETHOD(device_attach, fd_attach), 109058299Skato DEVMETHOD(device_detach, fd_detach), 109151719Snyan DEVMETHOD(device_shutdown, bus_generic_shutdown), 109251719Snyan DEVMETHOD(device_suspend, bus_generic_suspend), /* XXX */ 109351719Snyan DEVMETHOD(device_resume, bus_generic_resume), /* XXX */ 109451719Snyan 109551719Snyan { 0, 0 } 109651719Snyan}; 109751719Snyan 109851719Snyanstatic driver_t fd_driver = { 109951719Snyan "fd", 110051719Snyan fd_methods, 110151719Snyan sizeof(struct fd_data) 110251719Snyan}; 110351719Snyan 110453002SpeterDRIVER_MODULE(fd, fdc, fd_driver, fd_devclass, 0, 0); 110551719Snyan 110683548Snyan/* 110783548Snyan * More auxiliary functions. 110883548Snyan */ 110983548Snyan/* 111083548Snyan * Motor control stuff. 111183548Snyan * Remember to not deselect the drive we're working on. 111283548Snyan */ 111316359Sasamistatic void 111445783Skatoset_motor(struct fdc_data *fdc, int fdsu, int turnon) 111516359Sasami{ 111679704Snyan#ifdef PC98 111779704Snyan bus_space_write_1(fdc->sc_fdsiot, fdc->sc_fdsioh, 0, 111879704Snyan (pc98_trans != 1 ? FDP_FDDEXC : 0) | FDP_PORTEXC); 111979704Snyan DELAY(10); 112079704Snyan fdctl_wr(fdc, FDC_DMAE | FDC_MTON); 112179704Snyan#else 112283548Snyan int fdout; 112316359Sasami 112483548Snyan fdout = fdc->fdout; 112583548Snyan if (turnon) { 112616359Sasami fdout &= ~FDO_FDSEL; 112783548Snyan fdout |= (FDO_MOEN0 << fdsu) | FDO_FDMAEN | FDO_FRST | fdsu; 112816359Sasami } else 112916359Sasami fdout &= ~(FDO_MOEN0 << fdsu); 113083548Snyan fdc->fdout = fdout; 113153093Snyan fdout_wr(fdc, fdout); 113216359Sasami TRACE1("[0x%x->FDOUT]", fdout); 113316359Sasami#endif 113416359Sasami} 113516359Sasami 113616359Sasamistatic void 113745783Skatofd_turnoff(void *xfd) 113816359Sasami{ 113916359Sasami int s; 114045783Skato fd_p fd = xfd; 114116359Sasami 114245783Skato TRACE1("[fd%d: turnoff]", fd->fdu); 114316359Sasami 114458299Skato s = splbio(); 114516359Sasami /* 114616359Sasami * Don't turn off the motor yet if the drive is active. 114758299Skato * 114858299Skato * If we got here, this could only mean we missed an interrupt. 114958299Skato * This can e. g. happen on the Y-E Date PCMCIA floppy controller 115058299Skato * after a controller reset. Just schedule a pseudo-interrupt 115158299Skato * so the state machine gets re-entered. 115216359Sasami */ 115345783Skato if (fd->fdc->state != DEVIDLE && fd->fdc->fdu == fd->fdu) { 115458299Skato fdc_intr(fd->fdc); 115558299Skato splx(s); 115616359Sasami return; 115716359Sasami } 115816359Sasami 115916359Sasami fd->flags &= ~FD_MOTOR; 116045783Skato set_motor(fd->fdc, fd->fdsu, TURNOFF); 116116359Sasami splx(s); 116216359Sasami} 116316359Sasami 116416359Sasamistatic void 116545783Skatofd_motor_on(void *xfd) 116616359Sasami{ 116716359Sasami int s; 116845783Skato fd_p fd = xfd; 116916359Sasami 117016359Sasami s = splbio(); 117116359Sasami fd->flags &= ~FD_MOTOR_WAIT; 117216359Sasami if((fd->fdc->fd == fd) && (fd->fdc->state == MOTORWAIT)) 117316359Sasami { 117445783Skato fdc_intr(fd->fdc); 117516359Sasami } 117616359Sasami splx(s); 117716359Sasami} 117816359Sasami 117916359Sasamistatic void 118045783Skatofd_turnon(fd_p fd) 118116359Sasami{ 118216359Sasami if(!(fd->flags & FD_MOTOR)) 118316359Sasami { 118416359Sasami fd->flags |= (FD_MOTOR + FD_MOTOR_WAIT); 118545783Skato set_motor(fd->fdc, fd->fdsu, TURNON); 118645783Skato timeout(fd_motor_on, fd, hz); /* in 1 sec its ok */ 118716359Sasami } 118816359Sasami} 118916359Sasami 119016359Sasamistatic void 119116359Sasamifdc_reset(fdc_p fdc) 119216359Sasami{ 119316359Sasami /* Try a reset, keep motor on */ 119416359Sasami#ifdef PC98 119545783Skato set_density(fdc); 119616359Sasami if (pc98_machine_type & M_EPSON_PC98) 119779704Snyan fdctl_wr(fdc, FDC_RST | FDC_RDY | FDC_DD | FDC_MTON); 119816359Sasami else 119979704Snyan fdctl_wr(fdc, FDC_RST | FDC_RDY | FDC_DMAE | FDC_MTON); 120016359Sasami DELAY(200); 120179704Snyan fdctl_wr(fdc, FDC_DMAE | FDC_MTON); 120216359Sasami DELAY(10); 120316359Sasami#else 120453093Snyan fdout_wr(fdc, fdc->fdout & ~(FDO_FRST|FDO_FDMAEN)); 120516359Sasami TRACE1("[0x%x->FDOUT]", fdc->fdout & ~(FDO_FRST|FDO_FDMAEN)); 120616359Sasami DELAY(100); 120716359Sasami /* enable FDC, but defer interrupts a moment */ 120853093Snyan fdout_wr(fdc, fdc->fdout & ~FDO_FDMAEN); 120916359Sasami TRACE1("[0x%x->FDOUT]", fdc->fdout & ~FDO_FDMAEN); 121016359Sasami DELAY(100); 121153093Snyan fdout_wr(fdc, fdc->fdout); 121216359Sasami TRACE1("[0x%x->FDOUT]", fdc->fdout); 121316359Sasami#endif 121416359Sasami 121583548Snyan /* XXX after a reset, silently believe the FDC will accept commands */ 121616359Sasami#ifdef PC98 121745783Skato (void)fd_cmd(fdc, 3, NE7CMD_SPECIFY, 121816359Sasami NE7_SPEC_1(4, 240), NE7_SPEC_2(2, 0), 121916359Sasami 0); 122016359Sasami#else 122145783Skato (void)fd_cmd(fdc, 3, NE7CMD_SPECIFY, 122216359Sasami NE7_SPEC_1(3, 240), NE7_SPEC_2(2, 0), 122316359Sasami 0); 122416359Sasami#endif 122529568Skato if (fdc->flags & FDC_HAS_FIFO) 122629568Skato (void) enable_fifo(fdc); 122716359Sasami} 122816359Sasami 122983548Snyan/* 123083548Snyan * FDC IO functions, take care of the main status register, timeout 123183548Snyan * in case the desired status bits are never set. 123298430Snyan * 123398430Snyan * These PIO loops initially start out with short delays between 123498430Snyan * each iteration in the expectation that the required condition 123598430Snyan * is usually met quickly, so it can be handled immediately. After 123698430Snyan * about 1 ms, stepping is increased to achieve a better timing 123798430Snyan * accuracy in the calls to DELAY(). 123883548Snyan */ 123916359Sasamistatic int 124045783Skatofd_in(struct fdc_data *fdc, int *ptr) 124116359Sasami{ 124298430Snyan int i, j, step; 124398430Snyan 124498430Snyan for (j = 0, step = 1; 124598430Snyan (i = fdsts_rd(fdc) & (NE7_DIO|NE7_RQM)) != (NE7_DIO|NE7_RQM) && 124698430Snyan j < FDSTS_TIMEOUT; 124798430Snyan j += step) { 124816359Sasami if (i == NE7_RQM) 124996576Snyan return (fdc_err(fdc, "ready for output in input\n")); 125098430Snyan if (j == 1000) 125198430Snyan step = 1000; 125298430Snyan DELAY(step); 125396576Snyan } 125498430Snyan if (j >= FDSTS_TIMEOUT) 125596576Snyan return (fdc_err(fdc, bootverbose? "input ready timeout\n": 0)); 125629533Skato#ifdef FDC_DEBUG 125753093Snyan i = fddata_rd(fdc); 125816359Sasami TRACE1("[FDDATA->0x%x]", (unsigned char)i); 125916359Sasami *ptr = i; 126096576Snyan return (0); 126129533Skato#else /* !FDC_DEBUG */ 126253093Snyan i = fddata_rd(fdc); 126316359Sasami if (ptr) 126416359Sasami *ptr = i; 126596576Snyan return (0); 126629533Skato#endif /* FDC_DEBUG */ 126716359Sasami} 126816359Sasami 1269104137Snyanstatic int 127045783Skatoout_fdc(struct fdc_data *fdc, int x) 127116359Sasami{ 127298430Snyan int i, j, step; 127316359Sasami 127498430Snyan for (j = 0, step = 1; 127598430Snyan (i = fdsts_rd(fdc) & (NE7_DIO|NE7_RQM)) != NE7_RQM && 127698430Snyan j < FDSTS_TIMEOUT; 127798430Snyan j += step) { 127898430Snyan if (i == (NE7_DIO|NE7_RQM)) 127998430Snyan return (fdc_err(fdc, "ready for input in output\n")); 128098430Snyan if (j == 1000) 128198430Snyan step = 1000; 128298430Snyan DELAY(step); 128398430Snyan } 128498430Snyan if (j >= FDSTS_TIMEOUT) 128596576Snyan return (fdc_err(fdc, bootverbose? "output ready timeout\n": 0)); 128616359Sasami 128716359Sasami /* Send the command and return */ 128853093Snyan fddata_wr(fdc, x); 128916359Sasami TRACE1("[0x%x->FDDATA]", x); 129016359Sasami return (0); 129116359Sasami} 129216359Sasami 129383548Snyan/* 129483548Snyan * Block device driver interface functions (interspersed with even more 129583548Snyan * auxiliary functions). 129683548Snyan */ 1297104137Snyanstatic int 1298130585Sphkfdopen(struct cdev *dev, int flags, int mode, struct thread *td) 129916359Sasami{ 130045783Skato fd_p fd; 130116359Sasami fdc_p fdc; 1302131819Snyan#ifdef PC98 1303126289Snyan fdu_t fdu; 1304131819Snyan#endif 130588011Snyan int rv, unitattn, dflags; 130616359Sasami 1307120194Snyan fd = dev->si_drv1; 1308120194Snyan if (fd == NULL) 130945783Skato return (ENXIO); 131045783Skato fdc = fd->fdc; 131188011Snyan if ((fdc == NULL) || (fd->type == FDT_NONE)) 131245783Skato return (ENXIO); 1313131819Snyan#ifdef PC98 1314126289Snyan fdu = fd->fdu; 1315131819Snyan#endif 131688011Snyan dflags = device_get_flags(fd->dev); 131788011Snyan /* 131888011Snyan * This is a bit bogus. It's still possible that e. g. a 131988011Snyan * descriptor gets inherited to a child, but then it's at 132088011Snyan * least for the same subdevice. By checking FD_OPEN here, we 132188011Snyan * can ensure that a device isn't attempted to be opened with 132288011Snyan * different densities at the same time where the second open 132388011Snyan * could clobber the settings from the first one. 132488011Snyan */ 132588011Snyan if (fd->flags & FD_OPEN) 132688011Snyan return (EBUSY); 132788011Snyan 132816359Sasami#ifdef PC98 132916359Sasami if (pc98_fd_check_ready(fdu) == -1) 133016359Sasami return(EIO); 133188011Snyan#endif 133288011Snyan 1333126289Snyan if (flags & FNONBLOCK) { 1334126289Snyan /* 1335126289Snyan * Unfortunately, physio(9) discards its ioflag 1336126289Snyan * argument, thus preventing us from seeing the 1337139199Sphk * O_NONBLOCK bit. So we need to keep track 1338126289Snyan * ourselves. 1339126289Snyan */ 1340126289Snyan fd->flags |= FD_NONBLOCK; 1341126289Snyan fd->ft = 0; 1342126289Snyan } else { 1343126289Snyan /* 1344126289Snyan * Figure out a unit attention condition. 1345126289Snyan * 1346126289Snyan * If UA has been forced, proceed. 1347126289Snyan * 1348126289Snyan * If the drive has no changeline support, 1349126289Snyan * or if the drive parameters have been lost 1350126289Snyan * due to previous non-blocking access, 1351126289Snyan * assume a forced UA condition. 1352126289Snyan * 1353126289Snyan * If motor is off, turn it on for a moment 1354126289Snyan * and select our drive, in order to read the 1355126289Snyan * UA hardware signal. 1356126289Snyan * 1357126289Snyan * If motor is on, and our drive is currently 1358126289Snyan * selected, just read the hardware bit. 1359126289Snyan * 1360126289Snyan * If motor is on, but active for another 1361126289Snyan * drive on that controller, we are lost. We 1362126289Snyan * cannot risk to deselect the other drive, so 1363126289Snyan * we just assume a forced UA condition to be 1364126289Snyan * on the safe side. 1365126289Snyan */ 1366126289Snyan unitattn = 0; 1367126289Snyan if ((dflags & FD_NO_CHLINE) != 0 || 1368126289Snyan (fd->flags & FD_UA) != 0 || 1369126289Snyan fd->ft == 0) { 1370126289Snyan unitattn = 1; 1371126289Snyan fd->flags &= ~FD_UA; 137288011Snyan#ifndef PC98 1373126289Snyan } else if (fdc->fdout & (FDO_MOEN0 | FDO_MOEN1 | 1374126289Snyan FDO_MOEN2 | FDO_MOEN3)) { 1375126289Snyan if ((fdc->fdout & FDO_FDSEL) == fd->fdsu) 137688011Snyan unitattn = fdin_rd(fdc) & FDI_DCHG; 1377126289Snyan else 1378126289Snyan unitattn = 1; 1379126289Snyan } else { 1380126289Snyan set_motor(fdc, fd->fdsu, TURNON); 1381126289Snyan unitattn = fdin_rd(fdc) & FDI_DCHG; 1382126289Snyan set_motor(fdc, fd->fdsu, TURNOFF); 138388011Snyan#endif /* PC98 */ 138416359Sasami } 1385126289Snyan if (unitattn && (rv = fdautoselect(dev)) != 0) 1386126289Snyan return (rv); 138716359Sasami } 138845783Skato fd->flags |= FD_OPEN; 1389131819Snyan 1390131819Snyan if ((fdc->flags & FDC_NODMA) == 0) { 1391131819Snyan if (fdc->dmacnt++ == 0) { 1392131819Snyan isa_dma_acquire(fdc->dmachan); 1393131819Snyan isa_dmainit(fdc->dmachan, MAX_SEC_SIZE); 1394131819Snyan } 1395131819Snyan } 1396131819Snyan 139783548Snyan /* 139883548Snyan * Clearing the DMA overrun counter at open time is a bit messy. 139983548Snyan * Since we're only managing one counter per controller, opening 140083548Snyan * the second drive could mess it up. Anyway, if the DMA overrun 140183548Snyan * condition is really persistent, it will eventually time out 140283548Snyan * still. OTOH, clearing it here will ensure we'll at least start 140383548Snyan * trying again after a previous (maybe even long ago) failure. 140483548Snyan * Also, this is merely a stop-gap measure only that should not 140583548Snyan * happen during normal operation, so we can tolerate it to be a 140683548Snyan * bit sloppy about this. 140783548Snyan */ 140883548Snyan fdc->dma_overruns = 0; 140958299Skato 141016359Sasami return 0; 141116359Sasami} 141216359Sasami 1413104137Snyanstatic int 1414130585Sphkfdclose(struct cdev *dev, int flags, int mode, struct thread *td) 141516359Sasami{ 141645783Skato struct fd_data *fd; 1417131819Snyan fdc_p fdc; 141816359Sasami 1419120194Snyan fd = dev->si_drv1; 1420131819Snyan fdc = fd->fdc; 142188011Snyan fd->flags &= ~(FD_OPEN | FD_NONBLOCK); 142276615Skato fd->options &= ~(FDOPT_NORETRY | FDOPT_NOERRLOG | FDOPT_NOERROR); 142316359Sasami 1424131819Snyan if ((fdc->flags & FDC_NODMA) == 0) 1425131819Snyan if (--fdc->dmacnt == 0) 1426131819Snyan isa_dma_release(fdc->dmachan); 1427131819Snyan 142845783Skato return (0); 142916359Sasami} 143016359Sasami 1431104137Snyanstatic void 143259249Sphkfdstrategy(struct bio *bp) 143316359Sasami{ 143483548Snyan long blknum, nblocks; 143516359Sasami int s; 143616359Sasami fdu_t fdu; 143716359Sasami fdc_p fdc; 143816359Sasami fd_p fd; 143916359Sasami size_t fdblk; 144016359Sasami 1441120194Snyan fd = bp->bio_dev->si_drv1; 1442126289Snyan fdu = fd->fdu; 144316359Sasami fdc = fd->fdc; 1444119984Snyan bp->bio_resid = bp->bio_bcount; 144588011Snyan if (fd->type == FDT_NONE || fd->ft == 0) { 1446119984Snyan if (fd->type != FDT_NONE && (fd->flags & FD_NONBLOCK)) 1447119984Snyan bp->bio_error = EAGAIN; 1448119984Snyan else 1449119984Snyan bp->bio_error = ENXIO; 145059249Sphk bp->bio_flags |= BIO_ERROR; 145155652Snyan goto bad; 145283548Snyan } 145316359Sasami fdblk = 128 << (fd->ft->secsize); 1454104515Sphk if (bp->bio_cmd != FDBIO_FORMAT && bp->bio_cmd != FDBIO_RDSECTID) { 145588011Snyan if (fd->flags & FD_NONBLOCK) { 145688011Snyan bp->bio_error = EAGAIN; 145788011Snyan bp->bio_flags |= BIO_ERROR; 145888011Snyan goto bad; 145988011Snyan } 1460121215Sphk if (bp->bio_offset < 0) { 146116359Sasami printf( 1462121215Sphk "fd%d: fdstrat: bad request offset = %ju, bcount = %ld\n", 1463121215Sphk fdu, (intmax_t)bp->bio_offset, bp->bio_bcount); 146459249Sphk bp->bio_error = EINVAL; 146559249Sphk bp->bio_flags |= BIO_ERROR; 146616359Sasami goto bad; 146716359Sasami } 146859249Sphk if ((bp->bio_bcount % fdblk) != 0) { 146959249Sphk bp->bio_error = EINVAL; 147059249Sphk bp->bio_flags |= BIO_ERROR; 147116359Sasami goto bad; 147216359Sasami } 147316359Sasami } 147416359Sasami 147516359Sasami /* 147616359Sasami * Set up block calculations. 147716359Sasami */ 1478131819Snyan#ifndef PC98 1479131819Snyan if (bp->bio_offset >= ((off_t)128 << fd->ft->secsize) * fd->ft->size) { 1480131819Snyan bp->bio_error = EINVAL; 1481131819Snyan bp->bio_flags |= BIO_ERROR; 1482131819Snyan goto bad; 1483131819Snyan } 1484131819Snyan#endif 1485121215Sphk blknum = bp->bio_offset / fdblk; 148616359Sasami nblocks = fd->ft->size; 148783548Snyan if (blknum + bp->bio_bcount / fdblk > nblocks) { 148883548Snyan if (blknum >= nblocks) { 1489119984Snyan if (bp->bio_cmd != BIO_READ) { 149083548Snyan bp->bio_error = ENOSPC; 149183548Snyan bp->bio_flags |= BIO_ERROR; 149283548Snyan } 149383548Snyan goto bad; /* not always bad, but EOF */ 149416359Sasami } 149583548Snyan bp->bio_bcount = (nblocks - blknum) * fdblk; 149616359Sasami } 1497103384Snyan bp->bio_pblkno = blknum; 149816359Sasami s = splbio(); 1499112946Sphk bioq_disksort(&fdc->head, bp); 150045783Skato untimeout(fd_turnoff, fd, fd->toffhandle); /* a good idea */ 1501112260Sphk devstat_start_transaction_bio(fd->device_stats, bp); 150258299Skato device_busy(fd->dev); 150345783Skato fdstart(fdc); 150416359Sasami splx(s); 150516359Sasami return; 150616359Sasami 150716359Sasamibad: 150816359Sasami biodone(bp); 150916359Sasami} 151016359Sasami 151183548Snyan/* 151283548Snyan * fdstart 151383548Snyan * 151483548Snyan * We have just queued something. If the controller is not busy 151583548Snyan * then simulate the case where it has just finished a command 151683548Snyan * So that it (the interrupt routine) looks on the queue for more 151783548Snyan * work to do and picks up what we just added. 151883548Snyan * 151983548Snyan * If the controller is already busy, we need do nothing, as it 152083548Snyan * will pick up our work when the present work completes. 152183548Snyan */ 152216359Sasamistatic void 152345783Skatofdstart(struct fdc_data *fdc) 152416359Sasami{ 152516359Sasami int s; 152616359Sasami 152716359Sasami s = splbio(); 152845783Skato if(fdc->state == DEVIDLE) 152916359Sasami { 153045783Skato fdc_intr(fdc); 153116359Sasami } 153216359Sasami splx(s); 153316359Sasami} 153416359Sasami 153516359Sasamistatic void 153645783Skatofd_iotimeout(void *xfdc) 153716359Sasami{ 153837971Skato fdc_p fdc; 153916359Sasami int s; 154016359Sasami 154145783Skato fdc = xfdc; 154237971Skato TRACE1("fd%d[fd_iotimeout()]", fdc->fdu); 154316359Sasami 154416359Sasami /* 154516359Sasami * Due to IBM's brain-dead design, the FDC has a faked ready 154616359Sasami * signal, hardwired to ready == true. Thus, any command 154716359Sasami * issued if there's no diskette in the drive will _never_ 154816359Sasami * complete, and must be aborted by resetting the FDC. 154916359Sasami * Many thanks, Big Blue! 155037971Skato * The FDC must not be reset directly, since that would 155137971Skato * interfere with the state machine. Instead, pretend that 155237971Skato * the command completed but was invalid. The state machine 155337971Skato * will reset the FDC and retry once. 155416359Sasami */ 155516359Sasami s = splbio(); 155637971Skato fdc->status[0] = NE7_ST0_IC_IV; 155737971Skato fdc->flags &= ~FDC_STAT_VALID; 155837971Skato fdc->state = IOTIMEDOUT; 155945783Skato fdc_intr(fdc); 156016359Sasami splx(s); 156116359Sasami} 156216359Sasami 156383548Snyan/* Just ensure it has the right spl. */ 156416359Sasamistatic void 156545783Skatofd_pseudointr(void *xfdc) 156616359Sasami{ 156716359Sasami int s; 156816359Sasami 156916359Sasami s = splbio(); 157045783Skato fdc_intr(xfdc); 157116359Sasami splx(s); 157216359Sasami} 157316359Sasami 157483548Snyan/* 157583548Snyan * fdc_intr 157683548Snyan * 157783548Snyan * Keep calling the state machine until it returns a 0. 157883548Snyan * Always called at splbio. 157983548Snyan */ 158040565Sbdestatic void 158145783Skatofdc_intr(void *xfdc) 158216359Sasami{ 158345783Skato fdc_p fdc = xfdc; 158445783Skato while(fdstate(fdc)) 158545783Skato ; 158616359Sasami} 158716359Sasami 158841779Skato/* 158983548Snyan * Magic pseudo-DMA initialization for YE FDC. Sets count and 159083548Snyan * direction. 159141779Skato */ 159255652Snyan#define SET_BCDR(fdc,wr,cnt,port) \ 159355652Snyan bus_space_write_1(fdc->portt, fdc->porth, fdc->port_off + port, \ 159455652Snyan ((cnt)-1) & 0xff); \ 159555652Snyan bus_space_write_1(fdc->portt, fdc->porth, fdc->port_off + port + 1, \ 159655652Snyan ((wr ? 0x80 : 0) | ((((cnt)-1) >> 8) & 0x7f))); 159741779Skato 159841779Skato/* 159983548Snyan * fdcpio(): perform programmed IO read/write for YE PCMCIA floppy. 160041779Skato */ 160183548Snyanstatic int 160283548Snyanfdcpio(fdc_p fdc, long flags, caddr_t addr, u_int count) 160341779Skato{ 160441779Skato u_char *cptr = (u_char *)addr; 160541779Skato 160658345Sphk if (flags == BIO_READ) { 160741779Skato if (fdc->state != PIOREAD) { 160841779Skato fdc->state = PIOREAD; 160941779Skato return(0); 161083548Snyan } 161155652Snyan SET_BCDR(fdc, 0, count, 0); 161255652Snyan bus_space_read_multi_1(fdc->portt, fdc->porth, fdc->port_off + 161355652Snyan FDC_YE_DATAPORT, cptr, count); 161441779Skato } else { 161555652Snyan bus_space_write_multi_1(fdc->portt, fdc->porth, fdc->port_off + 161655652Snyan FDC_YE_DATAPORT, cptr, count); 161755652Snyan SET_BCDR(fdc, 0, count, 0); 161883548Snyan } 161941779Skato return(1); 162041779Skato} 162141779Skato 162283548Snyan/* 162388011Snyan * Try figuring out the density of the media present in our device. 162488011Snyan */ 162588011Snyanstatic int 1626130585Sphkfdautoselect(struct cdev *dev) 162788011Snyan{ 162888011Snyan fd_p fd; 162988011Snyan struct fd_type *fdtp; 163088011Snyan struct fdc_readid id; 163188011Snyan int i, n, oopts, rv; 163288011Snyan 1633120194Snyan fd = dev->si_drv1; 163488011Snyan 163588011Snyan switch (fd->type) { 163688011Snyan default: 163788011Snyan return (ENXIO); 163888011Snyan 163988011Snyan#ifndef PC98 164088011Snyan case FDT_360K: 164188011Snyan case FDT_720K: 164288011Snyan /* no autoselection on those drives */ 164388011Snyan fd->ft = fd_native_types + fd->type; 164488011Snyan return (0); 164588011Snyan#endif 164688011Snyan 164788011Snyan case FDT_12M: 164888011Snyan fdtp = fd_searchlist_12m; 164988011Snyan n = sizeof fd_searchlist_12m / sizeof(struct fd_type); 165088011Snyan break; 165188011Snyan 165288011Snyan case FDT_144M: 165388011Snyan fdtp = fd_searchlist_144m; 165488011Snyan n = sizeof fd_searchlist_144m / sizeof(struct fd_type); 165588011Snyan break; 165688011Snyan 165788011Snyan#ifndef PC98 165888011Snyan case FDT_288M: 165988011Snyan fdtp = fd_searchlist_288m; 166088011Snyan n = sizeof fd_searchlist_288m / sizeof(struct fd_type); 166188011Snyan break; 166288011Snyan#endif 166388011Snyan } 166488011Snyan 166588011Snyan /* 166688011Snyan * Try reading sector ID fields, first at cylinder 0, head 0, 166788011Snyan * then at cylinder 2, head N. We don't probe cylinder 1, 166888011Snyan * since for 5.25in DD media in a HD drive, there are no data 166988011Snyan * to read (2 step pulses per media cylinder required). For 167088011Snyan * two-sided media, the second probe always goes to head 1, so 167188011Snyan * we can tell them apart from single-sided media. As a 167288011Snyan * side-effect this means that single-sided media should be 167388011Snyan * mentioned in the search list after two-sided media of an 167488011Snyan * otherwise identical density. Media with a different number 167588011Snyan * of sectors per track but otherwise identical parameters 167688011Snyan * cannot be distinguished at all. 167788011Snyan * 167888011Snyan * If we successfully read an ID field on both cylinders where 167988011Snyan * the recorded values match our expectation, we are done. 168088011Snyan * Otherwise, we try the next density entry from the table. 168188011Snyan * 168288011Snyan * Stepping to cylinder 2 has the side-effect of clearing the 168388011Snyan * unit attention bit. 168488011Snyan */ 168588011Snyan oopts = fd->options; 168688011Snyan fd->options |= FDOPT_NOERRLOG | FDOPT_NORETRY; 168788011Snyan for (i = 0; i < n; i++, fdtp++) { 168888011Snyan fd->ft = fdtp; 168988011Snyan 169088011Snyan id.cyl = id.head = 0; 1691104515Sphk rv = fdmisccmd(dev, FDBIO_RDSECTID, &id); 169288011Snyan if (rv != 0) 169388011Snyan continue; 169488011Snyan if (id.cyl != 0 || id.head != 0 || 169588011Snyan id.secshift != fdtp->secsize) 169688011Snyan continue; 169788011Snyan id.cyl = 2; 169888011Snyan id.head = fd->ft->heads - 1; 1699104515Sphk rv = fdmisccmd(dev, FDBIO_RDSECTID, &id); 170088011Snyan if (id.cyl != 2 || id.head != fdtp->heads - 1 || 170188011Snyan id.secshift != fdtp->secsize) 170288011Snyan continue; 170388011Snyan if (rv == 0) 170488011Snyan break; 170588011Snyan } 170688011Snyan 170788011Snyan fd->options = oopts; 170888011Snyan if (i == n) { 170996576Snyan if (bootverbose) 171096576Snyan device_printf(fd->dev, "autoselection failed\n"); 171188011Snyan fd->ft = 0; 171288011Snyan return (EIO); 171388011Snyan } else { 171496576Snyan if (bootverbose) 171596576Snyan device_printf(fd->dev, "autoselected %d KB medium\n", 1716127521Snyan#ifdef PC98 1717127521Snyan (128 << (fd->ft->secsize)) * 1718127521Snyan fd->ft->size / 1024); 1719127521Snyan#else 172096576Snyan fd->ft->size / 2); 1721127521Snyan#endif 172288011Snyan return (0); 172388011Snyan } 172488011Snyan} 172588011Snyan 172688011Snyan 172788011Snyan/* 172883548Snyan * The controller state machine. 172983548Snyan * 173083548Snyan * If it returns a non zero value, it should be called again immediately. 173183548Snyan */ 173216359Sasamistatic int 173345783Skatofdstate(fdc_p fdc) 173416359Sasami{ 173583548Snyan struct fdc_readid *idp; 173683548Snyan int read, format, rdsectid, cylinder, head, i, sec = 0, sectrac; 173788011Snyan int st0, cyl, st3, idf, ne7cmd, mfm, steptrac; 173883548Snyan unsigned long blknum; 173916359Sasami fdu_t fdu = fdc->fdu; 174016359Sasami fd_p fd; 174159249Sphk register struct bio *bp; 174216359Sasami struct fd_formb *finfo = NULL; 174316359Sasami size_t fdblk; 174416359Sasami 174542725Skato bp = fdc->bp; 174642725Skato if (bp == NULL) { 1747136765Sphk bp = bioq_takefirst(&fdc->head); 1748136765Sphk if (bp != NULL) 174942725Skato fdc->bp = bp; 175042725Skato } 175142725Skato if (bp == NULL) { 175283548Snyan /* 175383548Snyan * Nothing left for this controller to do, 175483548Snyan * force into the IDLE state. 175583548Snyan */ 175616359Sasami fdc->state = DEVIDLE; 175745783Skato if (fdc->fd) { 175855652Snyan device_printf(fdc->fdc_dev, 175955652Snyan "unexpected valid fd pointer\n"); 176016359Sasami fdc->fd = (fd_p) 0; 176116359Sasami fdc->fdu = -1; 176216359Sasami } 176345783Skato TRACE1("[fdc%d IDLE]", fdc->fdcu); 176445783Skato return (0); 176516359Sasami } 1766120194Snyan fd = bp->bio_dev->si_drv1; 1767126289Snyan fdu = fd->fdu; 176816359Sasami fdblk = 128 << fd->ft->secsize; 176955652Snyan if (fdc->fd && (fd != fdc->fd)) 177055652Snyan device_printf(fd->dev, "confused fd pointers\n"); 177159249Sphk read = bp->bio_cmd == BIO_READ; 177288011Snyan mfm = (fd->ft->flags & FL_MFM)? NE7CMD_MFM: 0; 177388011Snyan steptrac = (fd->ft->flags & FL_2STEP)? 2: 1; 177458743Skato if (read) 177558743Skato idf = ISADMA_READ; 177658743Skato else 177758743Skato idf = ISADMA_WRITE; 1778104515Sphk format = bp->bio_cmd == FDBIO_FORMAT; 1779104515Sphk rdsectid = bp->bio_cmd == FDBIO_RDSECTID; 178083548Snyan if (format) 178159249Sphk finfo = (struct fd_formb *)bp->bio_data; 178216359Sasami TRACE1("fd%d", fdu); 178316359Sasami TRACE1("[%s]", fdstates[fdc->state]); 178416359Sasami TRACE1("(0x%x)", fd->flags); 178545783Skato untimeout(fd_turnoff, fd, fd->toffhandle); 178645783Skato fd->toffhandle = timeout(fd_turnoff, fd, 4 * hz); 178716359Sasami switch (fdc->state) 178816359Sasami { 178916359Sasami case DEVIDLE: 179016359Sasami case FINDWORK: /* we have found new work */ 179116359Sasami fdc->retry = 0; 179216359Sasami fd->skip = 0; 179316359Sasami fdc->fd = fd; 179416359Sasami fdc->fdu = fdu; 179516359Sasami#ifdef PC98 179616359Sasami pc98_trans = fd->ft->trans; 179716359Sasami if (pc98_trans_prev != pc98_trans) { 179816359Sasami int i; 179945783Skato set_density(fdc); 180016359Sasami for (i = 0; i < 10; i++) { 180116359Sasami outb(0x5f, 0); 180216359Sasami outb(0x5f, 0); 180316359Sasami } 180416359Sasami pc98_trans_prev = pc98_trans; 180516359Sasami } 180616359Sasami if (pc98_trans != fd->pc98_trans) { 180788011Snyan if (fd->type == FDT_144M) { 180879704Snyan bus_space_write_1(fdc->sc_fdemsiot, 180979704Snyan fdc->sc_fdemsioh, 181079704Snyan 0, 181179704Snyan (fdu << 5) | 0x10 | 181279704Snyan (pc98_trans >> 1)); 181316359Sasami outb(0x5f, 0); 181416359Sasami outb(0x5f, 0); 181516359Sasami } 181616359Sasami fd->pc98_trans = pc98_trans; 181716359Sasami } 181816359Sasami#else 181958299Skato fdc->fdctl_wr(fdc, fd->ft->trans); 182016359Sasami#endif 182116359Sasami TRACE1("[0x%x->FDCTL]", fd->ft->trans); 182283548Snyan /* 182383548Snyan * If the next drive has a motor startup pending, then 182483548Snyan * it will start up in its own good time. 182583548Snyan */ 182645783Skato if(fd->flags & FD_MOTOR_WAIT) { 182716359Sasami fdc->state = MOTORWAIT; 182883548Snyan return (0); /* will return later */ 182916359Sasami } 183083548Snyan /* 183183548Snyan * Maybe if it's not starting, it SHOULD be starting. 183283548Snyan */ 183316359Sasami if (!(fd->flags & FD_MOTOR)) 183416359Sasami { 183516359Sasami fdc->state = MOTORWAIT; 183645783Skato fd_turnon(fd); 183783548Snyan return (0); /* will return later */ 183816359Sasami } 183916359Sasami else /* at least make sure we are selected */ 184016359Sasami { 184145783Skato set_motor(fdc, fd->fdsu, TURNON); 184216359Sasami } 184337971Skato if (fdc->flags & FDC_NEEDS_RESET) { 184437971Skato fdc->state = RESETCTLR; 184537971Skato fdc->flags &= ~FDC_NEEDS_RESET; 184637971Skato } else 184737971Skato fdc->state = DOSEEK; 184883548Snyan return (1); /* will return immediately */ 184983548Snyan 185016359Sasami case DOSEEK: 185183548Snyan blknum = bp->bio_pblkno + fd->skip / fdblk; 185283548Snyan cylinder = blknum / (fd->ft->sectrac * fd->ft->heads); 185383548Snyan if (cylinder == fd->track) 185416359Sasami { 185516359Sasami fdc->state = SEEKCOMPLETE; 185683548Snyan return (1); /* will return immediately */ 185716359Sasami } 185816359Sasami#ifdef PC98 185916359Sasami pc98_fd_check_ready(fdu); 186016359Sasami#endif 186145783Skato if (fd_cmd(fdc, 3, NE7CMD_SEEK, 186288011Snyan fd->fdsu, cylinder * steptrac, 0)) 186316359Sasami { 186416359Sasami /* 186583548Snyan * Seek command not accepted, looks like 186616359Sasami * the FDC went off to the Saints... 186716359Sasami */ 186816359Sasami fdc->retry = 6; /* try a reset */ 186945783Skato return(retrier(fdc)); 187016359Sasami } 187116359Sasami fd->track = FD_NO_TRACK; 187216359Sasami fdc->state = SEEKWAIT; 187316359Sasami return(0); /* will return later */ 187483548Snyan 187516359Sasami case SEEKWAIT: 187616359Sasami /* allow heads to settle */ 187745783Skato timeout(fd_pseudointr, fdc, hz / 16); 187816359Sasami fdc->state = SEEKCOMPLETE; 187916359Sasami return(0); /* will return later */ 188083548Snyan 188183548Snyan case SEEKCOMPLETE : /* seek done, start DMA */ 188283548Snyan blknum = bp->bio_pblkno + fd->skip / fdblk; 188383548Snyan cylinder = blknum / (fd->ft->sectrac * fd->ft->heads); 188483548Snyan 188583548Snyan /* Make sure seek really happened. */ 188645783Skato if(fd->track == FD_NO_TRACK) { 188788011Snyan int descyl = cylinder * steptrac; 188816359Sasami do { 188916359Sasami /* 189016359Sasami * This might be a "ready changed" interrupt, 189116359Sasami * which cannot really happen since the 189216359Sasami * RDY pin is hardwired to + 5 volts. This 189316359Sasami * generally indicates a "bouncing" intr 189416359Sasami * line, so do one of the following: 189516359Sasami * 189616359Sasami * When running on an enhanced FDC that is 189716359Sasami * known to not go stuck after responding 189816359Sasami * with INVALID, fetch all interrupt states 189916359Sasami * until seeing either an INVALID or a 190016359Sasami * real interrupt condition. 190116359Sasami * 190216359Sasami * When running on a dumb old NE765, give 190316359Sasami * up immediately. The controller will 190416359Sasami * provide up to four dummy RC interrupt 190516359Sasami * conditions right after reset (for the 190616359Sasami * corresponding four drives), so this is 190716359Sasami * our only chance to get notice that it 190816359Sasami * was not the FDC that caused the interrupt. 190916359Sasami */ 191016359Sasami if (fd_sense_int(fdc, &st0, &cyl) 191116359Sasami == FD_NOT_VALID) 191283548Snyan return (0); /* will return later */ 191316359Sasami if(fdc->fdct == FDC_NE765 191416359Sasami && (st0 & NE7_ST0_IC) == NE7_ST0_IC_RC) 191583548Snyan return (0); /* hope for a real intr */ 191616359Sasami } while ((st0 & NE7_ST0_IC) == NE7_ST0_IC_RC); 191716359Sasami 191845783Skato if (0 == descyl) { 191916359Sasami int failed = 0; 192016359Sasami /* 192116359Sasami * seek to cyl 0 requested; make sure we are 192216359Sasami * really there 192316359Sasami */ 192416359Sasami if (fd_sense_drive_status(fdc, &st3)) 192516359Sasami failed = 1; 192616359Sasami if ((st3 & NE7_ST3_T0) == 0) { 192716359Sasami printf( 192816359Sasami "fd%d: Seek to cyl 0, but not really there (ST3 = %b)\n", 192916359Sasami fdu, st3, NE7_ST3BITS); 193016359Sasami failed = 1; 193116359Sasami } 193216359Sasami 193345783Skato if (failed) { 193416359Sasami if(fdc->retry < 3) 193516359Sasami fdc->retry = 3; 193645783Skato return (retrier(fdc)); 193716359Sasami } 193816359Sasami } 193916359Sasami 194045783Skato if (cyl != descyl) { 194116359Sasami printf( 194216359Sasami "fd%d: Seek to cyl %d failed; am at cyl %d (ST0 = 0x%x)\n", 194316359Sasami fdu, descyl, cyl, st0); 194437760Skato if (fdc->retry < 3) 194537760Skato fdc->retry = 3; 194645783Skato return (retrier(fdc)); 194716359Sasami } 194816359Sasami } 194916359Sasami 195083548Snyan fd->track = cylinder; 195183548Snyan if (format) 195283548Snyan fd->skip = (char *)&(finfo->fd_formb_cylno(0)) 195383548Snyan - (char *)finfo; 195483548Snyan if (!rdsectid && !(fdc->flags & FDC_NODMA)) 195559249Sphk isa_dmastart(idf, bp->bio_data+fd->skip, 195659249Sphk format ? bp->bio_bcount : fdblk, fdc->dmachan); 195783548Snyan blknum = bp->bio_pblkno + fd->skip / fdblk; 195816359Sasami sectrac = fd->ft->sectrac; 195916359Sasami sec = blknum % (sectrac * fd->ft->heads); 196016359Sasami head = sec / sectrac; 196116359Sasami sec = sec % sectrac + 1; 196288011Snyan if (head != 0 && fd->ft->offset_side2 != 0) 196388011Snyan sec += fd->ft->offset_side2; 196416359Sasami fd->hddrv = ((head&1)<<2)+fdu; 196545783Skato 196683548Snyan if(format || !(read || rdsectid)) 196716359Sasami { 196816359Sasami /* make sure the drive is writable */ 196916359Sasami if(fd_sense_drive_status(fdc, &st3) != 0) 197016359Sasami { 197116359Sasami /* stuck controller? */ 197258299Skato if (!(fdc->flags & FDC_NODMA)) 197358743Skato isa_dmadone(idf, 197459249Sphk bp->bio_data + fd->skip, 197559249Sphk format ? bp->bio_bcount : fdblk, 197658299Skato fdc->dmachan); 197716359Sasami fdc->retry = 6; /* reset the beast */ 197845783Skato return (retrier(fdc)); 197916359Sasami } 198016359Sasami if(st3 & NE7_ST3_WP) 198116359Sasami { 198216359Sasami /* 198316359Sasami * XXX YES! this is ugly. 198416359Sasami * in order to force the current operation 198516359Sasami * to fail, we will have to fake an FDC 198616359Sasami * error - all error handling is done 198716359Sasami * by the retrier() 198816359Sasami */ 198916359Sasami fdc->status[0] = NE7_ST0_IC_AT; 199016359Sasami fdc->status[1] = NE7_ST1_NW; 199116359Sasami fdc->status[2] = 0; 199216359Sasami fdc->status[3] = fd->track; 199316359Sasami fdc->status[4] = head; 199416359Sasami fdc->status[5] = sec; 199516359Sasami fdc->retry = 8; /* break out immediately */ 199616359Sasami fdc->state = IOTIMEDOUT; /* not really... */ 199783548Snyan return (1); /* will return immediately */ 199816359Sasami } 199916359Sasami } 200016359Sasami 200145783Skato if (format) { 200288011Snyan ne7cmd = NE7CMD_FORMAT | mfm; 200358299Skato if (fdc->flags & FDC_NODMA) { 200458299Skato /* 200558299Skato * This seems to be necessary for 200658299Skato * whatever obscure reason; if we omit 200758299Skato * it, we end up filling the sector ID 200858299Skato * fields of the newly formatted track 200958299Skato * entirely with garbage, causing 201058299Skato * `wrong cylinder' errors all over 201158299Skato * the place when trying to read them 201258299Skato * back. 201358299Skato * 201458299Skato * Umpf. 201558299Skato */ 201659249Sphk SET_BCDR(fdc, 1, bp->bio_bcount, 0); 201758299Skato 201859249Sphk (void)fdcpio(fdc,bp->bio_cmd, 201959249Sphk bp->bio_data+fd->skip, 202059249Sphk bp->bio_bcount); 202158299Skato 202258299Skato } 202316359Sasami /* formatting */ 202488011Snyan if(fd_cmd(fdc, 6, ne7cmd, head << 2 | fdu, 202516359Sasami finfo->fd_formb_secshift, 202616359Sasami finfo->fd_formb_nsecs, 202716359Sasami finfo->fd_formb_gaplen, 202845783Skato finfo->fd_formb_fillbyte, 0)) { 202916359Sasami /* controller fell over */ 203058299Skato if (!(fdc->flags & FDC_NODMA)) 203158743Skato isa_dmadone(idf, 203259249Sphk bp->bio_data + fd->skip, 203359249Sphk format ? bp->bio_bcount : fdblk, 203458299Skato fdc->dmachan); 203516359Sasami fdc->retry = 6; 203645783Skato return (retrier(fdc)); 203716359Sasami } 203883548Snyan } else if (rdsectid) { 203988011Snyan ne7cmd = NE7CMD_READID | mfm; 204088011Snyan if (fd_cmd(fdc, 2, ne7cmd, head << 2 | fdu, 0)) { 204183548Snyan /* controller jamming */ 204283548Snyan fdc->retry = 6; 204383548Snyan return (retrier(fdc)); 204483548Snyan } 204545783Skato } else { 204683548Snyan /* read or write operation */ 204788011Snyan ne7cmd = (read ? NE7CMD_READ | NE7CMD_SK : NE7CMD_WRITE) | mfm; 204855652Snyan if (fdc->flags & FDC_NODMA) { 204941779Skato /* 205083548Snyan * This seems to be necessary even when 205183548Snyan * reading data. 205241779Skato */ 205355652Snyan SET_BCDR(fdc, 1, fdblk, 0); 205441779Skato 205541779Skato /* 205683548Snyan * Perform the write pseudo-DMA before 205783548Snyan * the WRITE command is sent. 205841779Skato */ 205941779Skato if (!read) 206059249Sphk (void)fdcpio(fdc,bp->bio_cmd, 206159249Sphk bp->bio_data+fd->skip, 206241779Skato fdblk); 206341779Skato } 206445783Skato if (fd_cmd(fdc, 9, 206588011Snyan ne7cmd, 206616359Sasami head << 2 | fdu, /* head & unit */ 206716359Sasami fd->track, /* track */ 206816359Sasami head, 206916359Sasami sec, /* sector + 1 */ 207016359Sasami fd->ft->secsize, /* sector size */ 207116359Sasami sectrac, /* sectors/track */ 207216359Sasami fd->ft->gap, /* gap size */ 207316359Sasami fd->ft->datalen, /* data length */ 207445783Skato 0)) { 207516359Sasami /* the beast is sleeping again */ 207658299Skato if (!(fdc->flags & FDC_NODMA)) 207758743Skato isa_dmadone(idf, 207859249Sphk bp->bio_data + fd->skip, 207959249Sphk format ? bp->bio_bcount : fdblk, 208058299Skato fdc->dmachan); 208116359Sasami fdc->retry = 6; 208245783Skato return (retrier(fdc)); 208316359Sasami } 208416359Sasami } 208583548Snyan if (!rdsectid && (fdc->flags & FDC_NODMA)) 208641779Skato /* 208783548Snyan * If this is a read, then simply await interrupt 208883548Snyan * before performing PIO. 208941779Skato */ 209059249Sphk if (read && !fdcpio(fdc,bp->bio_cmd, 209159249Sphk bp->bio_data+fd->skip,fdblk)) { 209255652Snyan fd->tohandle = timeout(fd_iotimeout, fdc, hz); 209341779Skato return(0); /* will return later */ 209483548Snyan } 209541779Skato 209641779Skato /* 209783548Snyan * Write (or format) operation will fall through and 209883548Snyan * await completion interrupt. 209941779Skato */ 210016359Sasami fdc->state = IOCOMPLETE; 210145783Skato fd->tohandle = timeout(fd_iotimeout, fdc, hz); 210245783Skato return (0); /* will return later */ 210316359Sasami 210441779Skato case PIOREAD: 210541779Skato /* 210683548Snyan * Actually perform the PIO read. The IOCOMPLETE case 210783548Snyan * removes the timeout for us. 210841779Skato */ 210959249Sphk (void)fdcpio(fdc,bp->bio_cmd,bp->bio_data+fd->skip,fdblk); 211041779Skato fdc->state = IOCOMPLETE; 211141779Skato /* FALLTHROUGH */ 211283548Snyan case IOCOMPLETE: /* IO done, post-analyze */ 211345783Skato untimeout(fd_iotimeout, fdc, fd->tohandle); 211416359Sasami 211583548Snyan if (fd_read_status(fdc)) { 211683548Snyan if (!rdsectid && !(fdc->flags & FDC_NODMA)) 211759249Sphk isa_dmadone(idf, bp->bio_data + fd->skip, 211859249Sphk format ? bp->bio_bcount : fdblk, 211958299Skato fdc->dmachan); 212016359Sasami if (fdc->retry < 6) 212116359Sasami fdc->retry = 6; /* force a reset */ 212245783Skato return (retrier(fdc)); 212316359Sasami } 212416359Sasami 212516359Sasami fdc->state = IOTIMEDOUT; 212616359Sasami 212716359Sasami /* FALLTHROUGH */ 212816359Sasami case IOTIMEDOUT: 212983548Snyan if (!rdsectid && !(fdc->flags & FDC_NODMA)) 213059249Sphk isa_dmadone(idf, bp->bio_data + fd->skip, 213159249Sphk format ? bp->bio_bcount : fdblk, fdc->dmachan); 213245783Skato if (fdc->status[0] & NE7_ST0_IC) { 213316359Sasami if ((fdc->status[0] & NE7_ST0_IC) == NE7_ST0_IC_AT 213416359Sasami && fdc->status[1] & NE7_ST1_OR) { 213516359Sasami /* 213683548Snyan * DMA overrun. Someone hogged the bus and 213783548Snyan * didn't release it in time for the next 213883548Snyan * FDC transfer. 213983548Snyan * 214083548Snyan * We normally restart this without bumping 214183548Snyan * the retry counter. However, in case 214283548Snyan * something is seriously messed up (like 214383548Snyan * broken hardware), we rather limit the 214483548Snyan * number of retries so the IO operation 214583548Snyan * doesn't block indefinately. 214683548Snyan */ 214783548Snyan if (fdc->dma_overruns++ < FDC_DMAOV_MAX) { 214883548Snyan fdc->state = SEEKCOMPLETE; 214983548Snyan return (1);/* will return immediately */ 215083548Snyan } /* else fall through */ 215116359Sasami } 215283548Snyan if((fdc->status[0] & NE7_ST0_IC) == NE7_ST0_IC_IV 215316359Sasami && fdc->retry < 6) 215416359Sasami fdc->retry = 6; /* force a reset */ 215516359Sasami else if((fdc->status[0] & NE7_ST0_IC) == NE7_ST0_IC_AT 215616359Sasami && fdc->status[2] & NE7_ST2_WC 215716359Sasami && fdc->retry < 3) 215816359Sasami fdc->retry = 3; /* force recalibrate */ 215945783Skato return (retrier(fdc)); 216016359Sasami } 216116359Sasami /* All OK */ 216283548Snyan if (rdsectid) { 216383548Snyan /* copy out ID field contents */ 216483548Snyan idp = (struct fdc_readid *)bp->bio_data; 216583548Snyan idp->cyl = fdc->status[3]; 216683548Snyan idp->head = fdc->status[4]; 216783548Snyan idp->sec = fdc->status[5]; 216883548Snyan idp->secshift = fdc->status[6]; 216983548Snyan } 217083548Snyan /* Operation successful, retry DMA overruns again next time. */ 217183548Snyan fdc->dma_overruns = 0; 217216359Sasami fd->skip += fdblk; 217383548Snyan if (!rdsectid && !format && fd->skip < bp->bio_bcount) { 217416359Sasami /* set up next transfer */ 217516359Sasami fdc->state = DOSEEK; 217645783Skato } else { 217716359Sasami /* ALL DONE */ 217816359Sasami fd->skip = 0; 217983548Snyan bp->bio_resid = 0; 218042725Skato fdc->bp = NULL; 218158299Skato device_unbusy(fd->dev); 2182112006Sphk biofinish(bp, fd->device_stats, 0); 218316359Sasami fdc->fd = (fd_p) 0; 218416359Sasami fdc->fdu = -1; 218516359Sasami fdc->state = FINDWORK; 218616359Sasami } 218783548Snyan return (1); /* will return immediately */ 218883548Snyan 218916359Sasami case RESETCTLR: 219016359Sasami fdc_reset(fdc); 219116359Sasami fdc->retry++; 219237971Skato fdc->state = RESETCOMPLETE; 219383548Snyan return (0); /* will return later */ 219483548Snyan 219537971Skato case RESETCOMPLETE: 219637971Skato /* 219737971Skato * Discard all the results from the reset so that they 219837971Skato * can't cause an unexpected interrupt later. 219937971Skato */ 220037971Skato for (i = 0; i < 4; i++) 220137971Skato (void)fd_sense_int(fdc, &st0, &cyl); 220216359Sasami fdc->state = STARTRECAL; 220383548Snyan /* FALLTHROUGH */ 220416359Sasami case STARTRECAL: 220516359Sasami#ifdef PC98 220616359Sasami pc98_fd_check_ready(fdu); 220716359Sasami#endif 220845783Skato if(fd_cmd(fdc, 2, NE7CMD_RECAL, fdu, 0)) { 220916359Sasami /* arrgl */ 221016359Sasami fdc->retry = 6; 221145783Skato return (retrier(fdc)); 221216359Sasami } 221316359Sasami fdc->state = RECALWAIT; 221445783Skato return (0); /* will return later */ 221583548Snyan 221616359Sasami case RECALWAIT: 221716359Sasami /* allow heads to settle */ 221845783Skato timeout(fd_pseudointr, fdc, hz / 8); 221916359Sasami fdc->state = RECALCOMPLETE; 222045783Skato return (0); /* will return later */ 222183548Snyan 222216359Sasami case RECALCOMPLETE: 222316359Sasami do { 222416359Sasami /* 222516359Sasami * See SEEKCOMPLETE for a comment on this: 222616359Sasami */ 222716359Sasami if (fd_sense_int(fdc, &st0, &cyl) == FD_NOT_VALID) 222883548Snyan return (0); /* will return later */ 222916359Sasami if(fdc->fdct == FDC_NE765 223016359Sasami && (st0 & NE7_ST0_IC) == NE7_ST0_IC_RC) 223183548Snyan return (0); /* hope for a real intr */ 223216359Sasami } while ((st0 & NE7_ST0_IC) == NE7_ST0_IC_RC); 223316359Sasami if ((st0 & NE7_ST0_IC) != NE7_ST0_IC_NT || cyl != 0) 223416359Sasami { 223516359Sasami if(fdc->retry > 3) 223616359Sasami /* 223783548Snyan * A recalibrate from beyond cylinder 77 223816359Sasami * will "fail" due to the FDC limitations; 223916359Sasami * since people used to complain much about 224016359Sasami * the failure message, try not logging 224116359Sasami * this one if it seems to be the first 224283548Snyan * time in a line. 224316359Sasami */ 224416359Sasami printf("fd%d: recal failed ST0 %b cyl %d\n", 224516359Sasami fdu, st0, NE7_ST0BITS, cyl); 224616359Sasami if(fdc->retry < 3) fdc->retry = 3; 224745783Skato return (retrier(fdc)); 224816359Sasami } 224916359Sasami fd->track = 0; 225016359Sasami /* Seek (probably) necessary */ 225116359Sasami fdc->state = DOSEEK; 225283548Snyan return (1); /* will return immediately */ 225383548Snyan 225416359Sasami case MOTORWAIT: 225516359Sasami if(fd->flags & FD_MOTOR_WAIT) 225616359Sasami { 225745783Skato return (0); /* time's not up yet */ 225816359Sasami } 225937971Skato if (fdc->flags & FDC_NEEDS_RESET) { 226037971Skato fdc->state = RESETCTLR; 226137971Skato fdc->flags &= ~FDC_NEEDS_RESET; 226283548Snyan } else 226383548Snyan fdc->state = DOSEEK; 226483548Snyan return (1); /* will return immediately */ 226583548Snyan 226616359Sasami default: 226755652Snyan device_printf(fdc->fdc_dev, "unexpected FD int->"); 226883548Snyan if (fd_read_status(fdc) == 0) 226937569Skato printf("FDC status :%x %x %x %x %x %x %x ", 227016359Sasami fdc->status[0], 227116359Sasami fdc->status[1], 227216359Sasami fdc->status[2], 227316359Sasami fdc->status[3], 227416359Sasami fdc->status[4], 227516359Sasami fdc->status[5], 227616359Sasami fdc->status[6] ); 227716359Sasami else 227816359Sasami printf("No status available "); 227916359Sasami if (fd_sense_int(fdc, &st0, &cyl) != 0) 228016359Sasami { 228116359Sasami printf("[controller is dead now]\n"); 228283548Snyan return (0); /* will return later */ 228316359Sasami } 228416359Sasami printf("ST0 = %x, PCN = %x\n", st0, cyl); 228583548Snyan return (0); /* will return later */ 228616359Sasami } 228783548Snyan /* noone should ever get here */ 228816359Sasami} 228916359Sasami 229016359Sasamistatic int 229145783Skatoretrier(struct fdc_data *fdc) 229216359Sasami{ 229368360Snyan struct bio *bp; 229445783Skato struct fd_data *fd; 229545783Skato int fdu; 229616359Sasami 229742725Skato bp = fdc->bp; 229816359Sasami 229945783Skato /* XXX shouldn't this be cached somewhere? */ 2300120194Snyan fd = bp->bio_dev->si_drv1; 2301126289Snyan fdu = fd->fdu; 230245783Skato if (fd->options & FDOPT_NORETRY) 230316359Sasami goto fail; 230445783Skato 230545783Skato switch (fdc->retry) { 230616359Sasami case 0: case 1: case 2: 230716359Sasami fdc->state = SEEKCOMPLETE; 230816359Sasami break; 230916359Sasami case 3: case 4: case 5: 231016359Sasami fdc->state = STARTRECAL; 231116359Sasami break; 231216359Sasami case 6: 231316359Sasami fdc->state = RESETCTLR; 231416359Sasami break; 231516359Sasami case 7: 231616359Sasami break; 231716359Sasami default: 231816359Sasami fail: 231983548Snyan if ((fd->options & FDOPT_NOERRLOG) == 0) { 2320103675Sphk disk_err(bp, "hard error", 2321103675Sphk fdc->fd->skip / DEV_BSIZE, 0); 232283548Snyan if (fdc->flags & FDC_STAT_VALID) { 232383548Snyan printf( 232483548Snyan " (ST0 %b ST1 %b ST2 %b cyl %u hd %u sec %u)\n", 232583548Snyan fdc->status[0], NE7_ST0BITS, 232683548Snyan fdc->status[1], NE7_ST1BITS, 232783548Snyan fdc->status[2], NE7_ST2BITS, 232883548Snyan fdc->status[3], fdc->status[4], 232983548Snyan fdc->status[5]); 233083548Snyan } 233176615Skato else 233283548Snyan printf(" (No status)\n"); 233316359Sasami } 233476615Skato if ((fd->options & FDOPT_NOERROR) == 0) { 233576615Skato bp->bio_flags |= BIO_ERROR; 233676615Skato bp->bio_error = EIO; 233783548Snyan bp->bio_resid = bp->bio_bcount - fdc->fd->skip; 233883548Snyan } else 233983548Snyan bp->bio_resid = 0; 234042725Skato fdc->bp = NULL; 234116359Sasami fdc->fd->skip = 0; 234258299Skato device_unbusy(fd->dev); 2343112006Sphk biofinish(bp, fdc->fd->device_stats, 0); 234416359Sasami fdc->state = FINDWORK; 234537971Skato fdc->flags |= FDC_NEEDS_RESET; 234616359Sasami fdc->fd = (fd_p) 0; 234716359Sasami fdc->fdu = -1; 234845783Skato return (1); 234916359Sasami } 235016359Sasami fdc->retry++; 235145783Skato return (1); 235216359Sasami} 235316359Sasami 235462952Snyanstatic void 235562952Snyanfdbiodone(struct bio *bp) 235662952Snyan{ 235762952Snyan wakeup(bp); 235862952Snyan} 235962952Snyan 236016359Sasamistatic int 2361130585Sphkfdmisccmd(struct cdev *dev, u_int cmd, void *data) 236216359Sasami{ 236383548Snyan fdu_t fdu; 236483548Snyan fd_p fd; 236562952Snyan struct bio *bp; 236683548Snyan struct fd_formb *finfo; 236783548Snyan struct fdc_readid *idfield; 236816359Sasami size_t fdblk; 2369103384Snyan int error; 237016359Sasami 2371120194Snyan fd = dev->si_drv1; 2372126289Snyan fdu = fd->fdu; 237316359Sasami fdblk = 128 << fd->ft->secsize; 237483548Snyan finfo = (struct fd_formb *)data; 237583548Snyan idfield = (struct fdc_readid *)data; 237616359Sasami 2377112335Sphk bp = malloc(sizeof(struct bio), M_TEMP, M_WAITOK | M_ZERO); 237816359Sasami 237916359Sasami /* 2380121215Sphk * Set up a bio request for fdstrategy(). bio_offset is faked 2381218909Sbrucec * so that fdstrategy() will seek to the requested 238291061Sphk * cylinder, and use the desired head. 238316359Sasami */ 238483548Snyan bp->bio_cmd = cmd; 2385104515Sphk if (cmd == FDBIO_FORMAT) { 2386121215Sphk bp->bio_offset = 238783548Snyan (finfo->cyl * (fd->ft->sectrac * fd->ft->heads) + 2388121215Sphk finfo->head * fd->ft->sectrac) * fdblk; 238983548Snyan bp->bio_bcount = sizeof(struct fd_idfield_data) * 239083548Snyan finfo->fd_formb_nsecs; 2391104515Sphk } else if (cmd == FDBIO_RDSECTID) { 2392121215Sphk bp->bio_offset = 239383548Snyan (idfield->cyl * (fd->ft->sectrac * fd->ft->heads) + 2394121215Sphk idfield->head * fd->ft->sectrac) * fdblk; 239583548Snyan bp->bio_bcount = sizeof(struct fdc_readid); 239683548Snyan } else 239783548Snyan panic("wrong cmd in fdmisccmd()"); 239883548Snyan bp->bio_data = data; 239962952Snyan bp->bio_dev = dev; 240062952Snyan bp->bio_done = fdbiodone; 240191061Sphk bp->bio_flags = 0; 240216359Sasami 2403103384Snyan /* Now run the command. */ 240483548Snyan fdstrategy(bp); 2405103384Snyan error = biowait(bp, "fdcmd"); 240683548Snyan 240716359Sasami free(bp, M_TEMP); 2408103384Snyan return (error); 240916359Sasami} 241016359Sasami 241135336Skatostatic int 2412130585Sphkfdioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flag, struct thread *td) 241316359Sasami{ 241483548Snyan fdu_t fdu; 241583548Snyan fd_p fd; 241676615Skato struct fdc_status *fsp; 241783548Snyan struct fdc_readid *rid; 2418126289Snyan int error; 241916359Sasami 2420120194Snyan fd = dev->si_drv1; 2421126289Snyan fdu = fd->fdu; 242216359Sasami 242316359Sasami#ifdef PC98 242445783Skato pc98_fd_check_ready(fdu); 242516359Sasami#endif 242683548Snyan 242788011Snyan /* 242888011Snyan * First, handle everything that could be done with 242988011Snyan * FD_NONBLOCK still being set. 243088011Snyan */ 243188011Snyan switch (cmd) { 2432104515Sphk 2433104515Sphk case DIOCGMEDIASIZE: 2434119984Snyan if (fd->ft == 0) 2435119984Snyan return ((fd->flags & FD_NONBLOCK) ? EAGAIN : ENXIO); 2436104515Sphk *(off_t *)addr = (128 << (fd->ft->secsize)) * fd->ft->size; 2437104515Sphk return (0); 2438104515Sphk 2439104515Sphk case DIOCGSECTORSIZE: 2440119984Snyan if (fd->ft == 0) 2441119984Snyan return ((fd->flags & FD_NONBLOCK) ? EAGAIN : ENXIO); 2442104515Sphk *(u_int *)addr = 128 << (fd->ft->secsize); 2443104515Sphk return (0); 2444104515Sphk 244588011Snyan case FIONBIO: 244688011Snyan if (*(int *)addr != 0) 244788011Snyan fd->flags |= FD_NONBLOCK; 244888011Snyan else { 244988011Snyan if (fd->ft == 0) { 245088011Snyan /* 245188011Snyan * No drive type has been selected yet, 245288011Snyan * cannot turn FNONBLOCK off. 245388011Snyan */ 245488011Snyan return (EINVAL); 245588011Snyan } 245688011Snyan fd->flags &= ~FD_NONBLOCK; 245788011Snyan } 245888011Snyan return (0); 245988011Snyan 246088011Snyan case FIOASYNC: 246188011Snyan /* keep the generic fcntl() code happy */ 246288011Snyan return (0); 246388011Snyan 246488011Snyan case FD_GTYPE: /* get drive type */ 246588011Snyan if (fd->ft == 0) 246688011Snyan /* no type known yet, return the native type */ 246788011Snyan *(struct fd_type *)addr = fd_native_types[fd->type]; 246888011Snyan else 246988011Snyan *(struct fd_type *)addr = *fd->ft; 247088011Snyan return (0); 247188011Snyan 247288011Snyan case FD_STYPE: /* set drive type */ 2473128640Snyan /* 2474128640Snyan * Allow setting drive type temporarily iff 2475128640Snyan * currently unset. Used for fdformat so any 2476128640Snyan * user can set it, and then start formatting. 2477128640Snyan */ 2478128640Snyan if (fd->ft) 2479128640Snyan return (EINVAL); /* already set */ 2480126289Snyan fd->fts[0] = *(struct fd_type *)addr; 2481128640Snyan fd->ft = &fd->fts[0]; 2482128640Snyan fd->flags |= FD_UA; 248388011Snyan return (0); 248488011Snyan 248588011Snyan case FD_GOPTS: /* get drive options */ 2486126289Snyan *(int *)addr = fd->options + FDOPT_AUTOSEL; 248788011Snyan return (0); 248888011Snyan 248988011Snyan case FD_SOPTS: /* set drive options */ 249088011Snyan fd->options = *(int *)addr & ~FDOPT_AUTOSEL; 249188011Snyan return (0); 249288011Snyan 249388011Snyan#ifdef FDC_DEBUG 249488011Snyan case FD_DEBUG: 249588011Snyan if ((fd_debug != 0) != (*(int *)addr != 0)) { 249688011Snyan fd_debug = (*(int *)addr != 0); 249788011Snyan printf("fd%d: debugging turned %s\n", 249888011Snyan fd->fdu, fd_debug ? "on" : "off"); 249988011Snyan } 250088011Snyan return (0); 250188011Snyan#endif 250288011Snyan 250388011Snyan case FD_CLRERR: 2504164033Srwatson if (priv_check(td, PRIV_DRIVER) != 0) 250588011Snyan return (EPERM); 250688011Snyan fd->fdc->fdc_errs = 0; 250788011Snyan return (0); 250888011Snyan 250988011Snyan case FD_GSTAT: 251088011Snyan fsp = (struct fdc_status *)addr; 251188011Snyan if ((fd->fdc->flags & FDC_STAT_VALID) == 0) 251288011Snyan return (EINVAL); 251388011Snyan memcpy(fsp->status, fd->fdc->status, 7 * sizeof(u_int)); 251488011Snyan return (0); 251588011Snyan 251688011Snyan case FD_GDTYPE: 251788011Snyan *(enum fd_drivetype *)addr = fd->type; 251888011Snyan return (0); 251988011Snyan } 252088011Snyan 252188011Snyan /* 252288011Snyan * Now handle everything else. Make sure we have a valid 252388011Snyan * drive type. 252488011Snyan */ 252588011Snyan if (fd->flags & FD_NONBLOCK) 252688011Snyan return (EAGAIN); 252788011Snyan if (fd->ft == 0) 252888011Snyan return (ENXIO); 252983548Snyan error = 0; 253083548Snyan 253145783Skato switch (cmd) { 253216359Sasami 253316359Sasami case FD_FORM: 253445783Skato if ((flag & FWRITE) == 0) 253583548Snyan return (EBADF); /* must be opened for writing */ 253683548Snyan if (((struct fd_formb *)addr)->format_version != 253783548Snyan FD_FORMAT_VERSION) 253883548Snyan return (EINVAL); /* wrong version of formatting prog */ 2539104515Sphk error = fdmisccmd(dev, FDBIO_FORMAT, addr); 254016359Sasami break; 254116359Sasami 254216359Sasami case FD_GTYPE: /* get drive type */ 254335336Skato *(struct fd_type *)addr = *fd->ft; 254416359Sasami break; 254516359Sasami 254616359Sasami case FD_STYPE: /* set drive type */ 254716359Sasami /* this is considered harmful; only allow for superuser */ 2548164033Srwatson if (priv_check(td, PRIV_DRIVER) != 0) 254983548Snyan return (EPERM); 255035336Skato *fd->ft = *(struct fd_type *)addr; 255116359Sasami break; 255216359Sasami 255316359Sasami case FD_GOPTS: /* get drive options */ 255435336Skato *(int *)addr = fd->options; 255516359Sasami break; 255616359Sasami 255716359Sasami case FD_SOPTS: /* set drive options */ 255835336Skato fd->options = *(int *)addr; 255916359Sasami break; 256016359Sasami 256183548Snyan#ifdef FDC_DEBUG 256283548Snyan case FD_DEBUG: 256383548Snyan if ((fd_debug != 0) != (*(int *)addr != 0)) { 256483548Snyan fd_debug = (*(int *)addr != 0); 256583548Snyan printf("fd%d: debugging turned %s\n", 256683548Snyan fd->fdu, fd_debug ? "on" : "off"); 256783548Snyan } 256883548Snyan break; 256983548Snyan#endif 257083548Snyan 257176615Skato case FD_CLRERR: 2572164033Srwatson if (priv_check(td, PRIV_DRIVER) != 0) 257383548Snyan return (EPERM); 257476615Skato fd->fdc->fdc_errs = 0; 257576615Skato break; 257676615Skato 257776615Skato case FD_GSTAT: 257876615Skato fsp = (struct fdc_status *)addr; 257976615Skato if ((fd->fdc->flags & FDC_STAT_VALID) == 0) 258083548Snyan return (EINVAL); 258176615Skato memcpy(fsp->status, fd->fdc->status, 7 * sizeof(u_int)); 258276615Skato break; 258376615Skato 258483548Snyan case FD_READID: 258583548Snyan rid = (struct fdc_readid *)addr; 258683548Snyan if (rid->cyl > MAX_CYLINDER || rid->head > MAX_HEAD) 258783548Snyan return (EINVAL); 2588104515Sphk error = fdmisccmd(dev, FDBIO_RDSECTID, addr); 258983548Snyan break; 259083548Snyan 259116359Sasami default: 259216359Sasami error = ENOTTY; 259316359Sasami break; 259416359Sasami } 259516359Sasami return (error); 259616359Sasami} 2597