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