Home | History | Annotate | Line # | Download | only in obio
      1  1.62     hauke /*	$NetBSD: iwm_fd.c,v 1.62 2025/08/06 17:25:38 hauke Exp $	*/
      2   1.1    scottr 
      3   1.1    scottr /*
      4   1.1    scottr  * Copyright (c) 1997, 1998 Hauke Fath.  All rights reserved.
      5   1.1    scottr  *
      6   1.1    scottr  * Redistribution and use in source and binary forms, with or without
      7   1.1    scottr  * modification, are permitted provided that the following conditions
      8   1.1    scottr  * are met:
      9   1.1    scottr  * 1. Redistributions of source code must retain the above copyright
     10   1.1    scottr  *    notice, this list of conditions and the following disclaimer.
     11   1.1    scottr  * 2. Redistributions in binary form must reproduce the above copyright
     12   1.1    scottr  *    notice, this list of conditions and the following disclaimer in the
     13   1.1    scottr  *    documentation and/or other materials provided with the distribution.
     14   1.1    scottr  *
     15   1.1    scottr  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
     16   1.1    scottr  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     17   1.1    scottr  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     18   1.1    scottr  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
     19   1.1    scottr  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
     20   1.1    scottr  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     21   1.1    scottr  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     22   1.1    scottr  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     23   1.1    scottr  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
     24   1.1    scottr  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     25   1.1    scottr  */
     26   1.1    scottr 
     27   1.1    scottr /*
     28   1.2    scottr  * iwm_fd.c -- Sony (floppy disk) driver for m68k Macintoshes
     29   1.1    scottr  *
     30   1.2    scottr  * The present implementation supports the GCR format (800K) on
     31   1.2    scottr  * non-{DMA,IOP} machines.
     32   1.1    scottr  */
     33  1.24     lukem 
     34  1.24     lukem #include <sys/cdefs.h>
     35  1.62     hauke __KERNEL_RCSID(0, "$NetBSD: iwm_fd.c,v 1.62 2025/08/06 17:25:38 hauke Exp $");
     36  1.29       chs 
     37  1.29       chs #include "locators.h"
     38  1.24     lukem 
     39   1.1    scottr #include <sys/param.h>
     40   1.1    scottr #include <sys/systm.h>
     41   1.8   thorpej #include <sys/callout.h>
     42   1.1    scottr #include <sys/kernel.h>
     43   1.1    scottr #include <sys/file.h>
     44   1.1    scottr #include <sys/ioctl.h>
     45  1.58   thorpej #include <sys/kmem.h>
     46   1.1    scottr #include <sys/device.h>
     47  1.18  jdolecek #include <sys/event.h>
     48   1.1    scottr 
     49   1.1    scottr #define FSTYPENAMES
     50   1.2    scottr #define DKTYPENAMES
     51   1.1    scottr #include <sys/disklabel.h>
     52   1.1    scottr 
     53   1.1    scottr #include <sys/disk.h>
     54   1.1    scottr #include <sys/dkbad.h>
     55   1.1    scottr #include <sys/buf.h>
     56  1.28      yamt #include <sys/bufq.h>
     57   1.1    scottr #include <sys/uio.h>
     58   1.1    scottr #include <sys/stat.h>
     59   1.1    scottr #include <sys/syslog.h>
     60   1.1    scottr #include <sys/conf.h>
     61   1.1    scottr 
     62   1.1    scottr #include <machine/autoconf.h>
     63   1.1    scottr #include <machine/cpu.h>
     64   1.1    scottr 
     65   1.1    scottr #include <mac68k/obio/iwmreg.h>
     66   1.1    scottr #include <mac68k/obio/iwm_fdvar.h>
     67   1.1    scottr 
     68   1.1    scottr /* Autoconfig */
     69  1.47       chs int	iwm_match(device_t, cfdata_t, void *);
     70  1.47       chs void	iwm_attach(device_t, device_t, void *);
     71  1.31       chs int	iwm_print(void *, const char *);
     72  1.47       chs int	fd_match(device_t, cfdata_t, void *);
     73  1.47       chs void	fd_attach(device_t, device_t, void *);
     74  1.31       chs int	fd_print(void *, const char *);
     75   1.1    scottr 
     76  1.60     hauke /**
     77  1.60     hauke  **	Private functions
     78  1.60     hauke  **/
     79  1.60     hauke 
     80   1.1    scottr /* Disklabel stuff */
     81  1.31       chs static void fdGetDiskLabel(fd_softc_t *, dev_t);
     82  1.31       chs static void fdPrintDiskLabel(struct disklabel *);
     83   1.1    scottr 
     84  1.31       chs static fdInfo_t *getFDType(short);
     85  1.31       chs static fdInfo_t *fdDeviceToType(fd_softc_t *, dev_t);
     86   1.1    scottr 
     87  1.31       chs static void fdstart(fd_softc_t *);
     88  1.31       chs static void remap_geometry(daddr_t, int, diskPosition_t *);
     89  1.31       chs static void motor_off(void *);
     90  1.31       chs static int seek(fd_softc_t *, int);
     91  1.31       chs static int checkTrack(diskPosition_t *, int);
     92  1.31       chs static int initCylinderCache(fd_softc_t *);
     93  1.31       chs static void invalidateCylinderCache(fd_softc_t *);
     94   1.1    scottr 
     95  1.31       chs static int fdstart_Init(fd_softc_t *);
     96  1.31       chs static int fdstart_Seek(fd_softc_t *);
     97  1.31       chs static int fdstart_Read(fd_softc_t *);
     98  1.31       chs static int fdstart_Write(fd_softc_t *);
     99  1.31       chs static int fdstart_Flush(fd_softc_t *);
    100  1.31       chs static int fdstart_IOFinish(fd_softc_t *);
    101  1.31       chs static int fdstart_IOErr(fd_softc_t *);
    102  1.31       chs static int fdstart_Fault(fd_softc_t *);
    103  1.31       chs static int fdstart_Exit(fd_softc_t *);
    104   1.2    scottr 
    105   1.1    scottr 
    106   1.1    scottr /**
    107   1.1    scottr  **	Driver debugging
    108   1.1    scottr  **/
    109   1.1    scottr 
    110   1.2    scottr #ifdef DEBUG
    111   1.2    scottr #define IWM_DEBUG
    112   1.2    scottr #endif
    113   1.2    scottr 
    114   1.2    scottr 
    115  1.31       chs static void hexDump(u_char *, int);
    116   1.1    scottr 
    117   1.1    scottr /*
    118   1.2    scottr  * Stuff taken from Egan/Teixeira ch 8: 'if(TRACE_FOO)' debug output
    119   1.2    scottr  * statements don't break indentation, and when DEBUG is not defined,
    120   1.2    scottr  * the compiler code optimizer drops them as dead code.
    121   1.1    scottr  */
    122   1.2    scottr #ifdef IWM_DEBUG
    123   1.1    scottr #define M_TRACE_CONFIG	0x0001
    124   1.1    scottr #define M_TRACE_OPEN	0x0002
    125   1.1    scottr #define M_TRACE_CLOSE	0x0004
    126   1.1    scottr #define M_TRACE_READ	0x0008
    127   1.1    scottr #define M_TRACE_WRITE	0x0010
    128   1.1    scottr #define M_TRACE_STRAT	(M_TRACE_READ | M_TRACE_WRITE)
    129   1.1    scottr #define M_TRACE_IOCTL	0x0020
    130   1.1    scottr #define M_TRACE_STEP	0x0040
    131   1.1    scottr #define M_TRACE_ALL	0xFFFF
    132   1.1    scottr 
    133   1.1    scottr #define TRACE_CONFIG	(iwmDebugging & M_TRACE_CONFIG)
    134   1.1    scottr #define TRACE_OPEN	(iwmDebugging & M_TRACE_OPEN)
    135   1.1    scottr #define TRACE_CLOSE	(iwmDebugging & M_TRACE_CLOSE)
    136   1.1    scottr #define TRACE_READ	(iwmDebugging & M_TRACE_READ)
    137   1.1    scottr #define TRACE_WRITE	(iwmDebugging & M_TRACE_WRITE)
    138   1.1    scottr #define TRACE_STRAT	(iwmDebugging & M_TRACE_STRAT)
    139   1.1    scottr #define TRACE_IOCTL	(iwmDebugging & M_TRACE_IOCTL)
    140   1.1    scottr #define TRACE_STEP	(iwmDebugging & M_TRACE_STEP)
    141   1.1    scottr #define TRACE_ALL	(iwmDebugging & M_TRACE_ALL)
    142   1.1    scottr 
    143   1.1    scottr  /* -1 = all active */
    144   1.2    scottr int     iwmDebugging = 0 /* | M_TRACE_OPEN | M_TRACE_STRAT | M_TRACE_IOCTL */ ;
    145   1.1    scottr 
    146   1.1    scottr #else
    147   1.1    scottr #define TRACE_CONFIG	0
    148   1.1    scottr #define TRACE_OPEN	0
    149   1.1    scottr #define TRACE_CLOSE	0
    150   1.1    scottr #define TRACE_READ	0
    151   1.1    scottr #define TRACE_WRITE	0
    152   1.1    scottr #define TRACE_STRAT	0
    153   1.1    scottr #define TRACE_IOCTL	0
    154   1.1    scottr #define TRACE_STEP	0
    155   1.1    scottr #define TRACE_ALL	0
    156   1.1    scottr #endif
    157   1.1    scottr 
    158   1.1    scottr #define DISABLED 	0
    159   1.1    scottr 
    160   1.1    scottr 
    161   1.1    scottr 
    162   1.1    scottr /**
    163   1.1    scottr  ** Module-global Variables
    164   1.1    scottr  **/
    165   1.1    scottr 
    166  1.60     hauke /* The controller base address */
    167   1.1    scottr u_long IWMBase;
    168   1.1    scottr 
    169   1.1    scottr /*
    170   1.1    scottr  * Table of supported disk types.
    171   1.1    scottr  * The table order seems to be pretty standardized across NetBSD ports, but
    172   1.1    scottr  * then, they are all MFM... So we roll our own for now.
    173   1.1    scottr  */
    174   1.1    scottr static fdInfo_t fdTypes[] = {
    175   1.1    scottr 	{1, 80, 512, 10, 10,  800, 12, 2, IWM_GCR, "400K Sony"},
    176   1.1    scottr 	{2, 80, 512, 10, 20, 1600, 12, 2, IWM_GCR, "800K Sony"}
    177   1.1    scottr };
    178   1.1    scottr 
    179   1.1    scottr /* Table of GCR disk zones for one side (see IM II-211, The Disk Driver) */
    180   1.1    scottr static diskZone_t diskZones[] = {
    181   1.1    scottr 	{16, 12,   0, 191},
    182   1.1    scottr 	{16, 11, 192, 367},
    183   1.1    scottr 	{16, 10, 368, 527},
    184   1.1    scottr 	{16,  9, 528, 671},
    185   1.1    scottr 	{16,  8, 672, 799}
    186   1.1    scottr };
    187   1.1    scottr 
    188   1.1    scottr /* Drive format codes/indexes */
    189   1.1    scottr enum {
    190   1.2    scottr 	IWM_400K_GCR = 0,
    191   1.2    scottr 	IWM_800K_GCR = 1,
    192   1.2    scottr 	IWM_720K_MFM = 2,
    193   1.2    scottr 	IWM_1440K_MFM = 3
    194   1.1    scottr };
    195   1.1    scottr 
    196   1.1    scottr 
    197   1.1    scottr /**
    198   1.1    scottr  ** Autoconfiguration code
    199   1.1    scottr  **/
    200   1.1    scottr 
    201   1.1    scottr /*
    202   1.1    scottr  * Autoconfig data structures
    203   1.1    scottr  *
    204   1.1    scottr  * These data structures (see <sys/device.h>) are referenced in
    205   1.1    scottr  * compile/$KERNEL/ioconf.c, which is generated by config(8).
    206   1.1    scottr  * Their names are formed like {device}_{ca,cd}.
    207   1.1    scottr  *
    208   1.2    scottr  * {device}_ca
    209   1.1    scottr  * is used for dynamically allocating driver data, probing and
    210   1.1    scottr  * attaching a device;
    211   1.1    scottr  *
    212   1.1    scottr  * {device}_cd
    213   1.1    scottr  * references all found devices of a type.
    214   1.1    scottr  */
    215   1.1    scottr 
    216   1.1    scottr extern struct cfdriver iwm_cd;
    217   1.1    scottr extern struct cfdriver fd_cd;
    218   1.1    scottr 
    219   1.1    scottr /* IWM floppy disk controller */
    220  1.47       chs CFATTACH_DECL_NEW(iwm, sizeof(iwm_softc_t),
    221  1.16   thorpej     iwm_match, iwm_attach, NULL, NULL);
    222   1.1    scottr 
    223   1.1    scottr /* Attached floppy disk drives */
    224  1.47       chs CFATTACH_DECL_NEW(fd, sizeof(fd_softc_t),
    225  1.16   thorpej     fd_match, fd_attach, NULL, NULL);
    226   1.1    scottr 
    227  1.13   gehenna dev_type_open(fdopen);
    228  1.13   gehenna dev_type_close(fdclose);
    229  1.13   gehenna dev_type_read(fdread);
    230  1.13   gehenna dev_type_write(fdwrite);
    231  1.13   gehenna dev_type_ioctl(fdioctl);
    232  1.13   gehenna dev_type_strategy(fdstrategy);
    233  1.13   gehenna 
    234  1.13   gehenna const struct bdevsw fd_bdevsw = {
    235  1.48  dholland 	.d_open = fdopen,
    236  1.48  dholland 	.d_close = fdclose,
    237  1.48  dholland 	.d_strategy = fdstrategy,
    238  1.48  dholland 	.d_ioctl = fdioctl,
    239  1.48  dholland 	.d_dump = nodump,
    240  1.48  dholland 	.d_psize = nosize,
    241  1.49  dholland 	.d_discard = nodiscard,
    242  1.48  dholland 	.d_flag = D_DISK
    243  1.13   gehenna };
    244   1.1    scottr 
    245  1.13   gehenna const struct cdevsw fd_cdevsw = {
    246  1.48  dholland 	.d_open = fdopen,
    247  1.48  dholland 	.d_close = fdclose,
    248  1.48  dholland 	.d_read = fdread,
    249  1.48  dholland 	.d_write = fdwrite,
    250  1.48  dholland 	.d_ioctl = fdioctl,
    251  1.48  dholland 	.d_stop = nostop,
    252  1.48  dholland 	.d_tty = notty,
    253  1.48  dholland 	.d_poll = nopoll,
    254  1.48  dholland 	.d_mmap = nommap,
    255  1.48  dholland 	.d_kqfilter = nokqfilter,
    256  1.50  dholland 	.d_discard = nodiscard,
    257  1.48  dholland 	.d_flag = D_DISK
    258  1.13   gehenna };
    259  1.13   gehenna 
    260  1.13   gehenna /* disk(9) framework device switch */
    261  1.13   gehenna struct dkdriver fd_dkDriver = {
    262  1.56   mlelstv 	.d_strategy = fdstrategy
    263  1.13   gehenna };
    264   1.1    scottr 
    265   1.1    scottr /***  Configure the IWM controller  ***/
    266   1.1    scottr 
    267   1.1    scottr /*
    268   1.1    scottr  * iwm_match
    269   1.1    scottr  *
    270  1.47       chs  * Is the IWM chip present? Here, *aux is a ptr to struct confargs
    271   1.2    scottr  * (see <mac68k/mac68k/autoconf.h>), which does not hold any information
    272   1.2    scottr  * to match against. After all, that's what the obio concept is
    273   1.2    scottr  * about: Onboard components that are present depending (only)
    274   1.2    scottr  * on machine type.
    275  1.60     hauke  *
    276  1.60     hauke  * While here, map the machine-dependent physical IO address of IWM
    277  1.60     hauke  * to VM address.
    278  1.60     hauke  *
    279  1.62     hauke  * We do not match, nor return an IWMBase address, for machines whose
    280  1.60     hauke  * SWIM does not support the IWM register set used by this driver
    281  1.60     hauke  * (SWIM II/III, SWIM behind IOP, AV models' DMA based controllers).
    282  1.60     hauke  * Unfortunately, this distinction does not run cleanly along
    283  1.60     hauke  * MACH_CLASS* lines, and we will have to look at MACH_MAC{model} tags.
    284  1.60     hauke  *
    285  1.60     hauke  * See also "What chips are in what Macs?" at
    286  1.60     hauke  * <http://bitsavers.org/pdf/apple/mac/mess/Mac_Technical_Notes.html>,
    287   1.1    scottr  */
    288   1.1    scottr int
    289  1.47       chs iwm_match(device_t parent, cfdata_t match, void *aux)
    290   1.1    scottr {
    291  1.60     hauke 	int matched = 0;
    292   1.1    scottr 	extern u_long IOBase;		/* from mac68k/machdep.c */
    293   1.1    scottr 	extern u_long IWMBase;
    294  1.60     hauke 
    295  1.60     hauke 	IWMBase = 0L;
    296  1.60     hauke 
    297  1.60     hauke 	switch (current_mac_model->class) {
    298  1.62     hauke 	case MACH_CLASSPB:	/* Not: Powerbook 5x0, 190x */
    299  1.62     hauke 		if (current_mac_model->machineid != MACH_MACPB500 &&
    300  1.62     hauke 		    current_mac_model->machineid != MACH_MACPB190 &&
    301  1.62     hauke 		    current_mac_model->machineid != MACH_MACPB190CS) {
    302  1.62     hauke 			IWMBase = IOBase + 0x16000;
    303  1.62     hauke 		        matched = 1;
    304  1.60     hauke 			break;
    305  1.62     hauke 		}
    306  1.60     hauke 		/* FALLTHROUGH */
    307  1.60     hauke 	case MACH_CLASSLC:	/* Only: LC II, Classic II */
    308  1.62     hauke 		if (current_mac_model->machineid == MACH_MACLCII ||
    309  1.62     hauke 		    current_mac_model->machineid == MACH_MACCLASSICII) {
    310  1.62     hauke 			IWMBase = IOBase + 0x16000;
    311  1.62     hauke 		        matched = 1;
    312  1.60     hauke 			break;
    313  1.62     hauke 		}
    314  1.60     hauke 		/* FALLTHROUGH */
    315  1.60     hauke 	case MACH_CLASSII:	/* All */
    316  1.60     hauke 	case MACH_CLASSIIci:	/* All */
    317  1.60     hauke 	case MACH_CLASSIIsi:	/* All */
    318  1.60     hauke 	case MACH_CLASSIIvx:	/* All */
    319  1.60     hauke 	case MACH_CLASSDUO:	/* All */
    320  1.60     hauke 		IWMBase = IOBase + 0x16000;
    321  1.60     hauke 		matched = 1;
    322  1.60     hauke 		break;
    323  1.62     hauke 	case MACH_CLASSQ:	/* Only: Quadra 700 */
    324  1.60     hauke 		if (current_mac_model->machineid == MACH_MACQ700) {
    325  1.60     hauke 			IWMBase = IOBase + 0x1E000;
    326  1.60     hauke 			matched = 1;
    327  1.60     hauke 			break;
    328  1.60     hauke 		}
    329  1.60     hauke 		/* FALLTHROUGH */
    330  1.60     hauke 	case MACH_CLASSQ2:	/* None */
    331  1.60     hauke 	case MACH_CLASSP580:	/* None */
    332  1.60     hauke 	case MACH_CLASSIIfx:	/* None */
    333  1.60     hauke 	case MACH_CLASSAV:	/* None */
    334  1.60     hauke 	default:
    335  1.60     hauke 		break;
    336  1.60     hauke 	}
    337  1.60     hauke 
    338  1.60     hauke 	if (TRACE_CONFIG) {
    339  1.60     hauke 		if (matched == 0)
    340  1.60     hauke 			printf("IWM or original SWIM not found.\n");
    341  1.60     hauke 		else
    342  1.60     hauke 			printf("IWMBase mapped to VM addr 0x%lx.\n",
    343   1.1    scottr 			    IWMBase);
    344   1.1    scottr 	}
    345   1.1    scottr 	return matched;
    346   1.1    scottr }
    347   1.1    scottr 
    348   1.1    scottr 
    349   1.1    scottr /*
    350   1.1    scottr  * iwm_attach
    351   1.1    scottr  *
    352   1.1    scottr  * The IWM is present, initialize it. Then look up the connected drives
    353   1.1    scottr  * and attach them.
    354   1.1    scottr  */
    355   1.1    scottr void
    356  1.47       chs iwm_attach(device_t parent, device_t self, void *aux)
    357   1.1    scottr {
    358   1.1    scottr 	int iwmErr;
    359   1.1    scottr 	iwm_softc_t *iwm;
    360   1.1    scottr 	iwmAttachArgs_t ia;
    361   1.1    scottr 
    362   1.1    scottr 	printf(": Apple GCR floppy disk controller\n");
    363  1.47       chs 	iwm = device_private(self);
    364   1.1    scottr 
    365   1.1    scottr 	iwmErr = iwmInit();
    366   1.1    scottr 	if (TRACE_CONFIG)
    367   1.1    scottr 		printf("initIWM() says %d.\n", iwmErr);
    368   1.1    scottr 
    369   1.1    scottr 	if (0 == iwmErr) {
    370   1.1    scottr 		/* Set up the IWM softc */
    371   1.1    scottr 		iwm->maxRetries = 10;
    372   1.1    scottr 
    373   1.1    scottr 		/* Look for attached drives */
    374   1.1    scottr 		for (ia.unit = 0; ia.unit < IWM_MAX_DRIVE; ia.unit++) {
    375   1.1    scottr 			iwm->fd[ia.unit] = NULL;
    376   1.1    scottr 			ia.driveType = getFDType(ia.unit);
    377   1.1    scottr 			if (NULL != ia.driveType)
    378  1.26  drochner 				config_found(self, (void *)&ia,
    379  1.61   thorpej 				    fd_print, CFARGS_NONE);
    380   1.1    scottr 		}
    381   1.1    scottr 		if (TRACE_CONFIG)
    382   1.1    scottr 			printf("iwm: Initialization completed.\n");
    383   1.1    scottr 	} else {
    384  1.60     hauke 		printf("iwm: Initialization failed (%d)\n", iwmErr);
    385   1.1    scottr 	}
    386   1.1    scottr }
    387   1.1    scottr 
    388   1.1    scottr 
    389   1.1    scottr /*
    390   1.1    scottr  * iwm_print -- print device configuration.
    391   1.1    scottr  *
    392   1.2    scottr  * If the device is not configured 'controller' it is NULL and
    393   1.2    scottr  * we print a message in the *Attach routine; the return value
    394   1.2    scottr  * of *Print() is ignored.
    395   1.1    scottr  */
    396   1.1    scottr int
    397  1.47       chs iwm_print(void *aux, const char *controller)
    398   1.1    scottr {
    399   1.1    scottr 	return UNCONF;
    400   1.1    scottr }
    401   1.1    scottr 
    402   1.2    scottr 
    403   1.1    scottr 
    404   1.1    scottr /***  Configure Sony disk drive(s)  ***/
    405   1.1    scottr 
    406   1.1    scottr /*
    407   1.1    scottr  * fd_match
    408   1.1    scottr  */
    409   1.1    scottr int
    410  1.47       chs fd_match(device_t parent, cfdata_t match, void *aux)
    411   1.1    scottr {
    412   1.1    scottr 	int matched, cfUnit;
    413   1.1    scottr 	struct cfdata *cfp;
    414   1.1    scottr 	iwmAttachArgs_t *fdParams;
    415   1.1    scottr 
    416   1.1    scottr 	cfp = match;
    417  1.47       chs 	fdParams = aux;
    418  1.29       chs 	cfUnit = cfp->cf_loc[IWMCF_DRIVE];
    419   1.1    scottr 	matched = (cfUnit == fdParams->unit || cfUnit == -1) ? 1 : 0;
    420   1.1    scottr 	if (TRACE_CONFIG) {
    421   1.1    scottr 		printf("fdMatch() drive %d ? cfUnit = %d\n",
    422  1.29       chs 		    fdParams->unit, cfUnit);
    423   1.1    scottr 	}
    424   1.1    scottr 	return matched;
    425   1.1    scottr }
    426   1.1    scottr 
    427   1.1    scottr 
    428   1.1    scottr /*
    429   1.1    scottr  * fd_attach
    430   1.1    scottr  *
    431   1.1    scottr  * We have checked that the IWM is fine and the drive is present,
    432   1.1    scottr  * so we can attach it.
    433   1.1    scottr  */
    434   1.1    scottr void
    435  1.47       chs fd_attach(device_t parent, device_t self, void *aux)
    436   1.1    scottr {
    437   1.1    scottr 	iwm_softc_t *iwm;
    438   1.1    scottr 	fd_softc_t *fd;
    439   1.1    scottr 	iwmAttachArgs_t *ia;
    440   1.1    scottr 	int driveInfo;
    441   1.1    scottr 
    442  1.47       chs 	iwm = device_private(parent);
    443  1.47       chs 	fd = device_private(self);
    444  1.57   msaitoh 	fd->sc_dev = self;
    445  1.47       chs 	ia = aux;
    446   1.1    scottr 
    447   1.1    scottr 	driveInfo = iwmCheckDrive(ia->unit);
    448   1.1    scottr 
    449   1.1    scottr 	fd->currentType = ia->driveType;
    450   1.1    scottr 	fd->unit = ia->unit;
    451   1.2    scottr 	fd->defaultType = &fdTypes[IWM_800K_GCR];
    452   1.1    scottr 	fd->stepDirection = 0;
    453   1.1    scottr 
    454   1.1    scottr 	iwm->fd[ia->unit] = fd;		/* iwm has ptr to this drive */
    455   1.1    scottr 	iwm->drives++;
    456   1.5     ender 
    457  1.34      yamt 	bufq_alloc(&fd->bufQueue, "disksort", BUFQ_SORT_CYLINDER);
    458  1.37        ad 	callout_init(&fd->motor_ch, 0);
    459   1.5     ender 
    460   1.1    scottr 	printf(" drive %d: ", fd->unit);
    461   1.1    scottr 
    462   1.1    scottr 	if (IWM_NO_DISK & driveInfo) {
    463   1.1    scottr 		printf("(drive empty)\n");
    464   1.1    scottr 	} else
    465   1.1    scottr 		if (!(IWM_DD_DISK & driveInfo)) {
    466   1.1    scottr 			printf("(HD disk -- not supported)\n");
    467   1.1    scottr 			iwmDiskEject(fd->unit);	/* XXX */
    468   1.1    scottr 		} else {
    469   1.1    scottr 			printf("%s %d cyl, %d head(s)\n",
    470   1.1    scottr 			    fd->currentType->description,
    471   1.1    scottr 			    fd->currentType->tracks,
    472   1.1    scottr 			    fd->currentType->heads);
    473   1.1    scottr 		}
    474   1.1    scottr 	if (TRACE_CONFIG) {
    475   1.1    scottr 		int reg, flags, spl;
    476   1.1    scottr 
    477   1.1    scottr 		/* List contents of drive status registers */
    478   1.2    scottr 		spl = spl6();
    479   1.1    scottr 		for (reg = 0; reg < 0x10; reg++) {
    480   1.1    scottr 			flags = iwmQueryDrvFlag(fd->unit, reg);
    481   1.1    scottr 			printf("iwm: Drive register 0x%x = 0x%x\n", reg, flags);
    482   1.1    scottr 		}
    483   1.1    scottr 		splx(spl);
    484   1.1    scottr 	}
    485  1.47       chs 	disk_init(&fd->diskInfo, device_xname(fd->sc_dev), &fd_dkDriver);
    486   1.1    scottr 	disk_attach(&fd->diskInfo);
    487   1.1    scottr }
    488   1.1    scottr 
    489   1.1    scottr 
    490   1.1    scottr /*
    491   1.1    scottr  * fdPrint -- print device configuration.
    492   1.1    scottr  *
    493   1.1    scottr  * If the device is not configured 'controller' refers to a name string
    494   1.1    scottr  * we print here.
    495   1.1    scottr  * Else it is NULL and we print a message in the *Attach routine; the
    496   1.1    scottr  * return value of *Print() is ignored.
    497   1.1    scottr  */
    498   1.1    scottr int
    499  1.47       chs fd_print(void *aux, const char *controller)
    500   1.1    scottr {
    501   1.1    scottr 	iwmAttachArgs_t *ia;
    502   1.1    scottr 
    503  1.47       chs 	ia = aux;
    504   1.1    scottr 	if (NULL != controller)
    505  1.20   thorpej 		aprint_normal("fd%d at %s", ia->unit, controller);
    506   1.1    scottr 	return UNCONF;
    507   1.1    scottr }
    508   1.1    scottr 
    509   1.1    scottr /**
    510   1.1    scottr  ** Implementation section of driver interface
    511   1.1    scottr  **
    512   1.1    scottr  ** The prototypes for these functions are set up automagically
    513   1.1    scottr  ** by macros in mac68k/conf.c. Their names are generated from {fd}
    514   1.1    scottr  ** and {open,close,strategy,dump,size,read,write}. The driver entry
    515   1.1    scottr  ** points are then plugged into bdevsw[] and cdevsw[].
    516   1.1    scottr  **/
    517   1.1    scottr 
    518   1.1    scottr 
    519   1.1    scottr /*
    520   1.1    scottr  * fdopen
    521   1.1    scottr  *
    522   1.1    scottr  * Open a floppy disk device.
    523   1.1    scottr  */
    524   1.1    scottr int
    525  1.35  christos fdopen(dev_t dev, int flags, int devType, struct lwp *l)
    526   1.1    scottr {
    527   1.1    scottr 	fd_softc_t *fd;
    528   1.1    scottr 	fdInfo_t *info;
    529   1.1    scottr 	int partitionMask;
    530   1.1    scottr 	int fdType, fdUnit;
    531   1.1    scottr 	int ierr, err;
    532  1.43   tsutsui 	iwm_softc_t *iwm = device_lookup_private(&iwm_cd, 0); /* XXX */
    533   1.1    scottr 	info = NULL;		/* XXX shut up egcs */
    534  1.25     fredb 	fd = NULL;		/* XXX shut up gcc3 */
    535   1.1    scottr 
    536   1.1    scottr 	/*
    537   1.1    scottr 	 * See <device.h> for struct cfdriver, <disklabel.h> for
    538   1.2    scottr 	 * DISKUNIT() and <atari/atari/device.h> for getsoftc().
    539   1.1    scottr 	 */
    540   1.1    scottr 	fdType = minor(dev) % MAXPARTITIONS;
    541   1.1    scottr 	fdUnit = minor(dev) / MAXPARTITIONS;
    542   1.1    scottr 	if (TRACE_OPEN)
    543   1.1    scottr 		printf("iwm: Open drive %d", fdUnit);
    544   1.1    scottr 
    545   1.1    scottr 	/* Check if device # is valid */
    546   1.1    scottr 	err = (iwm->drives < fdUnit) ? ENXIO : 0;
    547   1.1    scottr 	if (!err) {
    548   1.1    scottr 		(void)iwmSelectDrive(fdUnit);
    549   1.1    scottr 		if (TRACE_OPEN)
    550   1.1    scottr 			printf(".\n Get softc");
    551   1.1    scottr 
    552   1.1    scottr 		/* Get fd state */
    553   1.1    scottr 		fd = iwm->fd[fdUnit];
    554   1.1    scottr 		err = (NULL == fd) ? ENXIO : 0;
    555   1.1    scottr 	}
    556   1.1    scottr 	if (!err) {
    557   1.1    scottr 		if (fd->state & IWM_FD_IS_OPEN) {
    558   1.1    scottr 			/*
    559   1.1    scottr 			 * Allow multiple open calls only if for identical
    560   1.1    scottr 			 * floppy format.
    561   1.1    scottr 			 */
    562   1.1    scottr 			if (TRACE_OPEN)
    563   1.1    scottr 				printf(".\n Drive already opened!\n");
    564   1.1    scottr 			err = (fd->partition == fdType) ? 0 : ENXIO;
    565   1.1    scottr 		} else {
    566   1.1    scottr 			if (TRACE_OPEN)
    567   1.1    scottr 				printf(".\n Get format info");
    568   1.1    scottr 
    569   1.1    scottr 			/* Get format type */
    570   1.1    scottr 			info = fdDeviceToType(fd, dev);
    571   1.1    scottr 			if (NULL == info) {
    572   1.1    scottr 				err = ENXIO;
    573   1.1    scottr 				if (TRACE_OPEN)
    574   1.1    scottr 					printf(".\n No such drive.\n");
    575   1.1    scottr 			}
    576   1.1    scottr 		}
    577   1.1    scottr 	}
    578   1.1    scottr 	if (!err && !(fd->state & IWM_FD_IS_OPEN)) {
    579   1.1    scottr 		if (TRACE_OPEN)
    580   1.1    scottr 			printf(".\n Set diskInfo flags.\n");
    581   1.1    scottr 
    582   1.2    scottr 		fd->writeLabel = 0;		/* XXX currently unused */
    583   1.1    scottr 		fd->partition = fdType;
    584   1.1    scottr 		fd->currentType = info;
    585   1.1    scottr 		fd->drvFlags = iwmCheckDrive(fd->unit);
    586   1.1    scottr 
    587   1.1    scottr 		if (fd->drvFlags & IWM_NO_DISK) {
    588   1.1    scottr 			err = EIO;
    589   1.1    scottr #ifdef DIAGNOSTIC
    590   1.1    scottr 			printf(" Drive %d is empty.\n", fd->unit);
    591   1.1    scottr #endif
    592   1.2    scottr 		} else {
    593  1.21       wiz 			if (!(fd->drvFlags & IWM_WRITABLE) && (flags & FWRITE)) {
    594   1.2    scottr 
    595   1.1    scottr 				err = EPERM;
    596   1.1    scottr #ifdef DIAGNOSTIC
    597   1.1    scottr 				printf(" Disk is write protected.\n");
    598   1.1    scottr #endif
    599   1.2    scottr 			} else {
    600   1.1    scottr 				if (!(fd->drvFlags & IWM_DD_DISK)) {
    601   1.1    scottr 					err = ENXIO;
    602   1.1    scottr #ifdef DIAGNOSTIC
    603   1.1    scottr 					printf(" HD format not supported.\n");
    604   1.1    scottr #endif
    605   1.1    scottr 					(void)iwmDiskEject(fd->unit);
    606   1.2    scottr 				} else {
    607   1.1    scottr 					/* We're open now! */
    608   1.1    scottr 					fd->state |= IWM_FD_IS_OPEN;
    609   1.2    scottr 					err = initCylinderCache(fd);
    610   1.2    scottr 				}
    611   1.2    scottr 			}
    612   1.2    scottr 		}
    613   1.1    scottr 	}
    614   1.1    scottr 	if (!err) {
    615   1.1    scottr 		/*
    616   1.1    scottr 		 * Later, we might not want to recalibrate the drive when it
    617   1.1    scottr 		 * is already open. For now, it doesn't hurt.
    618   1.1    scottr 		 */
    619   1.1    scottr 		if (TRACE_OPEN)
    620   1.1    scottr 			printf(" Seek track 00 says");
    621   1.1    scottr 
    622   1.2    scottr 		memset(&fd->pos, 0, sizeof(diskPosition_t));
    623   1.2    scottr 		ierr = seek(fd, IWM_SEEK_RECAL);
    624   1.1    scottr 		if (TRACE_OPEN)
    625   1.1    scottr 			printf(" %d.\n", ierr);
    626   1.2    scottr 		err = (0 == ierr) ? 0 : EIO;
    627   1.1    scottr 	}
    628   1.1    scottr 	if (!err) {
    629   1.1    scottr 		/*
    630   1.1    scottr 		 * Update disklabel if we are not yet open.
    631   1.1    scottr 		 * (We shouldn't be: We are synchronous.)
    632   1.1    scottr 		 */
    633   1.1    scottr 		if (fd->diskInfo.dk_openmask == 0)
    634   1.1    scottr 			fdGetDiskLabel(fd, dev);
    635   1.1    scottr 
    636   1.1    scottr 		partitionMask = (1 << fdType);
    637   1.1    scottr 
    638   1.1    scottr 		switch (devType) {
    639   1.1    scottr 		case S_IFCHR:
    640   1.1    scottr 			fd->diskInfo.dk_copenmask |= partitionMask;
    641   1.1    scottr 			break;
    642   1.1    scottr 
    643   1.1    scottr 		case S_IFBLK:
    644   1.1    scottr 			fd->diskInfo.dk_bopenmask |= partitionMask;
    645   1.1    scottr 			break;
    646   1.1    scottr 		}
    647   1.1    scottr 		fd->diskInfo.dk_openmask =
    648   1.1    scottr 		    fd->diskInfo.dk_copenmask | fd->diskInfo.dk_bopenmask;
    649   1.1    scottr 	}
    650   1.1    scottr 	if (TRACE_OPEN)
    651   1.1    scottr 		printf("iwm: fdopen() says %d.\n", err);
    652   1.1    scottr 	return err;
    653   1.1    scottr }
    654   1.1    scottr 
    655   1.1    scottr 
    656   1.1    scottr /*
    657   1.1    scottr  * fdclose
    658   1.1    scottr  */
    659   1.1    scottr int
    660  1.35  christos fdclose(dev_t dev, int flags, int devType, struct lwp *l)
    661   1.1    scottr {
    662   1.1    scottr 	fd_softc_t *fd;
    663   1.1    scottr 	int partitionMask, fdUnit, fdType;
    664  1.43   tsutsui 	iwm_softc_t *iwm = device_lookup_private(&iwm_cd, 0);
    665   1.1    scottr 
    666   1.1    scottr 	if (TRACE_CLOSE)
    667   1.1    scottr 		printf("iwm: Closing driver.");
    668   1.1    scottr 	fdUnit = minor(dev) / MAXPARTITIONS;
    669   1.1    scottr 	fdType = minor(dev) % MAXPARTITIONS;
    670   1.1    scottr 	fd = iwm->fd[fdUnit];
    671   1.2    scottr 	/* release cylinder cache memory */
    672  1.58   thorpej 	if (fd->cbuf != NULL) {
    673  1.58   thorpej 		     kmem_free(fd->cbuf,
    674  1.58   thorpej 		         IWM_MAX_GCR_SECTORS * fd->currentType->sectorSize);
    675  1.58   thorpej 	}
    676  1.58   thorpej 
    677   1.1    scottr 	partitionMask = (1 << fdType);
    678   1.1    scottr 
    679   1.1    scottr 	/* Set state flag. */
    680   1.1    scottr 	fd->state &= ~IWM_FD_IS_OPEN;
    681   1.1    scottr 
    682   1.1    scottr 	switch (devType) {
    683   1.1    scottr 	case S_IFCHR:
    684   1.1    scottr 		fd->diskInfo.dk_copenmask &= ~partitionMask;
    685   1.1    scottr 		break;
    686   1.1    scottr 
    687   1.1    scottr 	case S_IFBLK:
    688   1.1    scottr 		fd->diskInfo.dk_bopenmask &= ~partitionMask;
    689   1.1    scottr 		break;
    690   1.1    scottr 	}
    691   1.1    scottr 	fd->diskInfo.dk_openmask =
    692   1.1    scottr 	    fd->diskInfo.dk_copenmask | fd->diskInfo.dk_bopenmask;
    693   1.1    scottr 	return 0;
    694   1.1    scottr }
    695   1.1    scottr 
    696   1.1    scottr 
    697   1.1    scottr /*
    698   1.1    scottr  * fdioctl
    699   1.1    scottr  *
    700   1.1    scottr  * We deal with all the disk-specific ioctls in <sys/dkio.h> here even if
    701   1.1    scottr  * we do not support them.
    702   1.1    scottr  */
    703   1.1    scottr int
    704  1.53  christos fdioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l)
    705   1.1    scottr {
    706   1.1    scottr 	int result, fdUnit, fdType;
    707   1.1    scottr 	fd_softc_t *fd;
    708  1.43   tsutsui 	iwm_softc_t *iwm = device_lookup_private(&iwm_cd, 0);
    709  1.52  christos 	int error;
    710   1.1    scottr 
    711   1.1    scottr 	if (TRACE_IOCTL)
    712   1.1    scottr 		printf("iwm: Execute ioctl... ");
    713   1.1    scottr 
    714   1.1    scottr 	/* Check if device # is valid and get its softc */
    715   1.1    scottr 	fdUnit = minor(dev) / MAXPARTITIONS;
    716   1.1    scottr 	fdType = minor(dev) % MAXPARTITIONS;
    717   1.1    scottr 	if (fdUnit >= iwm->drives) {
    718   1.1    scottr 		if (TRACE_IOCTL) {
    719   1.1    scottr 			printf("iwm: Wanted device no (%d) is >= %d.\n",
    720   1.1    scottr 			    fdUnit, iwm->drives);
    721   1.1    scottr 		}
    722   1.1    scottr 		return ENXIO;
    723   1.1    scottr 	}
    724   1.1    scottr 	fd = iwm->fd[fdUnit];
    725   1.1    scottr 	result = 0;
    726   1.1    scottr 
    727  1.55  christos 	error = disk_ioctl(&fd->diskInfo, fdType, cmd, data, flag, l);
    728  1.51  christos 	if (error != EPASSTHROUGH)
    729  1.51  christos 		return error;
    730  1.51  christos 
    731   1.1    scottr 	switch (cmd) {
    732   1.1    scottr 	case DIOCSDINFO:
    733   1.1    scottr 		if (TRACE_IOCTL)
    734   1.1    scottr 			printf(" DIOCSDINFO: Set in-core disklabel.\n");
    735  1.53  christos 		result = ((flag & FWRITE) == 0) ? EBADF : 0;
    736   1.1    scottr 		if (result == 0)
    737   1.1    scottr 			result = setdisklabel(fd->diskInfo.dk_label,
    738   1.1    scottr 			    (struct disklabel *)data, 0,
    739   1.1    scottr 			    fd->diskInfo.dk_cpulabel);
    740   1.1    scottr 		break;
    741   1.1    scottr 
    742   1.1    scottr 	case DIOCWDINFO:
    743   1.1    scottr 		if (TRACE_IOCTL)
    744   1.1    scottr 			printf(" DIOCWDINFO: Set in-core disklabel "
    745   1.1    scottr 			    "& update disk.\n");
    746  1.53  christos 		result = ((flag & FWRITE) == 0) ? EBADF : 0;
    747   1.1    scottr 
    748   1.1    scottr 		if (result == 0)
    749   1.1    scottr 			result = setdisklabel(fd->diskInfo.dk_label,
    750   1.1    scottr 			    (struct disklabel *)data, 0,
    751   1.1    scottr 			    fd->diskInfo.dk_cpulabel);
    752   1.1    scottr 		if (result == 0)
    753   1.1    scottr 			result = writedisklabel(dev, fdstrategy,
    754   1.1    scottr 			    fd->diskInfo.dk_label,
    755   1.1    scottr 			    fd->diskInfo.dk_cpulabel);
    756   1.1    scottr 		break;
    757   1.1    scottr 
    758   1.1    scottr 	case DIOCRFORMAT:
    759   1.1    scottr 	case DIOCWFORMAT:
    760   1.1    scottr 		if (TRACE_IOCTL)
    761   1.1    scottr 			printf(" DIOC{R,W}FORMAT: No formatter support (yet?).\n");
    762   1.1    scottr 		result = EINVAL;
    763   1.1    scottr 		break;
    764   1.1    scottr 
    765   1.1    scottr 	case DIOCSSTEP:
    766   1.1    scottr 		if (TRACE_IOCTL)
    767   1.1    scottr 			printf(" DIOCSSTEP: IWM does step handshake.\n");
    768   1.1    scottr 		result = EINVAL;
    769   1.1    scottr 		break;
    770   1.1    scottr 
    771   1.1    scottr 	case DIOCSRETRIES:
    772   1.1    scottr 		if (TRACE_IOCTL)
    773   1.1    scottr 			printf(" DIOCSRETRIES: Set max. # of retries.\n");
    774   1.1    scottr 		if (*(int *)data < 0)
    775   1.1    scottr 			result = EINVAL;
    776   1.1    scottr 		else {
    777   1.1    scottr 			iwm->maxRetries = *(int *)data;
    778   1.1    scottr 			result = 0;
    779   1.1    scottr 		}
    780   1.1    scottr 		break;
    781   1.1    scottr 
    782   1.1    scottr 	case DIOCWLABEL:
    783   1.1    scottr 		if (TRACE_IOCTL)
    784   1.1    scottr 			printf(" DIOCWLABEL: Set write access to disklabel.\n");
    785  1.53  christos 		result = ((flag & FWRITE) == 0) ? EBADF : 0;
    786   1.1    scottr 
    787   1.1    scottr 		if (result == 0)
    788   1.1    scottr 			fd->writeLabel = *(int *)data;
    789   1.1    scottr 		break;
    790   1.1    scottr 
    791   1.1    scottr 	case DIOCSBAD:
    792   1.1    scottr 		if (TRACE_IOCTL)
    793   1.1    scottr 			printf(" DIOCSBAD: No bad144-style handling.\n");
    794   1.1    scottr 		result = EINVAL;
    795   1.1    scottr 		break;
    796   1.1    scottr 
    797   1.2    scottr 	case ODIOCEJECT:
    798   1.1    scottr 	case DIOCEJECT:
    799   1.1    scottr 		/* XXX Eject disk only when unlocked */
    800   1.1    scottr 		if (TRACE_IOCTL)
    801   1.1    scottr 			printf(" DIOCEJECT: Eject disk from unit %d.\n",
    802   1.1    scottr 			    fd->unit);
    803   1.1    scottr 		result = iwmDiskEject(fd->unit);
    804   1.1    scottr 		break;
    805   1.1    scottr 
    806   1.1    scottr 	case DIOCLOCK:
    807   1.1    scottr 		/* XXX Use lock to prevent ejectimg a mounted disk */
    808   1.1    scottr 		if (TRACE_IOCTL)
    809   1.1    scottr 			printf(" DIOCLOCK: No need to (un)lock Sony drive.\n");
    810   1.1    scottr 		result = 0;
    811   1.1    scottr 		break;
    812   1.1    scottr 
    813   1.1    scottr 	default:
    814   1.1    scottr 		if (TRACE_IOCTL)
    815   1.1    scottr 			printf(" Not a disk related ioctl!\n");
    816   1.1    scottr 		result = ENOTTY;
    817   1.1    scottr 		break;
    818   1.1    scottr 	}
    819   1.1    scottr 	return result;
    820   1.1    scottr }
    821   1.1    scottr 
    822   1.1    scottr 
    823   1.1    scottr /*
    824   1.1    scottr  * fdread
    825   1.1    scottr  */
    826   1.1    scottr int
    827  1.31       chs fdread(dev_t dev, struct uio *uio, int flags)
    828   1.1    scottr {
    829   1.2    scottr 	return physio(fdstrategy, NULL, dev, B_READ, minphys, uio);
    830   1.1    scottr }
    831   1.1    scottr 
    832   1.1    scottr 
    833   1.1    scottr /*
    834   1.1    scottr  * fdwrite
    835   1.1    scottr  */
    836   1.1    scottr int
    837  1.31       chs fdwrite(dev_t dev, struct uio *uio, int flags)
    838   1.1    scottr {
    839   1.2    scottr 	return physio(fdstrategy, NULL, dev, B_WRITE, minphys, uio);
    840   1.1    scottr }
    841   1.1    scottr 
    842   1.1    scottr 
    843   1.1    scottr /*
    844   1.2    scottr  * fdstrategy
    845   1.1    scottr  *
    846   1.2    scottr  * Entry point for read and write requests. The strategy routine usually
    847   1.2    scottr  * queues io requests and kicks off the next transfer if the device is idle;
    848   1.2    scottr  * but we get no interrupts from the IWM and have to do synchronous
    849   1.2    scottr  * transfers - no queue.
    850   1.1    scottr  */
    851   1.2    scottr void
    852  1.31       chs fdstrategy(struct buf *bp)
    853   1.2    scottr {
    854   1.2    scottr 	int fdUnit, err, done, spl;
    855   1.2    scottr 	int sectSize, transferSize;
    856   1.2    scottr 	diskPosition_t physDiskLoc;
    857   1.1    scottr 	fd_softc_t *fd;
    858  1.43   tsutsui 	iwm_softc_t *iwm = device_lookup_private(&iwm_cd, 0);
    859   1.1    scottr 
    860   1.2    scottr 	err = 0;
    861   1.2    scottr 	done = 0;
    862  1.25     fredb 	sectSize = 0;		/* XXX shut up gcc3 */
    863  1.25     fredb 	fd = NULL;		/* XXX shut up gcc3 */
    864   1.1    scottr 
    865   1.2    scottr 	fdUnit = minor(bp->b_dev) / MAXPARTITIONS;
    866   1.2    scottr 	if (TRACE_STRAT) {
    867   1.2    scottr 		printf("iwm: fdstrategy()...\n");
    868   1.2    scottr 		printf("     struct buf is at %p\n", bp);
    869  1.27      yamt 		printf("     Allocated buffer size (b_bufsize): 0x0%x\n",
    870   1.2    scottr 		    bp->b_bufsize);
    871  1.10   thorpej 		printf("     Base address of buffer (b_data): %p\n",
    872  1.10   thorpej 		    bp->b_data);
    873  1.27      yamt 		printf("     Bytes to be transferred (b_bcount): 0x0%x\n",
    874   1.2    scottr 		    bp->b_bcount);
    875  1.27      yamt 		printf("     Remaining I/O (b_resid): 0x0%x\n",
    876   1.2    scottr 		    bp->b_resid);
    877   1.1    scottr 	}
    878   1.2    scottr 	/* Check for valid fd unit, controller and io request */
    879   1.1    scottr 
    880   1.2    scottr 	if (fdUnit >= iwm->drives) {
    881   1.1    scottr 		if (TRACE_STRAT)
    882   1.2    scottr 			printf(" No such unit (%d)\n", fdUnit);
    883   1.2    scottr 		err = EINVAL;
    884   1.2    scottr 	}
    885   1.2    scottr 	if (!err) {
    886   1.2    scottr 		fd = iwm->fd[fdUnit];
    887   1.2    scottr 		err = (NULL == fd) ? EINVAL : 0;
    888   1.2    scottr 	}
    889   1.2    scottr 	if (!err) {
    890   1.2    scottr 		sectSize = fd->currentType->sectorSize;
    891   1.2    scottr 		if (bp->b_blkno < 0
    892   1.2    scottr 		    || (bp->b_bcount % sectSize) != 0) {
    893   1.1    scottr 			if (TRACE_STRAT)
    894   1.2    scottr 				printf(" Illegal transfer size: "
    895  1.27      yamt 				    "block %lld, %d bytes\n",
    896  1.22  jdolecek 				    (long long) bp->b_blkno, bp->b_bcount);
    897   1.2    scottr 			err = EINVAL;
    898   1.2    scottr 		}
    899   1.2    scottr 	}
    900   1.2    scottr 	if (!err) {
    901   1.2    scottr 		/* Null transfer: Return, nothing to do. */
    902   1.2    scottr 		if (0 == bp->b_bcount) {
    903   1.1    scottr 			if (TRACE_STRAT)
    904   1.2    scottr 				printf(" Zero transfer length.\n");
    905   1.2    scottr 			done = 1;
    906   1.2    scottr 		}
    907   1.2    scottr 	}
    908   1.2    scottr 	if (!err && !done) {
    909   1.2    scottr 		/* What to do if we touch the boundaries of the disk? */
    910   1.2    scottr 		transferSize = (bp->b_bcount + (sectSize - 1)) / sectSize;
    911   1.2    scottr 		if (bp->b_blkno + transferSize > fd->currentType->secPerDisk) {
    912   1.2    scottr 			if (TRACE_STRAT) {
    913   1.2    scottr 				printf("iwm: Transfer beyond end of disk!\n" \
    914  1.22  jdolecek 				    " (Starting block %lld, # of blocks %d," \
    915   1.2    scottr 				    " last disk block %d).\n",
    916  1.22  jdolecek 				    (long long) bp->b_blkno, transferSize,
    917   1.2    scottr 				    fd->currentType->secPerDisk);
    918   1.2    scottr 			}
    919   1.2    scottr 			/* Return EOF if we are exactly at the end of the
    920   1.2    scottr 			 * disk, EINVAL if we try to reach past the end; else
    921   1.2    scottr 			 * truncate the request. */
    922   1.2    scottr 			transferSize = fd->currentType->secPerDisk -
    923   1.2    scottr 			    bp->b_blkno;
    924   1.2    scottr 			if (0 == transferSize) {
    925   1.2    scottr 				bp->b_resid = bp->b_bcount;
    926   1.2    scottr 				done = 1;
    927   1.2    scottr 			} else
    928   1.2    scottr 				if (0 > transferSize)
    929   1.2    scottr 					err = EINVAL;
    930   1.2    scottr 				else
    931   1.2    scottr 					bp->b_bcount = transferSize << DEV_BSHIFT;
    932   1.2    scottr 		}
    933   1.2    scottr 	}
    934   1.2    scottr 	if (!err && !done) {
    935   1.2    scottr 		/*
    936   1.2    scottr 		 * Calculate cylinder # for disksort().
    937   1.2    scottr 		 *
    938   1.2    scottr 		 * XXX Shouldn't we use the (fake) logical cyl no here?
    939   1.2    scottr 		 */
    940   1.2    scottr 		remap_geometry(bp->b_blkno, fd->currentType->heads,
    941   1.2    scottr 		    &physDiskLoc);
    942   1.6   thorpej 		bp->b_rawblkno = bp->b_blkno;
    943   1.2    scottr 		bp->b_cylinder = physDiskLoc.track;
    944   1.2    scottr 
    945   1.2    scottr 		if (TRACE_STRAT) {
    946  1.22  jdolecek 			printf(" This job starts at b_blkno %lld; ",
    947  1.22  jdolecek 			    (long long) bp->b_blkno);
    948  1.27      yamt 			printf("it gets sorted for cylinder # %d.\n",
    949   1.2    scottr 			    bp->b_cylinder);
    950   1.2    scottr 		}
    951   1.2    scottr 		spl = splbio();
    952   1.8   thorpej 		callout_stop(&fd->motor_ch);
    953  1.46      yamt 		bufq_put(fd->bufQueue, bp);
    954   1.4   thorpej 		if (fd->sc_active == 0)
    955   1.2    scottr 			fdstart(fd);
    956   1.2    scottr 		splx(spl);
    957   1.2    scottr 	}
    958   1.2    scottr 	/* Clean up, if necessary */
    959   1.2    scottr 	else {
    960   1.2    scottr 		if (TRACE_STRAT)
    961   1.2    scottr 			printf(" fdstrategy() finished early, err = %d.\n",
    962   1.2    scottr 			    err);
    963  1.38        ad 		if (err)
    964   1.2    scottr 			bp->b_error = err;
    965   1.2    scottr 		bp->b_resid = bp->b_bcount;
    966   1.2    scottr 		biodone(bp);
    967   1.2    scottr 	}
    968   1.2    scottr 	/* Comment on results */
    969   1.2    scottr 	if (TRACE_STRAT) {
    970   1.2    scottr 		printf("iwm: fdstrategy() done.\n");
    971  1.27      yamt 		printf("     We have b_resid = %d bytes left, " \
    972   1.2    scottr 		    "b_error is %d;\n", bp->b_resid, bp->b_error);
    973  1.27      yamt 		printf("     b_flags are 0x0%x.\n", bp->b_flags);
    974   1.2    scottr 	}
    975   1.2    scottr }
    976   1.2    scottr 
    977   1.2    scottr 
    978   1.2    scottr 
    979   1.2    scottr /* ======================================================================== */
    980   1.2    scottr 
    981   1.2    scottr 
    982   1.2    scottr /*
    983   1.2    scottr  * fdstart
    984   1.2    scottr  *
    985   1.2    scottr  * we are called from the strategy() routine to perform a data transfer.
    986   1.2    scottr  *
    987   1.2    scottr  * The disk(9) framework demands we run at splbio(); our caller
    988   1.2    scottr  * takes care of that.
    989   1.2    scottr  *
    990   1.2    scottr  * Wish we had pascalish local functions here...
    991   1.2    scottr  */
    992   1.2    scottr 
    993   1.2    scottr /* fdstart FSM states */
    994   1.2    scottr enum {
    995   1.2    scottr 	state_Init = 0,
    996   1.2    scottr 	state_Seek,
    997   1.2    scottr 	state_Read,
    998   1.2    scottr 	state_Write,
    999   1.2    scottr 	state_Flush,
   1000   1.2    scottr 	state_IOFinish,
   1001   1.2    scottr 	state_IOErr,
   1002   1.2    scottr 	state_Fault,
   1003   1.2    scottr 	state_Exit,
   1004   1.2    scottr 	state_Done
   1005   1.2    scottr };
   1006   1.2    scottr 
   1007   1.2    scottr static void
   1008  1.31       chs fdstart(fd_softc_t *fd)
   1009   1.2    scottr {
   1010   1.2    scottr 	int st;
   1011   1.2    scottr 
   1012  1.33       jmc 	static const char *stateDesc[] = {
   1013   1.2    scottr 		"Init",
   1014   1.2    scottr 		"Seek",
   1015   1.2    scottr 		"Read",
   1016   1.2    scottr 		"Write",
   1017   1.2    scottr 		"Flush",
   1018   1.2    scottr 		"IOFinish",
   1019   1.2    scottr 		"IOErr",
   1020   1.2    scottr 		"Fault",
   1021   1.2    scottr 		"Exit",
   1022   1.2    scottr 		"Done"
   1023   1.2    scottr 	};
   1024  1.33       jmc 	int (*state[])(fd_softc_t *) = {
   1025   1.2    scottr 		fdstart_Init,
   1026   1.2    scottr 		fdstart_Seek,
   1027   1.2    scottr 		fdstart_Read,
   1028   1.2    scottr 		fdstart_Write,
   1029   1.2    scottr 		fdstart_Flush,
   1030   1.2    scottr 		fdstart_IOFinish,
   1031   1.2    scottr 		fdstart_IOErr,
   1032   1.2    scottr 		fdstart_Fault,
   1033   1.2    scottr 		fdstart_Exit
   1034   1.2    scottr 	};
   1035   1.2    scottr 
   1036   1.2    scottr 	st = state_Init;
   1037   1.2    scottr 	do {
   1038   1.2    scottr 		if (TRACE_STRAT)
   1039   1.2    scottr 			printf(" fdstart state %d [%s] ",
   1040   1.2    scottr 			    st, stateDesc[st]);
   1041   1.2    scottr 
   1042   1.2    scottr 		st = (*state[st])(fd);
   1043   1.2    scottr 
   1044   1.2    scottr 		if (TRACE_STRAT)
   1045   1.2    scottr 			printf(".\n");
   1046   1.2    scottr 	} while (st != state_Done);
   1047   1.2    scottr }
   1048   1.2    scottr 
   1049   1.2    scottr 
   1050   1.2    scottr /*
   1051   1.2    scottr  * fdstart_Init
   1052   1.2    scottr  *
   1053   1.2    scottr  * Set up things
   1054   1.2    scottr  */
   1055   1.2    scottr static int
   1056  1.31       chs fdstart_Init(fd_softc_t *fd)
   1057   1.2    scottr {
   1058   1.2    scottr 	struct buf *bp;
   1059   1.2    scottr 
   1060   1.2    scottr 	/*
   1061   1.2    scottr 	 * Get the first entry from the queue. This is the buf we gave to
   1062   1.2    scottr 	 * fdstrategy(); disksort() put it into our softc.
   1063   1.2    scottr 	 */
   1064  1.46      yamt 	bp = bufq_peek(fd->bufQueue);
   1065   1.2    scottr 	if (NULL == bp) {
   1066   1.2    scottr 		if (TRACE_STRAT)
   1067   1.2    scottr 			printf("Queue empty: Nothing to do");
   1068   1.2    scottr 		return state_Done;
   1069   1.2    scottr 	}
   1070   1.2    scottr 	fd->ioDirection = bp->b_flags & B_READ;
   1071   1.2    scottr 
   1072   1.2    scottr 	disk_busy(&fd->diskInfo);
   1073   1.2    scottr 	if (!(fd->state & IWM_FD_MOTOR_ON)) {
   1074   1.2    scottr 		iwmMotor(fd->unit, 1);
   1075   1.2    scottr 		fd->state |= IWM_FD_MOTOR_ON;
   1076   1.2    scottr 	}
   1077  1.10   thorpej 	fd->current_buffer = bp->b_data;
   1078   1.2    scottr 
   1079   1.2    scottr 	/* XXX - assumes blocks of 512 bytes */
   1080   1.2    scottr 	fd->startBlk = bp->b_blkno;
   1081   1.2    scottr 
   1082   1.2    scottr 	fd->iwmErr = 0;
   1083   1.2    scottr 	fd->ioRetries = 0;		/* XXX */
   1084   1.2    scottr 	fd->seekRetries = 0;
   1085   1.2    scottr 	fd->bytesDone = 0;
   1086   1.2    scottr 	fd->bytesLeft = bp->b_bcount;
   1087   1.2    scottr 	return state_Seek;
   1088   1.2    scottr }
   1089   1.2    scottr 
   1090   1.2    scottr 
   1091   1.2    scottr /*
   1092   1.2    scottr  * fdstart_Seek
   1093   1.2    scottr  */
   1094   1.2    scottr static int
   1095  1.31       chs fdstart_Seek(fd_softc_t *fd)
   1096   1.2    scottr {
   1097   1.2    scottr 	int state;
   1098   1.2    scottr 
   1099   1.2    scottr 	/* Calculate the side/track/sector our block is at. */
   1100   1.2    scottr 	if (TRACE_STRAT)
   1101  1.22  jdolecek 		printf(" Remap block %lld ", (long long) fd->startBlk);
   1102   1.2    scottr 	remap_geometry(fd->startBlk,
   1103   1.2    scottr 	    fd->currentType->heads, &fd->pos);
   1104   1.2    scottr 	if (TRACE_STRAT)
   1105   1.2    scottr 		printf("to c%d_h%d_s%d ", fd->pos.track,
   1106   1.2    scottr 		    fd->pos.side, fd->pos.sector);
   1107   1.2    scottr 
   1108   1.2    scottr 	if (fd->cachedSide != fd->pos.side) {
   1109   1.2    scottr 		if (TRACE_STRAT)
   1110   1.2    scottr 			printf(" (invalidate cache) ");
   1111   1.2    scottr 		invalidateCylinderCache(fd);
   1112   1.2    scottr 		fd->cachedSide = fd->pos.side;
   1113   1.2    scottr 	}
   1114   1.2    scottr 
   1115   1.2    scottr 	/*
   1116   1.2    scottr 	 * If necessary, seek to wanted track. Note that
   1117   1.2    scottr 	 * seek() performs any necessary retries.
   1118   1.2    scottr 	 */
   1119   1.2    scottr 	if (fd->pos.track != fd->pos.oldTrack &&
   1120   1.2    scottr 	    0 != (fd->iwmErr = seek(fd, IWM_SEEK_VANILLA))) {
   1121   1.2    scottr 		state = state_Fault;
   1122   1.2    scottr 	} else {
   1123   1.2    scottr 		state = (fd->ioDirection == IWM_WRITE)
   1124   1.2    scottr 		    ? state_Write : state_Read;
   1125   1.2    scottr 	}
   1126   1.2    scottr 	return state;
   1127   1.2    scottr }
   1128   1.2    scottr 
   1129   1.2    scottr 
   1130   1.2    scottr /*
   1131   1.2    scottr  * fdstart_Read
   1132   1.2    scottr  *
   1133   1.2    scottr  * Transfer a sector from disk. Get it from the track cache, if available;
   1134   1.2    scottr  * otherwise, while we are at it, store in the cache all the sectors we find
   1135   1.2    scottr  * on the way.
   1136   1.2    scottr  *
   1137   1.2    scottr  * Track buffering reads:
   1138   1.2    scottr  * o  Look if the sector is already cached.
   1139   1.2    scottr  * o  Else, read sectors into track cache until we meet the header of
   1140   1.2    scottr  *    the sector we want.
   1141   1.2    scottr  * o  Read that sector directly to fs buffer and return.
   1142   1.2    scottr  */
   1143   1.2    scottr static int
   1144  1.31       chs fdstart_Read(fd_softc_t *fd)
   1145   1.2    scottr {
   1146   1.2    scottr 	int i;
   1147   1.2    scottr 	diskPosition_t *pos;
   1148   1.2    scottr 	sectorHdr_t *shdr;
   1149  1.42    cegger 	iwm_softc_t *iwm = device_lookup_private(&iwm_cd, 0); /* XXX */
   1150   1.2    scottr 
   1151   1.2    scottr 	/* Initialize retry counters */
   1152   1.2    scottr 	fd->seekRetries = 0;
   1153   1.2    scottr 	fd->sectRetries = 0;
   1154   1.2    scottr 	pos = &fd->pos;
   1155   1.2    scottr 	shdr = &fd->sHdr;
   1156   1.2    scottr 
   1157   1.2    scottr 	if (TRACE_STRAT)
   1158   1.2    scottr 		printf("<%s c%d_h%d_s%d> ",
   1159   1.2    scottr 		    fd->ioDirection ? "Read" : "Write",
   1160   1.2    scottr 		    pos->track, pos->side, pos->sector);
   1161   1.2    scottr 
   1162   1.2    scottr 	/* Sector already cached? */
   1163   1.2    scottr 	i = pos->sector;
   1164   1.2    scottr 	if (fd->r_slots[i].valid) {
   1165   1.2    scottr 		if (TRACE_STRAT)
   1166   1.2    scottr 			printf("(cached)");
   1167   1.2    scottr 		memcpy(fd->current_buffer, fd->r_slots[i].secbuf,
   1168   1.2    scottr 		    fd->currentType->sectorSize);
   1169   1.2    scottr 		return state_IOFinish;
   1170   1.2    scottr 	}
   1171   1.2    scottr 
   1172   1.2    scottr 	/* Get sector from disk */
   1173   1.2    scottr 	shdr->side = pos->side;
   1174   1.2    scottr 	shdr->sector = pos->sector;
   1175   1.2    scottr 	shdr->track = pos->track;
   1176   1.2    scottr 
   1177   1.2    scottr 	(void)iwmSelectSide(pos->side);
   1178   1.2    scottr 	fd->iwmErr = iwmReadSector(&fd->sHdr, fd->r_slots,
   1179   1.2    scottr 	    fd->current_buffer);
   1180   1.2    scottr 
   1181   1.2    scottr 	/* Check possible error conditions */
   1182   1.2    scottr 	if (TRACE_STRAT)
   1183   1.2    scottr 		printf("c%d_h%d_s%d_err(%d)_sr%d ",
   1184   1.2    scottr 		    shdr->track, shdr->side >> 3,
   1185   1.2    scottr 		    shdr->sector, fd->iwmErr, fd->sectRetries);
   1186   1.2    scottr 
   1187   1.2    scottr 	/* IWM IO error? */
   1188   1.2    scottr 	if (fd->iwmErr != 0)
   1189   1.2    scottr 		return state_IOErr;
   1190   1.2    scottr 
   1191   1.2    scottr 	/* Bad seek? Retry */
   1192   1.2    scottr 	if (shdr->track != pos->track) {
   1193   1.2    scottr 		if (TRACE_STRAT) {
   1194   1.2    scottr 			printf("Wanted track %d, got %d, %d seek retries.\n",
   1195   1.2    scottr 			    pos->track, shdr->track, fd->seekRetries);
   1196   1.2    scottr 		}
   1197   1.2    scottr 		if (iwm->maxRetries > fd->seekRetries++) {
   1198   1.2    scottr 			fd->iwmErr = seek(fd, IWM_SEEK_RECAL);
   1199   1.2    scottr 			if (TRACE_STRAT) {
   1200   1.2    scottr 				printf("[%d]", fd->seekRetries);
   1201   1.2    scottr 				(void)checkTrack(&fd->pos, 1);
   1202   1.2    scottr 			}
   1203   1.2    scottr 		} else
   1204   1.2    scottr 			fd->iwmErr = seekErr;
   1205   1.2    scottr 		return (0 == fd->iwmErr) ? state_Read : state_Fault;
   1206   1.2    scottr 	}
   1207   1.2    scottr 
   1208   1.2    scottr 	/* Sector not found? */
   1209   1.2    scottr 	if (shdr->sector != pos->sector) {
   1210   1.2    scottr 		if (TRACE_STRAT)
   1211   1.2    scottr 			printf("c%d_h%d_s%d sect not found, %d retries ",
   1212   1.2    scottr 			    shdr->track, shdr->side >> 3,
   1213   1.2    scottr 			    shdr->sector, fd->sectRetries);
   1214   1.2    scottr 		fd->iwmErr = noAdrMkErr;
   1215   1.2    scottr 		return state_Fault;
   1216   1.2    scottr 	}
   1217   1.2    scottr 
   1218   1.2    scottr 	/* Success */
   1219   1.2    scottr 	return state_IOFinish;
   1220   1.2    scottr }
   1221   1.2    scottr 
   1222   1.2    scottr 
   1223   1.2    scottr /*
   1224   1.2    scottr  * fdstart_Write
   1225   1.2    scottr  *
   1226   1.2    scottr  * Insert a sector into a write buffer slot and mark the slot dirty.
   1227   1.2    scottr  */
   1228   1.2    scottr static int
   1229  1.31       chs fdstart_Write(fd_softc_t *fd)
   1230   1.2    scottr {
   1231   1.2    scottr 	int i;
   1232   1.2    scottr 
   1233   1.2    scottr 	/* XXX let's see... */
   1234   1.2    scottr 	fd->sHdr.side = fd->pos.side;
   1235   1.2    scottr 	fd->sHdr.sector = fd->pos.sector;
   1236   1.2    scottr 	fd->sHdr.track = fd->pos.track;
   1237   1.2    scottr 
   1238   1.2    scottr 	i = fd->pos.sector;
   1239   1.2    scottr 	fd->w_slots[i].secbuf = fd->current_buffer;
   1240   1.2    scottr 	fd->w_slots[i].valid = 1;	/* "valid" is a dirty buffer here */
   1241   1.2    scottr 
   1242   1.2    scottr 	if (TRACE_STRAT)
   1243   1.2    scottr 		printf("<%s c%d_h%d_s%d> (cached) ",
   1244   1.2    scottr 		    fd->ioDirection ? "Read" : "Write",
   1245   1.2    scottr 		    fd->pos.track, fd->pos.side, fd->pos.sector);
   1246   1.2    scottr 	return state_IOFinish;
   1247   1.2    scottr }
   1248   1.2    scottr 
   1249   1.2    scottr 
   1250   1.2    scottr 
   1251   1.2    scottr /*
   1252   1.2    scottr  * fdstart_Flush
   1253   1.2    scottr  *
   1254   1.2    scottr  * Flush dirty buffers in the track cache to disk.
   1255   1.2    scottr  */
   1256   1.2    scottr static int
   1257  1.31       chs fdstart_Flush(fd_softc_t *fd)
   1258   1.2    scottr {
   1259   1.2    scottr 	int state;
   1260   1.2    scottr 	int i, dcnt;
   1261   1.2    scottr 	diskPosition_t *pos;
   1262   1.2    scottr 	sectorHdr_t *shdr;
   1263  1.42    cegger 	iwm_softc_t *iwm = device_lookup_private(&iwm_cd, 0); /* XXX */
   1264  1.47       chs 
   1265   1.2    scottr 	dcnt = 0;
   1266   1.2    scottr 	pos = &fd->pos;
   1267   1.2    scottr 	shdr = &fd->sHdr;
   1268   1.2    scottr 
   1269   1.2    scottr 	if (TRACE_STRAT) {
   1270   1.2    scottr 		for (i=0; i < IWM_MAX_GCR_SECTORS; i++)
   1271   1.2    scottr 			if (fd->w_slots[i].valid) {
   1272   1.2    scottr 				printf("|%d", i);
   1273   1.2    scottr 				dcnt++;
   1274   1.2    scottr 			}
   1275   1.2    scottr 		printf("|\n");
   1276   1.2    scottr 
   1277   1.2    scottr 		printf(" <%s c%d_h%d_#s%d>\n",
   1278   1.2    scottr 		    fd->ioDirection ? "Read" : "Write",
   1279   1.2    scottr 		    pos->track, pos->side, dcnt);
   1280   1.2    scottr 	}
   1281   1.2    scottr 	(void)iwmSelectSide(pos->side);
   1282   1.2    scottr 	fd->iwmErr = iwmWriteSector(&fd->sHdr, fd->w_slots);
   1283   1.2    scottr 
   1284   1.2    scottr 	switch (fd->iwmErr) {
   1285   1.2    scottr 	case noErr:		/* Success */
   1286   1.2    scottr #ifdef DIAGNOSTIC
   1287   1.2    scottr 		/* XXX Panic if buffer not clean? */
   1288   1.2    scottr 		for (i=0; i<IWM_MAX_GCR_SECTORS; i++)
   1289   1.2    scottr 			if (0 != fd->w_slots[i].valid)
   1290   1.2    scottr 				printf("Oops! <c%d_h%d_s%d> not flushed.\n",
   1291   1.2    scottr 				    fd->pos.track, fd->pos.side,
   1292   1.2    scottr 				    fd->pos.sector);
   1293   1.2    scottr #endif
   1294   1.2    scottr 		if (TRACE_STRAT)
   1295   1.2    scottr 			printf("(Cache flushed, re-initialize) ");
   1296   1.2    scottr 		for (i=0; i < IWM_MAX_GCR_SECTORS; i++) {
   1297   1.2    scottr 			fd->w_slots[i].valid = 0;
   1298   1.2    scottr 			fd->w_slots[i].secbuf = NULL;
   1299   1.2    scottr 		}
   1300   1.2    scottr 		fd->seekRetries = 0;
   1301   1.2    scottr 		state = state_Exit;
   1302   1.2    scottr 		break;
   1303   1.2    scottr 
   1304   1.2    scottr 	case seekErr:		/* Bad seek? Retry */
   1305   1.2    scottr 		if (TRACE_STRAT) {
   1306   1.2    scottr 			printf("Wanted track %d, got %d, %d seek retries.\n",
   1307   1.2    scottr 			    pos->track, shdr->track, fd->seekRetries);
   1308   1.2    scottr 		}
   1309   1.2    scottr 		if (iwm->maxRetries > fd->seekRetries++) {
   1310   1.2    scottr 			fd->iwmErr = seek(fd, IWM_SEEK_RECAL);
   1311   1.2    scottr 			if (TRACE_STRAT) {
   1312   1.2    scottr 				printf("[%d]", fd->seekRetries);
   1313   1.1    scottr 			}
   1314   1.2    scottr 		}
   1315   1.2    scottr 		state = (0 == fd->iwmErr) ? state_Exit : state_Fault;
   1316   1.2    scottr 		break;
   1317   1.2    scottr 
   1318   1.2    scottr 	default:		/* General IWM IO error? */
   1319   1.2    scottr 		state = state_IOErr;
   1320   1.2    scottr 	}
   1321   1.2    scottr 	return state;
   1322   1.2    scottr }
   1323   1.2    scottr 
   1324   1.1    scottr 
   1325   1.2    scottr /*
   1326   1.2    scottr  * fdstart_IOFinish
   1327   1.2    scottr  *
   1328   1.2    scottr  * Prepare for next block, if any is available
   1329   1.2    scottr  */
   1330   1.2    scottr static int
   1331  1.31       chs fdstart_IOFinish(fd_softc_t *fd)
   1332   1.2    scottr {
   1333   1.2    scottr 	int state;
   1334   1.1    scottr 
   1335   1.2    scottr 	if (DISABLED && TRACE_STRAT)
   1336   1.2    scottr 		printf("%s c%d_h%d_s%d ok ",
   1337   1.2    scottr 		    fd->ioDirection ? "Read" : "Write",
   1338   1.2    scottr 		    fd->sHdr.track, fd->sHdr.side >> 3, fd->sHdr.sector);
   1339   1.2    scottr 
   1340   1.2    scottr 	fd->bytesDone += fd->currentType->sectorSize;
   1341   1.2    scottr 	fd->bytesLeft -= fd->currentType->sectorSize;
   1342   1.2    scottr 	fd->current_buffer += fd->currentType->sectorSize;
   1343   1.2    scottr 	/*
   1344   1.2    scottr 	 * Instead of recalculating the chs mapping for
   1345   1.2    scottr 	 * each and every sector, check for
   1346   1.2    scottr 	 * 'current sector# <= max sector#' and recalculate
   1347   1.2    scottr 	 * after overflow.
   1348   1.2    scottr 	 */
   1349   1.2    scottr 	fd->startBlk++;
   1350   1.2    scottr 	if (fd->bytesLeft > 0) {
   1351   1.2    scottr 		if (++fd->pos.sector < fd->pos.maxSect) {
   1352   1.1    scottr 			if (TRACE_STRAT)
   1353   1.2    scottr 				printf("continue");
   1354   1.2    scottr 			state = (fd->ioDirection == IWM_WRITE)
   1355   1.2    scottr 			    ? state_Write : state_Read;
   1356   1.2    scottr 		}
   1357   1.2    scottr 		else {
   1358   1.1    scottr 			/*
   1359   1.2    scottr 			 * Invalidate read cache when changing track;
   1360   1.2    scottr 			 * flush write cache to disk.
   1361   1.1    scottr 			 */
   1362   1.2    scottr 			if (fd->ioDirection == IWM_WRITE) {
   1363   1.2    scottr 				if (TRACE_STRAT)
   1364   1.2    scottr 					printf("flush ");
   1365   1.2    scottr 				state = (state_Exit == fdstart_Flush(fd))
   1366   1.2    scottr 				    ? state_Seek : state_IOErr;
   1367   1.1    scottr 			}
   1368   1.2    scottr 			else {
   1369   1.1    scottr 				if (TRACE_STRAT)
   1370   1.2    scottr 					printf("step ");
   1371   1.2    scottr 				invalidateCylinderCache(fd);
   1372   1.2    scottr 				state = state_Seek;
   1373   1.1    scottr 			}
   1374   1.2    scottr 		}
   1375   1.2    scottr 	} else {
   1376   1.2    scottr 		state = (fd->ioDirection == IWM_WRITE)
   1377   1.2    scottr 		    ? state_Flush : state_Exit;
   1378   1.2    scottr 	}
   1379   1.2    scottr 	return state;
   1380   1.2    scottr }
   1381   1.1    scottr 
   1382   1.1    scottr 
   1383   1.2    scottr /*
   1384   1.2    scottr  * fdstart_IOErr
   1385   1.2    scottr  *
   1386   1.2    scottr  * Bad IO, repeat
   1387   1.2    scottr  */
   1388   1.2    scottr static int
   1389  1.31       chs fdstart_IOErr(fd_softc_t *fd)
   1390   1.2    scottr {
   1391   1.2    scottr 	int state;
   1392  1.42    cegger 	iwm_softc_t *iwm = device_lookup_private(&iwm_cd, 0); /* XXX */
   1393   1.2    scottr 
   1394   1.2    scottr #ifdef DIAGNOSTIC
   1395   1.2    scottr 	printf("iwm%sSector() err = %d, %d retries, on c%d_h%d_s%d.\n",
   1396   1.2    scottr 	    fd->ioDirection ? "Read" : "Write",
   1397   1.2    scottr 	    fd->iwmErr, fd->ioRetries, fd->pos.track,
   1398   1.2    scottr 	    fd->pos.side, fd->pos.sector);
   1399   1.2    scottr #endif
   1400   1.2    scottr 	/* XXX Do statistics */
   1401   1.2    scottr 	if (fd->ioRetries++ < iwm->maxRetries)
   1402   1.2    scottr 		state = (fd->ioDirection == IWM_WRITE)
   1403   1.2    scottr 		    ? state_Flush : state_Read;
   1404   1.2    scottr 	else
   1405   1.2    scottr 		state = state_Fault;
   1406   1.2    scottr 	return state;
   1407   1.2    scottr }
   1408   1.1    scottr 
   1409   1.1    scottr 
   1410   1.2    scottr /*
   1411   1.2    scottr  * fdstart_Fault
   1412   1.2    scottr  *
   1413   1.2    scottr  * A non-recoverable error
   1414   1.2    scottr  */
   1415   1.2    scottr static int
   1416  1.31       chs fdstart_Fault(fd_softc_t *fd)
   1417   1.2    scottr {
   1418   1.1    scottr #ifdef DIAGNOSTIC
   1419   1.2    scottr 	printf("Seek retries %d, IO retries %d, sect retries %d :\n" \
   1420   1.2    scottr 	    "\t\t only found c%d_h%d_s%d \n",
   1421   1.2    scottr 	    fd->seekRetries, fd->ioRetries, fd->sectRetries,
   1422   1.2    scottr 	    fd->sHdr.track, fd->sHdr.side >> 3, fd->sHdr.sector);
   1423   1.2    scottr 	printf("A non-recoverable error: %d ", fd->iwmErr);
   1424   1.2    scottr #else
   1425   1.2    scottr 	/* ARGSUSED */
   1426   1.2    scottr #endif
   1427   1.2    scottr 	return state_Exit;
   1428   1.2    scottr }
   1429   1.2    scottr 
   1430   1.1    scottr 
   1431   1.2    scottr /*
   1432   1.2    scottr  * fdstart_Exit
   1433   1.2    scottr  *
   1434   1.2    scottr  * We are done, for good or bad
   1435   1.2    scottr  */
   1436   1.2    scottr static int
   1437  1.31       chs fdstart_Exit(fd_softc_t *fd)
   1438   1.2    scottr {
   1439   1.3    kleink 	struct buf *bp;
   1440   1.3    kleink #ifdef DIAGNOSTIC
   1441   1.2    scottr 	int i;
   1442   1.3    kleink #endif
   1443   1.2    scottr 
   1444   1.2    scottr 	invalidateCylinderCache(fd);
   1445   1.1    scottr 
   1446   1.2    scottr #ifdef DIAGNOSTIC
   1447   1.2    scottr 	/* XXX Panic if buffer not clean? */
   1448   1.2    scottr 	for (i=0; i<IWM_MAX_GCR_SECTORS; i++)
   1449   1.2    scottr 		if (0 != fd->w_slots[i].valid)
   1450   1.2    scottr 			printf("Oops! <c%d_h%d_s%d> not flushed.\n",
   1451   1.2    scottr 			    fd->pos.track, fd->pos.side, fd->pos.sector);
   1452   1.2    scottr #endif
   1453   1.1    scottr 
   1454  1.46      yamt 	bp = bufq_get(fd->bufQueue);
   1455   1.1    scottr 
   1456   1.2    scottr 	bp->b_resid = fd->bytesLeft;
   1457   1.2    scottr 	bp->b_error = (0 == fd->iwmErr) ? 0 : EIO;
   1458   1.1    scottr 
   1459   1.2    scottr 	if (TRACE_STRAT) {
   1460   1.2    scottr 		printf(" fdstart() finished job; fd->iwmErr = %d, b_error = %d",
   1461   1.2    scottr 		    fd->iwmErr, bp->b_error);
   1462   1.2    scottr 		if (DISABLED)
   1463  1.10   thorpej 			hexDump(bp->b_data, bp->b_bcount);
   1464   1.2    scottr 	}
   1465   1.2    scottr 	if (DISABLED && TRACE_STRAT)
   1466   1.4   thorpej 		printf(" Next buf (bufQueue first) at %p\n",
   1467  1.46      yamt 		    bufq_peek(fd->bufQueue));
   1468  1.19       mrg 	disk_unbusy(&fd->diskInfo, bp->b_bcount - bp->b_resid,
   1469  1.19       mrg 	    (bp->b_flags & B_READ));
   1470   1.2    scottr 	biodone(bp);
   1471   1.2    scottr 	/*
   1472   1.2    scottr 	 * Stop motor after 10s
   1473   1.2    scottr 	 *
   1474   1.2    scottr 	 * XXX Unloading the module while the timeout is still
   1475   1.2    scottr 	 *     running WILL crash the machine.
   1476   1.2    scottr 	 */
   1477   1.8   thorpej 	callout_reset(&fd->motor_ch, 10 * hz, motor_off, fd);
   1478   1.1    scottr 
   1479   1.2    scottr 	return state_Done;
   1480   1.1    scottr }
   1481   1.1    scottr 
   1482   1.1    scottr 
   1483   1.1    scottr /*
   1484   1.2    scottr  * remap_geometry
   1485   1.2    scottr  *
   1486   1.1    scottr  * Remap the rigid UN*X view of a disk's cylinder/sector geometry
   1487   1.1    scottr  * to our zone recorded real Sony drive by splitting the disk
   1488   1.1    scottr  * into zones.
   1489   1.1    scottr  *
   1490   1.1    scottr  * Loop {
   1491   1.1    scottr  * 	Look if logical block number is in current zone
   1492   1.1    scottr  *	NO:	Add # of tracks for current zone to track counter
   1493   1.1    scottr  *		Process next zone
   1494   1.1    scottr  *
   1495   1.1    scottr  *	YES:	Subtract (number of first sector of current zone times heads)
   1496   1.1    scottr  *		from logical block number, then break up the difference
   1497   1.1    scottr  *		in tracks/side/sectors (spt is constant within a zone).
   1498   1.1    scottr  *		Done
   1499   1.1    scottr  * }
   1500   1.1    scottr  */
   1501   1.1    scottr static void
   1502  1.31       chs remap_geometry(daddr_t block, int heads, diskPosition_t *loc)
   1503   1.1    scottr {
   1504   1.1    scottr 	int zone, spt;
   1505   1.1    scottr 	extern diskZone_t diskZones[];
   1506   1.1    scottr 
   1507   1.1    scottr 	loc->oldTrack = loc->track;
   1508   1.1    scottr 	loc->track = 0;
   1509  1.60     hauke 	spt = 0;
   1510   1.1    scottr 
   1511   1.1    scottr 	for (zone = 0; zone < IWM_GCR_DISK_ZONES; zone++) {
   1512   1.1    scottr 		if (block >= heads * (diskZones[zone].lastBlock + 1)) {
   1513   1.1    scottr 			/* Process full zones */
   1514   1.1    scottr 			loc->track += diskZones[zone].tracks;
   1515   1.1    scottr 		} else {
   1516   1.1    scottr 			/* Process partial zone */
   1517   1.1    scottr 			spt = diskZones[zone].sectPerTrack;
   1518   1.1    scottr 			block -= heads * diskZones[zone].firstBlock;
   1519   1.1    scottr 			loc->track += block / (spt * heads);
   1520   1.1    scottr 			loc->sector = (block % spt);
   1521   1.1    scottr 			loc->side = (block % (spt * heads)) / spt;
   1522   1.1    scottr 			break;
   1523   1.1    scottr 		}
   1524   1.1    scottr 	}
   1525   1.1    scottr 	loc->maxSect = spt;
   1526   1.1    scottr }
   1527   1.1    scottr 
   1528   1.1    scottr 
   1529   1.1    scottr /*
   1530   1.1    scottr  * motor_off
   1531   1.1    scottr  *
   1532   1.1    scottr  * Callback for timeout()
   1533   1.1    scottr  */
   1534   1.1    scottr static void
   1535  1.31       chs motor_off(void *param)
   1536   1.1    scottr {
   1537   1.1    scottr 	int spl;
   1538   1.1    scottr 	fd_softc_t *fd;
   1539   1.1    scottr 
   1540  1.47       chs 	fd = param;
   1541   1.1    scottr 	if (TRACE_STRAT)
   1542   1.1    scottr 		printf("iwm: Switching motor OFF (timeout).\n");
   1543   1.2    scottr 	spl = spl6();
   1544   1.1    scottr 	(void)iwmMotor(fd->unit, 0);
   1545   1.1    scottr 	fd->state &= ~IWM_FD_MOTOR_ON;
   1546   1.1    scottr 	splx(spl);
   1547   1.1    scottr }
   1548   1.1    scottr 
   1549   1.1    scottr 
   1550   1.1    scottr /*
   1551   1.1    scottr  * fdGetDiskLabel
   1552   1.1    scottr  *
   1553   1.1    scottr  * Set up disk label with parameters from current disk type.
   1554   1.1    scottr  * Then call the generic disklabel read routine which tries to
   1555   1.1    scottr  * read a label from disk and insert it. If it doesn't exist use
   1556   1.1    scottr  * our defaults.
   1557   1.1    scottr  */
   1558   1.1    scottr static void
   1559  1.31       chs fdGetDiskLabel(fd_softc_t *fd, dev_t dev)
   1560   1.1    scottr {
   1561  1.23       dsl 	const char *msg;
   1562   1.1    scottr 	int fdType;
   1563   1.1    scottr 	struct disklabel *lp;
   1564   1.1    scottr 	struct cpu_disklabel *clp;
   1565   1.1    scottr 
   1566   1.1    scottr 	if (TRACE_IOCTL)
   1567  1.45     oster 		printf("iwm: fdGetDiskLabel() for disk %" PRIu64 ".\n",
   1568  1.45     oster 		    (dev_t) (minor(dev) / MAXPARTITIONS));
   1569   1.1    scottr 	fdType = minor(dev) % MAXPARTITIONS;
   1570   1.1    scottr 	lp = fd->diskInfo.dk_label;
   1571   1.1    scottr 	clp = fd->diskInfo.dk_cpulabel;
   1572   1.2    scottr 	memset(lp, 0, sizeof(struct disklabel));
   1573   1.2    scottr 	memset(clp, 0, sizeof(struct cpu_disklabel));
   1574   1.1    scottr 	/*
   1575   1.1    scottr 	 * How to describe a drive with a variable # of sectors per
   1576   1.1    scottr 	 * track (8..12) and variable rpm (300..550)? Apple came up
   1577   1.1    scottr 	 * with ZBR in 1983! Un*x drive management sucks.
   1578   1.1    scottr 	 */
   1579  1.54  christos 	lp->d_type = DKTYPE_FLOPPY;
   1580   1.1    scottr 	lp->d_rpm = 300;
   1581   1.1    scottr 	lp->d_secsize = fd->currentType->sectorSize;
   1582   1.1    scottr 	lp->d_ntracks = fd->currentType->heads;
   1583   1.1    scottr 	lp->d_ncylinders = fd->currentType->tracks;
   1584   1.1    scottr 	lp->d_nsectors = fd->currentType->secPerTrack;
   1585   1.1    scottr 	lp->d_secpercyl = fd->currentType->secPerCyl;
   1586   1.1    scottr 	lp->d_secperunit = fd->currentType->secPerDisk;
   1587   1.1    scottr 	lp->d_interleave = fd->currentType->interleave;
   1588   1.2    scottr 	lp->d_trkseek = fd->currentType->stepRate;
   1589   1.1    scottr 
   1590  1.54  christos 	strcpy(lp->d_typename, dktypenames[DKTYPE_FLOPPY]);
   1591   1.1    scottr 	strncpy(lp->d_packname, "fictitious", sizeof(lp->d_packname));
   1592   1.1    scottr 
   1593   1.1    scottr 	lp->d_npartitions = fdType + 1;
   1594   1.1    scottr 	lp->d_partitions[fdType].p_offset = 0;
   1595   1.1    scottr 	lp->d_partitions[fdType].p_size = lp->d_secperunit;
   1596   1.1    scottr 	lp->d_partitions[fdType].p_fstype = FS_BSDFFS;
   1597   1.1    scottr 	lp->d_partitions[fdType].p_fsize = 512;
   1598   1.1    scottr 	lp->d_partitions[fdType].p_frag = 8;
   1599   1.1    scottr 
   1600   1.1    scottr 	lp->d_magic = DISKMAGIC;
   1601   1.1    scottr 	lp->d_magic2 = DISKMAGIC;
   1602   1.1    scottr 	lp->d_checksum = dkcksum(lp);
   1603   1.1    scottr 	/*
   1604   1.1    scottr 	 * Call the generic disklabel extraction routine.  If we don't
   1605   1.1    scottr 	 * find a label on disk, keep our faked one.
   1606   1.1    scottr 	 */
   1607   1.1    scottr 	if (TRACE_OPEN)
   1608   1.1    scottr 		printf(" now calling readdisklabel()...\n");
   1609   1.1    scottr 
   1610   1.1    scottr 	msg = readdisklabel(dev, fdstrategy, lp, clp);
   1611   1.1    scottr 	if (msg == NULL) {
   1612   1.1    scottr 		strncpy(lp->d_packname, "default label",
   1613   1.1    scottr 		    sizeof(lp->d_packname));	/* XXX - ?? */
   1614   1.1    scottr 	}
   1615   1.2    scottr #ifdef IWM_DEBUG
   1616   1.1    scottr 	else
   1617   1.1    scottr 		printf("iwm: %s.\n", msg);
   1618   1.1    scottr #endif
   1619   1.1    scottr 	if (TRACE_OPEN)
   1620   1.1    scottr 		fdPrintDiskLabel(lp);
   1621   1.1    scottr }
   1622   1.1    scottr 
   1623   1.1    scottr 
   1624   1.2    scottr 
   1625   1.2    scottr /*
   1626   1.2    scottr  * initCylinderCache
   1627   1.2    scottr  *
   1628   1.2    scottr  * Allocate cylinder cache and set up pointers to sectors.
   1629   1.2    scottr  */
   1630   1.2    scottr static int
   1631  1.31       chs initCylinderCache(fd_softc_t *fd)
   1632   1.2    scottr {
   1633   1.2    scottr 	int i;
   1634   1.2    scottr 	int err;
   1635   1.2    scottr 	int secsize;
   1636   1.2    scottr 
   1637   1.2    scottr 	err = 0;
   1638   1.2    scottr 	secsize = fd->currentType->sectorSize;
   1639   1.2    scottr 	fd->cachedSide = 0;
   1640   1.2    scottr 
   1641  1.58   thorpej 	fd->cbuf = kmem_alloc(IWM_MAX_GCR_SECTORS * secsize, KM_SLEEP);
   1642   1.2    scottr 	if (NULL == fd->cbuf)
   1643   1.2    scottr 		err = ENOMEM;
   1644   1.2    scottr 	else
   1645   1.2    scottr 		for (i=0; i < IWM_MAX_GCR_SECTORS; i++) {
   1646   1.2    scottr 			fd->w_slots[i].valid = 0;
   1647   1.2    scottr 			fd->w_slots[i].secbuf = NULL;
   1648   1.2    scottr 
   1649   1.2    scottr 			fd->r_slots[i].valid = 0;
   1650   1.2    scottr 			fd->r_slots[i].secbuf = fd->cbuf + i * secsize;
   1651   1.2    scottr 		}
   1652   1.2    scottr 	return err;
   1653   1.2    scottr }
   1654   1.2    scottr 
   1655   1.2    scottr 
   1656   1.2    scottr /*
   1657   1.2    scottr  * invalidateCylinderCache
   1658   1.2    scottr  *
   1659   1.2    scottr  * Switching cylinders (tracks?) invalidates the read cache.
   1660   1.2    scottr  */
   1661   1.2    scottr static void
   1662  1.31       chs invalidateCylinderCache(fd_softc_t *fd)
   1663   1.2    scottr {
   1664   1.2    scottr 	int i;
   1665   1.2    scottr 
   1666   1.2    scottr 	fd->cachedSide = 0;
   1667   1.2    scottr 	for (i=0; i < IWM_MAX_GCR_SECTORS; i++) {
   1668   1.2    scottr 		fd->r_slots[i].valid = 0;
   1669   1.2    scottr 	}
   1670   1.2    scottr }
   1671   1.2    scottr 
   1672   1.2    scottr 
   1673   1.1    scottr /*
   1674   1.1    scottr  * getFDType
   1675   1.1    scottr  *
   1676   1.1    scottr  * return pointer to disk format description
   1677   1.1    scottr  */
   1678   1.1    scottr static fdInfo_t *
   1679  1.31       chs getFDType(short unit)
   1680   1.1    scottr {
   1681   1.1    scottr 	int driveFlags;
   1682   1.1    scottr 	fdInfo_t *thisType;
   1683   1.1    scottr 	extern fdInfo_t fdTypes[];
   1684   1.1    scottr 
   1685   1.1    scottr 	driveFlags = iwmCheckDrive(unit);
   1686   1.1    scottr /*
   1687   1.1    scottr  * Drive flags are: Bit  0 - 1 = Drive is double sided
   1688   1.1    scottr  *			 1 - 1 = No disk inserted
   1689   1.1    scottr  *			 2 - 1 = Motor is off
   1690  1.21       wiz  *			 3 - 1 = Disk is writable
   1691   1.1    scottr  *			 4 - 1 = Disk is DD (800/720K)
   1692   1.1    scottr  *			31 - 1 = No drive / invalid drive #
   1693   1.1    scottr  */
   1694   1.1    scottr 	if (TRACE_CONFIG) {
   1695   1.1    scottr 		printf("iwm: Drive %d says 0x0%x (%d)\n",
   1696   1.1    scottr 		    unit, driveFlags, driveFlags);
   1697   1.1    scottr 	}
   1698   1.1    scottr 	if (driveFlags < 0)
   1699   1.1    scottr 		thisType = NULL;/* no such drive	 */
   1700   1.1    scottr 	else
   1701   1.1    scottr 		if (driveFlags & 0x01)
   1702   1.1    scottr 			thisType = &fdTypes[1];	/* double sided		 */
   1703   1.1    scottr 		else
   1704   1.1    scottr 			thisType = &fdTypes[0];	/* single sided		 */
   1705   1.1    scottr 
   1706   1.1    scottr 	return thisType;
   1707   1.1    scottr }
   1708   1.1    scottr 
   1709   1.1    scottr 
   1710   1.1    scottr /*
   1711   1.1    scottr  * fdDeviceToType
   1712   1.1    scottr  *
   1713   1.1    scottr  * maps the minor device number (elsewhere: partition type) to
   1714   1.1    scottr  * a corresponding disk format.
   1715   1.1    scottr  * This is currently:
   1716   1.1    scottr  * 	fdXa	default (800K GCR)
   1717   1.1    scottr  *	fdXb	400K GCR
   1718   1.1    scottr  *	fdXc	800K GCR
   1719   1.1    scottr  */
   1720   1.1    scottr static fdInfo_t *
   1721  1.31       chs fdDeviceToType(fd_softc_t *fd, dev_t dev)
   1722   1.1    scottr {
   1723   1.1    scottr 	int type;
   1724   1.1    scottr 	fdInfo_t *thisInfo;
   1725   1.1    scottr 	/* XXX This broke with egcs 1.0.2 */
   1726   1.1    scottr 	/* extern fdInfo_t	fdTypes[]; */
   1727   1.1    scottr 
   1728   1.1    scottr 	type = minor(dev) % MAXPARTITIONS;	/* 1,2,... */
   1729   1.1    scottr 	if (type > sizeof(fdTypes) / sizeof(fdTypes[0]))
   1730   1.1    scottr 		thisInfo = NULL;
   1731   1.1    scottr 	else
   1732   1.1    scottr 		thisInfo = (type == 0) ? fd->defaultType : &fdTypes[type - 1];
   1733   1.1    scottr 	return thisInfo;
   1734   1.1    scottr }
   1735   1.1    scottr 
   1736   1.1    scottr 
   1737   1.1    scottr /*
   1738   1.1    scottr  * seek
   1739   1.1    scottr  *
   1740   1.1    scottr  * Step to given track; optionally restore to track zero before
   1741   1.1    scottr  * and/or verify correct track.
   1742   1.1    scottr  * Note that any necessary retries are done here.
   1743   1.1    scottr  * We keep the current position on disk in a 'struct diskPosition'.
   1744   1.1    scottr  */
   1745   1.1    scottr static int
   1746  1.31       chs seek(fd_softc_t *fd, int style)
   1747   1.1    scottr {
   1748   1.1    scottr 	int state, done;
   1749   1.1    scottr 	int err, ierr;
   1750   1.1    scottr 	int steps;
   1751   1.2    scottr 
   1752   1.2    scottr 	diskPosition_t *loc;
   1753   1.1    scottr 	sectorHdr_t hdr;
   1754   1.1    scottr 	char action[32];
   1755  1.42    cegger 	iwm_softc_t *iwm = device_lookup_private(&iwm_cd, 0); /* XXX */
   1756   1.1    scottr 
   1757  1.33       jmc 	const char *stateDesc[] = {
   1758   1.1    scottr 		"Init",
   1759   1.1    scottr 		"Seek",
   1760   1.1    scottr 		"Recalibrate",
   1761   1.1    scottr 		"Verify",
   1762   1.1    scottr 		"Exit"
   1763   1.1    scottr 	};
   1764   1.1    scottr 	enum {
   1765  1.33       jmc 		seek_state_Init = 0,
   1766  1.33       jmc 		seek_state_Seek,
   1767  1.33       jmc 		seek_state_Recalibrate,
   1768  1.33       jmc 		seek_state_Verify,
   1769  1.33       jmc 		seek_state_Exit
   1770   1.1    scottr 	};
   1771   1.2    scottr 	/* XXX egcs */
   1772   1.2    scottr 	done = err = ierr = 0;
   1773   1.2    scottr 	fd->seekRetries = 0;
   1774   1.2    scottr 	fd->verifyRetries = 0;
   1775   1.2    scottr 
   1776   1.2    scottr 	loc = &fd->pos;
   1777   1.2    scottr 
   1778  1.33       jmc 	state = seek_state_Init;
   1779   1.1    scottr 	do {
   1780   1.1    scottr 		if (TRACE_STEP)
   1781   1.1    scottr 			printf(" seek state %d [%s].\n",
   1782   1.1    scottr 			    state, stateDesc[state]);
   1783   1.1    scottr 		switch (state) {
   1784   1.1    scottr 
   1785  1.33       jmc 		case seek_state_Init:
   1786   1.1    scottr 			if (TRACE_STEP)
   1787   1.1    scottr 				printf("Current track is %d, new track %d.\n",
   1788   1.1    scottr 				    loc->oldTrack, loc->track);
   1789   1.2    scottr 			memset(&hdr, 0, sizeof(hdr));
   1790   1.1    scottr 			err = ierr = 0;
   1791   1.2    scottr 			fd->seekRetries = 0;
   1792   1.2    scottr 			fd->verifyRetries = 0;
   1793   1.1    scottr 			state = (style == IWM_SEEK_RECAL)
   1794  1.33       jmc 			    ? seek_state_Recalibrate : seek_state_Seek;
   1795   1.1    scottr 			done = 0;
   1796   1.1    scottr 			break;
   1797   1.1    scottr 
   1798  1.33       jmc 		case seek_state_Recalibrate:
   1799   1.1    scottr 			ierr = iwmTrack00();
   1800   1.1    scottr 			if (ierr == 0) {
   1801   1.1    scottr 				loc->oldTrack = 0;
   1802  1.33       jmc 				state = seek_state_Seek;
   1803   1.1    scottr 			} else {
   1804   1.1    scottr 				strncpy(action, "Recalibrate (track 0)",
   1805   1.1    scottr 				    sizeof(action));
   1806  1.33       jmc 				state = seek_state_Exit;
   1807   1.1    scottr 			}
   1808   1.1    scottr 			break;
   1809   1.1    scottr 
   1810  1.33       jmc 		case seek_state_Seek:
   1811   1.1    scottr 			ierr = 0;
   1812   1.1    scottr 			steps = loc->track - loc->oldTrack;
   1813   1.1    scottr 
   1814   1.1    scottr 			if (steps != 0)
   1815   1.1    scottr 				ierr = iwmSeek(steps);
   1816   1.1    scottr 			if (ierr == 0) {
   1817   1.1    scottr 				/* No error or nothing to do */
   1818   1.1    scottr 				state = (style == IWM_SEEK_VERIFY)
   1819  1.33       jmc 				    ? seek_state_Verify : seek_state_Exit;
   1820   1.1    scottr 			} else {
   1821   1.2    scottr 				if (fd->seekRetries++ < iwm->maxRetries)
   1822  1.33       jmc 					state = seek_state_Recalibrate;
   1823   1.1    scottr 				else {
   1824   1.1    scottr 					strncpy(action, "Seek retries",
   1825   1.1    scottr 					    sizeof(action));
   1826  1.33       jmc 					state = seek_state_Exit;
   1827   1.1    scottr 				}
   1828   1.1    scottr 			}
   1829   1.1    scottr 			break;
   1830   1.1    scottr 
   1831  1.33       jmc 		case seek_state_Verify:
   1832   1.2    scottr 			ierr = checkTrack(loc, TRACE_STEP);
   1833   1.1    scottr 			if (ierr == 0 && loc->track == hdr.track)
   1834  1.33       jmc 				state = seek_state_Exit;
   1835   1.1    scottr 			else {
   1836   1.2    scottr 				if (fd->verifyRetries++ < iwm->maxRetries)
   1837  1.33       jmc 					state = seek_state_Recalibrate;
   1838   1.1    scottr 				else {
   1839   1.1    scottr 					strncpy(action, "Verify retries",
   1840   1.1    scottr 					    sizeof(action));
   1841  1.33       jmc 					state = seek_state_Exit;
   1842   1.1    scottr 				}
   1843   1.1    scottr 			}
   1844   1.1    scottr 			break;
   1845   1.1    scottr 
   1846  1.33       jmc 		case seek_state_Exit:
   1847   1.1    scottr 			if (ierr == 0) {
   1848   1.1    scottr 				loc->oldTrack = loc->track;
   1849   1.1    scottr 				err = 0;
   1850   1.1    scottr 				/* Give the head some time to settle down */
   1851   1.1    scottr 				delay(3000);
   1852   1.1    scottr 			} else {
   1853   1.1    scottr #ifdef DIAGNOSTIC
   1854   1.1    scottr 				printf(" seek() action \"%s\", err = %d.\n",
   1855   1.1    scottr 				    action, ierr);
   1856   1.1    scottr #endif
   1857   1.1    scottr 				err = EIO;
   1858   1.1    scottr 			}
   1859   1.1    scottr 			done = 1;
   1860   1.1    scottr 			break;
   1861   1.1    scottr 		}
   1862   1.1    scottr 	} while (!done);
   1863   1.1    scottr 	return err;
   1864   1.1    scottr }
   1865   1.1    scottr 
   1866   1.1    scottr 
   1867   1.1    scottr /*
   1868   1.1    scottr  * checkTrack
   1869   1.1    scottr  *
   1870   1.1    scottr  * After positioning, get a sector header for validation
   1871   1.1    scottr  */
   1872   1.1    scottr static int
   1873  1.31       chs checkTrack(diskPosition_t *loc, int debugFlag)
   1874   1.1    scottr {
   1875   1.1    scottr 	int spl;
   1876   1.1    scottr 	int iwmErr;
   1877   1.1    scottr 	sectorHdr_t hdr;
   1878   1.1    scottr 
   1879   1.2    scottr 	spl = spl6();
   1880   1.2    scottr 	iwmSelectSide(loc->side);
   1881   1.1    scottr 	iwmErr = iwmReadSectHdr(&hdr);
   1882   1.1    scottr 	splx(spl);
   1883   1.1    scottr 	if (debugFlag) {
   1884   1.1    scottr 		printf("Seeked for %d, got at %d, Hdr read err %d.\n",
   1885   1.2    scottr 		    loc->track, hdr.track, iwmErr);
   1886   1.1    scottr 	}
   1887   1.1    scottr 	return iwmErr;
   1888   1.1    scottr }
   1889   1.1    scottr 
   1890   1.1    scottr 
   1891   1.1    scottr /* Debugging stuff */
   1892   1.1    scottr 
   1893   1.1    scottr static void
   1894  1.31       chs hexDump(u_char *buf, int len)
   1895   1.1    scottr {
   1896   1.1    scottr 	int i, j;
   1897   1.1    scottr 	u_char ch;
   1898   1.1    scottr 
   1899   1.1    scottr 	printf("\nDump %d from %p:\n", len, buf);
   1900   1.1    scottr 	i = j = 0;
   1901   1.1    scottr 	if (NULL != buf) do {
   1902   1.1    scottr 		printf("%04x: ", i);
   1903   1.1    scottr 		for (j = 0; j < 8; j++)
   1904   1.1    scottr 			printf("%02x ", buf[i + j]);
   1905   1.1    scottr 		printf(" ");
   1906   1.1    scottr 		for (j = 8; j < 16; j++)
   1907   1.1    scottr 			printf("%02x ", buf[i + j]);
   1908   1.1    scottr 		printf(" ");
   1909   1.1    scottr 		for (j = 0; j < 16; j++) {
   1910   1.1    scottr 			ch = buf[i + j];
   1911   1.1    scottr 			if (ch > 31 && ch < 127)
   1912   1.1    scottr 				printf("%c", ch);
   1913   1.1    scottr 			else
   1914   1.1    scottr 				printf(".");
   1915   1.1    scottr 		}
   1916   1.1    scottr 		printf("\n");
   1917   1.1    scottr 		i += 16;
   1918   1.1    scottr 	} while (len > i);
   1919   1.1    scottr }
   1920   1.1    scottr 
   1921   1.1    scottr 
   1922   1.1    scottr static void
   1923  1.31       chs fdPrintDiskLabel(struct disklabel *lp)
   1924   1.1    scottr {
   1925   1.1    scottr 	int i;
   1926   1.1    scottr 
   1927   1.1    scottr 	printf("iwm: Disklabel entries of current floppy.\n");
   1928   1.1    scottr 	printf("\t d_type:\t%d (%s)\n", lp->d_type,
   1929   1.2    scottr 	    dktypenames[lp->d_type]);
   1930   1.1    scottr 	printf("\t d_typename:\t%s\n", lp->d_typename);
   1931   1.1    scottr 	printf("\t d_packname:\t%s\n", lp->d_packname);
   1932   1.1    scottr 
   1933   1.1    scottr 	printf("\t d_secsize:\t%d\n", lp->d_secsize);
   1934   1.1    scottr 	printf("\t d_nsectors:\t%d\n", lp->d_nsectors);
   1935   1.1    scottr 	printf("\t d_ntracks:\t%d\n", lp->d_ntracks);
   1936   1.1    scottr 	printf("\t d_ncylinders:\t%d\n", lp->d_ncylinders);
   1937   1.1    scottr 	printf("\t d_secpercyl:\t%d\n", lp->d_secpercyl);
   1938   1.1    scottr 	printf("\t d_secperunit:\t%d\n", lp->d_secperunit);
   1939   1.1    scottr 
   1940   1.1    scottr 	printf("\t d_rpm: \t%d\n", lp->d_rpm);
   1941   1.1    scottr 	printf("\t d_interleave:\t%d\n", lp->d_interleave);
   1942   1.2    scottr 	printf("\t d_trkseek:\t%d [ms]\n", lp->d_trkseek);
   1943   1.1    scottr 
   1944   1.1    scottr 	printf(" d_npartitions:\t%d\n", lp->d_npartitions);
   1945   1.1    scottr 	for (i = 0; i < lp->d_npartitions; i++) {
   1946   1.1    scottr 		printf("\t d_partitions[%d].p_offset:\t%d\n", i,
   1947   1.1    scottr 		    lp->d_partitions[i].p_offset);
   1948   1.1    scottr 		printf("\t d_partitions[%d].p_size:\t%d\n", i,
   1949   1.1    scottr 		    lp->d_partitions[i].p_size);
   1950   1.1    scottr 		printf("\t d_partitions[%d].p_fstype:\t%d (%s)\n", i,
   1951   1.1    scottr 		    lp->d_partitions[i].p_fstype,
   1952   1.1    scottr 		    fstypenames[lp->d_partitions[i].p_fstype]);
   1953   1.1    scottr 		printf("\t d_partitions[%d].p_frag:\t%d\n", i,
   1954   1.1    scottr 		    lp->d_partitions[i].p_frag);
   1955   1.1    scottr 		printf("\n");
   1956   1.1    scottr 	}
   1957   1.1    scottr }
   1958