diff --git a/etc/MAKEDEV b/etc/MAKEDEV index 03b5ae44d3a7..0f65cb61fc4a 100644 --- a/etc/MAKEDEV +++ b/etc/MAKEDEV @@ -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 diff --git a/etc/disktab b/etc/disktab index 08824c4d6a23..994737004ed1 100644 --- a/etc/disktab +++ b/etc/disktab @@ -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 # diff --git a/etc/etc.i386/MAKEDEV b/etc/etc.i386/MAKEDEV index 03b5ae44d3a7..0f65cb61fc4a 100644 --- a/etc/etc.i386/MAKEDEV +++ b/etc/etc.i386/MAKEDEV @@ -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 diff --git a/etc/etc.i386/disktab b/etc/etc.i386/disktab index 08824c4d6a23..994737004ed1 100644 --- a/etc/etc.i386/disktab +++ b/etc/etc.i386/disktab @@ -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 # diff --git a/sys/amd64/conf/GENERIC b/sys/amd64/conf/GENERIC index 14db321d7905..c89dee94caf5 100644 --- a/sys/amd64/conf/GENERIC +++ b/sys/amd64/conf/GENERIC @@ -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. diff --git a/sys/conf/NOTES b/sys/conf/NOTES index 7c1970318742..3c1f8c9920f2 100644 --- a/sys/conf/NOTES +++ b/sys/conf/NOTES @@ -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' # diff --git a/sys/conf/files.i386 b/sys/conf/files.i386 index 885dd0c7c9bf..e3867f4d62a6 100644 --- a/sys/conf/files.i386 +++ b/sys/conf/files.i386 @@ -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 diff --git a/sys/conf/majors b/sys/conf/majors index 270a02413410..75cac8cdba0f 100644 --- a/sys/conf/majors +++ b/sys/conf/majors @@ -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" diff --git a/sys/i386/conf/GENERIC b/sys/i386/conf/GENERIC index 14db321d7905..c89dee94caf5 100644 --- a/sys/i386/conf/GENERIC +++ b/sys/i386/conf/GENERIC @@ -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. diff --git a/sys/i386/conf/LINT b/sys/i386/conf/LINT index 7c1970318742..3c1f8c9920f2 100644 --- a/sys/i386/conf/LINT +++ b/sys/i386/conf/LINT @@ -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' # diff --git a/sys/i386/conf/NOTES b/sys/i386/conf/NOTES index 7c1970318742..3c1f8c9920f2 100644 --- a/sys/i386/conf/NOTES +++ b/sys/i386/conf/NOTES @@ -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' # diff --git a/sys/i386/conf/devices.i386 b/sys/i386/conf/devices.i386 index 6e93c0c4ad9d..93e3cf533233 100644 --- a/sys/i386/conf/devices.i386 +++ b/sys/i386/conf/devices.i386 @@ -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 diff --git a/sys/i386/conf/files.i386 b/sys/i386/conf/files.i386 index 885dd0c7c9bf..e3867f4d62a6 100644 --- a/sys/i386/conf/files.i386 +++ b/sys/i386/conf/files.i386 @@ -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 diff --git a/sys/i386/conf/majors.i386 b/sys/i386/conf/majors.i386 index 270a02413410..75cac8cdba0f 100644 --- a/sys/i386/conf/majors.i386 +++ b/sys/i386/conf/majors.i386 @@ -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" diff --git a/sys/i386/isa/atapi.c b/sys/i386/isa/atapi.c index 2a7025f53ad6..56fbbfbaf43b 100644 --- a/sys/i386/isa/atapi.c +++ b/sys/i386/isa/atapi.c @@ -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; diff --git a/sys/i386/isa/atapi.h b/sys/i386/isa/atapi.h index c61dad56ac5c..ca9b871ff130 100644 --- a/sys/i386/isa/atapi.h +++ b/sys/i386/isa/atapi.h @@ -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 */ diff --git a/sys/i386/isa/wd.c b/sys/i386/isa/wd.c index 6bfa9875888b..8812a6b9d8f3 100644 --- a/sys/i386/isa/wd.c +++ b/sys/i386/isa/wd.c @@ -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 */ diff --git a/sys/i386/isa/wfd.c b/sys/i386/isa/wfd.c new file mode 100644 index 000000000000..3f671345236f --- /dev/null +++ b/sys/i386/isa/wfd.c @@ -0,0 +1,780 @@ +/* + * Copyright (c) 1997,1998 Junichi Satoh + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef DEVFS +#include +#endif /*DEVFS*/ + +#include +#include + +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 +#include +#include + +/* + * 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; ataport) + 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; tflags & F_BOPEN) || (*t)->refcnt) + /* The device is opened, cannot unload the driver. */ + return EBUSY; + for (t=wfdtab; tata->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 */ diff --git a/sys/pc98/pc98/atapi.h b/sys/pc98/pc98/atapi.h index c61dad56ac5c..ca9b871ff130 100644 --- a/sys/pc98/pc98/atapi.h +++ b/sys/pc98/pc98/atapi.h @@ -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 */ diff --git a/sys/pc98/pc98/wfd.c b/sys/pc98/pc98/wfd.c new file mode 100644 index 000000000000..3f671345236f --- /dev/null +++ b/sys/pc98/pc98/wfd.c @@ -0,0 +1,780 @@ +/* + * Copyright (c) 1997,1998 Junichi Satoh + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef DEVFS +#include +#endif /*DEVFS*/ + +#include +#include + +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 +#include +#include + +/* + * 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; ataport) + 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; tflags & F_BOPEN) || (*t)->refcnt) + /* The device is opened, cannot unload the driver. */ + return EBUSY; + for (t=wfdtab; tata->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 */