xref: /minix/minix/drivers/storage/floppy/floppy.c (revision 433d6423)
1 /* This file contains the device dependent part of the driver for the Floppy
2  * Disk Controller (FDC) using the NEC PD765 chip.
3  *
4  * The file contains two entry points:
5  *
6  *   floppy_task:   main entry when system is brought up
7  *
8  * Changes:
9  *   Sep 11, 2005   code cleanup (Andy Tanenbaum)
10  *   Dec 01, 2004   floppy driver moved to user-space (Jorrit N. Herder)
11  *   Sep 15, 2004   sync alarms/ local timer management  (Jorrit N. Herder)
12  *   Aug 12, 2003   null seek no interrupt fix  (Mike Haertel)
13  *   May 14, 2000   d-d/i rewrite  (Kees J. Bot)
14  *   Apr 04, 1992   device dependent/independent split  (Kees J. Bot)
15  *   Mar 27, 1992   last details on density checking  (Kees J. Bot)
16  *   Feb 14, 1992   check drive density on opens only  (Andy Tanenbaum)
17  *	     1991   len[] / motors / reset / step rate / ...  (Bruce Evans)
18  *   May 13, 1991   renovated the errors loop  (Don Chapman)
19  *           1989   I/O vector to keep up with 1-1 interleave  (Bruce Evans)
20  *   Jan 06, 1988   allow 1.44 MB diskettes  (Al Crew)
21  *   Nov 28, 1986   better resetting for 386  (Peter Kay)
22  *   Oct 27, 1986   fdc_results fixed for 8 MHz  (Jakob Schripsema)
23  */
24 
25 #include "floppy.h"
26 #include <minix/timers.h>
27 #include <machine/diskparm.h>
28 #include <minix/sysutil.h>
29 #include <minix/syslib.h>
30 #include <minix/endpoint.h>
31 #include <stdio.h>
32 
33 /* I/O Ports used by floppy disk task. */
34 #define DOR            0x3F2	/* motor drive control bits */
35 #define FDC_STATUS     0x3F4	/* floppy disk controller status register */
36 #define FDC_DATA       0x3F5	/* floppy disk controller data register */
37 #define FDC_RATE       0x3F7	/* transfer rate register */
38 #define DMA_ADDR       0x004	/* port for low 16 bits of DMA address */
39 #define DMA_TOP        0x081	/* port for top 8 bits of 24-bit DMA addr */
40 #define DMA_COUNT      0x005	/* port for DMA count (count =  bytes - 1) */
41 #define DMA_FLIPFLOP   0x00C	/* DMA byte pointer flip-flop */
42 #define DMA_MODE       0x00B	/* DMA mode port */
43 #define DMA_INIT       0x00A	/* DMA init port */
44 #define DMA_RESET_VAL  0x006
45 
46 #define DMA_ADDR_MASK  0xFFFFFF	/* mask to verify DMA address is 24-bit */
47 
48 /* Status registers returned as result of operation. */
49 #define ST0             0x00	/* status register 0 */
50 #define ST1             0x01	/* status register 1 */
51 #define ST2             0x02	/* status register 2 */
52 #define ST3             0x00	/* status register 3 (return by DRIVE_SENSE) */
53 #define ST_CYL          0x03	/* slot where controller reports cylinder */
54 #define ST_HEAD         0x04	/* slot where controller reports head */
55 #define ST_SEC          0x05	/* slot where controller reports sector */
56 #define ST_PCN          0x01	/* slot where controller reports present cyl */
57 
58 /* Fields within the I/O ports. */
59 /* Main status register. */
60 #define CTL_BUSY        0x10	/* bit is set when read or write in progress */
61 #define DIRECTION       0x40	/* bit is set when reading data reg is valid */
62 #define MASTER          0x80	/* bit is set when data reg can be accessed */
63 
64 /* Digital output port (DOR). */
65 #define MOTOR_SHIFT        4	/* high 4 bits control the motors in DOR */
66 #define ENABLE_INT      0x0C	/* used for setting DOR port */
67 
68 /* ST0. */
69 #define ST0_BITS_TRANS  0xD8	/* check 4 bits of status */
70 #define TRANS_ST0       0x00	/* 4 bits of ST0 for READ/WRITE */
71 #define ST0_BITS_SEEK   0xF8	/* check top 5 bits of seek status */
72 #define SEEK_ST0        0x20	/* top 5 bits of ST0 for SEEK */
73 
74 /* ST1. */
75 #define BAD_SECTOR      0x05	/* if these bits are set in ST1, recalibrate */
76 #define WRITE_PROTECT   0x02	/* bit is set if diskette is write protected */
77 
78 /* ST2. */
79 #define BAD_CYL         0x1F	/* if any of these bits are set, recalibrate */
80 
81 /* ST3 (not used). */
82 #define ST3_FAULT       0x80	/* if this bit is set, drive is sick */
83 #define ST3_WR_PROTECT  0x40	/* set when diskette is write protected */
84 #define ST3_READY       0x20	/* set when drive is ready */
85 
86 /* Floppy disk controller command bytes. */
87 #define FDC_SEEK        0x0F	/* command the drive to seek */
88 #define FDC_READ        0xE6	/* command the drive to read */
89 #define FDC_WRITE       0xC5	/* command the drive to write */
90 #define FDC_SENSE       0x08	/* command the controller to tell its status */
91 #define FDC_RECALIBRATE 0x07	/* command the drive to go to cyl 0 */
92 #define FDC_SPECIFY     0x03	/* command the drive to accept params */
93 #define FDC_READ_ID     0x4A	/* command the drive to read sector identity */
94 #define FDC_FORMAT      0x4D	/* command the drive to format a track */
95 
96 /* DMA channel commands. */
97 #define DMA_READ        0x46	/* DMA read opcode */
98 #define DMA_WRITE       0x4A	/* DMA write opcode */
99 
100 /* Parameters for the disk drive. */
101 #define HC_SIZE         2880	/* # sectors on largest legal disk (1.44MB) */
102 #define NR_HEADS        0x02	/* two heads (i.e., two tracks/cylinder) */
103 #define MAX_SECTORS	  18	/* largest # sectors per track */
104 #define DTL             0xFF	/* determines data length (sector size) */
105 #define SPEC2           0x02	/* second parameter to SPECIFY */
106 #define MOTOR_OFF (3*system_hz)	/* how long to wait before stopping motor */
107 #define WAKEUP	  (2*system_hz)	/* timeout on I/O, FDC won't quit. */
108 
109 /* Error codes */
110 #define ERR_SEEK         (-1)	/* bad seek */
111 #define ERR_TRANSFER     (-2)	/* bad transfer */
112 #define ERR_STATUS       (-3)	/* something wrong when getting status */
113 #define ERR_READ_ID      (-4)	/* bad read id */
114 #define ERR_RECALIBRATE  (-5)	/* recalibrate didn't work properly */
115 #define ERR_DRIVE        (-6)	/* something wrong with a drive */
116 #define ERR_WR_PROTECT   (-7)	/* diskette is write protected */
117 #define ERR_TIMEOUT      (-8)	/* interrupt timeout */
118 
119 /* No retries on some errors. */
120 #define err_no_retry(err)	((err) <= ERR_WR_PROTECT)
121 
122 /* Encoding of drive type in minor device number. */
123 #define DEV_TYPE_BITS   0x7C	/* drive type + 1, if nonzero */
124 #define DEV_TYPE_SHIFT     2	/* right shift to normalize type bits */
125 #define FORMAT_DEV_BIT  0x80	/* bit in minor to turn write into format */
126 
127 /* Miscellaneous. */
128 #define MAX_ERRORS         6	/* how often to try rd/wt before quitting */
129 #define MAX_RESULTS        7	/* max number of bytes controller returns */
130 #define NR_DRIVES          2	/* maximum number of drives */
131 #define DIVISOR          128	/* used for sector size encoding */
132 #define SECTOR_SIZE_CODE   2	/* code to say "512" to the controller */
133 #define TIMEOUT_MICROS   5000000L	/* microseconds waiting for FDC */
134 #define NT                 7	/* number of diskette/drive combinations */
135 #define UNCALIBRATED       0	/* drive needs to be calibrated at next use */
136 #define CALIBRATED         1	/* no calibration needed */
137 #define BASE_SECTOR        1	/* sectors are numbered starting at 1 */
138 #define NO_SECTOR ((unsigned) -1)	/* current sector unknown */
139 #define NO_CYL		 (-1)	/* current cylinder unknown, must seek */
140 #define NO_DENS		 100	/* current media unknown */
141 #define BSY_IDLE	   0	/* busy doing nothing */
142 #define BSY_IO		   1	/* busy doing I/O */
143 #define BSY_WAKEN	   2	/* got a wakeup call */
144 
145 /* Seven combinations of diskette/drive are supported.
146  *
147  * # Diskette Drive  Sectors  Tracks   Rotation Data-rate  Comment
148  * 0   360K    360K     9       40     300 RPM  250 kbps   Standard PC DSDD
149  * 1   1.2M    1.2M    15       80     360 RPM  500 kbps   AT disk in AT drive
150  * 2   360K    720K     9       40     300 RPM  250 kbps   Quad density PC
151  * 3   720K    720K     9       80     300 RPM  250 kbps   Toshiba, et al.
152  * 4   360K    1.2M     9       40     360 RPM  300 kbps   PC disk in AT drive
153  * 5   720K    1.2M     9       80     360 RPM  300 kbps   Toshiba in AT drive
154  * 6   1.44M   1.44M   18	80     300 RPM  500 kbps   PS/2, et al.
155  *
156  * In addition, 720K diskettes can be read in 1.44MB drives, but that does
157  * not need a different set of parameters.  This combination uses
158  *
159  * 3   720K    1.44M    9       80     300 RPM  250 kbps   PS/2, et al.
160  */
161 static struct density {
162 	u8_t	secpt;		/* sectors per track */
163 	u8_t	cyls;		/* tracks per side */
164 	u8_t	steps;		/* steps per cylinder (2 = double step) */
165 	u8_t	test;		/* sector to try for density test */
166 	u8_t	rate;		/* data rate (2=250, 1=300, 0=500 kbps) */
167 	clock_t	start_ms;	/* motor start (milliseconds) */
168 	u8_t	gap;		/* gap size */
169 	u8_t	spec1;		/* first specify byte (SRT/HUT) */
170 } fdensity[NT] = {
171 	{  9, 40, 1, 4*9, 2, 500, 0x2A, 0xDF },	/*  360K / 360K  */
172 	{ 15, 80, 1,  14, 0, 500, 0x1B, 0xDF },	/*  1.2M / 1.2M  */
173 	{  9, 40, 2, 2*9, 2, 500, 0x2A, 0xDF },	/*  360K / 720K  */
174 	{  9, 80, 1, 4*9, 2, 750, 0x2A, 0xDF },	/*  720K / 720K  */
175 	{  9, 40, 2, 2*9, 1, 500, 0x23, 0xDF },	/*  360K / 1.2M  */
176 	{  9, 80, 1, 4*9, 1, 500, 0x23, 0xDF },	/*  720K / 1.2M  */
177 	{ 18, 80, 1,  17, 0, 750, 0x1B, 0xCF },	/* 1.44M / 1.44M */
178 };
179 
180 /* The following table is used with the test_sector array to recognize a
181  * drive/floppy combination.  The sector to test has been determined by
182  * looking at the differences in gap size, sectors/track, and double stepping.
183  * This means that types 0 and 3 can't be told apart, only the motor start
184  * time differs.  If a read test succeeds then the drive is limited to the
185  * set of densities it can support to avoid unnecessary tests in the future.
186  */
187 
188 #define b(d)	(1 << (d))	/* bit for density d. */
189 
190 static struct test_order {
191 	u8_t	t_density;	/* floppy/drive type */
192 	u8_t	t_class;	/* limit drive to this class of densities */
193 } test_order[NT-1] = {
194 	{ 6,  b(3) | b(6) },		/* 1.44M  {720K, 1.44M} */
195 	{ 1,  b(1) | b(4) | b(5) },	/* 1.2M   {1.2M, 360K, 720K} */
196 	{ 3,  b(2) | b(3) | b(6) },	/* 720K   {360K, 720K, 1.44M} */
197 	{ 4,  b(1) | b(4) | b(5) },	/* 360K   {1.2M, 360K, 720K} */
198 	{ 5,  b(1) | b(4) | b(5) },	/* 720K   {1.2M, 360K, 720K} */
199 	{ 2,  b(2) | b(3) },		/* 360K   {360K, 720K} */
200 	/* Note that type 0 is missing, type 3 can read/write it too, which is
201 	 * why the type 3 parameters have been pessimized to be like type 0.
202 	 */
203 };
204 
205 /* Variables. */
206 static struct floppy {		/* main drive struct, one entry per drive */
207   unsigned fl_curcyl;		/* current cylinder */
208   unsigned fl_hardcyl;		/* hardware cylinder, as opposed to: */
209   unsigned fl_cylinder;		/* cylinder number addressed */
210   unsigned fl_sector;		/* sector addressed */
211   unsigned fl_head;		/* head number addressed */
212   char fl_calibration;		/* CALIBRATED or UNCALIBRATED */
213   u8_t fl_density;		/* NO_DENS = ?, 0 = 360K; 1 = 360K/1.2M; etc.*/
214   u8_t fl_class;		/* bitmap for possible densities */
215   minix_timer_t fl_tmr_stop;		/* timer to stop motor */
216   struct device fl_geom;	/* Geometry of the drive */
217   struct device fl_part[NR_PARTITIONS];  /* partition's base & size */
218 } floppy[NR_DRIVES];
219 
220 static int irq_hook_id;	/* id of irq hook at the kernel */
221 int motor_status;	/* bitmap of current motor status */
222 static int need_reset;		/* set to 1 when controller must be reset */
223 unsigned f_drive;	/* selected drive */
224 static unsigned f_device;	/* selected minor device */
225 static struct floppy *f_fp;	/* current drive */
226 static struct density *f_dp;	/* current density parameters */
227 static struct density *prev_dp;/* previous density parameters */
228 static unsigned f_sectors;	/* equal to f_dp->secpt (needed a lot) */
229 u16_t f_busy;		/* BSY_IDLE, BSY_IO, BSY_WAKEN */
230 static struct device *f_dv;	/* device's base and size */
231 static struct disk_parameter_s fmt_param; /* parameters for format */
232 static u8_t f_results[MAX_RESULTS];/* the controller can give lots of output */
233 
234 /* The floppy uses various timers. These are managed by the floppy driver
235  * itself, because only a single synchronous alarm is available per process.
236  * Besides the 'f_tmr_timeout' timer below, the floppy structure for each
237  * floppy disk drive contains a 'fl_tmr_stop' timer.
238  */
239 static minix_timer_t f_tmr_timeout;		/* timer for various timeouts */
240 static u32_t system_hz;		/* system clock frequency */
241 static void f_expire_tmrs(clock_t stamp);
242 static void stop_motor(minix_timer_t *tp);
243 static void f_timeout(minix_timer_t *tp);
244 
245 static struct device *f_prepare(devminor_t device);
246 static struct device *f_part(devminor_t minor);
247 static void f_cleanup(void);
248 static ssize_t f_transfer(devminor_t minor, int do_write, u64_t position,
249 	endpoint_t proc_nr, iovec_t *iov, unsigned int nr_req, int flags);
250 static int dma_setup(int do_write);
251 static void start_motor(void);
252 static int seek(void);
253 static int fdc_transfer(int do_write);
254 static int fdc_results(void);
255 static int fdc_command(const u8_t *cmd, int len);
256 static void fdc_out(int val);
257 static int recalibrate(void);
258 static void f_reset(void);
259 static int f_intr_wait(void);
260 static int read_id(void);
261 static int f_do_open(devminor_t minor, int access);
262 static int f_do_close(devminor_t minor);
263 static int test_read(int density);
264 static void f_geometry(devminor_t minor, struct part_geom *entry);
265 
266 /* Entry points to this driver. */
267 static struct blockdriver f_dtab = {
268   .bdr_type	= BLOCKDRIVER_TYPE_DISK,	/* handle partition requests */
269   .bdr_open	= f_do_open,	/* open request, sense type of diskette */
270   .bdr_close	= f_do_close,	/* nothing on a close */
271   .bdr_transfer	= f_transfer,	/* do the I/O */
272   .bdr_cleanup	= f_cleanup,	/* cleanup before sending reply to caller */
273   .bdr_part	= f_part,	/* return partition information structure */
274   .bdr_geometry	= f_geometry,	/* tell the geometry of the diskette */
275   .bdr_alarm	= f_expire_tmrs /* expire all alarm timers */
276 };
277 
278 static char *floppy_buf;
279 static phys_bytes floppy_buf_phys;
280 
281 /* SEF functions and variables. */
282 static void sef_local_startup(void);
283 static int sef_cb_init_fresh(int type, sef_init_info_t *info);
284 static void sef_cb_signal_handler(int signo);
285 EXTERN int sef_cb_lu_prepare(int state);
286 EXTERN int sef_cb_lu_state_isvalid(int state);
287 EXTERN void sef_cb_lu_state_dump(int state);
288 int last_was_write;
289 
290 /*===========================================================================*
291  *				floppy_task				     *
292  *===========================================================================*/
293 int main(void)
294 {
295   /* SEF local startup. */
296   sef_local_startup();
297 
298   /* Call the generic receive loop. */
299   blockdriver_task(&f_dtab);
300 
301   return(OK);
302 }
303 
304 /*===========================================================================*
305  *			       sef_local_startup			     *
306  *===========================================================================*/
307 static void sef_local_startup(void)
308 {
309   /* Register init callbacks. */
310   sef_setcb_init_fresh(sef_cb_init_fresh);
311   sef_setcb_init_lu(sef_cb_init_fresh);
312 
313   /* Register live update callbacks. */
314   sef_setcb_lu_prepare(sef_cb_lu_prepare);
315   sef_setcb_lu_state_isvalid(sef_cb_lu_state_isvalid);
316   sef_setcb_lu_state_dump(sef_cb_lu_state_dump);
317 
318   /* Register signal callbacks. */
319   sef_setcb_signal_handler(sef_cb_signal_handler);
320 
321   /* Let SEF perform startup. */
322   sef_startup();
323 }
324 
325 /*===========================================================================*
326  *		            sef_cb_init_fresh                                *
327  *===========================================================================*/
328 static int sef_cb_init_fresh(int type, sef_init_info_t *UNUSED(info))
329 {
330 /* Initialize the floppy driver. */
331   struct floppy *fp;
332   int s;
333 
334   /* Initialize the floppy structure and the timers. */
335   system_hz = sys_hz();
336 
337   if(!(floppy_buf = alloc_contig(2*DMA_BUF_SIZE,
338 	AC_LOWER16M | AC_ALIGN4K, &floppy_buf_phys)))
339   	panic("couldn't allocate dma buffer");
340 
341   init_timer(&f_tmr_timeout);
342 
343   for (fp = &floppy[0]; fp < &floppy[NR_DRIVES]; fp++) {
344 	fp->fl_curcyl = NO_CYL;
345 	fp->fl_density = NO_DENS;
346 	fp->fl_class = ~0;
347 	init_timer(&fp->fl_tmr_stop);
348   }
349 
350   /* Set IRQ policy, only request notifications, do not automatically
351    * reenable interrupts. ID return on interrupt is the IRQ line number.
352    */
353   irq_hook_id = FLOPPY_IRQ;
354   if ((s=sys_irqsetpolicy(FLOPPY_IRQ, 0, &irq_hook_id )) != OK)
355   	panic("Couldn't set IRQ policy: %d", s);
356   if ((s=sys_irqenable(&irq_hook_id)) != OK)
357   	panic("Couldn't enable IRQs: %d", s);
358 
359   /* Announce we are up! */
360   blockdriver_announce(type);
361 
362   return(OK);
363 }
364 
365 /*===========================================================================*
366  *		           sef_cb_signal_handler                             *
367  *===========================================================================*/
368 static void sef_cb_signal_handler(int signo)
369 {
370   int s;
371 
372   /* Only check for termination signal, ignore anything else. */
373   if (signo != SIGTERM) return;
374 
375   /* Stop all activity and cleanly exit with the system. */
376   if ((s=sys_outb(DOR, ENABLE_INT)) != OK)
377       panic("Sys_outb failed: %d", s);
378   exit(0);
379 }
380 
381 /*===========================================================================*
382  *				f_expire_tmrs				     *
383  *===========================================================================*/
384 static void f_expire_tmrs(clock_t stamp)
385 {
386 /* A synchronous alarm message was received. Call the watchdog function for
387  * each expired timer, if any.
388  */
389 
390   expire_timers(stamp);
391 }
392 
393 /*===========================================================================*
394  *				f_prepare				     *
395  *===========================================================================*/
396 static struct device *f_prepare(devminor_t device)
397 {
398 /* Prepare for I/O on a device. */
399 
400   f_device = device;
401   f_drive = device & ~(DEV_TYPE_BITS | FORMAT_DEV_BIT);
402   if (device < 0 || f_drive >= NR_DRIVES) return(NULL);
403 
404   f_fp = &floppy[f_drive];
405   f_dv = &f_fp->fl_geom;
406   if (f_fp->fl_density < NT) {
407 	f_dp = &fdensity[f_fp->fl_density];
408 	f_sectors = f_dp->secpt;
409 	f_fp->fl_geom.dv_size = (u64_t)(NR_HEADS * f_sectors * f_dp->cyls) *
410 								SECTOR_SIZE;
411   }
412 
413   /* A partition? */
414   if ((device &= DEV_TYPE_BITS) >= MINOR_fd0p0)
415 	f_dv = &f_fp->fl_part[(device - MINOR_fd0p0) >> DEV_TYPE_SHIFT];
416 
417   return f_dv;
418 }
419 
420 /*===========================================================================*
421  *				f_part					     *
422  *===========================================================================*/
423 static struct device *f_part(devminor_t minor)
424 {
425 /* Return a pointer to the partition information of the given minor device. */
426 
427   return f_prepare(minor);
428 }
429 
430 /*===========================================================================*
431  *				f_cleanup				     *
432  *===========================================================================*/
433 static void f_cleanup(void)
434 {
435   /* Start a timer to turn the motor off in a few seconds. */
436   set_timer(&f_fp->fl_tmr_stop, MOTOR_OFF, stop_motor, f_drive);
437 
438   /* Exiting the floppy driver, so forget where we are. */
439   f_fp->fl_sector = NO_SECTOR;
440 }
441 
442 /*===========================================================================*
443  *				f_transfer				     *
444  *===========================================================================*/
445 static ssize_t f_transfer(
446   devminor_t minor,		/* minor device number */
447   int do_write,			/* read or write? */
448   u64_t pos64,			/* offset on device to read or write */
449   endpoint_t proc_nr,		/* process doing the request */
450   iovec_t *iov,			/* pointer to read or write request vector */
451   unsigned int nr_req,		/* length of request vector */
452   int UNUSED(flags)		/* transfer flags */
453 )
454 {
455 #define NO_OFFSET -1
456   struct floppy *fp;
457   iovec_t *iop, *iov_end = iov + nr_req;
458   int s, r, errors, nr;
459   unsigned block, nbytes, count, chunk, sector;
460   u64_t dv_size;
461   vir_bytes user_offset, iov_offset = 0, iop_offset;
462   unsigned long position;
463   signed long uoffsets[MAX_SECTORS], *up;
464   cp_grant_id_t ugrants[MAX_SECTORS], *ug = NULL;
465   u8_t cmd[3];
466   ssize_t total;
467 
468   if (f_prepare(minor) == NULL) return(ENXIO);
469 
470   fp = f_fp;
471   dv_size = f_dv->dv_size;
472 
473   if (ex64hi(pos64) != 0)
474 	return OK;	/* Way beyond EOF */
475   position= pos64;
476   total = 0;
477 
478   /* Record the direction of the last transfer performed. */
479   last_was_write = do_write;
480 
481   /* Check disk address. */
482   if ((position & SECTOR_MASK) != 0) return(EINVAL);
483 
484 #if 0	/* XXX hack to create a disk driver that crashes */
485   { static int count= 0; if (++count > 10) {
486 	printf("floppy: time to die\n"); *(int *)-1= 42;
487   }}
488 #endif
489 
490   errors = 0;
491   while (nr_req > 0) {
492 	/* How many bytes to transfer? */
493 	nbytes = 0;
494 	for (iop = iov; iop < iov_end; iop++) nbytes += iop->iov_size;
495 
496 	/* Which block on disk and how close to EOF? */
497 	if (position >= dv_size) return(total);		/* At EOF */
498 	if (position + nbytes > dv_size) nbytes = dv_size - position;
499 	block = (unsigned long)((f_dv->dv_base + position) / SECTOR_SIZE);
500 
501 	if ((nbytes & SECTOR_MASK) != 0) return(EINVAL);
502 
503 	/* Using a formatting device? */
504 	if (f_device & FORMAT_DEV_BIT) {
505 		if (!do_write) return(EIO);
506 		if (iov->iov_size < SECTOR_SIZE + sizeof(fmt_param))
507 			return(EINVAL);
508 
509 		if(proc_nr != SELF) {
510 		   s=sys_safecopyfrom(proc_nr, iov->iov_addr,
511 			SECTOR_SIZE + iov_offset, (vir_bytes) &fmt_param,
512 			(phys_bytes) sizeof(fmt_param));
513 		   if(s != OK)
514 			panic("sys_safecopyfrom failed: %d", s);
515 		} else {
516 			memcpy(&fmt_param, (void *) (iov->iov_addr +
517 				SECTOR_SIZE + iov_offset),
518 				(phys_bytes) sizeof(fmt_param));
519 		}
520 
521 		/* Check that the number of sectors in the data is reasonable,
522 		 * to avoid division by 0.  Leave checking of other data to
523 		 * the FDC.
524 		 */
525 		if (fmt_param.sectors_per_cylinder == 0) return(EIO);
526 
527 		/* Only the first sector of the parameters now needed. */
528 		iov->iov_size = nbytes = SECTOR_SIZE;
529 	}
530 
531 	/* Only try one sector if there were errors. */
532 	if (errors > 0) nbytes = SECTOR_SIZE;
533 
534 	/* Compute cylinder and head of the track to access. */
535 	fp->fl_cylinder = block / (NR_HEADS * f_sectors);
536 	fp->fl_hardcyl = fp->fl_cylinder * f_dp->steps;
537 	fp->fl_head = (block % (NR_HEADS * f_sectors)) / f_sectors;
538 
539 	/* For each sector on this track compute the user address it is to
540 	 * go or to come from.
541 	 */
542 	for (up = uoffsets; up < uoffsets + MAX_SECTORS; up++) *up = NO_OFFSET;
543 	count = 0;
544 	iop = iov;
545 	sector = block % f_sectors;
546 	nr = 0;
547 	iop_offset = iov_offset;
548 	for (;;) {
549 		nr++;
550 		user_offset = iop_offset;
551 		chunk = iop->iov_size;
552 		if ((chunk & SECTOR_MASK) != 0) return(EINVAL);
553 
554 		while (chunk > 0) {
555 			ugrants[sector] = iop->iov_addr;
556 			uoffsets[sector++] = user_offset;
557 			chunk -= SECTOR_SIZE;
558 			user_offset += SECTOR_SIZE;
559 			count += SECTOR_SIZE;
560 			if (sector == f_sectors || count == nbytes)
561 				goto track_set_up;
562 		}
563 		iop_offset = 0;
564 		iop++;
565 	}
566   track_set_up:
567 
568 	/* First check to see if a reset is needed. */
569 	if (need_reset) f_reset();
570 
571 	/* See if motor is running; if not, turn it on and wait. */
572 	start_motor();
573 
574 	/* Set the stepping rate and data rate */
575 	if (f_dp != prev_dp) {
576 		cmd[0] = FDC_SPECIFY;
577 		cmd[1] = f_dp->spec1;
578 		cmd[2] = SPEC2;
579 		(void) fdc_command(cmd, 3);
580 		if ((s=sys_outb(FDC_RATE, f_dp->rate)) != OK)
581 			panic("Sys_outb failed: %d", s);
582 		prev_dp = f_dp;
583 	}
584 
585 	/* If we are going to a new cylinder, perform a seek. */
586 	r = seek();
587 
588 	/* Avoid read_id() if we don't plan to read much. */
589 	if (fp->fl_sector == NO_SECTOR && count < (6 * SECTOR_SIZE))
590 		fp->fl_sector = 0;
591 
592 	for (nbytes = 0; nbytes < count; nbytes += SECTOR_SIZE) {
593 		if (fp->fl_sector == NO_SECTOR) {
594 			/* Find out what the current sector is.  This often
595 			 * fails right after a seek, so try it twice.
596 			 */
597 			if (r == OK && read_id() != OK) r = read_id();
598 		}
599 
600 		/* Look for the next job in uoffsets[] */
601 		if (r == OK) {
602 			for (;;) {
603 				if (fp->fl_sector >= f_sectors)
604 					fp->fl_sector = 0;
605 
606 				up = &uoffsets[fp->fl_sector];
607 				ug = &ugrants[fp->fl_sector];
608 				if (*up != NO_OFFSET) break;
609 				fp->fl_sector++;
610 			}
611 
612 			if (do_write) {
613 				/* Copy the user bytes to the DMA buffer. */
614 				if(proc_nr != SELF) {
615 				   s=sys_safecopyfrom(proc_nr, *ug, *up,
616 					(vir_bytes) floppy_buf,
617 					 (phys_bytes) SECTOR_SIZE);
618 				   if(s != OK)
619 					panic("sys_safecopyfrom failed: %d", s);
620 				} else {
621 				   memcpy(floppy_buf, (void *) (*ug + *up), SECTOR_SIZE);
622 				}
623 			}
624 		}
625 
626 		/* Set up the DMA chip and perform the transfer. */
627 		if (r == OK) {
628 			if (dma_setup(do_write) != OK) {
629 				/* This can only fail for addresses above 16MB
630 				 * that cannot be handled by the controller,
631  				 * because it uses 24-bit addressing.
632 				 */
633 				return(EIO);
634 			}
635 			r = fdc_transfer(do_write);
636 		}
637 
638 		if (r == OK && !do_write) {
639 			/* Copy the DMA buffer to user space. */
640 			if(proc_nr != SELF) {
641 		   	   s=sys_safecopyto(proc_nr, *ug, *up,
642 				(vir_bytes) floppy_buf,
643 			  	 (phys_bytes) SECTOR_SIZE);
644 			if(s != OK)
645 				panic("sys_safecopyto failed: %d", s);
646 			} else {
647 			   memcpy((void *) (*ug + *up), floppy_buf, SECTOR_SIZE);
648 			}
649 		}
650 
651 		if (r != OK) {
652 			/* Don't retry if write protected or too many errors. */
653 			if (err_no_retry(r) || ++errors == MAX_ERRORS) {
654 				return(EIO);
655 			}
656 
657 			/* Recalibrate if halfway. */
658 			if (errors == MAX_ERRORS / 2)
659 				fp->fl_calibration = UNCALIBRATED;
660 
661 			nbytes = 0;
662 			break;		/* retry */
663 		}
664 	}
665 
666 	/* Book the bytes successfully transferred. */
667 	position += nbytes;
668 	total += nbytes;
669 	while (nbytes > 0) {
670 		if (nbytes < iov->iov_size) {
671 			/* Not done with this one yet. */
672 			iov_offset += nbytes;
673 			iov->iov_size -= nbytes;
674 			break;
675 		}
676 		iov_offset = 0;
677 		nbytes -= iov->iov_size;
678 		iov->iov_size = 0;
679 		iov++;
680 		nr_req--;
681 	}
682   }
683   return(total);
684 }
685 
686 /*===========================================================================*
687  *				dma_setup				     *
688  *===========================================================================*/
689 static int dma_setup(int do_write)
690 {
691 /* The IBM PC can perform DMA operations by using the DMA chip.  To use it,
692  * the DMA (Direct Memory Access) chip is loaded with the 20-bit memory address
693  * to be read from or written to, the byte count minus 1, and a read or write
694  * opcode.  This routine sets up the DMA chip.  Note that the chip is not
695  * capable of doing a DMA across a 64K boundary (e.g., you can't read a
696  * 512-byte block starting at physical address 65520).
697  *
698  * Warning! Also note that it's not possible to do DMA above 16 MB because
699  * the ISA bus uses 24-bit addresses. Addresses above 16 MB therefore will
700  * be interpreted modulo 16 MB, dangerously overwriting arbitrary memory.
701  * A check here denies the I/O if the address is out of range.
702  */
703   pvb_pair_t byte_out[9];
704   int s;
705 
706   /* First check the DMA memory address not to exceed maximum. */
707   if (floppy_buf_phys != (floppy_buf_phys & DMA_ADDR_MASK)) {
708 	printf("floppy: DMA denied because address out of range\n");
709 	return(EIO);
710   }
711 
712   /* Set up the DMA registers.  (The comment on the reset is a bit strong,
713    * it probably only resets the floppy channel.)
714    */
715   pv_set(byte_out[0], DMA_INIT, DMA_RESET_VAL);	/* reset the dma controller */
716   pv_set(byte_out[1], DMA_FLIPFLOP, 0);		/* write anything to reset it */
717   pv_set(byte_out[2], DMA_MODE, do_write ? DMA_WRITE : DMA_READ);
718   pv_set(byte_out[3], DMA_ADDR, (unsigned) (floppy_buf_phys >>  0) & 0xff);
719   pv_set(byte_out[4], DMA_ADDR, (unsigned) (floppy_buf_phys >>  8) & 0xff);
720   pv_set(byte_out[5], DMA_TOP,  (unsigned) (floppy_buf_phys >> 16) & 0xff);
721   pv_set(byte_out[6], DMA_COUNT, (((SECTOR_SIZE - 1) >> 0)) & 0xff);
722   pv_set(byte_out[7], DMA_COUNT, (SECTOR_SIZE - 1) >> 8);
723   pv_set(byte_out[8], DMA_INIT, 2);		/* some sort of enable */
724 
725   if ((s=sys_voutb(byte_out, 9)) != OK)
726   	panic("Sys_voutb in dma_setup() failed: %d", s);
727   return(OK);
728 }
729 
730 /*===========================================================================*
731  *				start_motor				     *
732  *===========================================================================*/
733 static void start_motor(void)
734 {
735 /* Control of the floppy disk motors is a big pain.  If a motor is off, you
736  * have to turn it on first, which takes 1/2 second.  You can't leave it on
737  * all the time, since that would wear out the diskette.  However, if you turn
738  * the motor off after each operation, the system performance will be awful.
739  * The compromise used here is to leave it on for a few seconds after each
740  * operation.  If a new operation is started in that interval, it need not be
741  * turned on again.  If no new operation is started, a timer goes off and the
742  * motor is turned off.  I/O port DOR has bits to control each of 4 drives.
743  */
744 
745   int s, motor_bit, running;
746   message mess;
747   int ipc_status;
748 
749   motor_bit = 1 << f_drive;		/* bit mask for this drive */
750   running = motor_status & motor_bit;	/* nonzero if this motor is running */
751   motor_status |= motor_bit;		/* want this drive running too */
752 
753   if ((s=sys_outb(DOR,
754   		(motor_status << MOTOR_SHIFT) | ENABLE_INT | f_drive)) != OK)
755 	panic("Sys_outb in start_motor() failed: %d", s);
756 
757   /* If the motor was already running, we don't have to wait for it. */
758   if (running) return;			/* motor was already running */
759 
760   /* Set an alarm timer to force a timeout if the hardware does not interrupt
761    * in time. Expect an interrupt, but check for a timeout.
762    */
763   set_timer(&f_tmr_timeout, f_dp->start_ms * system_hz / 1000, f_timeout, 0);
764   f_busy = BSY_IO;
765   do {
766 	if ((s = driver_receive(ANY, &mess, &ipc_status)) != OK)
767 		panic("Couldn't receive message: %d", s);
768 
769 	if (is_ipc_notify(ipc_status)) {
770 		switch (_ENDPOINT_P(mess.m_source)) {
771 			case CLOCK:
772 				f_expire_tmrs(mess.m_notify.timestamp);
773 				break;
774 			default :
775 				f_busy = BSY_IDLE;
776 				break;
777 		}
778   	} else {
779   		f_busy = BSY_IDLE;
780   	}
781   } while (f_busy == BSY_IO);
782   f_fp->fl_sector = NO_SECTOR;
783 }
784 
785 /*===========================================================================*
786  *				stop_motor				     *
787  *===========================================================================*/
788 static void stop_motor(minix_timer_t *tp)
789 {
790 /* This routine is called from an alarm timer after several seconds have
791  * elapsed with no floppy disk activity.  It turns the drive motor off.
792  */
793   int s;
794   motor_status &= ~(1 << tmr_arg(tp)->ta_int);
795   if ((s=sys_outb(DOR, (motor_status << MOTOR_SHIFT) | ENABLE_INT)) != OK)
796 	panic("Sys_outb in stop_motor() failed: %d", s);
797 }
798 
799 /*===========================================================================*
800  *				seek					     *
801  *===========================================================================*/
802 static int seek(void)
803 {
804 /* Issue a SEEK command on the indicated drive unless the arm is already
805  * positioned on the correct cylinder.
806  */
807 
808   struct floppy *fp = f_fp;
809   int r;
810   message mess;
811   int ipc_status;
812   u8_t cmd[3];
813 
814   /* Are we already on the correct cylinder? */
815   if (fp->fl_calibration == UNCALIBRATED)
816 	if (recalibrate() != OK) return(ERR_SEEK);
817   if (fp->fl_curcyl == fp->fl_hardcyl) return(OK);
818 
819   /* No.  Wrong cylinder.  Issue a SEEK and wait for interrupt. */
820   cmd[0] = FDC_SEEK;
821   cmd[1] = (fp->fl_head << 2) | f_drive;
822   cmd[2] = fp->fl_hardcyl;
823   if (fdc_command(cmd, 3) != OK) return(ERR_SEEK);
824   if (f_intr_wait() != OK) return(ERR_TIMEOUT);
825 
826   /* Interrupt has been received.  Check drive status. */
827   fdc_out(FDC_SENSE);		/* probe FDC to make it return status */
828   r = fdc_results();		/* get controller status bytes */
829   if (r != OK || (f_results[ST0] & ST0_BITS_SEEK) != SEEK_ST0
830 				|| f_results[ST1] != fp->fl_hardcyl) {
831 	/* seek failed, may need a recalibrate */
832 	return(ERR_SEEK);
833   }
834   /* Give head time to settle on a format, no retrying here! */
835   if (f_device & FORMAT_DEV_BIT) {
836 	/* Set a synchronous alarm to force a timeout if the hardware does
837 	 * not interrupt.
838  	 */
839  	set_timer(&f_tmr_timeout, system_hz/30, f_timeout, 0);
840 	f_busy = BSY_IO;
841   	do {
842 		if ((r = driver_receive(ANY, &mess, &ipc_status)) != OK)
843 			panic("Couldn't receive message: %d", r);
844 
845 		if (is_ipc_notify(ipc_status)) {
846 			switch (_ENDPOINT_P(mess.m_source)) {
847 				case CLOCK:
848 					f_expire_tmrs(mess.m_notify.timestamp);
849 					break;
850 				default :
851 					f_busy = BSY_IDLE;
852 					break;
853 			}
854   		} else {
855   			f_busy = BSY_IDLE;
856   		}
857   	} while (f_busy == BSY_IO);
858   }
859   fp->fl_curcyl = fp->fl_hardcyl;
860   fp->fl_sector = NO_SECTOR;
861   return(OK);
862 }
863 
864 /*===========================================================================*
865  *				fdc_transfer				     *
866  *===========================================================================*/
867 static int fdc_transfer(int do_write)
868 {
869 /* The drive is now on the proper cylinder.  Read, write or format 1 block. */
870 
871   struct floppy *fp = f_fp;
872   int r, s;
873   u8_t cmd[9];
874 
875   /* Never attempt a transfer if the drive is uncalibrated or motor is off. */
876   if (fp->fl_calibration == UNCALIBRATED) return(ERR_TRANSFER);
877   if ((motor_status & (1 << f_drive)) == 0) return(ERR_TRANSFER);
878 
879   /* The command is issued by outputting several bytes to the controller chip.
880    */
881   if (f_device & FORMAT_DEV_BIT) {
882 	cmd[0] = FDC_FORMAT;
883 	cmd[1] = (fp->fl_head << 2) | f_drive;
884 	cmd[2] = fmt_param.sector_size_code;
885 	cmd[3] = fmt_param.sectors_per_cylinder;
886 	cmd[4] = fmt_param.gap_length_for_format;
887 	cmd[5] = fmt_param.fill_byte_for_format;
888 	if (fdc_command(cmd, 6) != OK) return(ERR_TRANSFER);
889   } else {
890 	cmd[0] = do_write ? FDC_WRITE : FDC_READ;
891 	cmd[1] = (fp->fl_head << 2) | f_drive;
892 	cmd[2] = fp->fl_cylinder;
893 	cmd[3] = fp->fl_head;
894 	cmd[4] = BASE_SECTOR + fp->fl_sector;
895 	cmd[5] = SECTOR_SIZE_CODE;
896 	cmd[6] = f_sectors;
897 	cmd[7] = f_dp->gap;	/* sector gap */
898 	cmd[8] = DTL;		/* data length */
899 	if (fdc_command(cmd, 9) != OK) return(ERR_TRANSFER);
900   }
901 
902   /* Block, waiting for disk interrupt. */
903   if (f_intr_wait() != OK) {
904 	printf("fd%u: disk interrupt timed out.\n", f_drive);
905   	return(ERR_TIMEOUT);
906   }
907 
908   /* Get controller status and check for errors. */
909   r = fdc_results();
910   if (r != OK) return(r);
911 
912   if (f_results[ST1] & WRITE_PROTECT) {
913 	printf("fd%u: diskette is write protected.\n", f_drive);
914 	return(ERR_WR_PROTECT);
915   }
916 
917   if ((f_results[ST0] & ST0_BITS_TRANS) != TRANS_ST0) return(ERR_TRANSFER);
918   if (f_results[ST1] | f_results[ST2]) return(ERR_TRANSFER);
919 
920   if (f_device & FORMAT_DEV_BIT) return(OK);
921 
922   /* Compare actual numbers of sectors transferred with expected number. */
923   s =  (f_results[ST_CYL] - fp->fl_cylinder) * NR_HEADS * f_sectors;
924   s += (f_results[ST_HEAD] - fp->fl_head) * f_sectors;
925   s += (f_results[ST_SEC] - BASE_SECTOR - fp->fl_sector);
926   if (s != 1) return(ERR_TRANSFER);
927 
928   /* This sector is next for I/O: */
929   fp->fl_sector = f_results[ST_SEC] - BASE_SECTOR;
930 #if 0
931   if (processor < 386) fp->fl_sector++;		/* Old CPU can't keep up. */
932 #endif
933   return(OK);
934 }
935 
936 /*===========================================================================*
937  *				fdc_results				     *
938  *===========================================================================*/
939 static int fdc_results(void)
940 {
941 /* Extract results from the controller after an operation, then allow floppy
942  * interrupts again.
943  */
944 
945   int s, result_nr;
946   u32_t status;
947   spin_t spin;
948 
949   /* Extract bytes from FDC until it says it has no more.  The loop is
950    * really an outer loop on result_nr and an inner loop on status.
951    * A timeout flag alarm is set.
952    */
953   result_nr = 0;
954   SPIN_FOR(&spin, TIMEOUT_MICROS) {
955 	/* Reading one byte is almost a mirror of fdc_out() - the DIRECTION
956 	 * bit must be set instead of clear, but the CTL_BUSY bit destroys
957 	 * the perfection of the mirror.
958 	 */
959 	if ((s=sys_inb(FDC_STATUS, &status)) != OK)
960 		panic("Sys_inb in fdc_results() failed: %d", s);
961 	status &= (MASTER | DIRECTION | CTL_BUSY);
962 	if (status == (MASTER | DIRECTION | CTL_BUSY)) {
963 		u32_t tmp_r;
964 		if (result_nr >= MAX_RESULTS) break;	/* too many results */
965 		if ((s=sys_inb(FDC_DATA, &tmp_r)) != OK)
966 		   panic("Sys_inb in fdc_results() failed: %d", s);
967 		f_results[result_nr] = tmp_r;
968 		result_nr ++;
969 		continue;
970 	}
971 	if (status == MASTER) {			/* all read */
972 		if ((s=sys_irqenable(&irq_hook_id)) != OK)
973 			panic("Couldn't enable IRQs: %d", s);
974 
975 		return(OK);			/* only good exit */
976 	}
977   }
978   need_reset = TRUE;		/* controller chip must be reset */
979 
980   if ((s=sys_irqenable(&irq_hook_id)) != OK)
981 	panic("Couldn't enable IRQs: %d", s);
982   return(ERR_STATUS);
983 }
984 
985 /*===========================================================================*
986  *				fdc_command				     *
987  *===========================================================================*/
988 static int fdc_command(
989   const u8_t *cmd,	/* command bytes */
990   int len		/* command length */
991 )
992 {
993 /* Output a command to the controller. */
994 
995   /* Set a synchronous alarm to force a timeout if the hardware does
996    * not interrupt.
997    * Note that the actual check is done by the code that issued the
998    * fdc_command() call.
999    */
1000   set_timer(&f_tmr_timeout, WAKEUP, f_timeout, 0);
1001 
1002   f_busy = BSY_IO;
1003   while (len > 0) {
1004 	fdc_out(*cmd++);
1005 	len--;
1006   }
1007   return(need_reset ? ERR_DRIVE : OK);
1008 }
1009 
1010 /*===========================================================================*
1011  *				fdc_out					     *
1012  *===========================================================================*/
1013 static void fdc_out(
1014   int val		/* write this byte to floppy disk controller */
1015 )
1016 {
1017 /* Output a byte to the controller.  This is not entirely trivial, since you
1018  * can only write to it when it is listening, and it decides when to listen.
1019  * If the controller refuses to listen, the FDC chip is given a hard reset.
1020  */
1021   spin_t spin;
1022   int s;
1023   u32_t status;
1024 
1025   if (need_reset) return;	/* if controller is not listening, return */
1026 
1027   /* It may take several tries to get the FDC to accept a command.  */
1028   SPIN_FOR(&spin, TIMEOUT_MICROS) {
1029   	if ((s=sys_inb(FDC_STATUS, &status)) != OK)
1030   		panic("Sys_inb in fdc_out() failed: %d", s);
1031 
1032   	if ((status & (MASTER | DIRECTION)) == (MASTER | 0)) {
1033 		if ((s=sys_outb(FDC_DATA, val)) != OK)
1034 			panic("Sys_outb in fdc_out() failed: %d", s);
1035 
1036 		return;
1037 	}
1038   }
1039 
1040   need_reset = TRUE;	/* hit it over the head */
1041 }
1042 
1043 /*===========================================================================*
1044  *				recalibrate				     *
1045  *===========================================================================*/
1046 static int recalibrate(void)
1047 {
1048 /* The floppy disk controller has no way of determining its absolute arm
1049  * position (cylinder).  Instead, it steps the arm a cylinder at a time and
1050  * keeps track of where it thinks it is (in software).  However, after a
1051  * SEEK, the hardware reads information from the diskette telling where the
1052  * arm actually is.  If the arm is in the wrong place, a recalibration is done,
1053  * which forces the arm to cylinder 0.  This way the controller can get back
1054  * into sync with reality.
1055  */
1056 
1057   struct floppy *fp = f_fp;
1058   int r;
1059   u8_t cmd[2];
1060 
1061   /* Issue the RECALIBRATE command and wait for the interrupt. */
1062   cmd[0] = FDC_RECALIBRATE;	/* tell drive to recalibrate itself */
1063   cmd[1] = f_drive;		/* specify drive */
1064   if (fdc_command(cmd, 2) != OK) return(ERR_SEEK);
1065   if (f_intr_wait() != OK) return(ERR_TIMEOUT);
1066 
1067   /* Determine if the recalibration succeeded. */
1068   fdc_out(FDC_SENSE);		/* issue SENSE command to request results */
1069   r = fdc_results();		/* get results of the FDC_RECALIBRATE command*/
1070   fp->fl_curcyl = NO_CYL;	/* force a SEEK next time */
1071   fp->fl_sector = NO_SECTOR;
1072   if (r != OK ||		/* controller would not respond */
1073      (f_results[ST0] & ST0_BITS_SEEK) != SEEK_ST0 || f_results[ST_PCN] != 0) {
1074 	/* Recalibration failed.  FDC must be reset. */
1075 	need_reset = TRUE;
1076 	return(ERR_RECALIBRATE);
1077   } else {
1078 	/* Recalibration succeeded. */
1079 	fp->fl_calibration = CALIBRATED;
1080 	fp->fl_curcyl = f_results[ST_PCN];
1081 	return(OK);
1082   }
1083 }
1084 
1085 /*===========================================================================*
1086  *				f_reset					     *
1087  *===========================================================================*/
1088 static void f_reset(void)
1089 {
1090 /* Issue a reset to the controller.  This is done after any catastrophe,
1091  * like the controller refusing to respond.
1092  */
1093   pvb_pair_t byte_out[2];
1094   int s,i;
1095   message mess;
1096   int ipc_status;
1097 
1098   /* Disable interrupts and strobe reset bit low. */
1099   need_reset = FALSE;
1100 
1101   /* It is not clear why the next lock is needed.  Writing 0 to DOR causes
1102    * interrupt, while the PC documentation says turning bit 8 off disables
1103    * interrupts.  Without the lock:
1104    *   1) the interrupt handler sets the floppy mask bit in the 8259.
1105    *   2) writing ENABLE_INT to DOR causes the FDC to assert the interrupt
1106    *      line again, but the mask stops the cpu being interrupted.
1107    *   3) the sense interrupt clears the interrupt (not clear which one).
1108    * and for some reason the reset does not work.
1109    */
1110   (void) fdc_command((u8_t *) 0, 0);   /* need only the timer */
1111   motor_status = 0;
1112   pv_set(byte_out[0], DOR, 0);			/* strobe reset bit low */
1113   pv_set(byte_out[1], DOR, ENABLE_INT);		/* strobe it high again */
1114   if ((s=sys_voutb(byte_out, 2)) != OK)
1115   	panic("Sys_voutb in f_reset() failed: %d", s);
1116 
1117   /* A synchronous alarm timer was set in fdc_command. Expect an interrupt,
1118    * but be prepared to handle a timeout.
1119    */
1120   do {
1121 	if ((s = driver_receive(ANY, &mess, &ipc_status)) != OK)
1122 		panic("Couldn't receive message: %d", s);
1123 	if (is_ipc_notify(ipc_status)) {
1124 		switch (_ENDPOINT_P(mess.m_source)) {
1125 			case CLOCK:
1126 				f_expire_tmrs(mess.m_notify.timestamp);
1127 				break;
1128 			default :
1129 				f_busy = BSY_IDLE;
1130 				break;
1131 		}
1132   	} else {			/* expect hw interrupt */
1133   		f_busy = BSY_IDLE;
1134   	}
1135   } while (f_busy == BSY_IO);
1136 
1137   /* The controller supports 4 drives and returns a result for each of them.
1138    * Collect all the results now.  The old version only collected the first
1139    * result.  This happens to work for 2 drives, but it doesn't work for 3
1140    * or more drives, at least with only drives 0 and 2 actually connected
1141    * (the controller generates an extra interrupt for the middle drive when
1142    * drive 2 is accessed and the driver panics).
1143    *
1144    * It would be better to keep collecting results until there are no more.
1145    * For this, fdc_results needs to return the number of results (instead
1146    * of OK) when it succeeds.
1147    */
1148   for (i = 0; i < 4; i++) {
1149 	fdc_out(FDC_SENSE);	/* probe FDC to make it return status */
1150 	(void) fdc_results();	/* flush controller */
1151   }
1152   for (i = 0; i < NR_DRIVES; i++)	/* clear each drive */
1153 	floppy[i].fl_calibration = UNCALIBRATED;
1154 
1155   /* The current timing parameters must be specified again. */
1156   prev_dp = NULL;
1157 }
1158 
1159 /*===========================================================================*
1160  *				f_intr_wait				     *
1161  *===========================================================================*/
1162 static int f_intr_wait(void)
1163 {
1164 /* Wait for an interrupt, but not forever.  The FDC may have all the time of
1165  * the world, but we humans do not.
1166  */
1167   message mess;
1168   int r, ipc_status;
1169 
1170   /* We expect an interrupt, but if a timeout, occurs, report an error. */
1171   do {
1172 	if ((r = driver_receive(ANY, &mess, &ipc_status)) != OK)
1173 		panic("Couldn't receive message: %d", r);
1174 	if (is_ipc_notify(ipc_status)) {
1175 		switch (_ENDPOINT_P(mess.m_source)) {
1176 			case CLOCK:
1177 				f_expire_tmrs(mess.m_notify.timestamp);
1178 				break;
1179 			default :
1180 				f_busy = BSY_IDLE;
1181 				break;
1182 		}
1183   	} else {
1184   		f_busy = BSY_IDLE;
1185   	}
1186   } while (f_busy == BSY_IO);
1187 
1188   if (f_busy == BSY_WAKEN) {
1189 
1190 	/* No interrupt from the FDC, this means that there is probably no
1191 	 * floppy in the drive.  Get the FDC down to earth and return error.
1192 	 */
1193 	need_reset = TRUE;
1194 	return(ERR_TIMEOUT);
1195   }
1196   return(OK);
1197 }
1198 
1199 /*===========================================================================*
1200  *				f_timeout				     *
1201  *===========================================================================*/
1202 static void f_timeout(minix_timer_t *UNUSED(tp))
1203 {
1204 /* This routine is called when a timer expires.  Usually to tell that a
1205  * motor has spun up, but also to forge an interrupt when it takes too long
1206  * for the FDC to interrupt (no floppy in the drive).  It sets a flag to tell
1207  * what has happened.
1208  */
1209   if (f_busy == BSY_IO) {
1210 	f_busy = BSY_WAKEN;
1211   }
1212 }
1213 
1214 /*===========================================================================*
1215  *				read_id					     *
1216  *===========================================================================*/
1217 static int read_id(void)
1218 {
1219 /* Determine current cylinder and sector. */
1220 
1221   struct floppy *fp = f_fp;
1222   int result;
1223   u8_t cmd[2];
1224 
1225   /* Never attempt a read id if the drive is uncalibrated or motor is off. */
1226   if (fp->fl_calibration == UNCALIBRATED) return(ERR_READ_ID);
1227   if ((motor_status & (1 << f_drive)) == 0) return(ERR_READ_ID);
1228 
1229   /* The command is issued by outputting 2 bytes to the controller chip. */
1230   cmd[0] = FDC_READ_ID;		/* issue the read id command */
1231   cmd[1] = (fp->fl_head << 2) | f_drive;
1232   if (fdc_command(cmd, 2) != OK) return(ERR_READ_ID);
1233   if (f_intr_wait() != OK) return(ERR_TIMEOUT);
1234 
1235   /* Get controller status and check for errors. */
1236   result = fdc_results();
1237   if (result != OK) return(result);
1238 
1239   if ((f_results[ST0] & ST0_BITS_TRANS) != TRANS_ST0) return(ERR_READ_ID);
1240   if (f_results[ST1] | f_results[ST2]) return(ERR_READ_ID);
1241 
1242   /* The next sector is next for I/O: */
1243   fp->fl_sector = f_results[ST_SEC] - BASE_SECTOR + 1;
1244   return(OK);
1245 }
1246 
1247 /*===========================================================================*
1248  *				f_do_open				     *
1249  *===========================================================================*/
1250 static int f_do_open(devminor_t minor, int UNUSED(access))
1251 {
1252 /* Handle an open on a floppy.  Determine diskette type if need be. */
1253 
1254   int dtype;
1255   struct test_order *top;
1256 
1257   /* Decode the message parameters. */
1258   if (f_prepare(minor) == NULL) return(ENXIO);
1259 
1260   dtype = f_device & DEV_TYPE_BITS;	/* get density from minor dev */
1261   if (dtype >= MINOR_fd0p0) dtype = 0;
1262 
1263   if (dtype != 0) {
1264 	/* All types except 0 indicate a specific drive/medium combination.*/
1265 	dtype = (dtype >> DEV_TYPE_SHIFT) - 1;
1266 	if (dtype >= NT) return(ENXIO);
1267 	f_fp->fl_density = dtype;
1268 	(void) f_prepare(f_device);	/* Recompute parameters. */
1269 	return(OK);
1270   }
1271   if (f_device & FORMAT_DEV_BIT) return(EIO);	/* Can't format /dev/fdN */
1272 
1273   /* The device opened is /dev/fdN.  Experimentally determine drive/medium.
1274    * First check fl_density.  If it is not NO_DENS, the drive has been used
1275    * before and the value of fl_density tells what was found last time. Try
1276    * that first.  If the motor is still running then assume nothing changed.
1277    */
1278   if (f_fp->fl_density != NO_DENS) {
1279 	if (motor_status & (1 << f_drive)) return(OK);
1280 	if (test_read(f_fp->fl_density) == OK) return(OK);
1281   }
1282 
1283   /* Either drive type is unknown or a different diskette is now present.
1284    * Use test_order to try them one by one.
1285    */
1286   for (top = &test_order[0]; top < &test_order[NT-1]; top++) {
1287 	dtype = top->t_density;
1288 
1289 	/* Skip densities that have been proven to be impossible */
1290 	if (!(f_fp->fl_class & (1 << dtype))) continue;
1291 
1292 	if (test_read(dtype) == OK) {
1293 		/* The test succeeded, use this knowledge to limit the
1294 		 * drive class to match the density just read.
1295 		 */
1296 		f_fp->fl_class &= top->t_class;
1297 		return(OK);
1298 	}
1299 	/* Test failed, wrong density or did it time out? */
1300 	if (f_busy == BSY_WAKEN) break;
1301   }
1302   f_fp->fl_density = NO_DENS;
1303   return(EIO);			/* nothing worked */
1304 }
1305 
1306 /*===========================================================================*
1307  *				f_do_close				     *
1308  *===========================================================================*/
1309 static int f_do_close(devminor_t UNUSED(minor))
1310 {
1311 /* Handle a close on a floppy.  Nothing to do here. */
1312 
1313   return(OK);
1314 }
1315 
1316 /*===========================================================================*
1317  *				test_read				     *
1318  *===========================================================================*/
1319 static int test_read(int density)
1320 {
1321 /* Try to read the highest numbered sector on cylinder 2.  Not all floppy
1322  * types have as many sectors per track, and trying cylinder 2 finds the
1323  * ones that need double stepping.
1324  */
1325   int device;
1326   off_t position;
1327   iovec_t iovec1;
1328   ssize_t result;
1329 
1330   f_fp->fl_density = density;
1331   device = ((density + 1) << DEV_TYPE_SHIFT) + f_drive;
1332 
1333   (void) f_prepare(device);
1334   position = (off_t) f_dp->test << SECTOR_SHIFT;
1335   iovec1.iov_addr = (vir_bytes) floppy_buf;
1336   iovec1.iov_size = SECTOR_SIZE;
1337   result = f_transfer(device, FALSE /*do_write*/, position, SELF,
1338 	&iovec1, 1, BDEV_NOFLAGS);
1339 
1340   if (result != SECTOR_SIZE) return(EIO);
1341 
1342   partition(&f_dtab, f_drive, P_FLOPPY, 0);
1343   return(OK);
1344 }
1345 
1346 /*===========================================================================*
1347  *				f_geometry				     *
1348  *===========================================================================*/
1349 static void f_geometry(devminor_t minor, struct part_geom *entry)
1350 {
1351   if (f_prepare(minor) == NULL) return;
1352 
1353   entry->cylinders = f_dp->cyls;
1354   entry->heads = NR_HEADS;
1355   entry->sectors = f_sectors;
1356 }
1357