* Copyright (c) 1990 The Regents of the University of California.
* This code is derived from software contributed to Berkeley by
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* 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.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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
* from: @(#)fd.c 7.4 (Berkeley) 5/25/91
#include <machine/ioctl_fd.h>
#include <sys/disklabel.h>
#include "i386/isa/isa.h"
#include "i386/isa/isa_device.h"
#include "i386/isa/fdreg.h"
#include "i386/isa/fdc.h"
#include "i386/isa/icu.h"
#include "i386/isa/rtc.h"
extern int ftopen(), ftintr(), ftattach(), ftclose(), ftioctl();
/* misuse a flag to identify format operation */
#define NUMDENS (NUMTYPES - 6)
/* This defines (-1) must match index for fd_types */
#define F_TAPE_TYPE 0x020 /* bit for fd_types to indicate tape */
#define NO_TYPE 0 /* must match NO_TYPE in ft.c */
struct fd_type fd_types
[NUMTYPES
] =
{ 21,2,0xFF,0x04,82,3444,1,FDC_500KBPS
,2,0x0C,2 }, /* 1.72M in HD 3.5in */
{ 18,2,0xFF,0x1B,82,2952,1,FDC_500KBPS
,2,0x6C,1 }, /* 1.48M in HD 3.5in */
{ 18,2,0xFF,0x1B,80,2880,1,FDC_500KBPS
,2,0x6C,1 }, /* 1.44M in HD 3.5in */
{ 15,2,0xFF,0x1B,80,2400,1,FDC_500KBPS
,2,0x54,1 }, /* 1.2M in HD 5.25/3.5 */
{ 10,2,0xFF,0x10,82,1640,1,FDC_250KBPS
,2,0x2E,1 }, /* 820K in HD 3.5in */
{ 10,2,0xFF,0x10,80,1600,1,FDC_250KBPS
,2,0x2E,1 }, /* 800K in HD 3.5in */
{ 9,2,0xFF,0x20,80,1440,1,FDC_250KBPS
,2,0x50,1 }, /* 720K in HD 3.5in */
{ 9,2,0xFF,0x2A,40, 720,1,FDC_300KBPS
,2,0x50,1 }, /* 360K in DD 5.25in */
{ 18,2,0xFF,0x02,82,2952,1,FDC_500KBPS
,2,0x02,2 }, /* 1.48M in HD 5.25in */
{ 18,2,0xFF,0x02,80,2880,1,FDC_500KBPS
,2,0x02,2 }, /* 1.44M in HD 5.25in */
{ 10,2,0xFF,0x10,82,1640,1,FDC_300KBPS
,2,0x2E,1 }, /* 820K in HD 5.25in */
{ 10,2,0xFF,0x10,80,1600,1,FDC_300KBPS
,2,0x2E,1 }, /* 800K in HD 5.25in */
{ 9,2,0xFF,0x20,80,1440,1,FDC_300KBPS
,2,0x50,1 }, /* 720K in HD 5.25in */
{ 9,2,0xFF,0x23,40, 720,2,FDC_300KBPS
,2,0x50,1 }, /* 360K in HD 5.25in */
#define DRVS_PER_CTLR 2 /* 2 floppies */
/***********************************************************************\
* Per controller structure. *
\***********************************************************************/
struct fdc_data fdc_data
[NFDC
];
/***********************************************************************\
* N per controller (DRVS_PER_CTLR) *
\***********************************************************************/
struct fdc_data
*fdc
; /* pointer to controller structure */
int fdsu
; /* this units number on this controller */
int type
; /* Drive type (HD, DD */
struct fd_type
*ft
; /* pointer to the type descriptor */
#define FD_OPEN 0x01 /* it's open */
#define FD_ACTIVE 0x02 /* it's active */
#define FD_MOTOR 0x04 /* motor should be on */
#define FD_MOTOR_WAIT 0x08 /* motor coming up */
int track
; /* where we think the head is */
/***********************************************************************\
* Throughout this file the following conventions will be used: *
* fd is a pointer to the fd_data struct for the drive in question *
* fdc is a pointer to the fdc_data struct for the controller *
* fdu is the floppy drive unit number *
* fdcu is the floppy controller unit number *
* fdsu is the floppy drive unit number on that controller. (sub-unit) *
\***********************************************************************/
#define id_physid id_scsiid /* this biotab field doubles as a field */
/* for the physical unit number on the controller */
static int retrier(fdcu_t
);
#define TRACE0(arg) if(fd_debug) printf(arg)
#define TRACE1(arg1,arg2) if(fd_debug) printf(arg1,arg2)
#define TRACE1(arg1,arg2)
static void fdstart(fdcu_t
);
static void fd_turnoff(caddr_t
, int);
/****************************************************************************/
/* autoconfiguration stuff */
/****************************************************************************/
static int fdprobe(struct isa_device
*);
static int fdattach(struct isa_device
*);
struct isa_driver fdcdriver
= {
fdprobe
, fdattach
, "fdc",
* probe for existance of controller
fdcu_t fdcu
= dev
->id_unit
;
if(fdc_data
[fdcu
].flags
& FDC_ATTACHED
)
printf("fdc: same unit (%d) used multiple times\n",fdcu
);
fdc_data
[fdcu
].baseport
= dev
->id_iobase
;
/* First - lets reset the floppy controller */
outb(dev
->id_iobase
+fdout
,0);
outb(dev
->id_iobase
+fdout
,FDO_FRST
);
/* see if it can handle a command */
if (out_fdc(fdcu
,NE7CMD_SPECIFY
) < 0)
* wire controller into system, look for floppy units
fdcu_t fdcu
= dev
->id_unit
;
fdc_p fdc
= fdc_data
+ fdcu
;
fdc
->flags
|= FDC_ATTACHED
;
fdc
->dmachan
= dev
->id_drq
;
/* check for each floppy drive */
for (fdup
= isa_biotab_fdc
; fdup
->id_driver
!= 0; fdup
++) {
if (fdup
->id_iobase
!= dev
->id_iobase
)
/* look up what bios thinks we have */
case 0: fdt
= (rtcin(RTC_FDISKETTE
) & 0xf0);
case 1: fdt
= ((rtcin(RTC_FDISKETTE
) << 4) & 0xf0);
default: fdt
= RTCFDT_NONE
;
|| (fdsu
>= DRVS_PER_CTLR
)) {
/* If BIOS says no floppy, or > 2nd device */
/* Probe for and attach a floppy tape. */
spinwait(1000); /* 1 sec */
out_fdc(fdcu
,NE7CMD_RECAL
); /* Recalibrate Function */
spinwait(1000); /* 1 sec */
/* anything responding */
out_fdc(fdcu
,NE7CMD_SENSEI
);
printf(" [%d: fd%d: ", fdsu
, fdu
);
fd_turnoff((caddr_t
)fdu
, 0);
/* Set transfer to 500kbps */
outb(fdc
->baseport
+fdctl
,0); /*XXX*/
/****************************************************************************/
/****************************************************************************/
void fdstrategy(struct buf
*bp
)
register struct buf
*dp
,*dp0
,*dp1
;
fdu
= FDUNIT(minor(bp
->b_dev
));
/* check for controller already busy with tape */
if (fdc
->flags
& FDC_TAPE_BUSY
) {
if ((fdu
>= NFD
) || (bp
->b_blkno
< 0)) {
printf("fdstrat: fdu = %d, blkno = %d, bcount = %d\n",
fdu
, bp
->b_blkno
, bp
->b_bcount
);
pg("fd:error in fdstrategy");
* Set up block calculations.
blknum
= (unsigned long) bp
->b_blkno
* DEV_BSIZE
/FDBLK
;
if (blknum
+ (bp
->b_bcount
/ FDBLK
) > nblocks
) {
bp
->b_resid
= bp
->b_bcount
;
bp
->b_cylin
= blknum
/ (fd
->ft
->sectrac
* fd
->ft
->heads
);
untimeout(fd_turnoff
, (caddr_t
)fdu
); /* a good idea */
/****************************************************************************/
/* motor control stuff */
/* remember to not deselect the drive we're working on */
/****************************************************************************/
set_motor(fdcu
, fdu
, reset
)
if(fd
= fdc_data
[fdcu
].fd
)/* yes an assign! */
m0
= fd_data
[fdcu
* DRVS_PER_CTLR
+ 0].flags
& FD_MOTOR
;
m1
= fd_data
[fdcu
* DRVS_PER_CTLR
+ 1].flags
& FD_MOTOR
;
outb(fdc_data
[fdcu
].baseport
+fdout
,
| (reset
? 0 : (FDO_FRST
|FDO_FDMAEN
))
| (reset
? 0 : (FDO_FRST
|FDO_FDMAEN
))
| (m1
? FDO_MOEN1
: 0)));
fd_turnoff(caddr_t arg1
, int arg2
)
set_motor(fd
->fdc
->fdcu
,fd
->fdsu
,0);
fd_motor_on(caddr_t arg1
, int arg2
)
fd
->flags
&= ~FD_MOTOR_WAIT
;
if((fd
->fdc
->fd
== fd
) && (fd
->fdc
->state
== MOTORWAIT
))
static void fd_turnon1(fdu_t
);
if(!(fd
->flags
& FD_MOTOR
))
fd
->flags
|= FD_MOTOR_WAIT
;
timeout(fd_motor_on
, (caddr_t
)fdu
, hz
); /* in 1 sec its ok */
set_motor(fd
->fdc
->fdcu
,fd
->fdsu
,0);
/****************************************************************************/
/****************************************************************************/
int baseport
= fdc_data
[fdcu
].baseport
;
while ((i
= inb(baseport
+fdsts
) & (NE7_DIO
|NE7_RQM
))
!= (NE7_DIO
|NE7_RQM
) && j
-- > 0)
if (i
== NE7_RQM
) return -1;
i
= inb(baseport
+fddata
);
TRACE1("[fddata->0x%x]",(unsigned char)i
);
return inb(baseport
+fddata
);
int baseport
= fdc_data
[fdcu
].baseport
;
/* Check that the direction bit is set */
while ((inb(baseport
+fdsts
) & NE7_DIO
) && i
-- > 0);
if (i
<= 0) return (-1); /* Floppy timed out */
/* Check that the floppy controller is ready for a command */
while ((inb(baseport
+fdsts
) & NE7_RQM
) == 0 && i
-- > 0);
if (i
<= 0) return (-1); /* Floppy timed out */
/* Send the command and return */
TRACE1("[0x%x->fddata]",x
);
/****************************************************************************/
/****************************************************************************/
fdu_t fdu
= FDUNIT(minor(dev
));
int type
= FDTYPE(minor(dev
));
/* check for a tape open */
return(ftopen(dev
, flags
));
if ((fdc
== NULL
) || (fd_data
[fdu
].type
== NO_TYPE
))
type
= fd_data
[fdu
].type
;
if (type
!= fd_data
[fdu
].type
) {
switch (fd_data
[fdu
].type
) {
fd_data
[fdu
].ft
= fd_types
+ type
- 1;
fd_data
[fdu
].flags
|= FD_OPEN
;
fdu_t fdu
= FDUNIT(minor(dev
));
int type
= FDTYPE(minor(dev
));
fd_data
[fdu
].flags
&= ~FD_OPEN
;
/***************************************************************\
* We have just queued something.. if the controller is not busy *
* then simulate the case where it has just finished a command *
* So that it (the interrupt routine) looks on the queue for more*
* work to do and picks up what we just added. *
* If the controller is already busy, we need do nothing, as it *
* will pick up our work when the present work completes *
\***************************************************************/
register struct buf
*dp
,*bp
;
if(fdc_data
[fdcu
].state
== DEVIDLE
)
fd_timeout(caddr_t arg1
, int arg2
)
fdcu_t fdcu
= (fdcu_t
)arg1
;
fdu_t fdu
= fdc_data
[fdcu
].fdu
;
dp
= &fdc_data
[fdcu
].head
;
out_fdc(fdcu
,NE7CMD_SENSED
);
out_fdc(fdcu
,fd_data
[fdu
].hddrv
);
out_fdc(fdcu
,NE7CMD_SENSEI
);
printf("fd%d: Operation timeout ST0 %b cyl %d ST3 %b\n",
fdc_data
[fdcu
].status
[0] = 0xc0;
fdc_data
[fdcu
].state
= IOTIMEDOUT
;
if( fdc_data
[fdcu
].retry
< 6)
fdc_data
[fdcu
].retry
= 6;
fdc_data
[fdcu
].fd
= (fd_p
) 0;
fdc_data
[fdcu
].state
= DEVIDLE
;
/* just ensure it has the right spl */
fd_pseudointr(caddr_t arg1
, int arg2
)
fdcu_t fdcu
= (fdcu_t
)arg1
;
/***********************************************************************\
* keep calling the state machine until it returns a 0 *
* ALWAYS called at SPLBIO *
\***********************************************************************/
fdc_p fdc
= fdc_data
+ fdcu
;
if (fdc
->flags
& FDC_TAPE_BUSY
)
while(fdstate(fdcu
, fdc
))
/***********************************************************************\
* The controller state machine. *
* if it returns a non zero value, it should be called again immediatly *
\***********************************************************************/
int read
, format
, head
, trac
, sec
= 0, i
= 0, s
, sectrac
, cyl
, st0
;
register struct buf
*dp
,*bp
;
struct fd_formb
*finfo
= NULL
;
/***********************************************\
* nothing left for this controller to do *
* Force into the IDLE state, *
\***********************************************/
printf("unexpected valid fd pointer (fdu = %d)\n"
TRACE1("[fdc%d IDLE]",fdcu
);
fdu
= FDUNIT(minor(bp
->b_dev
));
if (fdc
->fd
&& (fd
!= fdc
->fd
))
printf("confused fd pointers\n");
read
= bp
->b_flags
& B_READ
;
format
= bp
->b_flags
& B_FORMAT
;
finfo
= (struct fd_formb
*)bp
->b_un
.b_addr
;
TRACE1("[%s]",fdstates
[fdc
->state
]);
TRACE1("(0x%x)",fd
->flags
);
untimeout(fd_turnoff
, (caddr_t
)fdu
);
timeout(fd_turnoff
, (caddr_t
)fdu
, 4 * hz
);
case FINDWORK
: /* we have found new work */
/*******************************************************\
* If the next drive has a motor startup pending, then *
* it will start up in it's own good time *
\*******************************************************/
if(fd
->flags
& FD_MOTOR_WAIT
)
return(0); /* come back later */
/*******************************************************\
* Maybe if it's not starting, it SHOULD be starting *
\*******************************************************/
if (!(fd
->flags
& FD_MOTOR
))
else /* at least make sure we are selected */
set_motor(fdcu
,fd
->fdsu
,0);
if (bp
->b_cylin
== fd
->track
)
fdc
->state
= SEEKCOMPLETE
;
out_fdc(fdcu
,NE7CMD_SEEK
); /* Seek function */
out_fdc(fdcu
,fd
->fdsu
); /* Drive number */
out_fdc(fdcu
,bp
->b_cylin
* fd
->ft
->steptrac
);
timeout(fd_timeout
, (caddr_t
)fdcu
, 2 * hz
);
return(0); /* will return later */
untimeout(fd_timeout
, (caddr_t
)fdcu
);
/* allow heads to settle */
timeout(fd_pseudointr
, (caddr_t
)fdcu
, hz
/ 50);
fdc
->state
= SEEKCOMPLETE
;
return(0); /* will return later */
case SEEKCOMPLETE
: /* SEEK DONE, START DMA */
/* Make sure seek really happened*/
int descyl
= bp
->b_cylin
* fd
->ft
->steptrac
;
out_fdc(fdcu
,NE7CMD_SENSEI
);
printf("fd%d: Seek to cyl %d failed; am at cyl %d (ST0 = 0x%x)\n",
fdu
, descyl
, cyl
, i
, NE7_ST0BITS
);
fd
->skip
= (char *)&(finfo
->fd_formb_cylno(0))
isa_dmastart(bp
->b_flags
, bp
->b_un
.b_addr
+fd
->skip
,
format
? bp
->b_bcount
: FDBLK
, fdc
->dmachan
);
blknum
= (unsigned long)bp
->b_blkno
*DEV_BSIZE
/FDBLK
sectrac
= fd
->ft
->sectrac
;
sec
= blknum
% (sectrac
* fd
->ft
->heads
);
/*XXX*/ fd
->hddrv
= ((head
&1)<<2)+fdu
;
out_fdc(fdcu
,/* NE7CMD_FORMAT */ 0x4d);
out_fdc(fdcu
,head
<< 2 | fdu
);
out_fdc(fdcu
,finfo
->fd_formb_secshift
);
out_fdc(fdcu
,finfo
->fd_formb_nsecs
);
out_fdc(fdcu
,finfo
->fd_formb_gaplen
);
out_fdc(fdcu
,finfo
->fd_formb_fillbyte
);
out_fdc(fdcu
,NE7CMD_READ
); /* READ */
out_fdc(fdcu
,NE7CMD_WRITE
); /* WRITE */
out_fdc(fdcu
,head
<< 2 | fdu
); /* head & unit */
out_fdc(fdcu
,fd
->track
); /* track */
out_fdc(fdcu
,sec
); /* sector XXX +1? */
out_fdc(fdcu
,fd
->ft
->secsize
); /* sector size */
out_fdc(fdcu
,sectrac
); /* sectors/track */
out_fdc(fdcu
,fd
->ft
->gap
); /* gap size */
out_fdc(fdcu
,fd
->ft
->datalen
); /* data length */
timeout(fd_timeout
, (caddr_t
)fdcu
, 2 * hz
);
return(0); /* will return later */
case IOCOMPLETE
: /* IO DONE, post-analyze */
untimeout(fd_timeout
, (caddr_t
)fdcu
);
fdc
->status
[i
] = in_fdc(fdcu
);
isa_dmadone(bp
->b_flags
, bp
->b_un
.b_addr
+fd
->skip
,
format
? bp
->b_bcount
: FDBLK
, fdc
->dmachan
);
if (fdc
->status
[1] & 0x10) {
* Operation not completed in reasonable time.
* Just restart it, don't increment retry count.
fdc
->state
= SEEKCOMPLETE
;
if (!format
&& fd
->skip
< bp
->b_bcount
)
/* set up next transfer */
blknum
= (unsigned long)bp
->b_blkno
*DEV_BSIZE
/FDBLK
bp
->b_cylin
= (blknum
/ (fd
->ft
->sectrac
* fd
->ft
->heads
));
dp
->b_actf
= bp
->av_forw
;
/* Try a reset, keep motor on */
set_motor(fdcu
,fd
->fdsu
,1);
set_motor(fdcu
,fd
->fdsu
,0);
outb(fdc
->baseport
+fdctl
,fd
->ft
->trans
);
TRACE1("[0x%x->fdctl]",fd
->ft
->trans
);
out_fdc(fdcu
,NE7CMD_SPECIFY
); /* specify command */
out_fdc(fdcu
,NE7CMD_RECAL
); /* Recalibrate Function */
return(0); /* will return later */
/* allow heads to settle */
timeout(fd_pseudointr
, (caddr_t
)fdcu
, hz
/ 30);
fdc
->state
= RECALCOMPLETE
;
return(0); /* will return later */
out_fdc(fdcu
,NE7CMD_SENSEI
);
printf("fd%d: recal failed ST0 %b cyl %d\n", fdu
,
/* Seek (probably) necessary */
return(1); /* will return immediatly */
if(fd
->flags
& FD_MOTOR_WAIT
)
return(0); /* time's not up yet */
return(1); /* will return immediatly */
printf("Unexpected FD int->");
out_fdc(fdcu
,NE7CMD_SENSEI
);
printf("ST0 = %lx, PCN = %lx\n",i
,sec
);
fdc
->status
[i
] = in_fdc(fdcu
);
printf("intr status :%lx %lx %lx %lx %lx %lx %lx ",
return(1); /* Come back immediatly to new state */
fdc_p fdc
= fdc_data
+ fdcu
;
register struct buf
*dp
,*bp
;
fdc
->state
= SEEKCOMPLETE
;
dev_t sav_b_dev
= bp
->b_dev
;
bp
->b_dev
= makedev(major(bp
->b_dev
), (FDUNIT(minor(bp
->b_dev
))<<3)|3);
diskerr(bp
, "fd", "hard error", LOG_PRINTF
,
fdc
->fd
->skip
, (struct disklabel
*)NULL
);
printf(" (ST0 %b ", fdc
->status
[0], NE7_ST0BITS
);
printf(" ST1 %b ", fdc
->status
[1], NE7_ST1BITS
);
printf(" ST2 %b ", fdc
->status
[2], NE7_ST2BITS
);
printf("cyl %d hd %d sec %d)\n",
fdc
->status
[3], fdc
->status
[4], fdc
->status
[5]);
bp
->b_resid
= bp
->b_bcount
- fdc
->fd
->skip
;
dp
->b_actf
= bp
->av_forw
;
/* XXX abort current command, if any. */
fdu
= FDUNIT(minor(dev
));
/* set up a buffer header for fdstrategy() */
bp
= (struct buf
*)malloc(sizeof(struct buf
), M_TEMP
, M_NOWAIT
);
bzero((void *)bp
, sizeof(struct buf
));
bp
->b_flags
= B_BUSY
| B_PHYS
| B_FORMAT
;
* calculate a fake blkno, so fdstrategy() would initiate a
* seek to the requested cylinder
bp
->b_blkno
= (finfo
->cyl
* (fd
->ft
->sectrac
* fd
->ft
->heads
)
+ finfo
->head
* fd
->ft
->sectrac
) * FDBLK
/ DEV_BSIZE
;
bp
->b_bcount
= sizeof(struct fd_idfield_data
) * finfo
->fd_formb_nsecs
;
bp
->b_un
.b_addr
= (caddr_t
)finfo
;
/* ...and wait for it to complete */
while(!(bp
->b_flags
& B_DONE
))
rv
= tsleep((caddr_t
)bp
, PRIBIO
, "fdform", 20 * hz
);
* fdioctl() from jc@irbs.UUCP (John Capo)
* i386/i386/conf.c needs to have fdioctl() declared and remove the line that
* defines fdioctl to be enxio.
* Think about allocating buffer off stack.
* Don't pass uncast 0's and NULL's to read/write/setdisklabel().
* Watch out for NetBSD's different *disklabel() interface.
* Added functionality for floppy formatting
* joerg_wunsch@uriah.sax.de (Joerg Wunsch)
fdioctl (dev
, cmd
, addr
, flag
, p
)
int type
= FDTYPE(minor(dev
));
/* check for a tape ioctl */
return ftioctl(dev
, cmd
, addr
, flag
, p
);
bzero(buffer
, sizeof (buffer
));
dl
= (struct disklabel
*)buffer
;
fdt
= fd_data
[FDUNIT(minor(dev
))].ft
;
dl
->d_secpercyl
= fdt
->size
/ fdt
->tracks
;
dl
->d_type
= DTYPE_FLOPPY
;
if (readdisklabel(dev
, fdstrategy
, dl
, NULL
, 0, 0) == NULL
)
*(struct disklabel
*)addr
= *dl
;
if ((flag
& FWRITE
) == 0)
if ((flag
& FWRITE
) == 0)
if ((flag
& FWRITE
) == 0)
dl
= (struct disklabel
*)addr
;
if (error
= setdisklabel ((struct disklabel
*)buffer
,
error
= writedisklabel(dev
, fdstrategy
,
(struct disklabel
*)buffer
, NULL
);
error
= EBADF
; /* must be opened for writing */
else if(((struct fd_formb
*)addr
)->format_version
!=
error
= EINVAL
; /* wrong version of formatting prog */
error
= fdformat(dev
, (struct fd_formb
*)addr
, p
);
case FD_GTYPE
: /* get drive type */
*(struct fd_type
*)addr
= *fd_data
[FDUNIT(minor(dev
))].ft
;