The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/drivers/floppy/floppy.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

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

Cache object: d310e5fcf0edf9a144fbf361ac43da40


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.