Bring in IDE ATAPI floppy support.

This is Junichi's v1.0 driver.

NOTE: Major device numbers have been changed to avoid conflict with other
      FreeBSD 3.0 devices.  The new numbers should be considered "official."
      This driver is still considered "beta" quality, although we have been
      playing with it.  Please submit bugs to junichi and myself.

Submitted by:	junichi@astec.co.jp
This commit is contained in:
Paul Traina 1998-01-16 22:13:07 +00:00
parent a17bbc0dda
commit aaf862068b
20 changed files with 1681 additions and 29 deletions

View File

@ -37,6 +37,7 @@
#
# Disks:
# wd* "Winchester" disk drives (ST506,IDE,ESDI,RLL,...)
# wfd* "IDE floppy" disk drives (LS-120)
# fd* "floppy" disk drives (3 1/2", 5 1/4")
# sd* "SCSI disks"
# cd* "SCSI CD-ROM disks"
@ -106,7 +107,7 @@
# perfmon CPU performance-monitoring counters
# pci PCI configuration-space access from user mode
#
# $Id: MAKEDEV,v 1.148 1998/01/03 11:53:52 jkh Exp $
# $Id: MAKEDEV,v 1.149 1998/01/09 18:32:51 steve Exp $
#
PATH=/sbin:/bin/:/usr/bin:/usr/sbin:$PATH
@ -260,17 +261,27 @@ wt*)
;;
# Individual slices.
od*s*|sd*s*|vn*s*|wd*s*)
od*s*|sd*s*|vn*s*|wd*s*|wfd*s*)
umask $disk_umask
case $i in
od*s*) name=od; blk=20; chr=70;;
sd*s*) name=sd; blk=4; chr=13;;
wd*s*) name=wd; blk=0; chr=3;;
vn*s*) name=vn; blk=15; chr=43;;
wfd*s*) name=wfd; blk=24; chr=87;;
esac
case $i in
wfd*s*)
unit=`expr $i : '...\([0-9]*\)s'`
slice=`expr $i : '...[0-9]*s\([0-9]*\)'`
part=`expr $i : '...[0-9]*s[0-9]*\(.*\)'`
;;
*)
unit=`expr $i : '..\([0-9]*\)s'`
slice=`expr $i : '..[0-9]*s\([0-9]*\)'`
part=`expr $i : '..[0-9]*s[0-9]*\(.*\)'`
;;
esac
unit=`expr $i : '..\([0-9]*\)s'`
slice=`expr $i : '..[0-9]*s\([0-9]*\)'`
part=`expr $i : '..[0-9]*s[0-9]*\(.*\)'`
case $unit in
[0-9]|[0-9][0-9]|[0-4][0-9][0-9]|50[0-9]|51[0-1])
case $slice in
@ -419,15 +430,23 @@ ft*)
umask 77
;;
od*|sd*|vn*|wd*)
od*|sd*|vn*|wd*|wfd*)
umask $disk_umask
case $i in
od*) name=od; blk=20; chr=70;;
sd*) name=sd; blk=4; chr=13;;
vn*) name=vn; blk=15; chr=43;;
wd*) name=wd; blk=0; chr=3;;
wfd*) name=wfd; blk=24; chr=87;;
esac
case $i in
wfd*)
unit=`expr $i : '...\(.*\)'`
;;
*)
unit=`expr $i : '..\(.*\)'`
;;
esac
unit=`expr $i : '..\(.*\)'`
case $unit in
[0-9]|[0-9][0-9]|[0-4][0-9][0-9]|50[0-9]|51[0-1])
for slicepartname in s0h s1 s2 s3 s4

View File

@ -98,6 +98,15 @@ fd1720:\
:pb#3444:ob#0:bb#4096:fb#512:\
:pc#3444:oc#0:bc#4096:fc#512:
#
# LS-120 floppy-format.
#
fd120m|floppy120|floppy120m|3.5in LS-120 Floppy:\
:ty=floppy:se#512:nt#8:rm#300:ns#32:nc#963:\
:pa#246528:oa#0:ba#4096:fa#512:\
:pb#246528:ob#0:bb#4096:fb#512:\
:pc#246528:oc#0:bc#4096:fc#512:
#
# Harddisk formats
#

View File

@ -37,6 +37,7 @@
#
# Disks:
# wd* "Winchester" disk drives (ST506,IDE,ESDI,RLL,...)
# wfd* "IDE floppy" disk drives (LS-120)
# fd* "floppy" disk drives (3 1/2", 5 1/4")
# sd* "SCSI disks"
# cd* "SCSI CD-ROM disks"
@ -106,7 +107,7 @@
# perfmon CPU performance-monitoring counters
# pci PCI configuration-space access from user mode
#
# $Id: MAKEDEV,v 1.148 1998/01/03 11:53:52 jkh Exp $
# $Id: MAKEDEV,v 1.149 1998/01/09 18:32:51 steve Exp $
#
PATH=/sbin:/bin/:/usr/bin:/usr/sbin:$PATH
@ -260,17 +261,27 @@ wt*)
;;
# Individual slices.
od*s*|sd*s*|vn*s*|wd*s*)
od*s*|sd*s*|vn*s*|wd*s*|wfd*s*)
umask $disk_umask
case $i in
od*s*) name=od; blk=20; chr=70;;
sd*s*) name=sd; blk=4; chr=13;;
wd*s*) name=wd; blk=0; chr=3;;
vn*s*) name=vn; blk=15; chr=43;;
wfd*s*) name=wfd; blk=24; chr=87;;
esac
case $i in
wfd*s*)
unit=`expr $i : '...\([0-9]*\)s'`
slice=`expr $i : '...[0-9]*s\([0-9]*\)'`
part=`expr $i : '...[0-9]*s[0-9]*\(.*\)'`
;;
*)
unit=`expr $i : '..\([0-9]*\)s'`
slice=`expr $i : '..[0-9]*s\([0-9]*\)'`
part=`expr $i : '..[0-9]*s[0-9]*\(.*\)'`
;;
esac
unit=`expr $i : '..\([0-9]*\)s'`
slice=`expr $i : '..[0-9]*s\([0-9]*\)'`
part=`expr $i : '..[0-9]*s[0-9]*\(.*\)'`
case $unit in
[0-9]|[0-9][0-9]|[0-4][0-9][0-9]|50[0-9]|51[0-1])
case $slice in
@ -419,15 +430,23 @@ ft*)
umask 77
;;
od*|sd*|vn*|wd*)
od*|sd*|vn*|wd*|wfd*)
umask $disk_umask
case $i in
od*) name=od; blk=20; chr=70;;
sd*) name=sd; blk=4; chr=13;;
vn*) name=vn; blk=15; chr=43;;
wd*) name=wd; blk=0; chr=3;;
wfd*) name=wfd; blk=24; chr=87;;
esac
case $i in
wfd*)
unit=`expr $i : '...\(.*\)'`
;;
*)
unit=`expr $i : '..\(.*\)'`
;;
esac
unit=`expr $i : '..\(.*\)'`
case $unit in
[0-9]|[0-9][0-9]|[0-4][0-9][0-9]|50[0-9]|51[0-1])
for slicepartname in s0h s1 s2 s3 s4

View File

@ -98,6 +98,15 @@ fd1720:\
:pb#3444:ob#0:bb#4096:fb#512:\
:pc#3444:oc#0:bc#4096:fc#512:
#
# LS-120 floppy-format.
#
fd120m|floppy120|floppy120m|3.5in LS-120 Floppy:\
:ty=floppy:se#512:nt#8:rm#300:ns#32:nc#963:\
:pa#246528:oa#0:ba#4096:fa#512:\
:pb#246528:ob#0:bb#4096:fb#512:\
:pc#246528:oc#0:bc#4096:fc#512:
#
# Harddisk formats
#

View File

@ -11,7 +11,7 @@
# device lines is present in the ./LINT configuration file. If you are
# in doubt as to the purpose or necessity of a line, check first in LINT.
#
# $Id: GENERIC,v 1.101 1997/10/31 22:10:02 jseger Exp $
# $Id: GENERIC,v 1.102 1998/01/11 02:16:38 jkh Exp $
machine "i386"
cpu "I386_CPU"
@ -58,7 +58,8 @@ disk wd3 at wdc1 drive 1
options ATAPI #Enable ATAPI support for IDE bus
options ATAPI_STATIC #Don't do it as an LKM
device wcd0 #IDE CD-ROM
device wcd0 #IDE CD-ROM
device wfd0 #IDE Floppy (e.g. LS-120)
# A single entry for any of these controllers (ncr, ahb, ahc, amd) is
# sufficient for any number of installed devices.

