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