2021-10-11 18:37:13 -03:00

3177 lines
79 KiB
C

#ifndef lint
static char sccsid[] = "@(#)fd.c 1.1 94/10/31 SMI";
#endif
/*
* Copyright 1989, Sun Microsystems, Inc.
*/
/*
* Floppy Disk Driver
*
* Supports the Intel 82072 fdc (in non dma mode)
* contains support for vpc software package.
*
* ASSUMES:
* only one controller chip
* (for now) only one drive - although multiple drives should be "easy"
* only sun4c autoconf
* controller is *always* present on the board
* DESIGN NOTES: since (1) no one in their right mind would have more than
* two floppy drives, and (2) ditto for more than one controller (especially
* without dma support!!), and
* (3) 3.5" drives don`t have RDY so you can't do overlapped seeks so
* *all* operations are single threaded.
* therefore --- this device driver is designed to be as simple as possible.
*
* data structures:
* controller - "fdctlr" -
* per unit (drive) - "fdunit" - one preallocated per drive configured,
* hangs off fdctlr.
* per partition (minor device) - "fdpart" - one preallocated (for
* now 'cause they're short) for each possible minor device
* command/status block - "fdcsb" - one preallocated, hangs off of fdctlr
* a dk_label structure for each unit - hangs off fdunit
* one buf struct for all physio/ioctls that need it.
*
* control flow:
* for data xfr:
* read/write - call physio, which calls strategy
* strategy - checks operation, hangs buf struct off fdctlr, calls start
* if not already busy.
* start - if a bp is on queue, grab it. grab/wait-for the fdctlr and
* its fdcsb. fill in args, call fdexec(). due to need to handle
* cylinder crossings, we sleep for done in here.
* fdexec - check DISKCHG, check command busy bit - TBD if these errors
* else stuff commands into chip. if command has no interrupts
* then immediately grab result.
* To allow transparent retrys, all sleeps on operations done
* are in here - since error checking for diskchanged has to
* occur at process level (for recalibrate).
* for ioctls/raw/open-label_read/attach - grab/wait-for the fdctlr and
* its fdcsb. fill in args, call fdexec. ioctl may sleep for
* done on fdcsb.
* note: sleep for fdctlr (and its fdcsb) on address of fdctlr.c_flags,
* sleep for operation on the fdcsb on csb pointed to by fdctlr.c_csb.
* (this allows nested csb sleeping).
* interrupt:
* @level 11
* hardware: Operates like a DMA engine, see fd_asm.s for it.
* The two parts of the driver (fd_asm.s and fd.c) communicate
* via a set of shared variables, defined in fd_asm.s - so that
* fd.c can be deconfigured from the system. see the comments
* in fd_asm.s for a more complete description of the protocol.
* @level4
* software: Invoked by hardware after op is done and results are all in.
* It snarfs results back into fdcsb; if there was an error it
* invokes fdrecover() to retry and returns. If no errors,
* If someone is waiting on fdcsb done, then wake them.
* Note that fdstart() will get activated if it was waiting on
* the fdctlr/csb.
*
* ADDITION: 3rd density support was added
if (fdctlr.c_units[fdctlr.c_csb->csb_unit]->un_chars->medium)
*
*
*/
#include "fd.h"
#if NFD > 0
#if NFD > 3
DON'T MAKE NFD > 3, OK? - the driver doesn't support that
#endif
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/user.h>
#include <sys/buf.h>
#include <sys/ioctl.h>
#include <sys/uio.h>
#include <sys/kernel.h>
#include <sys/conf.h>
#include <sys/file.h>
#include <sun/autoconf.h>
#include <sun/dklabel.h>
#include <sun/dkio.h>
#include <sun/vddrv.h>
#include <sbusdev/fdreg.h>
#include <sbusdev/fdvar.h>
#include <machine/psl.h>
#if defined(sun4c) || defined(sun4m)
#include <machine/auxio.h>
#include <machine/intreg.h>
#endif sun4c || sun4m
#include <sys/vm.h>
#include <vm/hat.h>
#include <vm/as.h>
#include <vm/seg.h>
#include <machine/cpu.h>
#include <sundev/mbvar.h>
#include <sys/fcntlcom.h>
/* Sony MP-F17W-50D Drive Parameters
* High Capacity
* Capacity unformatted 2Mb
* Capacity formatted 1.47Mb
* Encoding method MFM
* Recording density 17434 bpi
* Track density 135 tpi
* Cylinders 80
* Heads 2
* Tracks 160
* Rotational speed 300 rpm
* Transfer rate 250/500 kbps
* Latency (average) 100 ms
* Access time
* Average 95 ms
* Track to track 3 ms
* Head settling time 15 ms
* Motor start time 500 ms
* Head load time ? ms
*/
/*
* DEFINES ********************************************************************
*/
/* the auxiliary register */
#define Auxio (*(u_char *)AUXIO_REG)
#define MEDIUM_DENSITY 0x40
#define SEC_SIZE_CODE (fdctlr.c_csb->csb_unit]->un_chars->medium ? 3 : 2)
#define CMD_READ (MT + SK + FRAW_RDCMD + MFM)
#define CMD_WRITE (MT + FRAW_WRCMD + MFM)
/* for main status and fifo registers on chip */
#ifdef I82077
#define Msr *fd_msr
#define Dsr *fd_dsr
#define Dor *fd_dor
#define Dir *fd_dir
#define Fifo *fd_fifo
#else
#define Msr (fdctlr_reg->fdc_control) /* main status reg */
#define Dsr (fdctlr_reg->fdc_control) /* data rate select reg */
#define Fifo (fdctlr_reg->fdc_fifo)
#endif
#define FDREAD 1 /* for fdrw() flag */
#define FDWRITE 2 /* for fdrw() flag */
#define FDPRI PRIBIO /* at what priority to sleep */
#define FD_CRETRY 1000000 /* retry while sending comand */
#define FD_RRETRY 1000000 /* retry while getting results */
#define FDXC_SLEEP 0x1 /* tell fdexec to sleep 'till done */
#define FDXC_CHECKCHG 0x2 /* tell fdexec to check disk chnged */
#define IOCTL_DEBUG 0xaa /* For debugging only */
/*
* EXTERNS ********************************************************************
*/
/*
* these are in fd_asm.s
*/
#ifndef lint
#ifdef I82077
extern union fdcreg *fdctlr_reg; /* ptr to floppy controller registers */
extern u_char *fd_msr, /* ptr to msr */
*fd_dsr, /* ptr to dsr */
*fd_dor, /* ptr to dor - 82077 only */
*fd_dir, /* ptr to dir - 82077 only */
*fd_fifo;
#else
extern struct fdcreg *fdctlr_reg; /* ptr to floppy controller registers */
#endif I82077
/* for interface with low level interrupt handler */
/* I = input - set before operation, O = output - available after */
extern u_int fdintr_opmode; /* mode for interrupt handler to run in */
/* I: 1 = r/w/fmt, 2 = seek/recal; */
/* O: hw intr sets it to 4 to notify us */
extern u_char *fdintr_addr; /* I/O: (current) data xfer address */
extern u_int fdintr_len; /* I: data xfer length; O: remainder */
extern u_int fdintr_status; /* I: n/a; O: 0 = ok, TBD XXX NYD errors */
extern u_int fdintr_timeout; /* timeout value for fdc_hardintr ??? */
extern u_char fdintr_statbuf[10]; /* I: n/a; O: 10 bytes of status buffer */
extern u_char *fdintr_statp; /* I: pointer for fdintr_statbuf; O: n/a */
#else lint
/* keep lint happy - pretend to declare these here */
#ifdef I82077
union fdcreg *fdctlr_reg;
u_char *fd_msr, *fd_dsr, *fd_dor, *fd_dir, *fd_fifo;
#else
struct fdcreg *fdctlr_reg;
#endif I82077
u_int fdintr_opmode;
u_char *fdintr_addr;
u_int fdintr_len;
u_int fdintr_status;
u_int fdintr_timeout;
u_char fdintr_statbuf[10];
u_char *fdintr_statp;
#endif lint
/*
* STATIC and other forward reference FUNCTIONS
*/
static void fdselect();
static fdeject();
static fdsense_chng();
fdwatch();
#if defined(sun4c) || defined(sun4m) /* campus sends TC in fdc_hardintr */
extern int fdc_hardintr(); /* defined in ../sun4c/fd_asm.s */
extern int fdc_intr(); /* defined in ../sun4c/fd_asm.s */
#else
static fdterm_count();
static fdsense_dnsty();
#endif
char *strcpy();
int fdopen();
int fdclose();
int fdstrategy();
int fddump();
int fdsize();
int fdread();
int fdwrite();
int fdioctl();
int fdtype = -1; /* Holds type of controller (i.e FD_82072 or FD_82077).
*
* XXX - This should be initialized in fdattach by
* checking the OBP.
*/
extern int nulldev();
extern int seltrue();
/*
* BSS UN-INITIALIZED DATA ****************************************************
*/
struct fdunit fdunits[NFD]; /* array of floppy unit state structs */
int fdpri; /* mask this level in critical sections */
struct buf fdkbuf; /* a buf structure for raw io and ioctls */
char fdkl_alabel[NFD][128]; /* space for packed label's ascii strings */
/*
* INITIALIZED DATA ***********************************************************
*/
struct fdctlr fdctlr = { /* floppy ctlr state struct */
&fdunits[0], /* init pts to unit data structs */
#if NFD > 1
&fdunits[1],
#endif
#if NFD > 2
&fdunits[2],
#endif
#if NFD > 3
&fdunits[3],
#endif
0 }; /* rest is uninitialized */
short rwretry = 25;
short skretry = 25;
/*
* ERROR HANDLING *************************************************************
*/
/*
* flags/masks for error printing.
* the levels are for severity
*/
#define FDEP_L0 0 /* chatty as can be - for debug! */
#define FDEP_L1 1 /* best for debug */
#define FDEP_L2 2 /* minor errors - retries, etc. */
#define FDEP_L3 3 /* major errors */
#define FDEP_L4 4 /* catastophic errors, don't mask! */
#define FDEP_LMAX 4 /* catastophic errors, don't mask! */
#define FDERRPRINT(l, m, args) \
{ if (((l) >= fderrlevel) && ((m) & fderrmask)) printf args; }
/*
* for each function, we can mask off its printing by clearing its bit in
* the fderrmask. Some functions (attach, ident) share a mask bit
*/
#define FDEM_IDEN 0x00000001 /* fdidentify */
#define FDEM_ATTA 0x00000001 /* fdattach */
#define FDEM_SIZE 0x00000002 /* fdsize */
#define FDEM_OPEN 0x00000004 /* fdopen */
#define FDEM_GETL 0x00000008 /* fdgetlabel */
#define FDEM_CLOS 0x00000010 /* fdclose */
#define FDEM_STRA 0x00000020 /* fdstrategy */
#define FDEM_STRT 0x00000040 /* fdstart */
#define FDEM_RDWR 0x00000080 /* fdrdwr */
#define FDEM_CMD 0x00000100 /* fdcmd */
#define FDEM_EXEC 0x00000200 /* fdexec */
#define FDEM_RECO 0x00000400 /* fdrecover */
#define FDEM_INTR 0x00000800 /* fdintr */
#define FDEM_WATC 0x00001000 /* fdwatch */
#define FDEM_IOCT 0x00002000 /* fdioctl */
#define FDEM_RAWI 0x00004000 /* fdrawioctl */
#define FDEM_DUMP 0x00008000 /* fddump */
#define FDEM_GETC 0x00010000 /* fdgetcsb */
#define FDEM_RETC 0x00020000 /* fdretcsb */
#define FDEM_RESE 0x00040000 /* fdreset */
#define FDEM_RECA 0x00080000 /* fdrecalseek */
#define FDEM_FORM 0x00100000 /* fdformat */
#define FDEM_RW 0x00200000 /* fdrw */
#define FDEM_CHEK 0x00400000 /* fdcheckdisk */
#define FDEM_DSEL 0x00800000 /* fdselect */
#define FDEM_EJEC 0x01000000 /* fdeject */
#define FDEM_SCHG 0x02000000 /* fdsense_chng */
#define FDEM_PACK 0x04000000 /* fdpacklabel */
#ifdef I82077
#define FDEM_MOFF 0x08000000 /* fdmotoff */
#endif I82077
int fderrmask = 0xFFFFFFFF;
static short fderrlevel = 3;
int fdhardtimeout = 100000;
int tosec = 16; /* long timeouts for sundiag for now */
/*
* SPECIFY/CONFIGURE CMD PARAMETERS *******************************************
*/
/* so they can be easily changed */
u_char fdspec[2] = {0xc2, 0x33}; /* the "specify" parameters */
u_char fdconf[3] = {0x64, 0x58, 0x00}; /* the "configure" parameters */
/*
* DEFAULT CHARACTERISTICS ****************************************************
*/
struct fdk_char fdtypes[] = {
/* struct fdk_char fdchar_highdens = */
{ 0, /* medium */
500, /* transfer rate */
80, /* number of cylinders */
2, /* number of heads */
512, /* sector size */
18, /* sectors per track */
-1, /* (NA) # steps per data track */
},
/* struct fd_char fdchar_meddens */
{
1, /* medium */
500, /* transfer rate */
77, /* number of cylinders */
2, /* number of heads */
1024, /* sector size */
8, /* sectors per track */
-1, /* (NA) # steps per data track */
},
/* struct fdk_char fdchar_lowdens = */
{ 0, /* medium */
250, /* transfer rate */
80, /* number of cylinders */
2, /* number of heads */
512, /* sector size */
9, /* sectors per track */
-1, /* (NA) # steps per data track */
},
};
int nfdtypes = sizeof (fdtypes)/sizeof (fdtypes[0]);
int curfdtype;
/*
* DEFAULT LABEL & PARTITION MAPS *********************************************
*/
/*
* since a label occupies 512 bytes, and we need at least 2, no make that 4
* for 40 and 80 in both high and low density. = 2K of mostly 0's.
* we stash them in a packed array, then call fdunpacklabel() to
* expand them when needed.
*/
struct packed_label fdlbl_high_80 = {
"3.5\" floppy cyl 80 alt 0 hd 2 sec 18", /* for compatibility */
300, /* rotations per minute */
80, /* # physical cylinders */
0, /* alternates per cylinder */
1, /* interleave factor */
80, /* # of data cylinders */
0, /* # of alternate cylinders */
2, /* # of heads in this partition */
18, /* # of 512 byte sectors per track */
{ 0, 79 * 2 * 18 }, /* part 0 - all but last cyl */
{ 79, 1 * 2 * 18 }, /* part 1 - just the last cyl */
{ 0, 80 * 2 * 18 }, /* part 2 - "the whole thing" */
{ 0, 0 },
{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
};
struct packed_label fdlbl_medium_80 = {
"3.5\" floppy cyl 77 alt 0 hd 2 sec 8",
360, /* rotations per minute */
77, /* # physical cylinders */
0, /* alternates per cylinder */
1, /* interleave factor */
77, /* # of data cylinders */
0, /* # of alternate cylinders */
2, /* # of heads in this partition */
8, /* # of 512 byte sectors per track */
{ 0, 76 * 2 * 8 * 2 }, /* part 0 - all but last cyl */
{ 76, 1 * 2 * 8 * 2 }, /* part 1 - just the last cyl */
{ 0, 77 * 2 * 8 * 2 }, /* part 2 - "the whole thing" */
{ 0, 0 },
{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
};
struct packed_label fdlbl_low_80 = {
"3.5\" floppy cyl 80 alt 0 hd 2 sec 9",
300, /* rotations per minute */
80, /* # physical cylinders */
0, /* alternates per cylinder */
1, /* interleave factor */
80, /* # of data cylinders */
0, /* # of alternate cylinders */
2, /* # of heads in this partition */
9, /* # of 512 byte sectors per track */
{ 0, 79 * 2 * 9 }, /* part 0 - all but last cyl */
{ 79, 1 * 2 * 9 }, /* part 1 - just the last cyl */
{ 0, 80 * 2 * 9 }, /* part 2 - "the whole thing" */
{ 0, 0 },
{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
};
/*
* SUN4C AUTOCONF SUPPORT ******************************************************
*/
/* for sun4c autoconf stuff, referred to in ioconf.c */
int fdidentify(), fdintr(), fdattach();
struct dev_ops fd_ops = {
1,
fdidentify,
fdattach,
};
/*
* LOADABLE MODULE SUPPORT ****************************************************
*/
#ifndef lint
struct bdevsw fd_bdevsw = {
fdopen, fdclose, fdstrategy, fddump, fdsize, 0
};
struct cdevsw fd_cdevsw = {
fdopen, fdclose, fdread, fdwrite, fdioctl, nulldev, seltrue, 0, 0
};
struct vdldrv fddrv = {
VDMAGIC_DRV, /* Drv_magic */
#ifdef I82077
"Onboard 82072/82077 Floppy Driver", /* *Drv_name */
#else
"Onboard 82072 Floppy Driver", /* *Drv_name */
#endif
&fd_ops, /* *Drv_dev_ops */
&fd_bdevsw, /* *Drv_bdevsw */
&fd_cdevsw, /* *Drv_cdevsw */
16, /* Drv_blockmajor */
54 /* Drv_charmajor */
};
#endif !lint
/*
* FUNCTIONS ******************************************************************
*/
#if defined(sun4c) || defined(sun4m) /* for new style autoconf stuff */
/*
* fdidentify
* identify ctlr
*/
int
fdidentify(name)
char *name;
{
FDERRPRINT(FDEP_L0, FDEM_IDEN, ("fdidentify: name %s\n", name));
if (strcmp(name, "fd") == 0 || strcmp(name, "SUNW,fdtwo") == 0) {
return (1);
} else
return (0);
}
/*
* fdattach
* attach controller
*/
fdattach(dev)
register struct dev_info *dev;
{
struct fdunit *un;
#ifdef I82077
u_char *fdtestaddr;
#endif I82077
FDERRPRINT(FDEP_L0, FDEM_ATTA, ("fdattach\n"));
/* ASSUME we only have one controller, ever! */
dev->devi_unit = 0;
/*
* map in controller regs; ASSUME it's ALWAYS there
*/
#ifdef I82077
fdctlr_reg = (union fdcreg *) map_regs(dev->devi_reg->reg_addr,
dev->devi_reg->reg_size,
dev->devi_reg->reg_bustype);
/* See if we have an 072 or 077. If we have an 072 the
* dsr/msr will be at location 0x2 since 0x2 maps to 0x0.
* If we have an 077, the dor will be at 0x2.
*/
fdtype = FD_82077;
fdtestaddr = (u_char *) fdctlr_reg + 2;
if (*fdtestaddr == 0x80) {
/* We expect the msr to 0x80, but we'll do some
* more checking just in case.
*/
*fdtestaddr = 0x2; /* default value of dsr */
DELAY(100);
if (*fdtestaddr == 0x80)
fdtype = FD_82072;
}
switch (fdtype) {
case FD_82072:
FDERRPRINT(FDEP_L0, FDEM_ATTA, ("fdattach: type is 82072\n"));
/* Initialize addresses of key registers.
*/
fd_msr = &fdctlr_reg->fdc_82072_reg.fdc_control;
fd_dsr = &fdctlr_reg->fdc_82072_reg.fdc_control;
fd_fifo = &fdctlr_reg->fdc_82072_reg.fdc_fifo;
FDERRPRINT(FDEP_L0, FDEM_ATTA, ("fdattach: msr/dsr at 0x%x\n", fd_msr));
/* Insure that the eject line is reset and TC is clear.
*/
set_auxioreg(AUX_EJECT, 1);
set_auxioreg(AUX_TC, 0);
break;
case FD_82077:
FDERRPRINT(FDEP_L0, FDEM_ATTA, ("fdattach: type is 82077\n"));
/* Initialize addresses of key registers.
*/
fd_msr = &fdctlr_reg->fdc_82077_reg.fdc_control;
fd_dsr = &fdctlr_reg->fdc_82077_reg.fdc_control;
fd_dor = &fdctlr_reg->fdc_82077_reg.fdc_dor;
fd_dir = &fdctlr_reg->fdc_82077_reg.fdc_dir;
fd_fifo = &fdctlr_reg->fdc_82077_reg.fdc_fifo;
FDERRPRINT(FDEP_L0, FDEM_ATTA, ("fdattach: msr/dsr at 0x%x\n", fd_msr));
/* The 82077 doesnt use the first configuration parameter
* so let's adjust that while we know we're an 82077.
*/
fdconf[0] = 0;
/* The reset bit must be cleared to take the 82077 out of
* reset state. (Dor = 0x0f after Reset).
*/
fd_set_dor_reg(0xe8, 0);
DELAY(5);
fd_set_dor_reg(RESET | DRVSEL, 1);
DELAY(5);
/* Insure that the eject line is reset and TC is clear.
*/
set_auxioreg(AUX_TC, 0);
break;
}
#else
fdctlr_reg = (struct fdcreg *) map_regs(dev->devi_reg->reg_addr,
dev->devi_reg->reg_size,
dev->devi_reg->reg_bustype);
set_auxioreg(AUX_EJECT, 1); /* insure that the eject line is reset */
#endif I82077
fdctlr.c_csb = (struct fdcsb *)kmem_zalloc(sizeof (struct fdcsb));
/* setup for commands will initialize the csb according to need */
un = fdctlr.c_units[0]; /* XXX unit 0 is hardcoded for now */
/*
* set initial controller/drive/disk "characteristics/geometry"
*/
un->un_chars =
(struct fdk_char *)kmem_zalloc(sizeof (struct fdk_char));
curfdtype = 0; /* init current fdtype pointer to beginning of tbl */
*(un->un_chars) = fdtypes[curfdtype]; /* structure copy */
un->un_label =
(struct packed_label *)kmem_zalloc(sizeof (struct packed_label));
*(un->un_label) = fdlbl_high_80; /* structure copy */
if (fdctlr.c_csb == NULL || un->un_chars == NULL || un->un_label == NULL) {
printf("fdattach%d: kmem_zalloc failed!\n", dev->devi_unit);
return (-1);
}
/* Add a direct trap to the assembly language interrupt handler. */
fdctlr.c_intr = dev->devi_intr->int_pri;
switch (fdtype) {
case FD_82072:
/* reset, specify and configure the controller */
fdgetcsb();
fdreset();
fdretcsb();
fdselect(0, 0); /* DE-select drive zero (used in fdreset) */
/* XXX unit 0 is hardcoded for now */
if (!settrap(fdctlr.c_intr, fdc_hardintr))
panic("fdattach: Cannot set fd trap vector");
break;
case FD_82077:
addintr(11, fdc_intr, dev->devi_name, 0);
/* reset, specify and configure the controller
* for Campus2s do the reset after adding ourselves to the
* level 11 handler list. The reset causes an interrupt when
* the driver is modloaded. Therefore I rearranged the
* addintr and reset sequences. Since nobody seems
* to why so, I have no choice but to rearrange the code.
*/
fdgetcsb();
fdreset();
fdretcsb();
fdselect(0, 0); /* DE-select drive zero (used in fdreset) */
/* XXX unit 0 is hardcoded for now */
break;
default:
panic("fdattach: cannot identify controller");
break;
}
/* Set up level 4 soft interrupt service routine. */
fdpri = ipltospl(4);
addintr(4, fdintr, dev->devi_name, 0);
report_dev(dev);
return (0);
}
#ifndef lint
/*
* fdinit
* for a loadable driver
* modload modstat & modunload
*/
/*ARGSUSED*/
fdinit(fcn, vdp, vdi, vds)
int fcn;
register struct vddrv *vdp;
caddr_t vdi;
struct vdstat *vds;
{
struct fdunit *un;
int status = 0;
switch (fcn) {
case VDLOAD:
vdp->vdd_vdtab = (struct vdlinkage *)&fddrv;
break;
case VDUNLOAD:
un = fdctlr.c_units[0]; /* XXX unit0 hardcoded */
/*
* is anybody still open?
*/
if (un->un_openmask || un->un_exclmask) {
status = EBUSY;
} else {
/* Remove the direct trap vector */
switch (fdtype) {
case FD_82072:
if (!settrap(fdctlr.c_intr, NULL))
panic("fdinit: Cannot reset fd trap vector");
break;
default:
break;
}
#ifdef VDDRV
(void) remintr(4, fdintr);
#endif
/* free space allocated in fdattach */
kmem_free((caddr_t)fdctlr.c_csb, sizeof (struct fdcsb));
kmem_free((caddr_t)un->un_chars,
sizeof (struct fdk_char));
kmem_free((caddr_t)un->un_label,
sizeof (struct packed_label));
}
break;
case VDSTAT:
break;
default:
printf("fdinit: unknown function 0x%x\n", fcn);
status = EINVAL;
}
return (status);
}
#endif !lint
#endif sun4c sun4m /* for new style autoconf stuff */
/*
* fdsize
* return the size of a logical partition
*/
fdsize(dev)
dev_t dev;
{
struct fdunit *un;
struct dk_map *lp;
int unit;
if ((unit = UNIT(dev)) >= NFD || fdtype == -1)
return (-1);
un = fdctlr.c_units[ unit ];
lp = &un->un_label->dkl_map[ PARTITION(dev) ];
FDERRPRINT(FDEP_L0, FDEM_SIZE,
("fdsize: unit %d, part %d, size 0x%x\n",
unit, PARTITION(dev), lp->dkl_nblk));
/*
* for now simply return what's there (from defaults set in fdattach)
* XXX someday maybe attempt to read a label if it hasn't been done yet
*/
return ((int)lp->dkl_nblk);
}
/*
* fdopen
*
*/
fdopen(dev, flag)
dev_t dev;
int flag;
{
int unit, part;
struct fdunit *un;
u_char pmask;
struct dk_map *dkm;
int err;
static int fdopening=0;
int fderr = 0;
int fderr2 = 0;
/* check unit */
unit = UNIT(dev);
if (unit >= NFD || fdtype == -1) {
fderr = ENXIO;
goto fdout;
}
un = fdctlr.c_units[ unit ];
/* check partition */
part = PARTITION(dev);
pmask = 1 << part;
dkm = &(un->un_label->dkl_map[part]);
if (dkm->dkl_nblk == 0) {
fderr = ENXIO;
goto fdout;
}
FDERRPRINT(FDEP_L1, FDEM_OPEN, ("**********FDOPEN --- A --->: unit %d, part %d\n",
unit, part));
/* go to sleep if there is a previous fdopen in process */
while (fdopening)
(void) sleep((caddr_t)&fdopening, FDPRI);
fdopening=1;
/*
* insure that drive is present with a recalibrate on first open.
*/
if (un->un_openmask == 0) {
fdgetcsb();
err = fdrecalseek(unit, -1, 0); /* no check changed! */
fdretcsb();
if (err) {
FDERRPRINT(FDEP_L3, FDEM_OPEN,
("fd%d: drive not ready\n", unit));
fdselect(unit, 0); /* deselect drv on last close */
fderr = ENXIO;
goto fdout;
}
}
fdctlr.c_csb->csb_unit = (u_char) UNIT(dev);
/*
* check for previous exclusive open, or trying to exclusive open
*/
if ((un->un_exclmask & pmask) ||
((flag & FEXCL) && (un->un_openmask & pmask))) {
fderr = EBUSY;
goto fdout;
}
if (flag & FEXCL) {
un->un_exclmask |= pmask;
}
/* don't attempt access, just return successfully */
if (flag & (FNDELAY | FNBIO)) {
goto out;
}
if ((un->un_openmask == 0) && (fderr2 = fdgetlabel(unit))) {
/* didn't find label (couldn't read anything) */
FDERRPRINT(FDEP_L3, FDEM_OPEN,
("fd%d: drive not ready\n", unit));
un->un_exclmask &= ~(pmask);
if (un->un_openmask == 0) {
fdselect(unit, 0); /* deselect drv on last close */
}
fderr = fderr2;
if (fderr == 0)
fderr = EIO;
goto fdout;
}
/*
* if opening for writing, check write protect on diskette
*/
if (flag & FWRITE) {
fdgetcsb();
err = fdsensedrv(unit) & WP_SR3;
fdretcsb();
if (err) {
fdselect (unit, 0);
fderr = EROFS;
goto fdout;
}
}
/* mark open */
out:
un->un_openmask |= pmask;
fdout:
fdopening = 0;
wakeup((caddr_t)&fdopening);
FDERRPRINT(FDEP_L1, FDEM_OPEN, ("___________ END FDOPEN\n"));
return (fderr);
}
/*
* fdgetlabel - read the SunOS lable off the diskette
* if it can read a valid label it does so, else it will use a
* default. If it can`t read the diskette - that is an error.
*
* RETURNS: 0 for ok - meaning that it could at least read the device,
* !0 for error XXX TBD NYD error codes
*/
fdgetlabel(unit)
int unit;
{
register struct dk_label *label;
register struct fdunit *un;
short *sp;
short count;
short xsum;
int i, tries;
int err = 0;
#if NO
short oldlvl;
#endif
FDERRPRINT(FDEP_L1, FDEM_GETL, ("fdgetlabel: unit %d\n", unit));
un = fdctlr.c_units[unit];
un->un_flags &= ~(FDUNIT_LABELOK|FDUNIT_UNLABELED);
/*
* get some space to play with the label
*/
label = (struct dk_label *)kmem_zalloc(sizeof (struct dk_label));
FDERRPRINT(FDEP_L0, FDEM_GETL,
("fdgetlabel, kmem_zalloc: ptr = 0x%x, size = 0x%x\n",
label, sizeof (struct dk_label)));
if (label == NULL)
return (ENOMEM);
/*
* read block 0 (0/0/1) to find the label
* (disk is potentially not present or unformatted)
*/
/* noerrprint since this is a private cmd */
#if NO
oldlvl = fderrlevel;
fderrlevel = FDEP_L4;
#endif
/* try different characteristics (ie densities) */
/*
* if curfdtype is -1 then the current characteristics were set by
* ioctl and need to try it as well as everything in the table
*
* Note: with new medium density, we need to check the content
* of the label as well (medium/high could be mistaken
* since the rotation speed is different (360 ->300 )
* (360rpm +medium could be confused with 300rpm + high)
*/
if (curfdtype == -1)
tries = nfdtypes+1;
else
tries = nfdtypes;
for (i=0; i < tries; i++) {
FDERRPRINT(FDEP_L0, FDEM_GETL,
("TRYING READ LABEL curfdtype = %d\n", curfdtype));
err = fdrw(FDREAD, unit, 0, 0, 1, (caddr_t)label,
sizeof (struct dk_label));
FDERRPRINT(FDEP_L0, FDEM_GETL,
("fdgetlabel: fdrw returned %d\n", err));
FDERRPRINT(FDEP_L0, FDEM_GETL,
("label: rpm = %d\n", label->dkl_rpm));
FDERRPRINT(FDEP_L0, FDEM_GETL,
(" pcyl = %d\n", label->dkl_pcyl));
FDERRPRINT(FDEP_L0, FDEM_GETL,
(" nsect = %d\n", label->dkl_nsect));
if (!err) break;
/* try the next entry in the characteristics tbl */
/* if curfdtype is -1, the nxt entry in tbl is 0 (the first) */
curfdtype = (curfdtype + 1) % nfdtypes;
*(un->un_chars) = fdtypes[curfdtype]; /* structure copy */
/* data transfer rate given to the controller in fdexec */
}
#if NO
fderrlevel = oldlvl; /* print errors again */
#endif
if (err)
goto out; /* couldn't read anything */
FDERRPRINT(FDEP_L0, FDEM_GETL, ("LABEL SUCCESSFULLY READ\n"));
/*
* _something_ was read - look for unixtype label
*/
if (label->dkl_magic != DKL_MAGIC) {
/* not a label - no magic number */
goto nolabel; /* no errors, tho` no label */
}
count = sizeof (struct dk_label)/sizeof (short);
sp = (short *)label;
xsum = 0;
while (count--)
xsum ^= *sp++; /* should add up to 0 */
if (xsum) {
/* not a label - checksum didn't compute */
goto nolabel; /* no errors, tho` no label */
}
/*
* if label found pack it away
*/
fdpacklabel(label, un->un_label, unit);
un->un_flags |= FDUNIT_LABELOK;
goto out;
nolabel:
/*
* if not found fill in label info from default (mark default used)
*/
un->un_flags |= FDUNIT_UNLABELED;
switch (un->un_chars->secptrack) {
case 9:
*(un->un_label) = fdlbl_low_80; /* structure copy */
break;
case 8:
*(un->un_label) = fdlbl_medium_80; /* structure copy */
break;
case 18:
default:
*(un->un_label) = fdlbl_high_80; /* structure copy */
break;
}
out:
kmem_free((caddr_t)label, sizeof (struct dk_label));
return (err);
}
/*
* fdclose
*
*/
fdclose(dev)
dev_t dev;
{
int unit;
register struct fdunit *un;
u_char npmask; /* "NOT" partition mask */
unit = UNIT(dev);
FDERRPRINT(FDEP_L1, FDEM_CLOS, ("fdclose: dev=0x%x\n", dev));
un = fdctlr.c_units[ unit ];
/*
* invalidate stuff
* XXX - clean busy operations still waiting??? - HOW CAN THAT HAPPEN?
*/
npmask = ~(1 << PARTITION(dev));
un->un_exclmask &= npmask;
un->un_openmask &= npmask;
if (un->un_openmask == 0) {
fdselect(unit, 0); /* deselect drive on last close */
un->un_flags &= ~FDUNIT_CHANGED;
}
return (0);
}
/*
* fdstrategy
* checks operation, hangs buf struct off fdctlr, calls fdstart
* if not already busy. Note that if we call start, then the operation
* will already be done on return (start sleeps).
*/
fdstrategy(bp)
register struct buf *bp;
{
register struct fdunit *un;
int unit, part;
int oldpri;
int err;
struct dk_map *dkm;
FDERRPRINT(FDEP_L1, FDEM_STRA, ("fdstrategy: bp = 0x%x, dev = 0x%x\n",
bp, bp->b_dev));
unit = UNIT(bp->b_dev);
un = fdctlr.c_units[ unit ]; /* at least unit # valid, get un */
part = PARTITION(bp->b_dev);
dkm = &(un->un_label->dkl_map[ part ]);
/* if this request is already off the end (existence checked in open) */
if ((bp->b_blkno > dkm->dkl_nblk)) {
FDERRPRINT(FDEP_L3, FDEM_STRA,
("fd%d: block %d is past the end! (nblk=%d)\n",
unit, bp->b_blkno, dkm->dkl_nblk));
bp->b_error = ENOSPC;
goto bad;
}
/* if at end of file, skip out now */
if (bp->b_blkno == dkm->dkl_nblk) {
if ((bp->b_flags & B_READ) == 0) {
/* a write needs to get an error! */
bp->b_error = ENOSPC;
goto bad;
}
bp->b_resid = bp->b_bcount;
iodone(bp);
return;
}
/* if operation not a multiple of sector size, is error! */
if (bp->b_bcount % 512) {
FDERRPRINT(FDEP_L3, FDEM_STRA,
("fd%d: count %d must be a multiple of 512\n",
unit, bp->b_bcount));
bp->b_error = EINVAL;
goto bad;
}
/*
* if the operation will go off the end of disk...
* handled in fdstart()
*/
/*
******** START CRITICAL SECTION ********
*/
oldpri = splr(fdpri); /* raise priority */
/*
* queue the buf request on controller's queue - first in, first out
* basis - nothing fancy here!
* NOTE: list from head.b_forw is singly linked using av_forw,
* also a pointer to the end of the queue is also kept in head.b_back
*/
bp->av_forw = (struct buf *)0; /* last guy points to nobody */
if (fdctlr.c_head.b_forw) { /* if someone already on queue... */
fdctlr.c_head.b_back->av_forw = bp; /* ...put on end... */
} else {
fdctlr.c_head.b_forw = bp; /* ...else onto head */
}
fdctlr.c_head.b_back = bp; /* and do back link also */
bp->av_back = (struct buf *)0; /* just to be clean */
/* if no operation in progress, call start */
if (!(fdctlr.c_flags & FDCFLG_BUSY)) {
err = fdstart();
}
if (err)
goto bad;
(void) splx(oldpri);
/*
******** END CRITICAL SECTION *******
*/
return;
bad: /* bad operation - mark buffer with err and vamanos */
bp->b_resid = bp->b_bcount;
bp->b_flags |= B_ERROR;
if ((bp->b_flags & B_DONE) == 0)
iodone(bp);
return;
}
/*
* fdstart
* called from fdstrategy() or from fdintr() to setup and
* start operations of read or write only (using buf structs).
* Because the chip doesn't handle crossing cylinder boundaries on
* the fly, this takes care of those boundary conditions. Note that
* it sleeps until the operation is done *within fdstart* - so that
* when fdstart returns, the operation is already done.
*
*/
fdstart()
{
register struct buf *bp;
register struct fdcsb *csb;
register struct fdunit *un;
register struct fdk_char *ch;
struct dk_map *dkm;
int err;
u_int sec_size;
u_int unit, part;
u_int len;
u_int logical_blk;
u_int fd_action;
u_int phys_blk, phys_blk_begin;
u_int plus1; /* real data starts middle of 1st sector */
u_int minus1; /* real data ends middle of last sector */
u_int sector_count; /* Number of physical sectors to xfer */
u_int plus2; /* xfer not multiple of sec_size */
u_int phys_blk_begin_part, phys_blk_end_part;
caddr_t addr_buf, temp_buf;
err = 0;
loop:
/*
* if no buf on queue, just bailout
*/
bp = fdctlr.c_head.b_forw;
if (bp == (struct buf *)0)
return (err);
bp->b_flags &= ~B_ERROR;
bp->b_error = 0;
bp->b_resid = bp->b_bcount; /* init resid */
FDERRPRINT(FDEP_L1, FDEM_STRT,
("fdstart: bp=0x%x blkno=0x%x bcount=0x%x\n",
bp, bp->b_blkno, bp->b_bcount));
/* we're here only if there are queued bufs */
fdgetcsb(); /* get csb (maybe wait for it) */
csb = fdctlr.c_csb;
csb->c_current = bp;
unit = UNIT(bp->b_dev); /* floppy unit number */
un = fdctlr.c_units[ unit ];
ch = un->un_chars;
part = PARTITION(bp->b_dev);
dkm = &(un->un_label->dkl_map[ part ]);
sec_size = ch->sec_size;
FDERRPRINT(FDEP_L1, FDEM_STRT,
("sec_size = %d secptrack = %d\n",ch->sec_size, ch->secptrack));
bp_mapin(bp); /* map in buffers */
/*
* now fill in the fdcsb to send to controller
*/
csb->csb_un = un; /* ptr to fdunit struct */
csb->csb_unit = unit; /* floppy unit number */
csb->csb_part = part; /* floppy partition number */
/* fill in cmd parameters that won't change */
if (bp->b_flags & B_READ)
fd_action = CMD_READ;
else
fd_action = CMD_WRITE;
csb->csb_cmds[5] = ch->medium ? 3 : 2;
csb->csb_cmds[6] = ch->secptrack; /* EOT - # of sectors/trk */
csb->csb_cmds[7] = GPLN; /* GPL - gap 3 size code */
csb->csb_cmds[8] = SSSDTL; /* DTL - be 0xFF if N != 0 */
csb->csb_ncmds = NCBRW; /* how many command bytes */
csb->csb_nrslts = NRBRW; /* number of result bytes */
/* opflags for hwintr handler et.al.*/
csb->csb_opflags = CSB_OFXFEROPS | CSB_OFTIMEIT;
/* ================================================================ */
logical_blk = bp->b_blkno; /* start logicl block in part */
phys_blk = logical_blk >> ch->medium; /* physical start block */
plus1 = 0;
plus2 = 0;
minus1 = 0;
sector_count = bp->b_bcount / sec_size;
if (ch->medium) {
plus1 = logical_blk % 2; /* Set if start block odd */
plus2 = (bp->b_bcount % ch->sec_size ? 1 : 0);
minus1 = plus1 ^ plus2;
if (plus1 | plus2)
sector_count++;
}
phys_blk_begin_part = (dkm->dkl_cylno * ch->secptrack * ch->nhead);
phys_blk_begin = phys_blk_begin_part + phys_blk;
phys_blk_end_part = phys_blk_begin_part + (dkm->dkl_nblk >> ch->medium);
/*
* Truncate len if extend beyond partition
*/
if (phys_blk_begin + sector_count > phys_blk_end_part)
len = (phys_blk_end_part - phys_blk_begin) * ch->sec_size;
else
len = sector_count * ch->sec_size;
addr_buf = bp->b_un.b_addr;
FDERRPRINT(FDEP_L1, FDEM_STRT,
("log %d phys %d secount %d len %d ppm %d%d%d\n", logical_blk,
phys_blk, sector_count, len, plus1, plus2, minus1));
/*
* Call transfer routine.
* If we have medium density, we need to use temp_buf
* and each write will be preceded by a read (unless plus1=minus1=0)
*/
if (plus1 || minus1) {
/*
* allocate len bytes in temp_buf, multiple of real sector
*/
temp_buf = (caddr_t)kmem_zalloc(len);
/*
* Transfer involving temp_buf
* if READ: we read more in temp_buf, then throw away 512 bytes
* if WRITE: we need to do a READ/MODIFY/WRITE
*/
if (fd_action == CMD_READ) {
err = temp_disk(fd_action, phys_blk_begin, len, temp_buf);
buf_temp(fd_action, plus1, bp, temp_buf);
} else {
err = temp_disk(CMD_READ, phys_blk_begin, len, temp_buf);
buf_temp(fd_action, plus1, bp, temp_buf);
if (err == 0)
err = temp_disk(fd_action, phys_blk_begin, len, temp_buf);
}
kmem_free((caddr_t)temp_buf, len);
} else {
/*
* Normal transfer directly from or to struct buf (addr_buf)
*/
FDERRPRINT(FDEP_L0, FDEM_STRT,("Normal transfer\n"));
err = temp_disk(fd_action, phys_blk_begin, len, addr_buf);
}
/* finish off the buffer operation just done */
FDERRPRINT(FDEP_L0, FDEM_STRT,
("fdstart done: b_resid %d, b_count %d, csb_rlen %d\n",
bp->b_resid, bp->b_bcount, csb->csb_rlen));
/* dequeue off of header */
if (bp->av_forw != (struct buf *)0) {
fdctlr.c_head.b_forw = bp->av_forw;
bp->av_forw = (struct buf *)0;
/* c_head.b_back doesn't matter (we hope) */
} else {
/* nobody else there, clear em all */
fdctlr.c_head.b_forw = (struct buf *)0;
fdctlr.c_head.b_back = (struct buf *)0;
}
/* if (the special buffer) just wants woke, just wake it only */
/* raw io also comes here */
if (bp == &fdkbuf) {
bp->b_flags |= B_DONE;
wakeup((caddr_t)bp);
} else {
/* block io comes here */
/* NOTE: the iodone() does a bp_mapout() */
iodone(bp);
}
/* release csb */
fdctlr.c_flags &= ~FDCFLG_BUSY;
fdretcsb();
goto loop;
}
/*
* TRANSFER data from Disk to temp_buf or vice-versa
* --------------------------------------------------
*
* fd_action Type of transfer (Read from or Write to disk)
* phys_block_begin_i phys block where to start on the disk
* len_i Number of Bytes to transfer.
* addr_i temp_buf address.
*
* plus1 real data starts middle of 1st sector
* minus1 real data ends middle of last sector.
* sector_count Number of physical sectors to xfer
*
*/
temp_disk(fd_action, phys_blk_begin_i, len_i, addr_i)
u_int fd_action;
u_int phys_blk_begin_i;
u_int len_i;
caddr_t addr_i;
{
u_int secpcyl; /* number of sectors per cylinder */
u_int begin_sec; /* block begin xfer within cyl. */
u_int sec_size;
u_int unit;
u_int cyl, head, sect;
u_int tlen;
register struct fdcsb *csb = fdctlr.c_csb;
register struct buf *bp = csb->c_current;
register struct fdunit *un;
register struct fdk_char *ch;
unit = UNIT(bp->b_dev); /* floppy unit number */
un = fdctlr.c_units[ unit ];
ch = un->un_chars;
sec_size = ch->sec_size;
secpcyl = ch->nhead * ch->secptrack; /* sectors per cylinder */
while (len_i != 0) {
cyl = phys_blk_begin_i / secpcyl;
begin_sec = phys_blk_begin_i % secpcyl;
head = begin_sec / ch->secptrack;
sect = (begin_sec % ch->secptrack) + 1;
/*
* Truncate tlen if len extends beyond cylinder
*/
if (len_i > ((secpcyl - begin_sec) * sec_size))
tlen = (secpcyl - begin_sec) * sec_size;
else
tlen = len_i;
FDERRPRINT(FDEP_L1, FDEM_STRT,
(" phys_blk_begin_i 0x%x, addr_i 0x%x, len_i 0x%x\n",
phys_blk_begin_i , addr_i, len_i));
FDERRPRINT(FDEP_L1, FDEM_STRT,
(" cyl 0x%x, head 0x%x, sec 0x%x\n", cyl, head, sect));
FDERRPRINT(FDEP_L1, FDEM_STRT,
(" resid 0x%x, tlen %d\n", bp->b_resid, tlen));
csb->csb_cmds[0] = fd_action;
csb->csb_cmds[1] = (head << 2) | (unit & 0x3);
csb->csb_cmds[2] = cyl; /* C - cylinder address */
csb->csb_cmds[3] = head; /* H - head number */
csb->csb_cmds[4] = sect; /* R - sector number */
csb->csb_len = tlen;
csb->csb_addr = addr_i;
csb->csb_maxretry = rwretry; /* retry this many times max */
csb->csb_retrys = 0;
/* Execute Operation - failure returns an errno */
if ((bp->b_error = fdexec(FDXC_SLEEP | FDXC_CHECKCHG)) != 0) {
FDERRPRINT(FDEP_L1, FDEM_STRT,
("fdstart: bad exec of bp: 0x%x, err %d\n",
bp, bp->b_error));
bp->b_flags |= B_ERROR;
break;
}
phys_blk_begin_i += tlen / sec_size;
len_i -= tlen;
addr_i += tlen;
bp->b_resid -= tlen;
}
if (bp->b_resid < 0)
bp->b_resid = 0;
return (bp->b_error);
} /* end temp_disk */
/*
* TRANSFER data from buf to temp_buf or vice-versa
* --------------------------------------------------
*
* fd_action Type of transfer (Read from or Write to disk)
* plus1 real data starts middle of 1st sector
* bp os buf pointer.
* addr_i temp_buf address.
*
* (minus1 real data ends middle of last sector.)
*/
buf_temp(fd_action, plus1, bp, addr_i)
u_int fd_action;
u_int plus1;
struct buf *bp;
caddr_t addr_i;
{
int i;
caddr_t pt_temp, pt_buf;
pt_buf = bp->b_un.b_addr;
pt_temp = addr_i;
FDERRPRINT(FDEP_L1, FDEM_STRT,
("buf_temp: b_bcount=%x plus1 %x\n",bp->b_bcount, plus1));
if (plus1)
pt_temp += 512;
if (fd_action == CMD_READ) {
for (i=0; i<bp->b_bcount; i++)
*pt_buf++ = *pt_temp++;
} else {
for (i=0; i<bp->b_bcount; i++) {
*pt_temp++ = *pt_buf++;
}
}
} /* end buf_temp */
/*
* raw read and write operations share a common function to do their "work" :-)
*/
fdread(dev, uio)
dev_t dev;
struct uio *uio;
{
return (fdrdwr(dev, uio, B_READ));
}
fdwrite(dev, uio)
dev_t dev;
struct uio *uio;
{
return (fdrdwr(dev, uio, B_WRITE));
}
static
fdrdwr(dev, uio, rw)
dev_t dev;
struct uio *uio;
int rw;
{
FDERRPRINT(FDEP_L0, FDEM_RDWR, ("fdrdwr, rw = %d\n", rw));
FDERRPRINT(FDEP_L0, FDEM_RDWR, ("uio->uio_iov->iov_base = 0x%X\n",
uio->uio_iov->iov_base));
FDERRPRINT(FDEP_L0, FDEM_RDWR, ("uio->uio_iov->iov_len = %d\n",
uio->uio_iov->iov_len));
/* checks for UNIT(dev)) >= NFD, etc. done in fdstrategy */
return (physio(fdstrategy, &fdkbuf, dev, rw, minphys, uio));
}
#ifdef I82077
static
fdmotoff()
{
FDERRPRINT(FDEP_L1, FDEM_MOFF, ("fdmotoff\n"));
if (!(Msr & CB) && (Dor & MOTEN))
fd_set_dor_reg(MOTEN, 0);
}
#endif I82077
/*
* fdexec
* all commands go thru here. Assumes the command block
* fdctlr.c_csb is filled in. The bytes are sent to the
* controller and then we do whatever else the csb says -
* like wait for immediate results, etc.
*
* All waiting for operations done is in here - to allow retrys
* and checking for disk changed - so we don't have to worry
* about sleeping at interrupt level.
*
* RETURNS: 0 if all ok,
* ENXIO - diskette not in drive
* ETIMEDOUT - for immediate operations that timed out
* EBUSY - if stupid chip is locked busy???
* ENOEXEC - for timeout during sending cmds to chip
*/
fdexec(flags)
int flags; /*
* to sleep: set FDXC_SLEEP, to check for disk
* changed: set FDXC_CHECKCHG
*/
{
register struct fdcsb *csb;
register int i;
int to;
u_char mstat, tmp;
int oldpri;
int medium;
medium = fdctlr.c_units[fdctlr.c_csb->csb_unit]->un_chars->medium;
FDERRPRINT(FDEP_L1, FDEM_EXEC, ("\n******************** FDEXEC: flags 0x%x\n", flags));
csb = fdctlr.c_csb;
retry:
#ifdef I82077
switch (fdtype) {
case FD_82077:
FDERRPRINT(FDEP_L1, FDEM_EXEC, ("fdexec: cmd is %s\n",
fdcmds[csb->csb_cmds[0] & 0x1f].cmdname));
untimeout(fdmotoff, (caddr_t) 0);
/* fd_set_dor(MEDIUM_DENSITY, 0); */
/* fd_set_dor_reg(MOTEN, 1); HR XXX NEW CHANGE */
if (!(Dor & MOTEN) || ((Dor & MEDIUM_DENSITY) >> 6) ^ medium ) {
/* Turn on the motor.
*/
FDERRPRINT(FDEP_L1, FDEM_EXEC, ("fdexec: turning on motor\n",
fdcmds[csb->csb_cmds[0] & 0x1f].cmdname));
fd_set_dor_reg(MOTEN, 1);
if (flags & FDXC_SLEEP) {
timeout(wakeup, (caddr_t) fdctlr_reg, MOTON_DELAY);
(void) sleep((caddr_t) fdctlr_reg, PZERO - 1);
} else {
DELAY(1000000);
}
}
break;
}
#endif I82077
fdselect((int)csb->csb_unit, 1); /* select drive */
/* select data rate for this unit/command */
FDERRPRINT(FDEP_L1, FDEM_EXEC, ("fdexec: medium = %d\n",
csb->csb_un->un_chars->medium ));
FDERRPRINT(FDEP_L1, FDEM_EXEC, ("fdexec: transfer rate = %d\n",
csb->csb_un->un_chars->transfer_rate));
FDERRPRINT(FDEP_L1, FDEM_EXEC, ("fdexec: ncyl = %d\n",
csb->csb_un->un_chars->ncyl));
FDERRPRINT(FDEP_L1, FDEM_EXEC, ("fdexec: sec_size = %d\n",
csb->csb_un->un_chars->sec_size ));
FDERRPRINT(FDEP_L1, FDEM_EXEC, ("fdexec: secptrack = %d\n",
csb->csb_un->un_chars->secptrack));
switch (csb->csb_un->un_chars->transfer_rate) {
case 500:
Dsr = 0;
break;
case 300:
Dsr = 1;
break;
case 250:
Dsr = 2;
break;
}
DELAY(2);
/*
* if checking for changed is enabled (ie not seeking in checkdisk)
* we sample the DSKCHG line to see if the diskette has wandered away
*/
if ((flags & FDXC_CHECKCHG) && fdsense_chng()) {
FDERRPRINT(FDEP_L1, FDEM_EXEC, ("diskette changed!!!\n"));
csb->csb_un->un_flags |= FDUNIT_CHANGED;
/* if the diskette is still gone... so are we, adios! */
if (fdcheckdisk((int)csb->csb_unit))
return (ENXIO);
}
/*
* gather some statistics
*/
switch (csb->csb_cmds[0] & 0x1f) {
case FRAW_RDCMD:
fdctlr.fdstats.rd++;
break;
case FRAW_WRCMD:
fdctlr.fdstats.wr++;
break;
case FRAW_REZERO:
fdctlr.fdstats.recal++;
break;
case FRAW_FORMAT:
fdctlr.fdstats.form++;
break;
default:
fdctlr.fdstats.other++;
break;
}
/*
* set info for level11 hardware interrupt handler
*/
/* if (operation is seek/relative-seek/recalibrate) ... */
if (csb->csb_opflags & CSB_OFSEEKOPS) {
fdintr_opmode = 2;
fdintr_addr = fdintr_statbuf; /* safe place to point */
fdintr_len = 0;
} else
/* if immediate mode ... */
if (csb->csb_opflags & CSB_OFIMMEDIATE) {
fdintr_opmode = 0;
fdintr_addr = fdintr_statbuf; /* safe place to point */
fdintr_len = 0;
} else {
fdintr_opmode = 1; /* normal data xfer commands */
fdintr_addr = (u_char *)csb->csb_addr;
fdintr_len = csb->csb_len;
}
fdintr_status = 0;
fdintr_statp = fdintr_statbuf; /* set pointer to statbuf !!!!! */
fdintr_timeout = fdhardtimeout; /* XXX load timeout value */
csb->csb_cmdstat = 0;
/*
* give cmd to controller
*/
/* check for a command in progress? - avoid catastrophic errs */
/*
* XXX ***
* i saw this (chip unexpectedly busy) happen when i shoved the
* floppy into the drive while
* running a dd if=/dev/rfd0c. so it *is* possible for this to happen.
* we need to do a ctlr reset ...
*/
if ((mstat = Msr) & CB) {
/* tried to give command to chip when it is busy! ***/
FDERRPRINT(FDEP_L3, FDEM_EXEC,
("fdc: unexpectedly busy - stat 0x%x\n", mstat));
#ifdef XXX
XXX arf! needs to avoid recusion
fdreset();
/* fdrecal already has csb */
fdrecalseek(unit, -1, 0); /* no check changed! */
#endif XXX
csb->csb_cmdstat = -1; /* XXX TBD ERRS NYD for now */
return (EBUSY);
}
/* if sleeping, raise the priority */
/*
******** START CRITICAL SECTION ********
*/
if (flags & FDXC_SLEEP) {
oldpri = splr(fdpri); /* raise priority */
}
FDERRPRINT(FDEP_L0, FDEM_EXEC, ("fdexec: C M D = "));
for (i = 0; i < csb->csb_ncmds; i++) {
#ifdef I82077
DELAY(10);
#endif I82077
/* is this loop really necessary? */
for (to = FD_CRETRY; to; to--) {
/* insure that rqm of main status reg is ok */
if ((Msr & (DIO|RQM)) == RQM)
break;
}
if (to == 0) {
/* was a timeout - XXX TBD NYD */
FDERRPRINT(FDEP_L3, FDEM_EXEC,
("fdc: no RQM - stat 0x%x\n", Msr));
csb->csb_cmdstat = -1; /* XXX TBD ERRS NYD for now */
if (flags & FDXC_SLEEP)
(void) splx(oldpri);
return (ENOEXEC);
}
Fifo = csb->csb_cmds[i]; /* send command to controller */
FDERRPRINT(FDEP_L0, FDEM_EXEC, ("%x%c ",
csb->csb_cmds[i],( Msr == 0x10 ? ' ':'?')));
}
/*
* start watchdog timer on data transfer type commands - required
* in case a diskette is not present or is unformatted
*/
if (csb->csb_opflags & CSB_OFTIMEIT) {
timeout(fdwatch, (caddr_t)0, tosec*hz);
}
FDERRPRINT(FDEP_L0, FDEM_EXEC,
("\nfdexec: cmd sent, Msr 0x%x\n", Msr));
/*
* if the operation has no results - then just return
*/
if (csb->csb_opflags & CSB_OFNORESULTS) {
if (flags & FDXC_SLEEP) /* not likely, but... */
(void) splx(oldpri);
#ifdef I82077
if (fdtype == FD_82077)
timeout(fdmotoff, (caddr_t) 0, MOTOFF_DELAY);
#endif I82077
return (0);
}
/*
* if this operation has no interrupt AND an immediate result
* then we just busy wait for the results and stuff them into
* the csb
*/
if (csb->csb_opflags & CSB_OFIMMEDIATE) {
DELAY(10*hz); /* 10 sec delay */
to = FD_RRETRY;
csb->csb_nrslts = 0;
/* while this command is still going on */
while ((tmp = Msr) & CB) {
/* if RQM + DIO, then a result byte is at hand */
if ((tmp & (RQM|DIO|CB)) == (RQM|DIO|CB)) {
csb->csb_rslt[ csb->csb_nrslts++ ] = Fifo;
/* XXX limit number of status bytes read? ***/
} else
if (--to == 0) {
FDERRPRINT(FDEP_L4, FDEM_EXEC,
("fdexec: rslt timeout, Msr 0x%x, nr %d\n",
Msr, csb->csb_nrslts));
/* XXX what to do now? ***/
csb->csb_status = 2;
/* should never be set, but... */
if (flags & FDXC_SLEEP)
(void) splx(oldpri);
#ifdef I82077
if (fdtype == FD_82077)
timeout(fdmotoff, (caddr_t) 0, MOTOFF_DELAY);
#endif I82077
return (ETIMEDOUT);
}
}
}
/* if told to sleep here, well then sleep! */
if (flags & FDXC_SLEEP) {
/* we're splr'd, so we can set this without worry (we hope) */
fdctlr.c_flags |= FDCFLG_WAITING;
/* Sleep till cmd complete */
while (fdctlr.c_flags & FDCFLG_WAITING) {
(void)sleep((caddr_t)(fdctlr.c_csb), FDPRI);
}
(void) splx(oldpri);
/*
******** END CRITICAL SECTION
*****************************/
}
/*
* see if there was an error detected, if so,
* fdrecover() will check it out and say what to do.
*/
if (((csb->csb_rslt[0] & IC_SR0) || (csb->csb_status)) &&
((csb->csb_cmds[0] != FRAW_SENSE_DRV) && /* not sense drv status */
(csb->csb_cmds[0] != DUMPREG))) { /* not dumpreg */
/* if it can restarted OK, then do so, else return error */
if (fdrecover() != 0) {
#ifdef I82077
if (fdtype == FD_82077)
timeout(fdmotoff, (caddr_t) 0, MOTOFF_DELAY);
#endif I82077
return (EIO);
} else {
/* ASSUMES that cmd is still intact in csb */
goto retry;
}
}
/* things went ok */
#ifdef I82077
if (fdtype == FD_82077)
timeout(fdmotoff, (caddr_t) 0, MOTOFF_DELAY);
#endif I82077
FDERRPRINT(FDEP_L1, FDEM_EXEC, ("____________________END_FDEXEC\n"));
return (0);
}
/*
* fdrecover
* see if possible to retry an operation.
* All we can do is restart the operation. If we are out of allowed
* retries - return non-zero so that the higher levels will be notified.
*
* RETURNS: 0 if ok to restart, !0 if can't or out of retries
*/
fdrecover()
{
struct fdcsb *ccsb; /* private csb for resetting */
struct fdcsb *csb;
int unit;
FDERRPRINT(FDEP_L1, FDEM_RECO, ("fdrecover\n"));
csb = fdctlr.c_csb;
if (fdctlr.c_flags & FDCFLG_TIMEDOUT) {
fdctlr.c_flags &= ~FDCFLG_TIMEDOUT;
csb->csb_rslt[1] |= 0x08;
FDERRPRINT(FDEP_L1, FDEM_RECO,
("fd%d: %s timed out\n", csb->csb_unit,
fdcmds[csb->csb_cmds[0] & 0x1f].cmdname));
unit = csb->csb_unit;
/* use private csb */
ccsb = (struct fdcsb *)kmem_zalloc(sizeof (struct fdcsb));
fdctlr.c_csb = ccsb;
FDERRPRINT(FDEP_L1, FDEM_RECO, ("fdc: resetting\n"));
fdreset();
/* check change first?? */
/* don't ckchg in fdexec, too convoluted */
(void)fdrecalseek(unit, -1, 0);
fdctlr.c_csb = csb; /* restore original csb */
kmem_free((caddr_t)ccsb, sizeof (struct fdcsb));
}
/*
* gather statistics on errors
*/
if (csb->csb_rslt[1] & DE_SR1) {
fdctlr.fdstats.de++;
}
if (csb->csb_rslt[1] & OR_SR1) {
fdctlr.fdstats.run++;
}
if (csb->csb_rslt[1] & (ND_SR1+MA_SR1)) {
fdctlr.fdstats.bfmt++;
}
if (csb->csb_rslt[1] & 0x08) {
fdctlr.fdstats.to++;
}
/* if raw ioctl don't examine results just pass status back via fdraw */
/* raw commands are timed too, so put this after the above check */
if (csb->csb_opflags & CSB_OFRAWIOCTL) {
return (1);
}
/*
* if we have run out of retries, return an error
* XXX need better status interp
*/
csb->csb_retrys++;
if (csb->csb_retrys > csb->csb_maxretry) {
FDERRPRINT(FDEP_L3, FDEM_RECO,
("fd%d: %s failed (%x %x %x)\n",
csb->csb_unit,
fdcmds[csb->csb_cmds[0] & 0x1f].cmdname,
csb->csb_rslt[0], csb->csb_rslt[1], csb->csb_rslt[2]));
FDERRPRINT(FDEP_L0, FDEM_RECO, ("fdrecover 1.1\n"));
if (csb->csb_rslt[1] & NW_SR1) {
FDERRPRINT(FDEP_L3, FDEM_RECO,
("fd%d: not writable\n", csb->csb_unit));
}
FDERRPRINT(FDEP_L0, FDEM_RECO, ("fdrecover 1.2\n"));
if (csb->csb_rslt[1] & DE_SR1) {
if (fdctlr.c_head.b_forw) {
FDERRPRINT(FDEP_L3, FDEM_RECO,
("fd%d: crc error blk %d\n",
csb->csb_unit,
fdctlr.c_head.b_forw->b_blkno));
} else {
FDERRPRINT(FDEP_L3, FDEM_RECO,
("fd%d: crc error fdrw\n",
csb->csb_unit));
}
}
FDERRPRINT(FDEP_L0, FDEM_RECO, ("fdrecover 1.3\n"));
if (csb->csb_rslt[1] & OR_SR1) {
FDERRPRINT(FDEP_L3, FDEM_RECO,
("fd%d: overrun/underrun\n", csb->csb_unit));
}
FDERRPRINT(FDEP_L0, FDEM_RECO, ("fdrecover 1.4\n"));
if (csb->csb_rslt[1] & (ND_SR1+MA_SR1)) {
FDERRPRINT(FDEP_L3, FDEM_RECO,
("fd%d: bad format\n", csb->csb_unit));
}
FDERRPRINT(FDEP_L0, FDEM_RECO, ("fdrecover 1.5\n"));
if (csb->csb_rslt[1] & 0x08) {
FDERRPRINT(FDEP_L3, FDEM_RECO,
("fd%d: timeout\n", csb->csb_unit));
}
FDERRPRINT(FDEP_L0, FDEM_RECO, ("fdrecover 1.6\n"));
csb->csb_cmdstat = -1; /* failed - give up */
return (1);
}
FDERRPRINT(FDEP_L0, FDEM_RECO, ("fdrecover 2\n"));
if (csb->csb_opflags & CSB_OFSEEKOPS) {
/* seek, recal type commands - just look at st0 */
FDERRPRINT(FDEP_L2, FDEM_RECO,
("fd%d: %s error : st0 0x%x\n",
csb->csb_unit,
fdcmds[csb->csb_cmds[0] & 0x1f].cmdname,
csb->csb_rslt[0]));
}
FDERRPRINT(FDEP_L0, FDEM_RECO, ("fdrecover 3\n"));
if (csb->csb_opflags & CSB_OFXFEROPS) {
/* rd, wr, fmt type commands - look at st0, st1, st2 */
FDERRPRINT(FDEP_L2, FDEM_RECO,
("fd%d: %s error : st0=0x%x st1=0x%x st2=0x%x\n",
csb->csb_unit, fdcmds[csb->csb_cmds[0] & 0x1f].cmdname,
csb->csb_rslt[0], csb->csb_rslt[1], csb->csb_rslt[2]));
}
return (0); /* tell fdexec to retry */
}
/*
* fdintr
* this is the level4 sw interrupt handler triggered by the level11
* trap handler when the command is complete. we also get here from
* fdwatch.
* NOTE: this software interrupt level is shared.
* NOTE: we must return 0 if not ours, 1 if it was.
*/
fdintr()
{
register struct fdcsb *csb;
register int i;
FDERRPRINT(FDEP_L1, FDEM_INTR, ("fdintr: opmode %d\n", fdintr_opmode));
/* check that lowlevel interrupt really meant to trigger us */
if (fdintr_opmode != 4)
return (0);
fdintr_opmode = 0;
csb = fdctlr.c_csb;
/* reset watchdog timer if armed and not already triggered */
if ((csb->csb_opflags & CSB_OFTIMEIT) &&
! (fdctlr.c_flags & FDCFLG_TIMEDOUT))
untimeout(fdwatch, (caddr_t)0);
/*
* examine results of command just completed (it places status
* bytes in buffer) - retry if there was a recoverable error.
*/
csb->csb_raddr = (caddr_t)fdintr_addr; /* (current) data xfer address */
csb->csb_rlen = fdintr_len; /* I: data xfer length; O: remainder */
csb->csb_status = fdintr_status; /* I: n/a; O: 0 = ok, TBD errors */
/* XXX - who to believe, chip or csb? */
for (i = 0; i < csb->csb_nrslts; i++) {
csb->csb_rslt[i] = fdintr_statbuf[i];
}
/*XXX what to do on a level11 timeout??? */
if (fdintr_timeout == 0) {
FDERRPRINT(FDEP_L4, FDEM_INTR,
("fdintr: fdintr_timeout!, opmode %d, MSR 0x%x\n",
fdintr_opmode, Msr));
}
if (fdctlr.c_flags & FDCFLG_WAITING) {
/* somebody's waiting on finish of fdctlr/csb, wake them */
fdctlr.c_flags &= ~FDCFLG_WAITING;
wakeup((caddr_t)(fdctlr.c_csb));
/*
* FDCFLG_BUSY is NOT cleared, NOR is the csb given back; so
* the operation just finished can look at the csb
*/
return (1);
}
FDERRPRINT(FDEP_L3, FDEM_INTR,
("fdintr: nobody sleeping\n"));
return (1);
}
/*
* fdwatch
* is called from timein() when a floppy operation has expired.
*/
fdwatch()
{
struct fdcsb *csb;
csb = fdctlr.c_csb;
FDERRPRINT(FDEP_L1, FDEM_WATC, ("fd%d: timeout, opmode = %d\n",
csb->csb_unit, fdintr_opmode));
fdintr_opmode = 4; /* for fdintr @level 4 */
fdctlr.c_flags |= FDCFLG_TIMEDOUT;
fdintr_status = CSB_CMDTO;
/* trigger the level4 int @fdintr */
set_intreg(IR_SOFT_INT4, 1);
}
/*
* fdioctl
* implements more ioctls than a floppy disk ought to have
*
* RETURNS: an errno for user >>> at end of each case <<<
*/
/*ARGSUSED*/
fdioctl(dev, cmd, arg, flag)
dev_t dev;
int cmd;
caddr_t arg;
int flag;
{
int unit;
struct fdunit *un;
#ifdef XXX
u_int sec_size;
#endif XXX
FDERRPRINT(FDEP_L1, FDEM_IOCT, ("fdioctl: cmd 0x%x, arg 0x%x\n",
cmd, arg));
/* check for valid unit - failure should *never happen* */
unit = UNIT(dev);
if (unit >= NFD || fdtype == -1) {
return (ENXIO);
}
un = fdctlr.c_units[ unit ];
#ifdef XXX
sec_size = ch->sec_size;
#endif XXX
switch (cmd) {
case DKIOCINFO: /* return struct dk_info describing controller/unit */
{
struct dk_info *dki = (struct dk_info *)arg;
dki->dki_ctlr = OBIO_FDC_ADDR; /* addres of controller */
dki->dki_unit = unit;
if (fdtype == FD_82072)
dki->dki_ctype = DKC_INTEL82072;
if (fdtype == FD_82077)
dki->dki_ctype = DKC_INTEL82077;
dki->dki_flags = DKI_FMTTRK; /* format track at a time */
}
return (0);
/* get disk geometry */
case DKIOCGGEOM: /* return struct dk_geom describing disk geometry */
{
struct dk_geom *dkg = (struct dk_geom *)arg;
dkg->dkg_ncyl = un->un_chars->ncyl;
dkg->dkg_nhead = un->un_chars->nhead;
dkg->dkg_nsect = un->un_chars->secptrack;
dkg->dkg_intrlv = un->un_label->dkl_intrlv;
dkg->dkg_rpm = un->un_label->dkl_rpm;
dkg->dkg_pcyl = un->un_chars->ncyl;
}
return (0);
case DKIOCSGEOM:
FDERRPRINT(FDEP_L3, FDEM_IOCT,
("fdioctl: DKIOCSGEOM not supported\n"));
return (EINVAL);
/*
* Return the map for the specified logical partition.
* This has been made obsolete by the get all partitions command.
*/
case DKIOCGPART:
/* structure copy! */
*(struct dk_map *)arg =
un->un_label->dkl_map[ PARTITION(dev) ];
return (0);
case DKIOCSPART:
{
struct dk_map *dkm_src = (struct dk_map *)arg;
struct dk_map *dkm_dst =
&(un->un_label->dkl_map[ PARTITION(dev) ]);
*dkm_dst = *dkm_src;
}
return (0);
/*
* return the map of all logical partitions
*/
case DKIOCGAPART:
/* structure copy! */
*(struct dk_allmap *)arg =
*(struct dk_allmap *)un->un_label->dkl_map;
return (0);
/*
* Set the map of all logical partitions
*/
case DKIOCSAPART:
{
struct dk_allmap *dkam_src = (struct dk_allmap *)arg;
struct dk_allmap *dkam_dst =
(struct dk_allmap *)un->un_label->dkl_map;
*dkam_dst = *dkam_src;
}
return (0);
case FDKIOGCHAR:
/* structure copy! */
*(struct fdk_char *)arg = *(un->un_chars);
return (0);
case FDKIOSCHAR:
{
struct fdk_char *fdchar = (struct fdk_char *)arg;
switch (fdchar->transfer_rate) {
case 500:
case 300:
case 250:
break;
default:
FDERRPRINT(FDEP_L3, FDEM_IOCT,
("fdioctl: FDKIOSCHAR unsupported transfer rate %d\n",
fdchar->transfer_rate));
return (EINVAL);
}
/* structure copy! */
*(un->un_chars) = *fdchar;
curfdtype = -1;
FDERRPRINT(FDEP_L0, FDEM_IOCT,
("fdioctl: S E T T I N G C H A R A C T\n"));
}
return (0);
case FDKEJECT: /* eject disk */
fdselect(UNIT(dev), 1);
fdeject();
return (0);
case FDKGETCHANGE: /* disk changed */
if (un->un_flags & FDUNIT_CHANGED)
*(int *)arg |= FDKGC_HISTORY;
else
*(int *)arg &= ~FDKGC_HISTORY;
un->un_flags &= ~FDUNIT_CHANGED;
if (fdsense_chng()) { /* check disk only if changed */
if (fdcheckdisk(unit)) {
*(int *)arg |= FDKGC_CURRENT;
} else {
*(int *)arg &= ~FDKGC_CURRENT;
}
} else {
*(int *)arg &= ~FDKGC_CURRENT;
}
return (0);
case FDKGETDRIVECHAR:
{
struct fdk_drive *drvchar = (struct fdk_drive *)arg;
drvchar->fdd_ejectable = -1; /* we do support autoeject */
drvchar->fdd_maxsearch = nfdtypes; /* density:hi, m, lo */
/* the rest of the fdk_drive struct is meaningless to us */
}
return (0);
case FDKSETDRIVECHAR:
FDERRPRINT(FDEP_L3, FDEM_IOCT,
("fdioctl: FDKSETDRIVECHAR not supported\n"));
return (EINVAL);
case DKIOCSCMD:
case FDKIOCSCMD:
{
struct dk_cmd *dkc = (struct dk_cmd *)arg;
int cyl, hd, spc, spt;
spt = un->un_chars->secptrack; /* sec/trk */
spc = un->un_chars->nhead * spt; /* sec/cyl */
cyl = dkc->dkc_blkno / spc;
hd = (dkc->dkc_blkno % spc) / spt;
switch (dkc->dkc_cmd) {
#ifdef XXX
/* XXX need to mapin and as_fault lock user address! XXX */
case FKREAD:
sec = ((dkc->dkc_blkno % spc) % spt) + 1;
if (fdrw(FDREAD, unit, cyl, hd, sec,
dkc->dkc_bufaddr,
(u_int)dkc->dkc_secnt * sec_size))
return (EIO);
return (0);
case FKWRITE:
sec = ((dkc->dkc_blkno % spc) % spt) + 1;
if (fdrw(FDWRITE, unit, cyl, hd, sec,
dkc->dkc_bufaddr,
(u_int)dkc->dkc_secnt * sec_size))
return (EIO);
return (0);
#endif XXX
case FKFORMAT_TRACK:
if (fdformat(unit, cyl, hd))
return (EIO);
return (0);
default:
FDERRPRINT(FDEP_L3, FDEM_IOCT,
("fdioctl: FDKIOCSCMD not yet complete\n"));
return (EINVAL);
}
}
/*
*
*/
case F_RAW:
return (fdrawioctl(dev, arg));
case IOCTL_DEBUG:
if (fderrlevel == 0)
fderrlevel = 3;
if (fderrlevel == 3)
fderrlevel = 0;
printf("fdioctl: TOGGLING trace\n");
return(0);
default:
FDERRPRINT(FDEP_L2, FDEM_IOCT,
("fdioctl: invalid ioctl 0x%x\n", cmd));
return (ENOTTY);
}
#ifdef NEVER
/* hopefuly nobody gets here! */
/*NOTREACHED*/
return (ENOTTY);
#endif NEVER
} /* end fdioctl */
/*
* fdrawioctl
*
*/
fdrawioctl(dev, arg)
dev_t dev;
caddr_t arg;
{
struct fdunit *un = fdctlr.c_units[ UNIT(dev) ];
struct fdraw *fdr = (struct fdraw *)arg;
struct fdcsb *csb;
struct buf *bp;
int i;
int flag = B_READ;
int oldpri;
caddr_t addr, fa;
u_int fc;
long count;
FDERRPRINT(FDEP_L1, FDEM_RAWI,
("fdrawioctl: dev=0x%x cmd[0]=0x%x\n", dev, fdr->fr_cmd[0]));
/*
* check if medium density is asked but not supported
*/
if (un->un_chars->medium && fdtype == FD_82072) {
printf("fdrawioctl: Medium density NOT supported\n");
return(ENXIO);
}
fdgetcsb();
csb = fdctlr.c_csb;
csb->csb_un = un;
csb->csb_unit = UNIT(dev);
csb->csb_part = 0;
/* copy cmd bytes into csb */
for (i=0; i<=fdr->fr_cnum; i++) {
csb->csb_cmds[i] = fdr->fr_cmd[i];
}
csb->csb_ncmds = fdr->fr_cnum;
csb->csb_maxretry = 0; /* let the application deal with errors */
csb->csb_retrys = 0;
switch (fdr->fr_cmd[0] & 0x0f) {
case FRAW_SPECIFY:
csb->csb_opflags = CSB_OFNORESULTS;
csb->csb_nrslts = 0;
break;
case FRAW_SENSE_DRV:
csb->csb_opflags = CSB_OFIMMEDIATE;
csb->csb_nrslts = 1;
break;
case FRAW_REZERO:
case FRAW_SEEK:
csb->csb_opflags = CSB_OFSEEKOPS + CSB_OFTIMEIT;
csb->csb_nrslts = 2;
break;
case FRAW_FORMAT:
csb->csb_opflags = CSB_OFXFEROPS + CSB_OFTIMEIT;
csb->csb_nrslts = NRBRW;
flag = B_WRITE;
fc = (u_int)(fdr->fr_nbytes + 16);
fa = (caddr_t)kmem_zalloc(fc);
(void) copyin(fdr->fr_addr, fa, (u_int)fdr->fr_nbytes);
/*XXX handle copyin errors */
break;
case FRAW_WRCMD:
case FRAW_WRITEDEL:
flag = B_WRITE;
case FRAW_RDCMD:
case FRAW_READDEL:
case FRAW_READTRACK:
csb->csb_opflags = CSB_OFXFEROPS + CSB_OFTIMEIT;
csb->csb_nrslts = NRBRW;
/* flag was set to B_READ above */
break;
#ifdef XXX
cmds not supported for now
case FRAW_READID:
break;
case FRAW_SENSE_INT:
break;
#endif XXX
default:
fdretcsb();
return (EINVAL);
}
if ((csb->csb_opflags & CSB_OFXFEROPS) && (fdr->fr_nbytes == 0)) {
fdretcsb();
return (EINVAL);
}
csb->csb_opflags |= CSB_OFRAWIOCTL;
if ((fdr->fr_cmd[0] & 0x0f) != FRAW_FORMAT) {
/* if data transfer involved need to use the special bp */
if (fdr->fr_nbytes > 0) {
bp = &fdkbuf;
oldpri = splr(fdpri);
while (bp->b_flags & B_BUSY) {
bp->b_flags |= B_WANTED;
(void) sleep((caddr_t)bp, FDPRI);
}
bp->b_flags = B_BUSY;
(void) splx(oldpri);
bp->b_flags |= B_PHYS;
addr = bp->b_un.b_addr = fdr->fr_addr;
count = bp->b_bcount = (long)fdr->fr_nbytes;
bp->b_proc = u.u_procp;
u.u_procp->p_flag |= SPHYSIO;
(void) as_fault(u.u_procp->p_as, addr,
(u_int)count, F_SOFTLOCK,
(flag == B_WRITE) ? S_WRITE : S_READ);
/*XXX handle errors from as_fault ****/
bp_mapin(bp);
csb->csb_addr = bp->b_un.b_addr;
csb->csb_len = bp->b_bcount;
} else {
/*XXX or maybe point someplace safer?? */
csb->csb_addr = 0;
csb->csb_len = 0;
}
} else {
csb->csb_addr = fa;
csb->csb_len = fc;
}
FDERRPRINT(FDEP_L1, FDEM_RAWI,
("cmd: %x %x %x %x %x %x %x %x %x %x\n", csb->csb_cmds[0],
csb->csb_cmds[1], csb->csb_cmds[2], csb->csb_cmds[3],
csb->csb_cmds[4], csb->csb_cmds[5], csb->csb_cmds[6],
csb->csb_cmds[7], csb->csb_cmds[8], csb->csb_cmds[9]));
FDERRPRINT(FDEP_L1, FDEM_RAWI,
("nbytes: %x, opflags: %x, addr: %x, len: %x\n",
csb->csb_ncmds, csb->csb_opflags, csb->csb_addr, csb->csb_len));
if ((csb->csb_opflags & CSB_OFNORESULTS) ||
(csb->csb_opflags & CSB_OFIMMEDIATE)) {
i = fdexec(0); /* don't sleep, don't check change */
} else {
i = fdexec(FDXC_SLEEP | FDXC_CHECKCHG); /* sleep till done */
}
DELAY(1*hz); /* 1 sec delay */
FDERRPRINT(FDEP_L1, FDEM_RAWI,
("rslt: %x %x %x %x %x %x %x %x %x %x\n", csb->csb_rslt[0],
csb->csb_rslt[1], csb->csb_rslt[2], csb->csb_rslt[3],
csb->csb_rslt[4], csb->csb_rslt[5], csb->csb_rslt[6],
csb->csb_rslt[7], csb->csb_rslt[8], csb->csb_rslt[9]));
if ((fdr->fr_cmd[0] & 0x0f) != FRAW_FORMAT) {
if (fdr->fr_nbytes > 0) {
bp_mapout(bp);
(void) as_fault(u.u_procp->p_as, addr,
(u_int)count, F_SOFTUNLOCK,
(flag == B_WRITE)? S_WRITE: S_READ);
/*XXX handle errors from as_fault ****/
oldpri = splr(fdpri);
u.u_procp->p_flag &= ~SPHYSIO;
if (bp->b_flags & B_WANTED)
wakeup((caddr_t)bp);
(void) splx(oldpri);
bp->b_flags &= ~(B_BUSY|B_WANTED|B_PHYS);
}
} else {
kmem_free(fa, fc);
}
/* copy cmd results into fdr */
for (i=0; i<=csb->csb_nrslts; i++)
fdr->fr_result[i] = csb->csb_rslt[i];
fdr->fr_nbytes = csb->csb_rlen; /* return resid */
fdretcsb();
return (0);
}
/*
* fddump
* 'cause the config stuff wants it
* it doesn't make sense to dump system on a floppy, so don't even
* try, just return an error.
* (dump occurs to swap area, and there isn't enough room on a floppy
* to swap on)
*/
/*ARGSUSED*/
fddump(dev, addr, blkno, nblk)
dev_t dev;
caddr_t addr;
daddr_t blkno, nblk;
{
return (ENOSPC);
}
/*
* fdgetcsb
* wait until the csb is free
*/
fdgetcsb()
{
int oldpri;
FDERRPRINT(FDEP_L1, FDEM_GETC, ("fdgetcsb\n"));
oldpri = splr(fdpri); /* raise priority */
while (fdctlr.c_flags & FDCFLG_BUSY) {
fdctlr.c_flags |= FDCFLG_WANT;
(void)sleep((caddr_t)&(fdctlr.c_flags), FDPRI);
}
fdctlr.c_flags |= FDCFLG_BUSY; /* got it! */
(void) splx(oldpri);
}
/*
* fdretcsb
* return csb
*/
fdretcsb()
{
FDERRPRINT(FDEP_L1, FDEM_RETC, ("fdretcsb\n"));
fdctlr.c_flags &= ~FDCFLG_BUSY; /* let go */
if (fdctlr.c_flags & FDCFLG_WANT) {
fdctlr.c_flags &= ~FDCFLG_WANT;
wakeup((caddr_t)&(fdctlr.c_flags));
}
}
/*
* fdreset
* reset THE controller, and configure it to be
* the way it ought to be
* ASSUMES: that it already owns the csb/fdctlr!
*/
fdreset()
{
register struct fdcsb *csb = fdctlr.c_csb;
FDERRPRINT(FDEP_L1, FDEM_RESE, ("fdreset\n"));
/* count resets */
fdctlr.fdstats.reset++;
/* toggle software reset */
Dsr = SWR;
DELAY(5);
/*
* select data rate for this unit/command
*/
switch (fdctlr.c_units[csb->csb_unit]->un_chars->transfer_rate) {
case 500:
Dsr = 0;
break;
case 300:
Dsr = 1;
break;
case 250:
Dsr = 2;
break;
}
DELAY(5);
#ifdef I82077
switch (fdtype) {
case FD_82077:
untimeout(fdmotoff, (caddr_t) 0);
/* The reset bit must be cleared to take the 077 out of
* reset state and the DMAGATE bit must be high to enable
* interrupts.
*/
fd_set_dor_reg(ZEROBITS, 0);
fd_set_dor_reg(DMAGATE|RESET, 1);
break;
}
#endif I82077
/* setup common things in csb */
csb->csb_un = fdctlr.c_units[0];
csb->csb_unit = 0;
csb->csb_part = 0;
csb->csb_nrslts = 0;
csb->csb_opflags = CSB_OFNORESULTS;
csb->csb_maxretry = 0;
csb->csb_retrys = 0;
/* send SPECIFY command to fdc */
/* csb->unit is don't care */
csb->csb_cmds[0] = FRAW_SPECIFY;
csb->csb_cmds[1] = fdspec[0]; /* step rate, head unload time */
csb->csb_cmds[2] = fdspec[1]; /* head load time, DMA mode */
csb->csb_ncmds = 3;
/* XXX for now ignore errors, they "CAN'T HAPPEN" */
(void) fdexec(0); /* no FDXC_CHECKCHG, ... */
/* no results */
/* send CONFIGURE command to fdc */
/* csb->unit is don't care */
csb->csb_cmds[0] = CONFIGURE;
csb->csb_cmds[1] = fdconf[0]; /* motor info, motor delays */
csb->csb_cmds[2] = fdconf[1]; /* enaimplsk, disapoll, fifothru */
csb->csb_cmds[3] = fdconf[2]; /* track precomp */
csb->csb_ncmds = 4;
csb->csb_retrys = 0;
/* XXX for now ignore errors, they "CAN'T HAPPEN" */
(void) fdexec(0); /* no FDXC_CHECKCHG, ... */
/* no results */
}
/*
* fdrecalseek
* performs recalibrates or seeks if the "arg" is -1 does a
* recalibrate on a drive, else it seeks to the cylinder of
* the drive. The recalibrate is also used to find a drive,
* ie if the drive is not there, the controller says "error"
* on the operation
* NOTE: that there is special handling of this operation in the hardware
* interrupt routine - it causes the operation to appear to have results;
* ie the results of the SENSE INTERRUPT STATUS that the hardware interrupt
* function did for us.
* NOTE: because it uses sleep/wakeup it must be protected in a critical
* section so create one before calling it!
*
* RETURNS: 0 for ok,
* else errno from fdexec,
* or ENODEV if error (infers hardware type error)
*/
fdrecalseek(unit, arg, execflg)
int unit;
int arg; /* -1 recalibrate, 0-? seek to here */
int execflg; /* bits to OR into flag sent to fdexec */
{
register struct fdcsb *csb;
int result;
FDERRPRINT(FDEP_L1, FDEM_RECA, ("fdrecalseek to %d\n", arg));
/*XXX TODO: check see argument for <= num cyls OR < 256 ****/
csb = fdctlr.c_csb;
csb->csb_un = fdctlr.c_units[unit];
csb->csb_unit = unit;
csb->csb_part = 0;
csb->csb_cmds[1] = unit & 0x03;
if (arg == -1) { /* is recal... */
csb->csb_cmds[0] = FRAW_REZERO;
csb->csb_ncmds = 2;
} else {
csb->csb_cmds[0] = FRAW_SEEK;
csb->csb_cmds[2] = (u_char)arg;
csb->csb_ncmds = 3;
}
csb->csb_nrslts = 2; /* 2 for SENSE INTERRUPTS */
csb->csb_opflags = CSB_OFSEEKOPS | CSB_OFTIMEIT;
/* MAYBE NYD need to set retries to different values? - depending on
* drive characteristics - if we get to high capacity drives */
csb->csb_maxretry = skretry;
csb->csb_retrys = 0;
/* send cmd off to fdexec */
if (result = fdexec(FDXC_SLEEP | execflg)) {
goto out;
}
/*
* if recal, test for equipment check error
* ASSUMES result = 0 from above call
*/
if (arg == -1) {
#ifdef I82077
result = 0;
#else
if (csb->csb_rslt[0] & EC_SR0)
result = ENODEV;
#endif I82077
} else {
/* for seeks, any old error will do */
if ((csb->csb_rslt[0] & IC_SR0) || csb->csb_cmdstat)
result = ENODEV;
}
out:
return (result);
}
/*
* fdformat
* format a track - builds a table of sector data values with 16 bytes
* (sizeof fdc's fifo) of dummy on end. This is so than when fdintr_len
* goes to 0 and fdc_hardintr sends TC that all the real formatting will
* have already been done.
*/
fdformat(unit, cyl, hd)
int unit, cyl, hd;
{
register struct fdcsb *csb;
register struct fdunit *un;
register struct fdk_char *ch;
int cmdresult;
u_char *fmthdrs;
register u_char *fd;
int i;
FDERRPRINT(FDEP_L1, FDEM_FORM, ("fdformat cyl %d, hd %d\n", cyl, hd));
fdgetcsb();
csb = fdctlr.c_csb;
un = fdctlr.c_units[ unit ];
ch = un->un_chars;
/* setup common things in csb */
csb->csb_un = un;
csb->csb_unit = unit;
csb->csb_part = 0;
/*
* stupid controller needs to do a seek before each format to get
* to right cylinder.
*/
if (fdrecalseek(unit, cyl, FDXC_CHECKCHG)) {
fdretcsb();
return (EIO);
}
/*
* now do the format itself
*/
csb->csb_nrslts = NRBRW;
csb->csb_opflags = CSB_OFXFEROPS | CSB_OFTIMEIT;
csb->csb_cmds[0] = FRAW_FORMAT;
/* always or in MFM bit */
csb->csb_cmds[0] |= MFM;
csb->csb_cmds[1] = (hd << 2) | (unit & 0x03);
csb->csb_cmds[2] = ch->medium ? 3 : 2;
csb->csb_cmds[3] = ch->secptrack;
csb->csb_cmds[4] = GPLF;
csb->csb_cmds[5] = FDATA;
csb->csb_ncmds = 6;
csb->csb_maxretry = rwretry;
csb->csb_retrys = 0;
/* just kmem zalloc space for formattrk cmd */
/* NOTE: have to add size of fifo also - for dummy format action */
fd = fmthdrs = (u_char *)kmem_zalloc(((u_int)4 * ch->secptrack) + 16);
csb->csb_addr = (caddr_t)fd;
csb->csb_len = (4 * ch->secptrack) + 16;
for (i = 1; i <= ch->secptrack; i++) {
*fd++ = cyl; /* cylinder */
*fd++ = hd; /* head */
*fd++ = (u_char)i; /* sector number */
*fd++ = ch->medium ? 3 : 2;
}
if ((cmdresult = fdexec(FDXC_SLEEP | FDXC_CHECKCHG)) == 0) {
if (csb->csb_cmdstat)
cmdresult = EIO; /* XXX TBD NYD for now */
}
fdretcsb();
kmem_free((caddr_t)fmthdrs, ((u_int)4 * ch->secptrack) + 16);
return (cmdresult);
}
/*
* fdrw
* used for internal sorts of reads/writes, ie reading labels,
* implementing raw commands thru ioctls, ...
*/
fdrw(flag, unit, cyl, head, sector, bufp, len)
int flag, unit, cyl, head, sector;
caddr_t bufp;
u_int len;
{
register struct fdcsb *csb;
int cmdresult;
FDERRPRINT(FDEP_L1, FDEM_RW, ("fdrw\n"));
fdgetcsb();
csb = fdctlr.c_csb;
if (flag == FDREAD)
csb->csb_cmds[0] = MT + SK + FRAW_RDCMD;
else /* write */
csb->csb_cmds[0] = MT + FRAW_WRCMD;
/* always or in MFM bit */
csb->csb_cmds[0] |= MFM;
csb->csb_cmds[1] = (unit & 0x3) | ((head & 0x1) << 2);
csb->csb_cmds[2] = cyl;
csb->csb_cmds[3] = head;
csb->csb_cmds[4] = sector;
csb->csb_cmds[5] = ((fdctlr.c_units[unit])->un_chars->sec_size == 512) ? 2 : 3;
csb->csb_cmds[6] = (fdctlr.c_units[unit])->un_chars->secptrack;
csb->csb_cmds[7] = GPLN;
csb->csb_cmds[8] = SSSDTL;
csb->csb_ncmds = NCBRW;
csb->csb_addr = bufp;
csb->csb_len = len;
csb->csb_maxretry = rwretry;
csb->csb_retrys = 0;
/* init result area ?? */
csb->csb_nrslts = NRBRW;
csb->csb_opflags = CSB_OFXFEROPS | CSB_OFTIMEIT;
cmdresult = 0;
if (fdexec(FDXC_SLEEP | FDXC_CHECKCHG) != 0) {
/* things was really hosed! */
cmdresult = EIO;
goto out;
}
if (csb->csb_cmdstat)
cmdresult = EIO; /* XXX TBD NYD for now */
out:
fdretcsb();
return (cmdresult);
}
/*
* fdsensedrv
* do a sense_drive command. used by fdopen and fdcheckdisk.
*/
fdsensedrv(unit)
int unit;
{
struct fdcsb *csb;
csb = fdctlr.c_csb;
/* setup common things in csb */
csb->csb_un = fdctlr.c_units[0];
csb->csb_unit = unit;
csb->csb_part = 0;
csb->csb_opflags = CSB_OFIMMEDIATE;
csb->csb_cmds[0] = FRAW_SENSE_DRV;
/* MOT bit set means don't delay */
csb->csb_cmds[1] = MOT | (unit & 0x03);
csb->csb_ncmds = 2;
csb->csb_nrslts = 1;
csb->csb_maxretry = skretry;
csb->csb_retrys = 0;
/* XXX for now ignore errors, they "CAN'T HAPPEN" */
(void) fdexec(0); /* DON't check changed!, no sleep */
return (csb->csb_rslt[0]); /* return status byte 3 */
}
/*
* fdcheckdisk
* check to see if the disk is still there - do a recalibrate,
* then see if DSKCHG line went away, if so, diskette is in; else
* it's (still) out.
* INPUTS/ASSUMES: unit #, assumes it owns the csb/fdctlr.
*
* RETURNS: 0 if diskette is in drive, -1 if otherwise
*/
fdcheckdisk(unit)
int unit; /* drive number to check */
{
struct fdcsb *ccsb; /* private csb for recal op */
struct fdcsb *csb; /* ptr to "old" csb */
int err, st3;
int seekto; /* where to seek for reset of DSKCHG */
FDERRPRINT(FDEP_L1, FDEM_CHEK, ("fdcheckdisk, unit %d\n", unit));
/* save old csb */
csb = fdctlr.c_csb;
ccsb = (struct fdcsb *)kmem_zalloc(sizeof (struct fdcsb));
fdctlr.c_csb = ccsb;
/*
* read drive status to see if at TRK0, if so, seek to cyl 1,
* else seek to cyl 0. We do this because the controller is
* "smart" enough to not send any step pulses (which are how
* the DSKCHG line gets reset) if it sees TRK0 'cause it
* knows the drive is already recalibrated.
*/
st3 = fdsensedrv(unit);
/* check TRK0 bit in status */
if (st3 & T0_SR3)
seekto = 1; /* at TRK0, seek out */
else
seekto = 0;
err = fdrecalseek(unit, seekto, 0); /* DON'T recurse check changed */
/* "restore" old csb, check change state */
fdctlr.c_csb = csb;
kmem_free((caddr_t)ccsb, sizeof (struct fdcsb));
/* any recal/seek errors are too serious to attend to */
if (err) {
FDERRPRINT(FDEP_L2, FDEM_CHEK, ("fdcheckdisk err %d\n", err));
return (err);
}
/* if disk change still asserted, no diskette in drive! */
if (fdsense_chng()) {
FDERRPRINT(FDEP_L2, FDEM_CHEK, ("fdcheckdisk no disk\n"));
return (1);
}
return (0);
}
/*
* the following functions are hw dependent
* fdselect() - select drive, needed for external to chip select logic
* fdeject() - ejects drive, must be previously selected
* fdterm_count() - sends terminal count to previously selected drive
* fdsense_chng() - sense disk changed line from previously selected drive
* returns 1 is signal asserted, else 0
* fdsense_dnsty() - sense density line from previously selected drive
* returns 1 is signal asserted, else 0
*/
static void
fdselect(unit, on)
int unit;
int on; /* non-zero = select, 0 = de-select */
{
FDERRPRINT(FDEP_L1, FDEM_DSEL,
("fdselect, unit %d, on = %d\n", unit, on));
#if defined(sun4c) || defined(sun4m)
#ifdef I82077
switch (fdtype) {
case FD_82077:
fd_set_dor_reg(DRVSEL, !on);
break;
case FD_82072:
set_auxioreg(AUX_DRVSELECT, on);
break;
}
#else
set_auxioreg(AUX_DRVSELECT, on);
#endif I82077
#endif sun4c sun4m
}
static
fdeject()
{
FDERRPRINT(FDEP_L1, FDEM_EJEC, ("fdeject\n"));
#if defined(sun4c) || defined(sun4m)
/* assume delay of function calling sufficient settling time */
/* eject line is NOT driven by inverter so it is true low */
#ifdef I82077
switch (fdtype) {
case FD_82077:
DELAY(4);
fd_set_dor_reg(EJECT, 1);
DELAY(4);
fd_set_dor_reg(EJECT, 0);
break;
case FD_82072:
DELAY(4);
set_auxioreg(AUX_EJECT, 0);
DELAY(4);
set_auxioreg(AUX_EJECT, 1);
break;
}
#else
DELAY(4);
set_auxioreg(AUX_EJECT, 0);
DELAY(4);
set_auxioreg(AUX_EJECT, 1);
#endif I82077
#endif sun4c sun4m
/*
* XXX set ejected state?
*/
}
static
fdsense_chng()
{
FDERRPRINT(FDEP_L1, FDEM_SCHG, ("fdsense_chng\n"));
#if defined(sun4c) || defined(sun4m)
#ifdef I82077
switch (fdtype) {
case FD_82077:
if (Dir & DISKCHG)
return (1);
break;
case FD_82072:
if (Auxio & AUX_DISKCHG)
return (1);
break;
}
#else
if (Auxio & AUX_DISKCHG)
return (1);
#endif
#endif sun4c sun4m
return (0);
}
#ifdef NEVER /* NOT NEEDED for Campus */
/* term count is issued by the level11 handler on Campus (in fd_asm.s) */
static
fdterm_count()
{
int i;
#if defined(sun4c) || defined(sun4m)
set_auxioreg(AUX_TC, 1);
DELAY(5);
set_auxioreg(AUX_TC, 0);
#endif sun4c sun4m
}
static
fdsense_dnsty()
{
#if defined(sun4c) || defined(sun4m)
if (Auxio & AUX_DENSITY)
return (1);
#endif sun4c sun4m
return (0);
}
#endif NEVER
/*
* fdpacklabel
* this packs an (unpacked) struct dk_label into a packed label.
*/
fdpacklabel(from, to, unit)
struct dk_label *from;
struct packed_label *to;
int unit;
{
FDERRPRINT(FDEP_L1, FDEM_PACK, ("fdpacklabel\n"));
/* clear the destination */
bzero((caddr_t)to, sizeof (struct packed_label));
to->dkl_asciip = fdkl_alabel[unit]; /* point at something reasonable */
(void)strcpy(to->dkl_asciip, from->dkl_asciilabel);
to->dkl_rpm = from->dkl_rpm; /* rotations per minute */
to->dkl_pcyl = from->dkl_pcyl; /* # physical cylinders */
to->dkl_apc = from->dkl_apc; /* alternates per cylinder */
to->dkl_intrlv = from->dkl_intrlv; /* interleave factor */
to->dkl_ncyl = from->dkl_ncyl; /* # of data cylinders */
to->dkl_acyl = from->dkl_acyl; /* # of alternate cylinders */
to->dkl_nhead = from->dkl_nhead; /* # of heads in this partition */
to->dkl_nsect = from->dkl_nsect; /* # of 512 byte sectors per track */
/* logical partitions */
bcopy((caddr_t)from->dkl_map, (caddr_t)to->dkl_map,
sizeof (struct dk_map) * NDKMAP);
}
#ifdef NEVER
/*
* fdunpacklabel
* this unpacks a packed default label into a struct dk_label,
* complete with magic number and checksum
*/
fdunpacklabel(from, to)
struct packed_label *from;
struct dk_label *to;
{
short xsum;
short *sp;
int i;
/* clear the destination */
bzero((caddr_t)to, sizeof (struct dk_label));
strcpy(to->dkl_asciilabel, from->dkl_asciip);
to->dkl_rpm = from->dkl_rpm; /* rotations per minute */
to->dkl_pcyl = from->dkl_pcyl; /* # physical cylinders */
to->dkl_apc = from->dkl_apc; /* alternates per cylinder */
to->dkl_intrlv = from->dkl_intrlv; /* interleave factor */
to->dkl_ncyl = from->dkl_ncyl; /* # of data cylinders */
to->dkl_acyl = from->dkl_acyl; /* # of alternate cylinders */
to->dkl_nhead = from->dkl_nhead; /* # of heads in this partition */
to->dkl_nsect = from->dkl_nsect; /* # of 512 byte sectors per track */
/* logical partitions */
bcopy((caddr_t)from->dkl_map, (caddr_t)to->dkl_map,
sizeof (struct dk_map) * NDKMAP);
to->dkl_magic = DKL_MAGIC;
xsum = 0;
sp = (short *)to;
for (i = (sizeof (struct dk_label)/sizeof (short)); i > 1; i--)
xsum ^= *sp++;
to->dkl_cksum = xsum;
}
#endif NEVER
fd_set_dor_reg(bit, flag)
int bit;
int flag;
{
if (bit & MOTEN ) {
/* deselect the drive according to Sony spec */
fd_set_dor(3,1);
if (fdctlr.c_units[fdctlr.c_csb->csb_unit]->un_chars->medium) {
bit |= MEDIUM_DENSITY;
fd_set_dor(MEDIUM_DENSITY , 1);
} else {
fd_set_dor(MEDIUM_DENSITY, 0);
}
DELAY(20);
/* select */
fd_set_dor(3,0);
if (fderrlevel == 0)
printf("----> M O T O R %d = %x\n",flag, bit);
}
fd_set_dor(bit, flag);
/*
* Give at least 500 ms MIN for the motor to spin
*/
if (flag)
DELAY(650000);
}
#endif /* NFD > 0 */