View File

@ -2,7 +2,7 @@
# LINT -- config file for checking all the sources, tries to pull in
# as much of the source tree as it can.
#
# $Id: LINT,v 1.390 1997/12/31 21:46:17 obrien Exp $
# $Id: LINT,v 1.391 1998/01/14 19:41:36 phk Exp $
#
# NB: You probably don't want to try running a kernel built from this
# file. Instead, you should start from GENERIC, and add options from
@ -833,6 +833,10 @@ options ATAPI_STATIC #Don't do it as an LKM
# IDE CD-ROM driver - requires wdc controller and ATAPI option
device wcd0
# IDE floppy driver - requires wdc controller and ATAPI option
device wfd0
#
# Standard floppy disk controllers and floppy tapes: `fdc', `fd', and `ft'
#

View File

@ -1,7 +1,7 @@
# This file tells config what files go into building a kernel,
# files marked standard are always included.
#
# $Id: files.i386,v 1.184 1998/01/08 23:13:19 jmg Exp $
# $Id: files.i386,v 1.185 1998/01/15 07:30:54 gibbs Exp $
#
# The long compile-with and dependency lines are required because of
# limitations in config: backslash-newline doesn't work in strings, and
@ -240,6 +240,7 @@ i386/isa/atapi.c optional atapi device-driver
i386/isa/wcd.c optional wcd device-driver
i386/isa/wd7000.c optional wds device-driver
i386/isa/wt.c optional wt device-driver
i386/isa/wfd.c optional wfd device-driver
i386/linux/imgact_linux.c optional compat_linux
i386/linux/linux_dummy.c optional compat_linux
i386/linux/linux_file.c optional compat_linux

View File

@ -1,4 +1,4 @@
$Id: majors.i386,v 1.22 1997/11/17 07:58:23 jmg Exp $
$Id: majors.i386,v 1.23 1997/12/09 10:51:11 jamil Exp $
Hopefully, this list will one day be obsoleted by DEVFS, but for now
this is the current allocation of device major numbers.
@ -37,6 +37,7 @@ blkdev name comments
21 ccd concatenated disk
22 gd Geometry disk.
23 worm SCSI "worm type"
24 wfd ATAPI Floppy client of "ata"
chrdev name comments
0 cn console
1 ctty /dev/tty
@ -125,3 +126,4 @@ chrdev name comments
84 ttxt Unitext teletext decoder (arg@arg1.demon.co.uk)
85 vesa VESA support device (j_mini@efn.org)
86 alog Industrial Computer Source AIO8-P driver
87 wfd ATAPI floppy client of "ata"

View File

@ -11,7 +11,7 @@
# device lines is present in the ./LINT configuration file. If you are
# in doubt as to the purpose or necessity of a line, check first in LINT.
#
# $Id: GENERIC,v 1.101 1997/10/31 22:10:02 jseger Exp $
# $Id: GENERIC,v 1.102 1998/01/11 02:16:38 jkh Exp $
machine "i386"
cpu "I386_CPU"
@ -58,7 +58,8 @@ disk wd3 at wdc1 drive 1
options ATAPI #Enable ATAPI support for IDE bus
options ATAPI_STATIC #Don't do it as an LKM
device wcd0 #IDE CD-ROM
device wcd0 #IDE CD-ROM
device wfd0 #IDE Floppy (e.g. LS-120)
# A single entry for any of these controllers (ncr, ahb, ahc, amd) is
# sufficient for any number of installed devices.

View File

@ -2,7 +2,7 @@
# LINT -- config file for checking all the sources, tries to pull in
# as much of the source tree as it can.
#
# $Id: LINT,v 1.390 1997/12/31 21:46:17 obrien Exp $
# $Id: LINT,v 1.391 1998/01/14 19:41:36 phk Exp $
#
# NB: You probably don't want to try running a kernel built from this
# file. Instead, you should start from GENERIC, and add options from
@ -833,6 +833,10 @@ options ATAPI_STATIC #Don't do it as an LKM
# IDE CD-ROM driver - requires wdc controller and ATAPI option
device wcd0
# IDE floppy driver - requires wdc controller and ATAPI option
device wfd0
#
# Standard floppy disk controllers and floppy tapes: `fdc', `fd', and `ft'
#

View File

@ -2,7 +2,7 @@
# LINT -- config file for checking all the sources, tries to pull in
# as much of the source tree as it can.
#
# $Id: LINT,v 1.390 1997/12/31 21:46:17 obrien Exp $
# $Id: LINT,v 1.391 1998/01/14 19:41:36 phk Exp $
#
# NB: You probably don't want to try running a kernel built from this
# file. Instead, you should start from GENERIC, and add options from
@ -833,6 +833,10 @@ options ATAPI_STATIC #Don't do it as an LKM
# IDE CD-ROM driver - requires wdc controller and ATAPI option
device wcd0
# IDE floppy driver - requires wdc controller and ATAPI option
device wfd0
#
# Standard floppy disk controllers and floppy tapes: `fdc', `fd', and `ft'
#

View File

@ -1,6 +1,6 @@
# This file tells what major numbers the various possible swap devices have.
#
# $Id$
# $Id: devices.i386,v 1.11 1997/02/22 09:31:40 peter Exp $
#
wd 0
dk 1
@ -15,3 +15,4 @@ scd 16
pcd 17
wcd 19
od 20
wfd 24

View File

@ -1,7 +1,7 @@
# This file tells config what files go into building a kernel,
# files marked standard are always included.
#
# $Id: files.i386,v 1.184 1998/01/08 23:13:19 jmg Exp $
# $Id: files.i386,v 1.185 1998/01/15 07:30:54 gibbs Exp $
#
# The long compile-with and dependency lines are required because of
# limitations in config: backslash-newline doesn't work in strings, and
@ -240,6 +240,7 @@ i386/isa/atapi.c optional atapi device-driver
i386/isa/wcd.c optional wcd device-driver
i386/isa/wd7000.c optional wds device-driver
i386/isa/wt.c optional wt device-driver
i386/isa/wfd.c optional wfd device-driver
i386/linux/imgact_linux.c optional compat_linux
i386/linux/linux_dummy.c optional compat_linux
i386/linux/linux_file.c optional compat_linux

View File

@ -1,4 +1,4 @@
$Id: majors.i386,v 1.22 1997/11/17 07:58:23 jmg Exp $
$Id: majors.i386,v 1.23 1997/12/09 10:51:11 jamil Exp $
Hopefully, this list will one day be obsoleted by DEVFS, but for now
this is the current allocation of device major numbers.
@ -37,6 +37,7 @@ blkdev name comments
21 ccd concatenated disk
22 gd Geometry disk.
23 worm SCSI "worm type"
24 wfd ATAPI Floppy client of "ata"
chrdev name comments
0 cn console
1 ctty /dev/tty
@ -125,3 +126,4 @@ chrdev name comments
84 ttxt Unitext teletext decoder (arg@arg1.demon.co.uk)
85 vesa VESA support device (j_mini@efn.org)
86 alog Industrial Computer Source AIO8-P driver
87 wfd ATAPI floppy client of "ata"

View File

