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