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