@ -104,6 +104,7 @@
#ifndef ATAPI_MODULE
# include "wcd.h"
# include "wfd.h"
/* # include "wmt.h" -- add your driver here */
/* # include "wmd.h" -- add your driver here */
#endif
@ -169,6 +170,7 @@ static int atapi_start_cmd (struct atapi *ata, struct atapicmd *ac);
static int atapi_wait_cmd (struct atapi *ata, struct atapicmd *ac);
extern int wdstart (int ctrlr);
extern int wfdattach(struct atapi*, int, struct atapi_params*, int);
extern int wcdattach(struct atapi*, int, struct atapi_params*, int);
/*
@ -217,6 +219,8 @@ int atapi_attach (int ctlr, int unit, int port)
case AT_DRQT_ACCEL: printf (", accel"); break;
default: printf (", drq%d", ap->drqtype);
}
if (ata->slow)
ata->intrcmd = 0;
/* overlap operation supported */
if (ap->ovlapflag)
@ -270,6 +274,14 @@ int atapi_attach (int ctlr, int unit, int port)
break;
case AT_TYPE_DIRECT: /* direct-access */
#if NWFD > 0
/* ATAPI Floppy(LS-120) */
if (wfdattach (ata, unit, ap, ata->debug) >= 0) {
/* Device attached successfully. */
ata->attached[unit] = 1;
return (1);
}
#endif
case AT_TYPE_CDROM: /* CD-ROM device */
#if NWCD > 0
/* ATAPI CD-ROM */
@ -316,6 +328,7 @@ static char *cmdname (u_char cmd)
case 0x1e: return ("PREVENT_ALLOW");
case 0x25: return ("READ_CAPACITY");
case 0x28: return ("READ_BIG");
case 0x2a: return ("WRITE_BIG");
case 0x43: return ("READ_TOC");
case 0x42: return ("READ_SUBCHANNEL");
case 0x55: return ("MODE_SELECT_BIG");
@ -479,7 +492,7 @@ static struct atapicmd *atapi_alloc (struct atapi *ata)
struct atapicmd *ac;
while (! ata->free)
tsleep ((caddr_t)ata, PRIBIO, "atacmd", 0);
tsleep ((caddr_t)ata, PRIBIO, "atacmd", 100);
ac = ata->free;
ata->free = ac->next;
ac->busy = 1;

View File

@ -111,6 +111,7 @@
#define ATAPI_PREVENT_ALLOW 0x1e /* prevent/allow media removal */
#define ATAPI_READ_CAPACITY 0x25 /* get volume capacity */
#define ATAPI_READ_BIG 0x28 /* read data */
#define ATAPI_WRITE_BIG 0x2a /* write data */
#define ATAPI_READ_TOC 0x43 /* get table of contents */
#define ATAPI_READ_SUBCHANNEL 0x42 /* get subchannel info */
#define ATAPI_MODE_SELECT_BIG 0x55 /* set device parameters */

View File

