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