Merge the formatting code from the i386-port.

This commit is contained in:
leo 1996-12-14 13:47:12 +00:00
parent a90e5523d6
commit ae092ee765
3 changed files with 367 additions and 43 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: hdfd.c,v 1.2 1996/11/13 06:48:24 thorpej Exp $ */
/* $NetBSD: hdfd.c,v 1.3 1996/12/14 13:47:12 leo Exp $ */
/*-
* Copyright (c) 1996 Leo Weppelman
@ -41,6 +41,23 @@
* @(#)fd.c 7.4 (Berkeley) 5/25/91
*/
/*
* Floppy formatting facilities merged from FreeBSD fd.c driver:
* Id: fd.c,v 1.53 1995/03/12 22:40:56 joerg Exp
* which carries the same copyright/redistribution notice as shown above with
* the addition of the following statement before the "Redistribution and
* use ..." clause:
*
* Copyright (c) 1993, 1994 by
* jc@irbs.UUCP (John Capo)
* vak@zebub.msk.su (Serge Vakulenko)
* ache@astral.msk.su (Andrew A. Chernov)
*
* Copyright (c) 1993, 1994, 1995 by
* joerg_wunsch@uriah.sax.de (Joerg Wunsch)
* dufault@hda.com (Peter Dufault)
*/
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
@ -51,9 +68,12 @@
#include <sys/dkstat.h>
#include <sys/disk.h>
#include <sys/buf.h>
#include <sys/malloc.h>
#include <sys/uio.h>
#include <sys/syslog.h>
#include <sys/queue.h>
#include <sys/proc.h>
#include <sys/fdio.h>
#include <sys/conf.h>
#include <sys/device.h>
@ -99,6 +119,9 @@ static void *intr_arg = NULL; /* XXX: arg. to intr_establish() */
#define FDUNIT(dev) (minor(dev) / 8)
#define FDTYPE(dev) (minor(dev) % 8)
/* XXX misuse a flag to identify format operation */
#define B_FORMAT B_XXX
#define b_cylin b_resid
enum fdc_state {
@ -161,6 +184,8 @@ struct fd_type {
int size; /* size of disk in sectors */
int step; /* steps per cylinder */
int rate; /* transfer speed code */
u_char fillbyte; /* format fill byte */
u_char interleave; /* interleave factor (formatting) */
char *name;
};
@ -170,11 +195,11 @@ struct fd_type {
*/
struct fd_type fd_types[] = {
/* 360kB in 720kB drive */
{ 9,2,18,2,0xff,0xdf,0x2a,0x50,40, 720,2,FDC_125KBPS, "360KB" },
{ 9,2,18,2,0xff,0xdf,0x2a,0x50,40, 720,2,FDC_125KBPS,0xf6,1,"360KB" },
/* 3.5" 720kB diskette */
{ 9,2,18,2,0xff,0xdf,0x2a,0x50,80,1440,1,FDC_125KBPS, "720KB" },
{ 9,2,18,2,0xff,0xdf,0x2a,0x50,80,1440,1,FDC_125KBPS,0xf6,1,"720KB" },
/* 1.44MB diskette */
{ 18,2,36,2,0xff,0xcf,0x1b,0x6c,80,2880,1,FDC_250KBPS, "1.44MB" },
{ 18,2,36,2,0xff,0xcf,0x1b,0x6c,80,2880,1,FDC_250KBPS,0xf6,1,"1.44MB" },
};
/* software state, per disk (with up to 4 disks per ctlr) */
@ -187,6 +212,7 @@ struct fd_softc {
daddr_t sc_blkno; /* starting block number */
int sc_bcount; /* byte count left */
int sc_opts; /* user-set options */
int sc_skip; /* bytes already transferred */
int sc_nblks; /* #blocks currently tranferring */
int sc_nbytes; /* #bytes currently tranferring */
@ -235,6 +261,8 @@ void fdcpseudointr __P((void *arg));
int fdcintr __P((void *));
void fdcretry __P((struct fdc_softc *fdc));
void fdfinish __P((struct fd_softc *fd, struct buf *bp));
int fdformat __P((dev_t, struct ne7_fd_formb *, struct proc *));
__inline struct fd_type *fd_dev_to_type __P((struct fd_softc *, dev_t));
int
@ -518,7 +546,8 @@ fdstrategy(bp)
/* Valid unit, controller, and request? */
if (bp->b_blkno < 0 ||
(bp->b_bcount % FDC_BSIZE) != 0) {
((bp->b_bcount % FDC_BSIZE) != 0 &&
(bp->b_flags & B_FORMAT) == 0)) {
bp->b_error = EINVAL;
goto bad;
}
@ -711,6 +740,7 @@ fdcresult(fdc)
}
fdc->sc_status[n++] = rd_fdc_reg(fddata);
}
else delay(10);
}
log(LOG_ERR, "fdcresult: timeout\n");
return -1;
@ -722,10 +752,8 @@ out_fdc(x)
{
int i = 100000;
while ((rd_fdc_reg(fdsts) & NE7_RQM) == 0 && i-- > 0);
if (i <= 0)
return -1;
while ((rd_fdc_reg(fdsts) & NE7_DIO) && i-- > 0);
while (((rd_fdc_reg(fdsts) & (NE7_DIO|NE7_RQM)) != NE7_RQM) && i-- > 0)
delay(1);
if (i <= 0)
return -1;
wrt_fdc_reg(fddata, x);
@ -774,6 +802,7 @@ fdclose(dev, flags, mode, p)
struct fd_softc *fd = hdfd_cd.cd_devs[FDUNIT(dev)];
fd->sc_flags &= ~FD_OPEN;
fd->sc_opts &= ~(FDOPT_NORETRY|FDOPT_SILENT);
return 0;
}
@ -873,14 +902,16 @@ int
fdcintr(arg)
void *arg;
{
struct fdc_softc *fdc = arg;
struct fdc_softc *fdc = arg;
#define st0 fdc->sc_status[0]
#define st1 fdc->sc_status[1]
#define cyl fdc->sc_status[1]
struct fd_softc *fd;
struct buf *bp;
int read, head, sec, i, nblks;
struct fd_type *type;
struct fd_softc *fd;
struct buf *bp;
int read, head, sec, i, nblks;
struct fd_type *type;
struct ne7_fd_formb *finfo = NULL;
loop:
/* Is there a drive for the controller to do a transfer with? */
@ -899,6 +930,9 @@ loop:
goto loop;
}
if (bp->b_flags & B_FORMAT)
finfo = (struct ne7_fd_formb *)bp->b_data;
switch (fdc->sc_state) {
case DEVIDLE:
fdc->sc_errors = 0;
@ -955,6 +989,10 @@ loop:
case DOIO:
doio:
if (finfo)
fd->sc_skip = (char *)&(finfo->fd_formb_cylno(0)) -
(char *)finfo;
type = fd->sc_type;
sec = fd->sc_blkno % type->seccyl;
head = sec / type->sectrac;
@ -963,7 +1001,7 @@ loop:
nblks = min(nblks, fd->sc_bcount / FDC_BSIZE);
nblks = min(nblks, FDC_MAXIOSIZE / FDC_BSIZE);
fd->sc_nblks = nblks;
fd->sc_nbytes = nblks * FDC_BSIZE;
fd->sc_nbytes = finfo ? bp->b_bcount : nblks * FDC_BSIZE;
#ifdef DIAGNOSTIC
{
int block;
@ -995,18 +1033,32 @@ loop:
#endif
fdc_ienable();
if (read)
out_fdc(NE7CMD_READ); /* READ */
else
out_fdc(NE7CMD_WRITE); /* WRITE */
out_fdc((head << 2) | fd->sc_drive);
out_fdc(fd->sc_cylin); /* track */
out_fdc(head); /* head */
out_fdc(sec + 1); /* sector +1 */
out_fdc(type->secsize); /* sector size */
out_fdc(sec + nblks); /* last sectors */
out_fdc(type->gap1); /* gap1 size */
out_fdc(type->datalen); /* data length */
if (finfo) {
/* formatting */
if (out_fdc(NE7CMD_FORMAT) < 0) {
fdc->sc_errors = 4;
fdcretry(fdc);
goto loop;
}
out_fdc((head << 2) | fd->sc_drive);
out_fdc(finfo->fd_formb_secshift);
out_fdc(finfo->fd_formb_nsecs);
out_fdc(finfo->fd_formb_gaplen);
out_fdc(finfo->fd_formb_fillbyte);
} else {
if (read)
out_fdc(NE7CMD_READ); /* READ */
else
out_fdc(NE7CMD_WRITE); /* WRITE */
out_fdc((head << 2) | fd->sc_drive);
out_fdc(fd->sc_cylin); /* track */
out_fdc(head); /* head */
out_fdc(sec + 1); /* sector +1 */
out_fdc(type->secsize); /* sector size */
out_fdc(sec + nblks); /* last sectors */
out_fdc(type->gap1); /* gap1 size */
out_fdc(type->datalen); /* data length */
}
fdc->sc_state = IOCOMPLETE;
disk_busy(&fd->sc_dk);
@ -1078,7 +1130,7 @@ loop:
fd->sc_blkno += fd->sc_nblks;
fd->sc_skip += fd->sc_nbytes;
fd->sc_bcount -= fd->sc_nbytes;
if (fd->sc_bcount > 0) {
if (!finfo && fd->sc_bcount > 0) {
bp->b_cylin = fd->sc_blkno / fd->sc_type->seccyl;
goto doseek;
}
@ -1159,6 +1211,9 @@ fdcretry(fdc)
fd = fdc->sc_drives.tqh_first;
bp = fd->sc_q.b_actf;
if (fd->sc_opts & FDOPT_NORETRY)
goto fail;
switch (fdc->sc_errors) {
case 0:
/* try again */
@ -1176,18 +1231,29 @@ fdcretry(fdc)
break;
default:
diskerr(bp, "fd", "hard error", LOG_PRINTF,
fd->sc_skip / FDC_BSIZE, (struct disklabel *)NULL);
printf(" (st0 %s", bitmask_snprintf(fdc->sc_status[0],
NE7_ST0BITS, bits, sizeof(bits)));
printf(" st1 %s", bitmask_snprintf(fdc->sc_status[1],
NE7_ST1BITS, bits, sizeof(bits)));
printf(" st2 %s", bitmask_snprintf(fdc->sc_status[2],
NE7_ST2BITS, bits, sizeof(bits)));
printf(" cyl %d head %d sec %d)\n",
fdc->sc_status[3], fdc->sc_status[4], fdc->sc_status[5]);
fail:
if ((fd->sc_opts & FDOPT_SILENT) == 0) {
diskerr(bp, "fd", "hard error", LOG_PRINTF,
fd->sc_skip / FDC_BSIZE,
(struct disklabel *)NULL);
printf(" (st0 %s",
bitmask_snprintf(fdc->sc_status[0],
NE7_ST0BITS, bits,
sizeof(bits)));
printf(" st1 %s",
bitmask_snprintf(fdc->sc_status[1],
NE7_ST1BITS, bits,
sizeof(bits)));
printf(" st2 %s",
bitmask_snprintf(fdc->sc_status[2],
NE7_ST2BITS, bits,
sizeof(bits)));
printf(" cyl %d head %d sec %d)\n",
fdc->sc_status[3],
fdc->sc_status[4],
fdc->sc_status[5]);
}
bp->b_flags |= B_ERROR;
bp->b_error = EIO;
fdfinish(fd, bp);
@ -1227,7 +1293,13 @@ fdioctl(dev, cmd, addr, flag, p)
struct fd_softc *fd;
struct disklabel buffer;
struct cpu_disklabel cpulab;
int error;
int error;
struct fdformat_parms *form_parms;
struct fdformat_cmd *form_cmd;
struct ne7_fd_formb fd_formb;
unsigned int scratch;
int il[FD_MAX_NSEC + 1];
register int i, j;
fd = hdfd_cd.cd_devs[FDUNIT(dev)];
@ -1256,13 +1328,127 @@ fdioctl(dev, cmd, addr, flag, p)
if ((flag & FWRITE) == 0)
return EBADF;
error = setdisklabel(&buffer, (struct disklabel *)addr, 0, NULL);
error = setdisklabel(&buffer, (struct disklabel *)addr, 0,NULL);
if (error)
return error;
error = writedisklabel(dev, fdstrategy, &buffer, NULL);
return error;
case FDIOCGETFORMAT:
form_parms = (struct fdformat_parms *)addr;
form_parms->fdformat_version = FDFORMAT_VERSION;
form_parms->nbps = 128 * (1 << fd->sc_type->secsize);
form_parms->ncyl = fd->sc_type->tracks;
form_parms->nspt = fd->sc_type->sectrac;
form_parms->ntrk = fd->sc_type->heads;
form_parms->stepspercyl = fd->sc_type->step;
form_parms->gaplen = fd->sc_type->gap2;
form_parms->fillbyte = fd->sc_type->fillbyte;
form_parms->interleave = fd->sc_type->interleave;
switch (fd->sc_type->rate) {
case FDC_500KBPS:
form_parms->xfer_rate = 500 * 1024;
break;
case FDC_300KBPS:
form_parms->xfer_rate = 300 * 1024;
break;
case FDC_250KBPS:
form_parms->xfer_rate = 250 * 1024;
break;
default:
return EINVAL;
}
return 0;
case FDIOCSETFORMAT:
if((flag & FWRITE) == 0)
return EBADF; /* must be opened for writing */
form_parms = (struct fdformat_parms *)addr;
if (form_parms->fdformat_version != FDFORMAT_VERSION)
return EINVAL; /* wrong version of formatting prog */
scratch = form_parms->nbps >> 7;
if ((form_parms->nbps & 0x7f) || ffs(scratch) == 0 ||
scratch & ~(1 << (ffs(scratch)-1)))
/* not a power-of-two multiple of 128 */
return EINVAL;
switch (form_parms->xfer_rate) {
case 500 * 1024:
fd->sc_type->rate = FDC_500KBPS;
break;
case 300 * 1024:
fd->sc_type->rate = FDC_300KBPS;
break;
case 250 * 1024:
fd->sc_type->rate = FDC_250KBPS;
break;
default:
return EINVAL;
}
if (form_parms->nspt > FD_MAX_NSEC ||
form_parms->fillbyte > 0xff ||
form_parms->interleave > 0xff)
return EINVAL;
fd->sc_type->sectrac = form_parms->nspt;
if (form_parms->ntrk != 2 && form_parms->ntrk != 1)
return EINVAL;
fd->sc_type->heads = form_parms->ntrk;
fd->sc_type->seccyl = form_parms->nspt * form_parms->ntrk;
fd->sc_type->secsize = ffs(scratch)-1;
fd->sc_type->gap2 = form_parms->gaplen;
fd->sc_type->tracks = form_parms->ncyl;
fd->sc_type->size = fd->sc_type->seccyl * form_parms->ncyl *
form_parms->nbps / DEV_BSIZE;
fd->sc_type->step = form_parms->stepspercyl;
fd->sc_type->fillbyte = form_parms->fillbyte;
fd->sc_type->interleave = form_parms->interleave;
return 0;
case FDIOCFORMAT_TRACK:
if((flag & FWRITE) == 0)
return EBADF; /* must be opened for writing */
form_cmd = (struct fdformat_cmd *)addr;
if (form_cmd->formatcmd_version != FDFORMAT_VERSION)
return EINVAL; /* wrong version of formatting prog */
if (form_cmd->head >= fd->sc_type->heads ||
form_cmd->cylinder >= fd->sc_type->tracks) {
return EINVAL;
}
fd_formb.head = form_cmd->head;
fd_formb.cyl = form_cmd->cylinder;
fd_formb.transfer_rate = fd->sc_type->rate;
fd_formb.fd_formb_secshift = fd->sc_type->secsize;
fd_formb.fd_formb_nsecs = fd->sc_type->sectrac;
fd_formb.fd_formb_gaplen = fd->sc_type->gap2;
fd_formb.fd_formb_fillbyte = fd->sc_type->fillbyte;
bzero(il,sizeof il);
for (j = 0, i = 1; i <= fd_formb.fd_formb_nsecs; i++) {
while (il[(j%fd_formb.fd_formb_nsecs)+1])
j++;
il[(j%fd_formb.fd_formb_nsecs)+1] = i;
j += fd->sc_type->interleave;
}
for (i = 0; i < fd_formb.fd_formb_nsecs; i++) {
fd_formb.fd_formb_cylno(i) = form_cmd->cylinder;
fd_formb.fd_formb_headno(i) = form_cmd->head;
fd_formb.fd_formb_secno(i) = il[i+1];
fd_formb.fd_formb_secsize(i) = fd->sc_type->secsize;
}
case FDIOCGETOPTS: /* get drive options */
*(int *)addr = fd->sc_opts;
return 0;
case FDIOCSETOPTS: /* set drive options */
fd->sc_opts = *(int *)addr;
return 0;
default:
return ENOTTY;
}
@ -1271,3 +1457,63 @@ fdioctl(dev, cmd, addr, flag, p)
panic("fdioctl: impossible");
#endif
}
int
fdformat(dev, finfo, p)
dev_t dev;
struct ne7_fd_formb *finfo;
struct proc *p;
{
int rv = 0, s;
struct fd_softc *fd = hdfd_cd.cd_devs[FDUNIT(dev)];
struct fd_type *type = fd->sc_type;
struct buf *bp;
/* set up a buffer header for fdstrategy() */
bp = (struct buf *)malloc(sizeof(struct buf), M_TEMP, M_NOWAIT);
if(bp == 0)
return ENOBUFS;
PHOLD(p);
bzero((void *)bp, sizeof(struct buf));
bp->b_flags = B_BUSY | B_PHYS | B_FORMAT;
bp->b_proc = p;
bp->b_dev = dev;
/*
* calculate a fake blkno, so fdstrategy() would initiate a
* seek to the requested cylinder
*/
bp->b_blkno = (finfo->cyl * (type->sectrac * type->heads)
+ finfo->head * type->sectrac) * FDC_BSIZE / DEV_BSIZE;
bp->b_bcount = sizeof(struct fd_idfield_data) * finfo->fd_formb_nsecs;
bp->b_data = (caddr_t)finfo;
#ifdef DEBUG
printf("fdformat: blkno %x count %x\n", bp->b_blkno, bp->b_bcount);
#endif
/* now do the format */
fdstrategy(bp);
/* ...and wait for it to complete */
s = splbio();
while(!(bp->b_flags & B_DONE)) {
rv = tsleep((caddr_t)bp, PRIBIO, "fdform", 20 * hz);
if (rv == EWOULDBLOCK)
break;
}
splx(s);
if (rv == EWOULDBLOCK) {
/* timed out */
rv = EIO;
biodone(bp);
}
if(bp->b_flags & B_ERROR) {
rv = bp->b_error;
}
PRELE(p);
free(bp, M_TEMP);
return rv;
}

View File

@ -1,4 +1,4 @@
/* $NetBSD: hdfd_intr.s,v 1.1 1996/11/09 22:27:26 leo Exp $
/* $NetBSD: hdfd_intr.s,v 1.2 1996/12/14 13:47:13 leo Exp $
/*
* Copyright (c) 1996 Leo Weppelman.
@ -38,6 +38,7 @@
*/
#include "assym.h"
#define ASSEMBLER /* XXX */
#include <atari/dev/hdfdreg.h>
.globl _fddmaaddr

View File

@ -1,4 +1,4 @@
/* $NetBSD: hdfdreg.h,v 1.1 1996/11/09 22:27:26 leo Exp $ */
/* $NetBSD: hdfdreg.h,v 1.2 1996/12/14 13:47:14 leo Exp $ */
/*-
* Copyright (c) 1991 The Regents of the University of California.
@ -75,3 +75,80 @@
#define FDC_BSIZE 512
#define FDC_NPORT 8
#define FDC_MAXIOSIZE NBPG /* XXX should be MAXBSIZE */
/*
* Copyright (C) 1992-1994 by Joerg Wunsch, Dresden
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* From: FreeBSD: Id: ioctl_fd.h,v 1.7 1994/10/30 19:17:39 joerg Exp
*/
#define FD_MAX_NSEC 36 /* highest known number of spt - allow for */
/* 2.88 MB drives */
#ifndef ASSEMBLER
struct ne7_fd_formb {
int cyl, head;
int transfer_rate; /* fdreg.h: FDC_???KBPS */
union {
struct fd_form_data {
/*
* DO NOT CHANGE THE LAYOUT OF THIS STRUCTS
* it is hardware-dependant since it exactly
* matches the byte sequence to write to FDC
* during its `format track' operation
*/
u_char secshift; /* 0 -> 128, ...; usually 2 -> 512 */
u_char nsecs; /* must be <= FD_MAX_NSEC */
u_char gaplen; /* GAP 3 length; usually 84 */
u_char fillbyte; /* usually 0xf6 */
struct fd_idfield_data {
/*
* data to write into id fields;
* for obscure formats, they mustn't match
* the real values (but mostly do)
*/
u_char cylno; /* 0 thru 79 (or 39) */
u_char headno; /* 0, or 1 */
u_char secno; /* starting at 1! */
u_char secsize; /* usually 2 */
} idfields[FD_MAX_NSEC]; /* 0 <= idx < nsecs used */
} structured;
u_char raw[1]; /* to have continuous indexed access */
} format_info;
};
#endif /* ASSEMBLER */
/* make life easier */
# define fd_formb_secshift format_info.structured.secshift
# define fd_formb_nsecs format_info.structured.nsecs
# define fd_formb_gaplen format_info.structured.gaplen
# define fd_formb_fillbyte format_info.structured.fillbyte
/* these data must be filled in for(i = 0; i < fd_formb_nsecs; i++) */
# define fd_formb_cylno(i) format_info.structured.idfields[i].cylno
# define fd_formb_headno(i) format_info.structured.idfields[i].headno
# define fd_formb_secno(i) format_info.structured.idfields[i].secno
# define fd_formb_secsize(i) format_info.structured.idfields[i].secsize