@ -34,7 +34,7 @@
* SUCH DAMAGE.
*
* from: @(#)wd.c 7.2 (Berkeley) 5/9/91
* $Id: wd.c,v 1.145 1997/12/02 21:06:32 phk Exp $
* $Id: wd.c,v 1.146 1997/12/06 14:27:20 bde Exp $
*/
/* TODO:
@ -357,7 +357,7 @@ wdprobe(struct isa_device *dvp)
* drive 2. (This seems to contradict the ATA spec.)
*/
du->dk_error = inb(du->dk_port + wd_error);
if(du->dk_error != 0x01) {
if(du->dk_error != 0x01 && du->dk_error != 0) {
if(du->dk_error & 0x80) { /* drive 1 failure */
/* first set the DRV bit */

780
sys/i386/isa/wfd.c Normal file
View File

@ -0,0 +1,780 @@
/*
* Copyright (c) 1997,1998 Junichi Satoh <junichi@astec.co.jp>
* 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 as
* the first lines of this file unmodified.
* 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 Junichi Satoh ``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 Junichi Satoh 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.
*
* $Id: wfd.c,v 1.6 1998/01/06 15:54:53 junichi Exp junichi $
*/
/*
* ATAPI Floppy, LS-120 driver
*/
#include "wdc.h"
#include "wfd.h"
#include "opt_atapi.h"
#if NWFD > 0 && NWDC > 0 && defined (ATAPI)
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/conf.h>
#include <sys/file.h>
#include <sys/fcntl.h>
#include <sys/proc.h>
#include <sys/malloc.h>
#include <sys/buf.h>
#include <sys/disklabel.h>
#include <sys/diskslice.h>
#include <sys/cdio.h>
#include <machine/ioctl_fd.h>
#ifdef DEVFS
#include <sys/devfsext.h>
#endif /*DEVFS*/
#include <i386/isa/atapi.h>
#include <i386/isa/fdc.h>
static d_open_t wfdbopen;
static d_close_t wfdbclose;
static d_ioctl_t wfdioctl;
static d_strategy_t wfdstrategy;
#define CDEV_MAJOR 87
#define BDEV_MAJOR 24
static struct cdevsw wfd_cdevsw;
static struct bdevsw wfd_bdevsw =
{ wfdbopen, wfdbclose, wfdstrategy, wfdioctl, /*22*/
nodump, nopsize, 0, "wfd", &wfd_cdevsw, -1 };
#ifndef ATAPI_STATIC
static
#endif
int wfdattach(struct atapi*, int, struct atapi_params*, int);
#define NUNIT (NWDC*2) /* Max. number of devices */
#define UNIT(d) ((minor(d) >> 3) & 3) /* Unit part of minor device number */
#define F_BOPEN 0x0001 /* The block device is opened */
#define F_MEDIA_CHANGED 0x0002 /* The media have changed since open */
#define F_DEBUG 0x0004 /* Print debug info */
/*
* LS-120 Capabilities and Mechanical Status Page
*/
struct cappage {
/* Mode data header */
u_short data_length;
u_char medium_type;
#define MDT_UNKNOWN 0x00
#define MDT_NO_DISC 0x70
#define MDT_DOOR_OPEN 0x71
#define MDT_FMT_ERROR 0x72
#define MDT_2DD_UN 0x10
#define MDT_2DD 0x11
#define MDT_2HD_UN 0x20
#define MDT_2HD_12_98 0x22
#define MDT_2HD_12 0x23
#define MDT_2HD_144 0x24
#define MDT_LS120 0x31
unsigned reserved0 :7;
unsigned wp :1; /* Write protect */
u_char reserved1[4];
/* Capabilities page */
unsigned page_code :6; /* Page code - Should be 0x5 */
#define CAP_PAGE 0x05
unsigned reserved1_6 :1; /* Reserved */
unsigned ps :1; /* The device is capable of savi
ng the page */
u_char page_length; /* Page Length - Should be 0x1e */
u_short transfer_rate; /* In kilobits per second */
u_char heads, sectors; /* Number of heads, Number of sectors per track */
u_short sector_size; /* Byes per sector */
u_short cyls; /* Number of cylinders */
u_char reserved10[10];
u_char motor_delay; /* Motor off delay */
u_char reserved21[7];
u_short rpm; /* Rotations per minute */
u_char reserved30[2];
};
/* misuse a flag to identify format operation */
#define B_FORMAT B_XXX
struct wfd {
struct atapi *ata; /* Controller structure */
int unit; /* IDE bus drive unit */
int lun; /* Logical device unit */
int flags; /* Device state flags */
int refcnt; /* The number of raw opens */
struct buf_queue_head buf_queue; /* Queue of i/o requests */
struct atapi_params *param; /* Drive parameters table */
struct cappage cap; /* Capabilities page info */
char description[80]; /* Device description */
#ifdef DEVFS
void *cdevs;
void *bdevs;
#endif
struct diskslices *dk_slices; /* virtual drives */
};
struct wfd *wfdtab[NUNIT]; /* Drive info by unit number */
static int wfdnlun = 0; /* Number of configured drives */
static void wfd_start (struct wfd *t);
static void wfd_done (struct wfd *t, struct buf *bp, int resid,
struct atapires result);
static void wfd_error (struct wfd *t, struct atapires result);
static int wfd_request_wait (struct wfd *t, u_char cmd, u_char a1, u_char a2,
u_char a3, u_char a4, u_char a5, u_char a6, u_char a7, u_char a8,
u_char a9, char *addr, int count);
static void wfd_describe (struct wfd *t);
static int wfd_eject (struct wfd *t, int closeit);
static void wfdstrategy1(struct buf *bp);
/*
* Dump the array in hexadecimal format for debugging purposes.
*/
static void wfd_dump (int lun, char *label, void *data, int len)
{
u_char *p = data;
printf ("wfd%d: %s %x", lun, label, *p++);
while (--len > 0)
printf ("-%x", *p++);
printf ("\n");
}
#ifndef ATAPI_STATIC
static
#endif
int
wfdattach (struct atapi *ata, int unit, struct atapi_params *ap, int debug)
{
struct wfd *t;
struct atapires result;
int lun, i;
#ifdef DEVFS
int mynor;
#endif
if (wfdnlun >= NUNIT) {
printf ("wfd: too many units\n");
return (0);
}
if (!atapi_request_immediate) {
printf("wfd: configuration error, ATAPI core code not present!\n");
printf("wfd: check `options ATAPI_STATIC' in your kernel config file!\n");
return (0);
}
t = malloc (sizeof (struct wfd), M_TEMP, M_NOWAIT);
if (! t) {
printf ("wfd: out of memory\n");
return (0);
}
wfdtab[wfdnlun] = t;
bzero (t, sizeof (struct wfd));
bufq_init(&t->buf_queue);
t->ata = ata;
t->unit = unit;
lun = t->lun = wfdnlun++;
t->param = ap;
t->flags = F_MEDIA_CHANGED;
t->refcnt = 0;
if (debug) {
t->flags |= F_DEBUG;
/* Print params. */
wfd_dump (t->lun, "info", ap, sizeof *ap);
}
/* Get drive capabilities. */
/* Do it twice to avoid the stale media changed state. */
for (i = 0; i < 2; i++) {
result = atapi_request_immediate (ata, unit, ATAPI_MODE_SENSE,
0, CAP_PAGE, 0, 0, 0, 0,
sizeof (t->cap) >> 8, sizeof (t->cap),
0, 0, 0, 0, 0, 0, 0, (char*) &t->cap, sizeof (t->cap));
}
if (result.code == RES_ERR &&
(result.error & AER_SKEY) == AER_SK_UNIT_ATTENTION)
result = atapi_request_immediate (ata, unit, ATAPI_MODE_SENSE,
0, CAP_PAGE, 0, 0, 0, 0, sizeof (t->cap) >> 8,
sizeof (t->cap), 0, 0, 0, 0, 0, 0, 0,
(char*) &t->cap, sizeof (t->cap));
/* Some drives have shorter capabilities page. */
if (result.code == RES_UNDERRUN)
result.code = 0;
if (result.code == 0) {
wfd_describe (t);
if (t->flags & F_DEBUG)
wfd_dump (t->lun, "cap", &t->cap, sizeof t->cap);
} else
return -1;
#ifdef DEVFS
mynor = dkmakeminor(unit, WHOLE_DISK_SLICE, RAW_PART);
t->bdevs = devfs_add_devswf(&wfd_bdevsw, mynor,
DV_BLK, UID_ROOT, GID_OPERATOR, 0640,
"wfd%d", unit);
t->cdevs = devfs_add_devswf(&wfd_cdevsw, mynor,
DV_CHR, UID_ROOT, GID_OPERATOR, 0640,
"rwfd%d", unit);
#endif /* DEVFS */
return (1);
}
void wfd_describe (struct wfd *t)
{
int no_print = 0;
t->cap.cyls = ntohs (t->cap.cyls);
t->cap.sector_size = ntohs (t->cap.sector_size);
printf ("wfd%d: ", t->lun);
switch (t->cap.medium_type) {
case MDT_UNKNOWN:
printf ("medium type unknown (no disk)");
no_print = 1;
break;
case MDT_2DD_UN:
printf ("2DD(capacity unknown) floppy disk loaded");
no_print = 1;
break;
case MDT_2DD:
printf ("720KB floppy disk loaded");
break;
case MDT_2HD_UN:
printf ("2HD(capacity unknown) floppy disk loaded");
no_print = 1;
break;
case MDT_2HD_12_98:
printf ("1.25MB(PC-9801 format) floppy disk loaded");
break;
case MDT_2HD_12:
printf ("1.2MB floppy disk loaded");
break;
case MDT_2HD_144:
printf ("1.44MB floppy disk loaded");
break;
case MDT_LS120:
printf ("120MB floppy disk loaded");
break;
case MDT_NO_DISC:
printf ("no disc inside");
no_print = 1;
break;
case MDT_DOOR_OPEN:
printf ("door open");
no_print = 1;
break;
case MDT_FMT_ERROR:
printf ("medium format error");
no_print = 1;
break;
default:
printf ("medium type=0x%x", t->cap.medium_type);
break;
}
if (t->cap.wp)
printf(", write protected");
printf ("\n");
if (!no_print) {
printf ("wfd%d: ", t->lun);
printf ("%lu cyls", t->cap.cyls);
printf (", %lu heads, %lu S/T", t->cap.heads, t->cap.sectors);
printf (", %lu B/S", t->cap.sector_size);
printf ("\n");
}
}
int wfdbopen (dev_t dev, int flags, int fmt, struct proc *p)
{
int lun = UNIT(dev);
struct wfd *t;
struct atapires result;
int errcode = 0;
struct disklabel label;
/* Check that the device number is legal
* and the ATAPI driver is loaded. */
if (lun >= wfdnlun || ! atapi_request_immediate) {
printf("ENXIO lun=%d, wfdnlun=%d, im=%d\n", lun, wfdnlun, atapi_request_immediate);
return (ENXIO);
}
t = wfdtab[lun];
t->flags &= ~F_MEDIA_CHANGED;
/* Lock the media. */
wfd_request_wait (t, ATAPI_PREVENT_ALLOW,
0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0);
/* Sense the media type */
result = atapi_request_wait (t->ata, t->unit, ATAPI_MODE_SENSE,
0, CAP_PAGE, 0, 0, 0, 0,
sizeof (t->cap) >> 8, sizeof (t->cap),
0, 0, 0, 0, 0, 0, 0,
(char*) &t->cap, sizeof (t->cap));
if (result.code)
printf ("wfd%d: Sense the media type is failed.\n", t->lun);
else {
t->cap.cyls = ntohs (t->cap.cyls);
t->cap.sector_size = ntohs (t->cap.sector_size);
}
/* Build label for whole disk. */
bzero(&label, sizeof label);
label.d_secsize = t->cap.sector_size;
label.d_nsectors = t->cap.sectors;
label.d_ntracks = t->cap.heads;
label.d_ncylinders = t->cap.cyls;
label.d_secpercyl = t->cap.heads * t->cap.sectors;
label.d_rpm = 720;
label.d_secperunit = label.d_secpercyl * t->cap.cyls;
/* Initialize slice tables. */
errcode = dsopen("wfd", dev, fmt, &t->dk_slices, &label, wfdstrategy1,
(ds_setgeom_t *)NULL, &wfd_bdevsw, &wfd_cdevsw);
if (errcode != 0)
return errcode;
t->flags |= F_BOPEN;
return (0);
}
/*
* Close the device. Only called if we are the LAST
* occurence of an open device.
*/
int wfdbclose (dev_t dev, int flags, int fmt, struct proc *p)
{
int lun = UNIT(dev);
struct wfd *t = wfdtab[lun];
dsclose(dev, fmt, t->dk_slices);
if(!dsisopen(t->dk_slices)) {
/* If we were the last open of the entire device, release it. */
if (! t->refcnt)
wfd_request_wait (t, ATAPI_PREVENT_ALLOW,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
t->flags &= ~F_BOPEN;
}
return (0);
}
static void
wfdstrategy1(struct buf *bp)
{
/*
* XXX - do something to make wdstrategy() but not this block while
* we're doing dsinit() and dsioctl().
*/
wfdstrategy(bp);
}
/*
* Actually translate the requested transfer into one the physical driver can
* understand. The transfer is described by a buf and will include only one
* physical transfer.
*/
void wfdstrategy (struct buf *bp)
{
int lun = UNIT(bp->b_dev);
struct wfd *t = wfdtab[lun];
int x;
/* If it's a null transfer, return immediatly. */
if (bp->b_bcount == 0) {
bp->b_resid = 0;
biodone (bp);
return;
}
/* Process transfer request. */
bp->b_pblkno = bp->b_blkno;
bp->b_resid = bp->b_bcount;
/*
* Do bounds checking, adjust transfer, and set b_pblkno.
*/
if (dscheck(bp, t->dk_slices) <= 0) {
biodone(bp);
return;
}
bp->b_blkno = bp->b_pblkno;
x = splbio();
/* Place it in the queue of disk activities for this disk. */
bufqdisksort (&t->buf_queue, bp);
/* Tell the device to get going on the transfer if it's
* not doing anything, otherwise just wait for completion. */
wfd_start (t);
splx(x);
}
/*
* Look to see if there is a buf waiting for the device
* and that the device is not already busy. If both are true,
* It dequeues the buf and creates an ATAPI command to perform the
* transfer in the buf.
* The bufs are queued by the strategy routine (wfdstrategy).
* Must be called at the correct (splbio) level.
*/
static void wfd_start (struct wfd *t)
{
struct buf *bp = bufq_first(&t->buf_queue);
u_long blkno, nblk;
u_char op_code;
long count;
/* See if there is a buf to do and we are not already doing one. */
if (! bp)
return;
/* Unqueue the request. */
bufq_remove(&t->buf_queue, bp);
/* We have a buf, now we should make a command
* First, translate the block to absolute and put it in terms of the
* logical blocksize of the device.
* What if something asks for 512 bytes not on a 2k boundary? */
blkno = bp->b_blkno / (t->cap.sector_size / 512);
nblk = (bp->b_bcount + (t->cap.sector_size - 1)) / t->cap.sector_size;
if(bp->b_flags & B_READ) {
op_code = ATAPI_READ_BIG;
count = bp->b_bcount;
} else {
op_code = ATAPI_WRITE_BIG;
count = -bp->b_bcount;
}
atapi_request_callback (t->ata, t->unit, op_code, 0,
blkno>>24, blkno>>16, blkno>>8, blkno, 0, nblk>>8, nblk, 0, 0,
0, 0, 0, 0, 0, (u_char*) bp->b_data, count,
(void*)wfd_done, t, bp);
}
static void wfd_done (struct wfd *t, struct buf *bp, int resid,
struct atapires result)
{
if (result.code) {
wfd_error (t, result);
bp->b_error = EIO;
bp->b_flags |= B_ERROR;
} else
bp->b_resid = resid;
biodone (bp);
wfd_start (t);
}
static void wfd_error (struct wfd *t, struct atapires result)
{
if (result.code != RES_ERR)
return;
switch (result.error & AER_SKEY) {
case AER_SK_NOT_READY:
if (result.error & ~AER_SKEY) {
/* Not Ready */
printf ("wfd%d: not ready\n", t->lun);
return;
}
/* Tray open. */
if (! (t->flags & F_MEDIA_CHANGED))
printf ("wfd%d: tray open\n", t->lun);
t->flags |= F_MEDIA_CHANGED;
return;
case AER_SK_UNIT_ATTENTION:
/* Media changed. */
if (! (t->flags & F_MEDIA_CHANGED))
printf ("wfd%d: media changed\n", t->lun);
t->flags |= F_MEDIA_CHANGED;
return;
case AER_SK_ILLEGAL_REQUEST:
/* Unknown command or invalid command arguments. */
if (t->flags & F_DEBUG)
printf ("wfd%d: invalid command\n", t->lun);
return;
}
printf ("wfd%d: i/o error, status=%b, error=%b\n", t->lun,
result.status, ARS_BITS, result.error, AER_BITS);
}
static int wfd_request_wait (struct wfd *t, u_char cmd, u_char a1, u_char a2,
u_char a3, u_char a4, u_char a5, u_char a6, u_char a7, u_char a8,
u_char a9, char *addr, int count)
{
struct atapires result;
result = atapi_request_wait (t->ata, t->unit, cmd,
a1, a2, a3, a4, a5, a6, a7, a8, a9, 0, 0, 0, 0, 0, 0,
addr, count);
if (result.code) {
wfd_error (t, result);
return (EIO);
}
return (0);
}
/*
* Perform special action on behalf of the user.
* Knows about the internals of this device
*/
int wfdioctl (dev_t dev, int cmd, caddr_t addr, int flag, struct proc *p)
{
int lun = UNIT(dev);
struct wfd *t = wfdtab[lun];
int error = 0;
struct disklabel *dl;
char buffer[DEV_BSIZE];
error = dsioctl("wfd", dev, cmd, addr, flag, &t->dk_slices,
wfdstrategy1, (ds_setgeom_t *)NULL);
if (error != -1)
return (error);
if (t->flags & F_MEDIA_CHANGED)
switch (cmd) {
case CDIOCSETDEBUG:
case CDIOCCLRDEBUG:
case CDIOCRESET:
/* These ops are media change transparent. */
break;
default:
/* Lock the media. */
wfd_request_wait (t, ATAPI_PREVENT_ALLOW,
0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0);
break;
}
switch (cmd) {
case CDIOCSETDEBUG:
if (p->p_cred->pc_ucred->cr_uid)
return (EPERM);
t->flags |= F_DEBUG;
atapi_debug (t->ata, 1);
return 0;
case CDIOCCLRDEBUG:
if (p->p_cred->pc_ucred->cr_uid)
return (EPERM);
t->flags &= ~F_DEBUG;
atapi_debug (t->ata, 0);
return 0;
case CDIOCRESET:
if (p->p_cred->pc_ucred->cr_uid)
return (EPERM);
return wfd_request_wait (t, ATAPI_TEST_UNIT_READY,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
case CDIOCEJECT:
/* Don't allow eject if the device is opened
* by somebody (not us) in block mode. */
if ((t->flags & F_BOPEN) && t->refcnt)
return (EBUSY);
return wfd_eject (t, 0);
case CDIOCCLOSE:
if ((t->flags & F_BOPEN) && t->refcnt)
return (0);
return wfd_eject (t, 1);
default:
return (ENOTTY);
}
return (error);
}
static int wfd_eject (struct wfd *t, int closeit)
{
struct atapires result;
/* Try to stop the disc. */
result = atapi_request_wait (t->ata, t->unit, ATAPI_START_STOP,
1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
if (result.code == RES_ERR &&
((result.error & AER_SKEY) == AER_SK_NOT_READY ||
(result.error & AER_SKEY) == AER_SK_UNIT_ATTENTION)) {
int err;
if (!closeit)
return (0);
/*
* The disc was unloaded.
* Load it (close tray).
* Read the table of contents.
*/
err = wfd_request_wait (t, ATAPI_START_STOP,
0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0);
if (err)
return (err);
/* Lock the media. */
wfd_request_wait (t, ATAPI_PREVENT_ALLOW,
0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0);
return (0);
}
if (result.code) {
wfd_error (t, result);
return (EIO);
}
if (closeit)
return (0);
/* Give it some time to stop spinning. */
tsleep ((caddr_t)&lbolt, PRIBIO, "wfdej1", 0);
tsleep ((caddr_t)&lbolt, PRIBIO, "wfdej2", 0);
/* Unlock. */
wfd_request_wait (t, ATAPI_PREVENT_ALLOW,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
/* Eject. */
t->flags |= F_MEDIA_CHANGED;
return wfd_request_wait (t, ATAPI_START_STOP,
0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0);
}
#ifdef WFD_MODULE
/*
* Loadable ATAPI Floppy driver stubs.
*/
#include <sys/exec.h>
#include <sys/sysent.h>
#include <sys/lkm.h>
/*
* Construct lkm_dev structures (see lkm.h).
* Our bdevsw/cdevsw slot numbers are 19/69.
*/
MOD_DEV(wfd, LM_DT_BLOCK, BDEV_MAJOR, &wfd_bdevsw);
MOD_DEV(rwfd, LM_DT_CHAR, CDEV_MAJOR, &wfd_cdevsw);
/*
* Function called when loading the driver.
*/
int wfd_load (struct lkm_table *lkmtp, int cmd)
{
struct atapi *ata;
int n, u;
if (! atapi_start)
/* No ATAPI driver available. */
return EPROTONOSUPPORT;
n = 0;
for (ata=atapi_tab; ata<atapi_tab+2; ++ata)
if (ata->port)
for (u=0; u<2; ++u)
/* Probing controller ata->ctrlr, unit u. */
if (ata->params[u] && ! ata->attached[u] &&
wfdattach (ata, u, ata->params[u],
ata->debug) >= 0)
{
/* Drive found. */
ata->attached[u] = 1;
++n;
}
if (! n)
/* No IDE Floppies found. */
return ENXIO;
return 0;
}
/*
* Function called when unloading the driver.
*/
int wfd_unload (struct lkm_table *lkmtp, int cmd)
{
struct wfd **t;
for (t=wfdtab; t<wfdtab+wfdnlun; ++t)
if (((*t)->flags & F_BOPEN) || (*t)->refcnt)
/* The device is opened, cannot unload the driver. */
return EBUSY;
for (t=wfdtab; t<wfdtab+wfdnlun; ++t) {
(*t)->ata->attached[(*t)->unit] = 0;
free (*t, M_TEMP);
}
wfdnlun = 0;
bzero (wfdtab, sizeof(wfdtab));
return 0;
}
/*
* Dispatcher function for the module (load/unload/stat).
*/
int wfd_mod (struct lkm_table *lkmtp, int cmd, int ver)
{
int err = 0;
if (ver != LKM_VERSION)
return EINVAL;
if (cmd == LKM_E_LOAD)
err = wfd_load (lkmtp, cmd);
else if (cmd == LKM_E_UNLOAD)
err = wfd_unload (lkmtp, cmd);
if (err)
return err;
/* XXX Poking around in the LKM internals like this is bad.
*/
/* Register the cdevsw entry. */
lkmtp->private.lkm_dev = & MOD_PRIVATE(rwfd);
err = lkmdispatch (lkmtp, cmd);
if (err)
return err;
/* Register the bdevsw entry. */
lkmtp->private.lkm_dev = & MOD_PRIVATE(wfd);
return lkmdispatch (lkmtp, cmd);
}
#endif /* WFD_MODULE */
static wfd_devsw_installed = 0;
static void wfd_drvinit(void *unused)
{
if( ! wfd_devsw_installed ) {
bdevsw_add_generic(BDEV_MAJOR, CDEV_MAJOR, &wfd_bdevsw);
wfd_devsw_installed = 1;
}
}
SYSINIT(wfddev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,wfd_drvinit,NULL)
#endif /* NWFD && NWDC && ATAPI */

View File

@ -111,6 +111,7 @@
#define ATAPI_PREVENT_ALLOW 0x1e /* prevent/allow media removal */
#define ATAPI_READ_CAPACITY 0x25 /* get volume capacity */
#define ATAPI_READ_BIG 0x28 /* read data */
#define ATAPI_WRITE_BIG 0x2a /* write data */
#define ATAPI_READ_TOC 0x43 /* get table of contents */
#define ATAPI_READ_SUBCHANNEL 0x42 /* get subchannel info */
#define ATAPI_MODE_SELECT_BIG 0x55 /* set device parameters */

780
sys/pc98/pc98/wfd.c Normal file
View File

@ -0,0 +1,780 @@
/*
* Copyright (c) 1997,1998 Junichi Satoh <junichi@astec.co.jp>
* 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 as
* the first lines of this file unmodified.
* 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 Junichi Satoh ``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 Junichi Satoh 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.
*
* $Id: wfd.c,v 1.6 1998/01/06 15:54:53 junichi Exp junichi $
*/
/*
* ATAPI Floppy, LS-120 driver
*/
#include "wdc.h"
#include "wfd.h"
#include "opt_atapi.h"
#if NWFD > 0 && NWDC > 0 && defined (ATAPI)
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/conf.h>
#include <sys/file.h>
#include <sys/fcntl.h>
#include <sys/proc.h>
#include <sys/malloc.h>
#include <sys/buf.h>
#include <sys/disklabel.h>
#include <sys/diskslice.h>
#include <sys/cdio.h>
#include <machine/ioctl_fd.h>
#ifdef DEVFS
#include <sys/devfsext.h>
#endif /*DEVFS*/
#include <i386/isa/atapi.h>
#include <i386/isa/fdc.h>
static d_open_t wfdbopen;
static d_close_t wfdbclose;
static d_ioctl_t wfdioctl;
static d_strategy_t wfdstrategy;
#define CDEV_MAJOR 87
#define BDEV_MAJOR 24
static struct cdevsw wfd_cdevsw;
static struct bdevsw wfd_bdevsw =
{ wfdbopen, wfdbclose, wfdstrategy, wfdioctl, /*22*/
nodump, nopsize, 0, "wfd", &wfd_cdevsw, -1 };
#ifndef ATAPI_STATIC
static
#endif
int wfdattach(struct atapi*, int, struct atapi_params*, int);
#define NUNIT (NWDC*2) /* Max. number of devices */
#define UNIT(d) ((minor(d) >> 3) & 3) /* Unit part of minor device number */
#define F_BOPEN 0x0001 /* The block device is opened */
#define F_MEDIA_CHANGED 0x0002 /* The media have changed since open */
#define F_DEBUG 0x0004 /* Print debug info */
/*
* LS-120 Capabilities and Mechanical Status Page
*/
struct cappage {
/* Mode data header */
u_short data_length;
u_char medium_type;
#define MDT_UNKNOWN 0x00
#define MDT_NO_DISC 0x70
#define MDT_DOOR_OPEN 0x71
#define MDT_FMT_ERROR 0x72
#define MDT_2DD_UN 0x10
#define MDT_2DD 0x11
#define MDT_2HD_UN 0x20
#define MDT_2HD_12_98 0x22
#define MDT_2HD_12 0x23
#define MDT_2HD_144 0x24
#define MDT_LS120 0x31
unsigned reserved0 :7;
unsigned wp :1; /* Write protect */
u_char reserved1[4];
/* Capabilities page */
unsigned page_code :6; /* Page code - Should be 0x5 */
#define CAP_PAGE 0x05
unsigned reserved1_6 :1; /* Reserved */
unsigned ps :1; /* The device is capable of savi
ng the page */
u_char page_length; /* Page Length - Should be 0x1e */
u_short transfer_rate; /* In kilobits per second */
u_char heads, sectors; /* Number of heads, Number of sectors per track */
u_short sector_size; /* Byes per sector */
u_short cyls; /* Number of cylinders */
u_char reserved10[10];
u_char motor_delay; /* Motor off delay */
u_char reserved21[7];
u_short rpm; /* Rotations per minute */
u_char reserved30[2];
};
/* misuse a flag to identify format operation */
#define B_FORMAT B_XXX
struct wfd {
struct atapi *ata; /* Controller structure */
int unit; /* IDE bus drive unit */
int lun; /* Logical device unit */
int flags; /* Device state flags */
int refcnt; /* The number of raw opens */
struct buf_queue_head buf_queue; /* Queue of i/o requests */
struct atapi_params *param; /* Drive parameters table */
struct cappage cap; /* Capabilities page info */
char description[80]; /* Device description */
#ifdef DEVFS
void *cdevs;
void *bdevs;
#endif
struct diskslices *dk_slices; /* virtual drives */
};
struct wfd *wfdtab[NUNIT]; /* Drive info by unit number */
static int wfdnlun = 0; /* Number of configured drives */
static void wfd_start (struct wfd *t);
static void wfd_done (struct wfd *t, struct buf *bp, int resid,
struct atapires result);
static void wfd_error (struct wfd *t, struct atapires result);
static int wfd_request_wait (struct wfd *t, u_char cmd, u_char a1, u_char a2,
u_char a3, u_char a4, u_char a5, u_char a6, u_char a7, u_char a8,
u_char a9, char *addr, int count);
static void wfd_describe (struct wfd *t);
static int wfd_eject (struct wfd *t, int closeit);
static void wfdstrategy1(struct buf *bp);
/*
* Dump the array in hexadecimal format for debugging purposes.
*/
static void wfd_dump (int lun, char *label, void *data, int len)
{
u_char *p = data;
printf ("wfd%d: %s %x", lun, label, *p++);
while (--len > 0)
printf ("-%x", *p++);
printf ("\n");
}
#ifndef ATAPI_STATIC
static
#endif
int
wfdattach (struct atapi *ata, int unit, struct atapi_params *ap, int debug)
{
struct wfd *t;
struct atapires result;
int lun, i;
#ifdef DEVFS
int mynor;
#endif
if (wfdnlun >= NUNIT) {
printf ("wfd: too many units\n");
return (0);
}
if (!atapi_request_immediate) {
printf("wfd: configuration error, ATAPI core code not present!\n");
printf("wfd: check `options ATAPI_STATIC' in your kernel config file!\n");
return (0);
}
t = malloc (sizeof (struct wfd), M_TEMP, M_NOWAIT);
if (! t) {
printf ("wfd: out of memory\n");
return (0);
}
wfdtab[wfdnlun] = t;
bzero (t, sizeof (struct wfd));
bufq_init(&t->buf_queue);
t->ata = ata;
t->unit = unit;
lun = t->lun = wfdnlun++;
t->param = ap;
t->flags = F_MEDIA_CHANGED;
t->refcnt = 0;
if (debug) {
t->flags |= F_DEBUG;
/* Print params. */
wfd_dump (t->lun, "info", ap, sizeof *ap);
}
/* Get drive capabilities. */
/* Do it twice to avoid the stale media changed state. */
for (i = 0; i < 2; i++) {
result = atapi_request_immediate (ata, unit, ATAPI_MODE_SENSE,
0, CAP_PAGE, 0, 0, 0, 0,
sizeof (t->cap) >> 8, sizeof (t->cap),
0, 0, 0, 0, 0, 0, 0, (char*) &t->cap, sizeof (t->cap));
}
if (result.code == RES_ERR &&
(result.error & AER_SKEY) == AER_SK_UNIT_ATTENTION)
result = atapi_request_immediate (ata, unit, ATAPI_MODE_SENSE,
0, CAP_PAGE, 0, 0, 0, 0, sizeof (t->cap) >> 8,
sizeof (t->cap), 0, 0, 0, 0, 0, 0, 0,
(char*) &t->cap, sizeof (t->cap));
/* Some drives have shorter capabilities page. */
if (result.code == RES_UNDERRUN)
result.code = 0;
if (result.code == 0) {
wfd_describe (t);
if (t->flags & F_DEBUG)
wfd_dump (t->lun, "cap", &t->cap, sizeof t->cap);
} else
return -1;
#ifdef DEVFS
mynor = dkmakeminor(unit, WHOLE_DISK_SLICE, RAW_PART);
t->bdevs = devfs_add_devswf(&wfd_bdevsw, mynor,
DV_BLK, UID_ROOT, GID_OPERATOR, 0640,
"wfd%d", unit);
t->cdevs = devfs_add_devswf(&wfd_cdevsw, mynor,
DV_CHR, UID_ROOT, GID_OPERATOR, 0640,
"rwfd%d", unit);
#endif /* DEVFS */
return (1);
}
void wfd_describe (struct wfd *t)
{
int no_print = 0;
t->cap.cyls = ntohs (t->cap.cyls);
t->cap.sector_size = ntohs (t->cap.sector_size);
printf ("wfd%d: ", t->lun);
switch (t->cap.medium_type) {
case MDT_UNKNOWN:
printf ("medium type unknown (no disk)");
no_print = 1;
break;
case MDT_2DD_UN:
printf ("2DD(capacity unknown) floppy disk loaded");
no_print = 1;
break;
case MDT_2DD:
printf ("720KB floppy disk loaded");
break;
case MDT_2HD_UN:
printf ("2HD(capacity unknown) floppy disk loaded");
no_print = 1;
break;
case MDT_2HD_12_98:
printf ("1.25MB(PC-9801 format) floppy disk loaded");
break;
case MDT_2HD_12:
printf ("1.2MB floppy disk loaded");
break;
case MDT_2HD_144:
printf ("1.44MB floppy disk loaded");
break;
case MDT_LS120:
printf ("120MB floppy disk loaded");
break;
case MDT_NO_DISC:
printf ("no disc inside");
no_print = 1;
break;
case MDT_DOOR_OPEN:
printf ("door open");
no_print = 1;
break;
case MDT_FMT_ERROR:
printf ("medium format error");
no_print = 1;
break;
default:
printf ("medium type=0x%x", t->cap.medium_type);
break;
}
if (t->cap.wp)
printf(", write protected");
printf ("\n");
if (!no_print) {
printf ("wfd%d: ", t->lun);
printf ("%lu cyls", t->cap.cyls);
printf (", %lu heads, %lu S/T", t->cap.heads, t->cap.sectors);
printf (", %lu B/S", t->cap.sector_size);
printf ("\n");
}
}
int wfdbopen (dev_t dev, int flags, int fmt, struct proc *p)
{
int lun = UNIT(dev);
struct wfd *t;
struct atapires result;
int errcode = 0;
struct disklabel label;
/* Check that the device number is legal
* and the ATAPI driver is loaded. */
if (lun >= wfdnlun || ! atapi_request_immediate) {
printf("ENXIO lun=%d, wfdnlun=%d, im=%d\n", lun, wfdnlun, atapi_request_immediate);
return (ENXIO);
}
t = wfdtab[lun];
t->flags &= ~F_MEDIA_CHANGED;
/* Lock the media. */
wfd_request_wait (t, ATAPI_PREVENT_ALLOW,
0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0);
/* Sense the media type */
result = atapi_request_wait (t->ata, t->unit, ATAPI_MODE_SENSE,
0, CAP_PAGE, 0, 0, 0, 0,
sizeof (t->cap) >> 8, sizeof (t->cap),
0, 0, 0, 0, 0, 0, 0,
(char*) &t->cap, sizeof (t->cap));
if (result.code)
printf ("wfd%d: Sense the media type is failed.\n", t->lun);
else {
t->cap.cyls = ntohs (t->cap.cyls);
t->cap.sector_size = ntohs (t->cap.sector_size);
}
/* Build label for whole disk. */
bzero(&label, sizeof label);
label.d_secsize = t->cap.sector_size;
label.d_nsectors = t->cap.sectors;
label.d_ntracks = t->cap.heads;
label.d_ncylinders = t->cap.cyls;
label.d_secpercyl = t->cap.heads * t->cap.sectors;
label.d_rpm = 720;
label.d_secperunit = label.d_secpercyl * t->cap.cyls;
/* Initialize slice tables. */
errcode = dsopen("wfd", dev, fmt, &t->dk_slices, &label, wfdstrategy1,
(ds_setgeom_t *)NULL, &wfd_bdevsw, &wfd_cdevsw);
if (errcode != 0)
return errcode;
t->flags |= F_BOPEN;
return (0);
}
/*
* Close the device. Only called if we are the LAST
* occurence of an open device.
*/
int wfdbclose (dev_t dev, int flags, int fmt, struct proc *p)
{
int lun = UNIT(dev);
struct wfd *t = wfdtab[lun];
dsclose(dev, fmt, t->dk_slices);
if(!dsisopen(t->dk_slices)) {
/* If we were the last open of the entire device, release it. */
if (! t->refcnt)
wfd_request_wait (t, ATAPI_PREVENT_ALLOW,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
t->flags &= ~F_BOPEN;
}
return (0);
}
static void
wfdstrategy1(struct buf *bp)
{
/*
* XXX - do something to make wdstrategy() but not this block while
* we're doing dsinit() and dsioctl().
*/
wfdstrategy(bp);
}
/*
* Actually translate the requested transfer into one the physical driver can
* understand. The transfer is described by a buf and will include only one
* physical transfer.
*/
void wfdstrategy (struct buf *bp)
{
int lun = UNIT(bp->b_dev);
struct wfd *t = wfdtab[lun];
int x;
/* If it's a null transfer, return immediatly. */
if (bp->b_bcount == 0) {
bp->b_resid = 0;
biodone (bp);
return;
}
/* Process transfer request. */
bp->b_pblkno = bp->b_blkno;
bp->b_resid = bp->b_bcount;
/*
* Do bounds checking, adjust transfer, and set b_pblkno.
*/
if (dscheck(bp, t->dk_slices) <= 0) {
biodone(bp);
return;
}
bp->b_blkno = bp->b_pblkno;
x = splbio();
/* Place it in the queue of disk activities for this disk. */
bufqdisksort (&t->buf_queue, bp);
/* Tell the device to get going on the transfer if it's
* not doing anything, otherwise just wait for completion. */
wfd_start (t);
splx(x);
}
/*
* Look to see if there is a buf waiting for the device
* and that the device is not already busy. If both are true,
* It dequeues the buf and creates an ATAPI command to perform the
* transfer in the buf.
* The bufs are queued by the strategy routine (wfdstrategy).
* Must be called at the correct (splbio) level.
*/
static void wfd_start (struct wfd *t)
{
struct buf *bp = bufq_first(&t->buf_queue);
u_long blkno, nblk;
u_char op_code;
long count;
/* See if there is a buf to do and we are not already doing one. */
if (! bp)
return;
/* Unqueue the request. */
bufq_remove(&t->buf_queue, bp);
/* We have a buf, now we should make a command
* First, translate the block to absolute and put it in terms of the
* logical blocksize of the device.
* What if something asks for 512 bytes not on a 2k boundary? */
blkno = bp->b_blkno / (t->cap.sector_size / 512);
nblk = (bp->b_bcount + (t->cap.sector_size - 1)) / t->cap.sector_size;
if(bp->b_flags & B_READ) {
op_code = ATAPI_READ_BIG;
count = bp->b_bcount;
} else {
op_code = ATAPI_WRITE_BIG;
count = -bp->b_bcount;
}
atapi_request_callback (t->ata, t->unit, op_code, 0,
blkno>>24, blkno>>16, blkno>>8, blkno, 0, nblk>>8, nblk, 0, 0,
0, 0, 0, 0, 0, (u_char*) bp->b_data, count,
(void*)wfd_done, t, bp);
}
static void wfd_done (struct wfd *t, struct buf *bp, int resid,
struct atapires result)
{
if (result.code) {
wfd_error (t, result);
bp->b_error = EIO;
bp->b_flags |= B_ERROR;
} else
bp->b_resid = resid;
biodone (bp);
wfd_start (t);
}
static void wfd_error (struct wfd *t, struct atapires result)
{
if (result.code != RES_ERR)
return;
switch (result.error & AER_SKEY) {
case AER_SK_NOT_READY:
if (result.error & ~AER_SKEY) {
/* Not Ready */
printf ("wfd%d: not ready\n", t->lun);
return;
}
/* Tray open. */
if (! (t->flags & F_MEDIA_CHANGED))
printf ("wfd%d: tray open\n", t->lun);
t->flags |= F_MEDIA_CHANGED;
return;
case AER_SK_UNIT_ATTENTION:
/* Media changed. */
if (! (t->flags & F_MEDIA_CHANGED))
printf ("wfd%d: media changed\n", t->lun);
t->flags |= F_MEDIA_CHANGED;
return;
case AER_SK_ILLEGAL_REQUEST:
/* Unknown command or invalid command arguments. */
if (t->flags & F_DEBUG)
printf ("wfd%d: invalid command\n", t->lun);
return;
}
printf ("wfd%d: i/o error, status=%b, error=%b\n", t->lun,
result.status, ARS_BITS, result.error, AER_BITS);
}
static int wfd_request_wait (struct wfd *t, u_char cmd, u_char a1, u_char a2,
u_char a3, u_char a4, u_char a5, u_char a6, u_char a7, u_char a8,
u_char a9, char *addr, int count)
{
struct atapires result;
result = atapi_request_wait (t->ata, t->unit, cmd,
a1, a2, a3, a4, a5, a6, a7, a8, a9, 0, 0, 0, 0, 0, 0,
addr, count);
if (result.code) {
wfd_error (t, result);
return (EIO);
}
return (0);
}
/*
* Perform special action on behalf of the user.
* Knows about the internals of this device
*/
int wfdioctl (dev_t dev, int cmd, caddr_t addr, int flag, struct proc *p)
{
int lun = UNIT(dev);
struct wfd *t = wfdtab[lun];
int error = 0;
struct disklabel *dl;
char buffer[DEV_BSIZE];
error = dsioctl("wfd", dev, cmd, addr, flag, &t->dk_slices,
wfdstrategy1, (ds_setgeom_t *)NULL);
if (error != -1)
return (error);
if (t->flags & F_MEDIA_CHANGED)
switch (cmd) {
case CDIOCSETDEBUG:
case CDIOCCLRDEBUG:
case CDIOCRESET:
/* These ops are media change transparent. */
break;
default:
/* Lock the media. */
wfd_request_wait (t, ATAPI_PREVENT_ALLOW,
0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0);
break;
}
switch (cmd) {
case CDIOCSETDEBUG:
if (p->p_cred->pc_ucred->cr_uid)
return (EPERM);
t->flags |= F_DEBUG;
atapi_debug (t->ata, 1);
return 0;
case CDIOCCLRDEBUG:
if (p->p_cred->pc_ucred->cr_uid)
return (EPERM);
t->flags &= ~F_DEBUG;
atapi_debug (t->ata, 0);
return 0;
case CDIOCRESET:
if (p->p_cred->pc_ucred->cr_uid)
return (EPERM);
return wfd_request_wait (t, ATAPI_TEST_UNIT_READY,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
case CDIOCEJECT:
/* Don't allow eject if the device is opened
* by somebody (not us) in block mode. */
if ((t->flags & F_BOPEN) && t->refcnt)
return (EBUSY);
return wfd_eject (t, 0);
case CDIOCCLOSE:
if ((t->flags & F_BOPEN) && t->refcnt)
return (0);
return wfd_eject (t, 1);
default:
return (ENOTTY);
}
return (error);
}
static int wfd_eject (struct wfd *t, int closeit)
{
struct atapires result;
/* Try to stop the disc. */
result = atapi_request_wait (t->ata, t->unit, ATAPI_START_STOP,
1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
if (result.code == RES_ERR &&
((result.error & AER_SKEY) == AER_SK_NOT_READY ||
(result.error & AER_SKEY) == AER_SK_UNIT_ATTENTION)) {
int err;
if (!closeit)
return (0);
/*
* The disc was unloaded.
* Load it (close tray).
* Read the table of contents.
*/
err = wfd_request_wait (t, ATAPI_START_STOP,
0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0);
if (err)
return (err);
/* Lock the media. */
wfd_request_wait (t, ATAPI_PREVENT_ALLOW,
0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0);
return (0);
}
if (result.code) {
wfd_error (t, result);
return (EIO);
}
if (closeit)
return (0);
/* Give it some time to stop spinning. */
tsleep ((caddr_t)&lbolt, PRIBIO, "wfdej1", 0);
tsleep ((caddr_t)&lbolt, PRIBIO, "wfdej2", 0);
/* Unlock. */
wfd_request_wait (t, ATAPI_PREVENT_ALLOW,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
/* Eject. */
t->flags |= F_MEDIA_CHANGED;
return wfd_request_wait (t, ATAPI_START_STOP,
0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0);
}
#ifdef WFD_MODULE
/*
* Loadable ATAPI Floppy driver stubs.
*/
#include <sys/exec.h>
#include <sys/sysent.h>
#include <sys/lkm.h>
/*
* Construct lkm_dev structures (see lkm.h).
* Our bdevsw/cdevsw slot numbers are 19/69.
*/
MOD_DEV(wfd, LM_DT_BLOCK, BDEV_MAJOR, &wfd_bdevsw);
MOD_DEV(rwfd, LM_DT_CHAR, CDEV_MAJOR, &wfd_cdevsw);
/*
* Function called when loading the driver.
*/
int wfd_load (struct lkm_table *lkmtp, int cmd)
{
struct atapi *ata;
int n, u;
if (! atapi_start)
/* No ATAPI driver available. */
return EPROTONOSUPPORT;
n = 0;
for (ata=atapi_tab; ata<atapi_tab+2; ++ata)
if (ata->port)
for (u=0; u<2; ++u)
/* Probing controller ata->ctrlr, unit u. */
if (ata->params[u] && ! ata->attached[u] &&
wfdattach (ata, u, ata->params[u],
ata->debug) >= 0)
{
/* Drive found. */
ata->attached[u] = 1;
++n;
}
if (! n)
/* No IDE Floppies found. */
return ENXIO;
return 0;
}
/*
* Function called when unloading the driver.
*/
int wfd_unload (struct lkm_table *lkmtp, int cmd)
{
struct wfd **t;
for (t=wfdtab; t<wfdtab+wfdnlun; ++t)
if (((*t)->flags & F_BOPEN) || (*t)->refcnt)
/* The device is opened, cannot unload the driver. */
return EBUSY;
for (t=wfdtab; t<wfdtab+wfdnlun; ++t) {
(*t)->ata->attached[(*t)->unit] = 0;
free (*t, M_TEMP);
}
wfdnlun = 0;
bzero (wfdtab, sizeof(wfdtab));
return 0;
}
/*
* Dispatcher function for the module (load/unload/stat).
*/
int wfd_mod (struct lkm_table *lkmtp, int cmd, int ver)
{
int err = 0;
if (ver != LKM_VERSION)
return EINVAL;
if (cmd == LKM_E_LOAD)
err = wfd_load (lkmtp, cmd);
else if (cmd == LKM_E_UNLOAD)
err = wfd_unload (lkmtp, cmd);
if (err)
return err;
/* XXX Poking around in the LKM internals like this is bad.
*/
/* Register the cdevsw entry. */
lkmtp->private.lkm_dev = & MOD_PRIVATE(rwfd);
err = lkmdispatch (lkmtp, cmd);
if (err)
return err;
/* Register the bdevsw entry. */
lkmtp->private.lkm_dev = & MOD_PRIVATE(wfd);
return lkmdispatch (lkmtp, cmd);
}
#endif /* WFD_MODULE */
static wfd_devsw_installed = 0;
static void wfd_drvinit(void *unused)
{
if( ! wfd_devsw_installed ) {
bdevsw_add_generic(BDEV_MAJOR, CDEV_MAJOR, &wfd_bdevsw);
wfd_devsw_installed = 1;
}
}
SYSINIT(wfddev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,wfd_drvinit,NULL)
#endif /* NWFD && NWDC && ATAPI */