wd.c revision 1.146 1 /* $NetBSD: wd.c,v 1.146 1996/03/01 04:08:51 mycroft Exp $ */
2
3 /*
4 * Copyright (c) 1994, 1995 Charles M. Hannum. All rights reserved.
5 *
6 * DMA and multi-sector PIO handling are derived from code contributed by
7 * Onno van der Linden.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. All advertising materials mentioning features or use of this software
18 * must display the following acknowledgement:
19 * This product includes software developed by Charles M. Hannum.
20 * 4. The name of the author may not be used to endorse or promote products
21 * derived from this software without specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
24 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
25 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
26 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
27 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
28 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
29 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
30 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
31 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
32 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 */
34
35 #include <sys/param.h>
36 #include <sys/systm.h>
37 #include <sys/kernel.h>
38 #include <sys/conf.h>
39 #include <sys/file.h>
40 #include <sys/stat.h>
41 #include <sys/ioctl.h>
42 #include <sys/buf.h>
43 #include <sys/uio.h>
44 #include <sys/malloc.h>
45 #include <sys/device.h>
46 #include <sys/disklabel.h>
47 #include <sys/disk.h>
48 #include <sys/syslog.h>
49
50 #include <vm/vm.h>
51
52 #include <machine/cpu.h>
53 #include <machine/pio.h>
54
55 #include <dev/isa/isavar.h>
56 #include <dev/isa/isadmavar.h>
57 #include <dev/isa/wdreg.h>
58
59 #define WAITTIME (4 * hz) /* time to wait for a completion */
60 #define RECOVERYTIME (hz / 2) /* time to recover from an error */
61
62 #define WDCDELAY 100
63 #define WDCNDELAY 100000 /* delay = 100us; so 10s for a controller state change */
64 #if 0
65 /* If you enable this, it will report any delays more than 100us * N long. */
66 #define WDCNDELAY_DEBUG 10
67 #endif
68
69 #define WDIORETRIES 5 /* number of retries before giving up */
70
71 #define WDUNIT(dev) DISKUNIT(dev)
72 #define WDPART(dev) DISKPART(dev)
73 #define MAKEWDDEV(maj, unit, part) MAKEDISKDEV(maj, unit, part)
74
75 #define WDLABELDEV(dev) (MAKEWDDEV(major(dev), WDUNIT(dev), RAW_PART))
76
77 struct wd_softc {
78 struct device sc_dev;
79 struct disk sc_dk;
80
81 /* Information about the current transfer: */
82 daddr_t sc_blkno; /* starting block number */
83 int sc_bcount; /* byte count left */
84 int sc_skip; /* bytes already transferred */
85 int sc_nblks; /* number of blocks currently transferring */
86 int sc_nbytes; /* number of bytes currently transferring */
87
88 /* Long-term state: */
89 int sc_drive; /* physical unit number */
90 int sc_state; /* control state */
91 #define RECAL 0 /* recalibrate */
92 #define RECAL_WAIT 1 /* done recalibrating */
93 #define GEOMETRY 2 /* upload geometry */
94 #define GEOMETRY_WAIT 3 /* done uploading geometry */
95 #define MULTIMODE 4 /* set multiple mode */
96 #define MULTIMODE_WAIT 5 /* done setting multiple mode */
97 #define OPEN 6 /* done with open */
98 int sc_mode; /* transfer mode */
99 #define WDM_PIOSINGLE 0 /* single-sector PIO */
100 #define WDM_PIOMULTI 1 /* multi-sector PIO */
101 #define WDM_DMA 2 /* DMA */
102 int sc_multiple; /* multiple for WDM_PIOMULTI */
103 int sc_flags; /* drive characteistics found */
104 #define WDF_LOCKED 0x01
105 #define WDF_WANTED 0x02
106 #define WDF_WLABEL 0x04 /* label is writable */
107 #define WDF_LABELLING 0x08 /* writing label */
108 /* XXX Nothing resets this yet, but disk change sensing will when ATAPI is
109 implemented. */
110 #define WDF_LOADED 0x10 /* parameters loaded */
111 #define WDF_32BIT 0x20 /* can do 32-bit transfer */
112
113 struct wdparams sc_params; /* ESDI/ATA drive parameters */
114 daddr_t sc_badsect[127]; /* 126 plus trailing -1 marker */
115
116 TAILQ_ENTRY(wd_softc) sc_drivechain;
117 struct buf sc_q;
118 };
119
120 struct wdc_softc {
121 struct device sc_dev;
122 void *sc_ih;
123
124 int sc_iobase; /* I/O port base */
125 int sc_drq; /* DMA channel */
126
127 TAILQ_HEAD(drivehead, wd_softc) sc_drives;
128 int sc_flags;
129 #define WDCF_ACTIVE 0x01 /* controller is active */
130 #define WDCF_SINGLE 0x02 /* sector at a time mode */
131 #define WDCF_ERROR 0x04 /* processing a disk error */
132 #define WDCF_WANTED 0x08 /* XXX locking for wd_get_parms() */
133 int sc_errors; /* errors during current transfer */
134 u_char sc_status; /* copy of status register */
135 u_char sc_error; /* copy of error register */
136 };
137
138 int wdcprobe __P((struct device *, void *, void *));
139 void wdcattach __P((struct device *, struct device *, void *));
140
141 struct cfdriver wdccd = {
142 NULL, "wdc", wdcprobe, wdcattach, DV_DULL, sizeof(struct wdc_softc)
143 };
144
145 int wdprobe __P((struct device *, void *, void *));
146 void wdattach __P((struct device *, struct device *, void *));
147
148 struct cfdriver wdcd = {
149 NULL, "wd", wdprobe, wdattach, DV_DISK, sizeof(struct wd_softc)
150 };
151
152 void wdgetdisklabel __P((struct wd_softc *));
153 int wd_get_parms __P((struct wd_softc *));
154 void wdstrategy __P((struct buf *));
155 void wdstart __P((struct wd_softc *));
156
157 struct dkdriver wddkdriver = { wdstrategy };
158
159 void wdfinish __P((struct wd_softc *, struct buf *));
160 int wdcintr __P((void *));
161 void wdcstart __P((struct wdc_softc *));
162 int wdcommand __P((struct wd_softc *, int, int, int, int, int));
163 int wdcommandshort __P((struct wdc_softc *, int, int));
164 int wdcontrol __P((struct wd_softc *));
165 int wdsetctlr __P((struct wd_softc *));
166 static void bad144intern __P((struct wd_softc *));
167 int wdcreset __P((struct wdc_softc *));
168 void wdcrestart __P((void *arg));
169 void wdcunwedge __P((struct wdc_softc *));
170 void wdctimeout __P((void *arg));
171 void wderror __P((void *, struct buf *, char *));
172 int wdcwait __P((struct wdc_softc *, int));
173 /* ST506 spec says that if READY or SEEKCMPLT go off, then the read or write
174 command is aborted. */
175 #define wait_for_drq(d) wdcwait(d, WDCS_DRDY | WDCS_DSC | WDCS_DRQ)
176 #define wait_for_ready(d) wdcwait(d, WDCS_DRDY | WDCS_DSC)
177 #define wait_for_unbusy(d) wdcwait(d, 0)
178
179 int
180 wdcprobe(parent, match, aux)
181 struct device *parent;
182 void *match, *aux;
183 {
184 struct wdc_softc *wdc = match;
185 struct isa_attach_args *ia = aux;
186 int iobase;
187
188 wdc->sc_iobase = iobase = ia->ia_iobase;
189
190 /* Check if we have registers that work. */
191 outb(iobase+wd_error, 0x5a); /* Error register not writable, */
192 outb(iobase+wd_cyl_lo, 0xa5); /* but all of cyllo are. */
193 if (inb(iobase+wd_error) == 0x5a || inb(iobase+wd_cyl_lo) != 0xa5)
194 return 0;
195
196 if (wdcreset(wdc) != 0) {
197 delay(500000);
198 if (wdcreset(wdc) != 0)
199 return 0;
200 }
201
202 /* Select drive 0. */
203 outb(iobase+wd_sdh, WDSD_IBM | 0);
204
205 /* Wait for controller to become ready. */
206 if (wait_for_unbusy(wdc) < 0)
207 return 0;
208
209 /* Start drive diagnostics. */
210 outb(iobase+wd_command, WDCC_DIAGNOSE);
211
212 /* Wait for command to complete. */
213 if (wait_for_unbusy(wdc) < 0)
214 return 0;
215
216 ia->ia_iosize = 8;
217 ia->ia_msize = 0;
218 return 1;
219 }
220
221 struct wdc_attach_args {
222 int wa_drive;
223 };
224
225 int
226 wdprint(aux, wdc)
227 void *aux;
228 char *wdc;
229 {
230 struct wdc_attach_args *wa = aux;
231
232 if (!wdc)
233 printf(" drive %d", wa->wa_drive);
234 return QUIET;
235 }
236
237 void
238 wdcattach(parent, self, aux)
239 struct device *parent, *self;
240 void *aux;
241 {
242 struct wdc_softc *wdc = (void *)self;
243 struct isa_attach_args *ia = aux;
244 struct wdc_attach_args wa;
245
246 TAILQ_INIT(&wdc->sc_drives);
247 wdc->sc_drq = ia->ia_drq;
248
249 printf("\n");
250
251 wdc->sc_ih = isa_intr_establish(ia->ia_irq, IST_EDGE, IPL_BIO, wdcintr,
252 wdc);
253
254 for (wa.wa_drive = 0; wa.wa_drive < 2; wa.wa_drive++)
255 (void)config_found(self, (void *)&wa, wdprint);
256 }
257
258 int
259 wdprobe(parent, match, aux)
260 struct device *parent;
261 void *match, *aux;
262 {
263 struct wdc_softc *wdc = (void *)parent;
264 struct cfdata *cf = match;
265 struct wdc_attach_args *wa = aux;
266 int drive = wa->wa_drive;
267
268 if (cf->cf_loc[0] != -1 && cf->cf_loc[0] != drive)
269 return 0;
270
271 if (wdcommandshort(wdc, drive, WDCC_RECAL) != 0 ||
272 wait_for_ready(wdc) != 0)
273 return 0;
274
275 return 1;
276 }
277
278 void
279 wdattach(parent, self, aux)
280 struct device *parent, *self;
281 void *aux;
282 {
283 struct wd_softc *wd = (void *)self;
284 struct wdc_softc *wdc = (void *)parent;
285 struct wdc_attach_args *wa = aux;
286 int i, blank;
287 char buf[41], c, *p, *q;
288
289 wd->sc_drive = wa->wa_drive;
290
291 /*
292 * Initialize and attach the disk structure.
293 */
294 wd->sc_dk.dk_driver = &wddkdriver;
295 wd->sc_dk.dk_name = wd->sc_dev.dv_xname;
296 disk_attach(&wd->sc_dk);
297
298 wd_get_parms(wd);
299 for (blank = 0, p = wd->sc_params.wdp_model, q = buf, i = 0;
300 i < sizeof(wd->sc_params.wdp_model); i++) {
301 c = *p++;
302 if (c == '\0')
303 break;
304 if (c != ' ') {
305 if (blank) {
306 *q++ = ' ';
307 blank = 0;
308 }
309 *q++ = c;
310 } else
311 blank = 1;
312 }
313 *q++ = '\0';
314
315 printf(": %dMB, %d cyl, %d head, %d sec, %d bytes/sec <%s>\n",
316 wd->sc_params.wdp_cylinders *
317 (wd->sc_params.wdp_heads * wd->sc_params.wdp_sectors) /
318 (1048576 / DEV_BSIZE),
319 wd->sc_params.wdp_cylinders,
320 wd->sc_params.wdp_heads,
321 wd->sc_params.wdp_sectors,
322 DEV_BSIZE,
323 buf);
324
325 if ((wd->sc_params.wdp_capabilities & WD_CAP_DMA) != 0 &&
326 wdc->sc_drq != DRQUNK) {
327 wd->sc_mode = WDM_DMA;
328 } else if (wd->sc_params.wdp_maxmulti > 1) {
329 wd->sc_mode = WDM_PIOMULTI;
330 wd->sc_multiple = min(wd->sc_params.wdp_maxmulti, 16);
331 } else {
332 wd->sc_mode = WDM_PIOSINGLE;
333 wd->sc_multiple = 1;
334 }
335
336 printf("%s: using", wd->sc_dev.dv_xname);
337 if (wd->sc_mode == WDM_DMA)
338 printf(" dma transfers,");
339 else
340 printf(" %d-sector %d-bit pio transfers,",
341 wd->sc_multiple, (wd->sc_flags & WDF_32BIT) == 0 ? 16 : 32);
342 if ((wd->sc_params.wdp_capabilities & WD_CAP_LBA) != 0)
343 printf(" lba addressing\n");
344 else
345 printf(" chs addressing\n");
346 }
347
348 /*
349 * Read/write routine for a buffer. Validates the arguments and schedules the
350 * transfer. Does not wait for the transfer to complete.
351 */
352 void
353 wdstrategy(bp)
354 struct buf *bp;
355 {
356 struct wd_softc *wd = wdcd.cd_devs[WDUNIT(bp->b_dev)];
357 int s;
358
359 /* Valid request? */
360 if (bp->b_blkno < 0 ||
361 (bp->b_bcount % wd->sc_dk.dk_label->d_secsize) != 0 ||
362 (bp->b_bcount / wd->sc_dk.dk_label->d_secsize) >= (1 << NBBY)) {
363 bp->b_error = EINVAL;
364 goto bad;
365 }
366
367 /* If device invalidated (e.g. media change, door open), error. */
368 if ((wd->sc_flags & WDF_LOADED) == 0) {
369 bp->b_error = EIO;
370 goto bad;
371 }
372
373 /* If it's a null transfer, return immediately. */
374 if (bp->b_bcount == 0)
375 goto done;
376
377 /*
378 * Do bounds checking, adjust transfer. if error, process.
379 * If end of partition, just return.
380 */
381 if (WDPART(bp->b_dev) != RAW_PART &&
382 bounds_check_with_label(bp, wd->sc_dk.dk_label,
383 (wd->sc_flags & (WDF_WLABEL|WDF_LABELLING)) != 0) <= 0)
384 goto done;
385
386 /* Queue transfer on drive, activate drive and controller if idle. */
387 s = splbio();
388 disksort(&wd->sc_q, bp);
389 if (!wd->sc_q.b_active)
390 wdstart(wd);
391 #if 0
392 else {
393 struct wdc_softc *wdc = (void *)wd->sc_dev.dv_parent;
394 if ((wdc->sc_flags & (WDCF_ACTIVE|WDCF_ERROR)) == 0) {
395 printf("wdstrategy: controller inactive\n");
396 wdcstart(wdc);
397 }
398 }
399 #endif
400 splx(s);
401 return;
402
403 bad:
404 bp->b_flags |= B_ERROR;
405 done:
406 /* Toss transfer; we're done early. */
407 bp->b_resid = bp->b_bcount;
408 biodone(bp);
409 }
410
411 /*
412 * Queue a drive for I/O.
413 */
414 void
415 wdstart(wd)
416 struct wd_softc *wd;
417 {
418 struct wdc_softc *wdc = (void *)wd->sc_dev.dv_parent;
419 int active = wdc->sc_drives.tqh_first != 0;
420
421 /* Link onto controller queue. */
422 wd->sc_q.b_active = 1;
423 TAILQ_INSERT_TAIL(&wdc->sc_drives, wd, sc_drivechain);
424
425 disk_busy(&wd->sc_dk);
426
427 /* If controller not already active, start it. */
428 if (!active)
429 wdcstart(wdc);
430 }
431
432 /*
433 * Finish an I/O operation. Clean up the drive and controller state, set the
434 * residual count, and inform the upper layers that the operation is complete.
435 */
436 void
437 wdfinish(wd, bp)
438 struct wd_softc *wd;
439 struct buf *bp;
440 {
441 struct wdc_softc *wdc = (void *)wd->sc_dev.dv_parent;
442
443 wdc->sc_flags &= ~(WDCF_SINGLE | WDCF_ERROR);
444 wdc->sc_errors = 0;
445 /*
446 * Move this drive to the end of the queue to give others a `fair'
447 * chance.
448 */
449 if (wd->sc_drivechain.tqe_next) {
450 TAILQ_REMOVE(&wdc->sc_drives, wd, sc_drivechain);
451 if (bp->b_actf) {
452 TAILQ_INSERT_TAIL(&wdc->sc_drives, wd, sc_drivechain);
453 } else
454 wd->sc_q.b_active = 0;
455 }
456 bp->b_resid = wd->sc_bcount;
457 wd->sc_skip = 0;
458 wd->sc_q.b_actf = bp->b_actf;
459
460 disk_unbusy(&wd->sc_dk, (bp->b_bcount - bp->b_resid));
461
462 if (!wd->sc_q.b_actf) {
463 TAILQ_REMOVE(&wdc->sc_drives, wd, sc_drivechain);
464 wd->sc_q.b_active = 0;
465 } else
466 disk_busy(&wd->sc_dk);
467
468 biodone(bp);
469 }
470
471 int
472 wdread(dev, uio)
473 dev_t dev;
474 struct uio *uio;
475 {
476
477 return (physio(wdstrategy, NULL, dev, B_READ, minphys, uio));
478 }
479
480 int
481 wdwrite(dev, uio)
482 dev_t dev;
483 struct uio *uio;
484 {
485
486 return (physio(wdstrategy, NULL, dev, B_WRITE, minphys, uio));
487 }
488
489 /*
490 * Start I/O on a controller. This does the calculation, and starts a read or
491 * write operation. Called to from wdstart() to start a transfer, from
492 * wdcintr() to continue a multi-sector transfer or start the next transfer, or
493 * wdcrestart() after recovering from an error.
494 */
495 void
496 wdcstart(wdc)
497 struct wdc_softc *wdc;
498 {
499 struct wd_softc *wd;
500 struct buf *bp;
501 struct disklabel *lp;
502 int nblks;
503
504 #ifdef DIAGNOSTIC
505 if ((wdc->sc_flags & WDCF_ACTIVE) != 0)
506 panic("wdcstart: controller still active");
507 #endif
508
509 /*
510 * XXX
511 * This is a kluge. See comments in wd_get_parms().
512 */
513 if ((wdc->sc_flags & WDCF_WANTED) != 0) {
514 wdc->sc_flags &= ~WDCF_WANTED;
515 wakeup(wdc);
516 return;
517 }
518
519 loop:
520 /* Is there a drive for the controller to do a transfer with? */
521 wd = wdc->sc_drives.tqh_first;
522 if (wd == NULL)
523 return;
524
525 /* Is there a transfer to this drive? If not, deactivate drive. */
526 bp = wd->sc_q.b_actf;
527
528 if (wdc->sc_errors >= WDIORETRIES) {
529 wderror(wd, bp, "hard error");
530 bp->b_error = EIO;
531 bp->b_flags |= B_ERROR;
532 wdfinish(wd, bp);
533 goto loop;
534 }
535
536 /* Do control operations specially. */
537 if (wd->sc_state < OPEN) {
538 /*
539 * Actually, we want to be careful not to mess with the control
540 * state if the device is currently busy, but we can assume
541 * that we never get to this point if that's the case.
542 */
543 if (wdcontrol(wd) == 0) {
544 /* The drive is busy. Wait. */
545 return;
546 }
547 }
548
549 /*
550 * WDCF_ERROR is set by wdcunwedge() and wdcintr() when an error is
551 * encountered. If we are in multi-sector mode, then we switch to
552 * single-sector mode and retry the operation from the start.
553 */
554 if (wdc->sc_flags & WDCF_ERROR) {
555 wdc->sc_flags &= ~WDCF_ERROR;
556 if ((wdc->sc_flags & WDCF_SINGLE) == 0) {
557 wdc->sc_flags |= WDCF_SINGLE;
558 wd->sc_skip = 0;
559 }
560 }
561
562 lp = wd->sc_dk.dk_label;
563
564 /* When starting a transfer... */
565 if (wd->sc_skip == 0) {
566 int part = WDPART(bp->b_dev);
567 daddr_t blkno;
568
569 #ifdef WDDEBUG
570 printf("\n%s: wdcstart %s %d@%d; map ", wd->sc_dev.dv_xname,
571 (bp->b_flags & B_READ) ? "read" : "write", bp->b_bcount,
572 bp->b_blkno);
573 #endif
574 wd->sc_bcount = bp->b_bcount;
575 blkno = bp->b_blkno;
576 if (part != RAW_PART)
577 blkno += lp->d_partitions[part].p_offset;
578 wd->sc_blkno = blkno / (lp->d_secsize / DEV_BSIZE);
579 } else {
580 #ifdef WDDEBUG
581 printf(" %d)%x", wd->sc_skip, inb(wd->sc_iobase+wd_altsts));
582 #endif
583 }
584
585 /* When starting a multi-sector transfer, or doing single-sector
586 transfers... */
587 if (wd->sc_skip == 0 || (wdc->sc_flags & WDCF_SINGLE) != 0 ||
588 wd->sc_mode == WDM_DMA) {
589 daddr_t blkno = wd->sc_blkno;
590 long cylin, head, sector;
591 int command;
592
593 if ((wdc->sc_flags & WDCF_SINGLE) != 0)
594 nblks = 1;
595 else if (wd->sc_mode != WDM_DMA)
596 nblks = wd->sc_bcount / lp->d_secsize;
597 else
598 nblks = min(wd->sc_bcount / lp->d_secsize, 8);
599
600 /* Check for bad sectors and adjust transfer, if necessary. */
601 if ((lp->d_flags & D_BADSECT) != 0
602 #ifdef B_FORMAT
603 && (bp->b_flags & B_FORMAT) == 0
604 #endif
605 ) {
606 long blkdiff;
607 int i;
608
609 for (i = 0; (blkdiff = wd->sc_badsect[i]) != -1; i++) {
610 blkdiff -= blkno;
611 if (blkdiff < 0)
612 continue;
613 if (blkdiff == 0) {
614 /* Replace current block of transfer. */
615 blkno =
616 lp->d_secperunit - lp->d_nsectors - i - 1;
617 }
618 if (blkdiff < nblks) {
619 /* Bad block inside transfer. */
620 wdc->sc_flags |= WDCF_SINGLE;
621 nblks = 1;
622 }
623 break;
624 }
625 /* Tranfer is okay now. */
626 }
627
628 if ((wd->sc_params.wdp_capabilities & WD_CAP_LBA) != 0) {
629 sector = (blkno >> 0) & 0xff;
630 cylin = (blkno >> 8) & 0xffff;
631 head = (blkno >> 24) & 0xf;
632 head |= WDSD_LBA;
633 } else {
634 sector = blkno % lp->d_nsectors;
635 sector++; /* Sectors begin with 1, not 0. */
636 blkno /= lp->d_nsectors;
637 head = blkno % lp->d_ntracks;
638 blkno /= lp->d_ntracks;
639 cylin = blkno;
640 head |= WDSD_CHS;
641 }
642
643 if (wd->sc_mode == WDM_PIOSINGLE ||
644 (wdc->sc_flags & WDCF_SINGLE) != 0)
645 wd->sc_nblks = 1;
646 else if (wd->sc_mode == WDM_PIOMULTI)
647 wd->sc_nblks = min(nblks, wd->sc_multiple);
648 else
649 wd->sc_nblks = nblks;
650 wd->sc_nbytes = wd->sc_nblks * lp->d_secsize;
651
652 #ifdef B_FORMAT
653 if (bp->b_flags & B_FORMAT) {
654 sector = lp->d_gap3;
655 nblks = lp->d_nsectors;
656 command = WDCC_FORMAT;
657 } else
658 #endif
659 switch (wd->sc_mode) {
660 case WDM_DMA:
661 command = (bp->b_flags & B_READ) ?
662 WDCC_READDMA : WDCC_WRITEDMA;
663 /* Start the DMA channel and bounce the buffer if
664 necessary. */
665 isa_dmastart(
666 bp->b_flags & B_READ ? DMAMODE_READ : DMAMODE_WRITE,
667 bp->b_data + wd->sc_skip,
668 wd->sc_nbytes, wdc->sc_drq);
669 break;
670 case WDM_PIOMULTI:
671 command = (bp->b_flags & B_READ) ?
672 WDCC_READMULTI : WDCC_WRITEMULTI;
673 break;
674 case WDM_PIOSINGLE:
675 command = (bp->b_flags & B_READ) ?
676 WDCC_READ : WDCC_WRITE;
677 break;
678 }
679
680 /* Initiate command! */
681 if (wdcommand(wd, command, cylin, head, sector, nblks) != 0) {
682 wderror(wd, NULL,
683 "wdcstart: timeout waiting for unbusy");
684 wdcunwedge(wdc);
685 return;
686 }
687
688 #ifdef WDDEBUG
689 printf("sector %d cylin %d head %d addr %x sts %x\n", sector,
690 cylin, head, bp->b_data, inb(wd->sc_iobase+wd_altsts));
691 #endif
692 } else if (wd->sc_nblks > 1) {
693 /* The number of blocks in the last stretch may be smaller. */
694 nblks = wd->sc_bcount / lp->d_secsize;
695 if (wd->sc_nblks > nblks) {
696 wd->sc_nblks = nblks;
697 wd->sc_nbytes = wd->sc_bcount;
698 }
699 }
700
701 /* If this was a write and not using DMA, push the data. */
702 if (wd->sc_mode != WDM_DMA &&
703 (bp->b_flags & (B_READ|B_WRITE)) == B_WRITE) {
704 if (wait_for_drq(wdc) < 0) {
705 wderror(wd, NULL, "wdcstart: timeout waiting for drq");
706 wdcunwedge(wdc);
707 return;
708 }
709
710 /* Push out data. */
711 if ((wd->sc_flags & WDF_32BIT) == 0)
712 outsw(wdc->sc_iobase+wd_data, bp->b_data + wd->sc_skip,
713 wd->sc_nbytes >> 1);
714 else
715 outsl(wdc->sc_iobase+wd_data, bp->b_data + wd->sc_skip,
716 wd->sc_nbytes >> 2);
717 }
718
719 wdc->sc_flags |= WDCF_ACTIVE;
720 timeout(wdctimeout, wdc, WAITTIME);
721 }
722
723 /*
724 * Interrupt routine for the controller. Acknowledge the interrupt, check for
725 * errors on the current operation, mark it done if necessary, and start the
726 * next request. Also check for a partially done transfer, and continue with
727 * the next chunk if so.
728 */
729 int
730 wdcintr(arg)
731 void *arg;
732 {
733 struct wdc_softc *wdc = arg;
734 struct wd_softc *wd;
735 struct buf *bp;
736
737 if ((wdc->sc_flags & WDCF_ACTIVE) == 0) {
738 /* Clear the pending interrupt and abort. */
739 (void) inb(wdc->sc_iobase+wd_status);
740 return 0;
741 }
742
743 wdc->sc_flags &= ~WDCF_ACTIVE;
744 untimeout(wdctimeout, wdc);
745
746 wd = wdc->sc_drives.tqh_first;
747 bp = wd->sc_q.b_actf;
748
749 #ifdef WDDEBUG
750 printf("I%d ", ctrlr);
751 #endif
752
753 if (wait_for_unbusy(wdc) < 0) {
754 wderror(wd, NULL, "wdcintr: timeout waiting for unbusy");
755 wdc->sc_status |= WDCS_ERR; /* XXX */
756 }
757
758 /* Is it not a transfer, but a control operation? */
759 if (wd->sc_state < OPEN) {
760 if (wdcontrol(wd) == 0) {
761 /* The drive is busy. Wait. */
762 return 1;
763 }
764 wdcstart(wdc);
765 return 1;
766 }
767
768 /* Turn off the DMA channel and unbounce the buffer. */
769 if (wd->sc_mode == WDM_DMA)
770 isa_dmadone(bp->b_flags & B_READ ? DMAMODE_READ : DMAMODE_WRITE,
771 bp->b_data + wd->sc_skip, wd->sc_nbytes, wdc->sc_drq);
772
773 /* Have we an error? */
774 if (wdc->sc_status & WDCS_ERR) {
775 lose:
776 #ifdef WDDEBUG
777 wderror(wd, NULL, "wdcintr");
778 #endif
779 if ((wdc->sc_flags & WDCF_SINGLE) == 0) {
780 wdc->sc_flags |= WDCF_ERROR;
781 goto restart;
782 }
783
784 #ifdef B_FORMAT
785 if (bp->b_flags & B_FORMAT)
786 goto bad;
787 #endif
788
789 if (++wdc->sc_errors < WDIORETRIES)
790 goto restart;
791 wderror(wd, bp, "hard error");
792
793 bad:
794 bp->b_error = EIO;
795 bp->b_flags |= B_ERROR;
796 goto done;
797 }
798
799 /* If this was a read and not using DMA, fetch the data. */
800 if (wd->sc_mode != WDM_DMA &&
801 (bp->b_flags & (B_READ|B_WRITE)) == B_READ) {
802 if ((wdc->sc_status & (WDCS_DRDY | WDCS_DSC | WDCS_DRQ))
803 != (WDCS_DRDY | WDCS_DSC | WDCS_DRQ)) {
804 wderror(wd, NULL, "wdcintr: read intr before drq");
805 wdcunwedge(wdc);
806 return 1;
807 }
808
809 /* Pull in data. */
810 if ((wd->sc_flags & WDF_32BIT) == 0)
811 insw(wdc->sc_iobase+wd_data, bp->b_data + wd->sc_skip,
812 wd->sc_nbytes >> 1);
813 else
814 insl(wdc->sc_iobase+wd_data, bp->b_data + wd->sc_skip,
815 wd->sc_nbytes >> 2);
816 }
817
818 /* If we encountered any abnormalities, flag it as a soft error. */
819 if (wdc->sc_errors > 0 ||
820 (wdc->sc_status & WDCS_CORR) != 0) {
821 wderror(wd, bp, "soft error (corrected)");
822 wdc->sc_errors = 0;
823 }
824
825 /* Adjust pointers for the next block, if any. */
826 wd->sc_blkno += wd->sc_nblks;
827 wd->sc_skip += wd->sc_nbytes;
828 wd->sc_bcount -= wd->sc_nbytes;
829
830 /* See if this transfer is complete. */
831 if (wd->sc_bcount > 0)
832 goto restart;
833
834 done:
835 /* Done with this transfer, with or without error. */
836 wdfinish(wd, bp);
837
838 restart:
839 /* Start the next operation, if any. */
840 wdcstart(wdc);
841
842 return 1;
843 }
844
845 /*
846 * Wait interruptibly for an exclusive lock.
847 *
848 * XXX
849 * Several drivers do this; it should be abstracted and made MP-safe.
850 */
851 int
852 wdlock(wd)
853 struct wd_softc *wd;
854 {
855 int error;
856
857 while ((wd->sc_flags & WDF_LOCKED) != 0) {
858 wd->sc_flags |= WDF_WANTED;
859 if ((error = tsleep(wd, PRIBIO | PCATCH, "wdlck", 0)) != 0)
860 return error;
861 }
862 wd->sc_flags |= WDF_LOCKED;
863 return 0;
864 }
865
866 /*
867 * Unlock and wake up any waiters.
868 */
869 void
870 wdunlock(wd)
871 struct wd_softc *wd;
872 {
873
874 wd->sc_flags &= ~WDF_LOCKED;
875 if ((wd->sc_flags & WDF_WANTED) != 0) {
876 wd->sc_flags &= ~WDF_WANTED;
877 wakeup(wd);
878 }
879 }
880
881 int
882 wdopen(dev, flag, fmt)
883 dev_t dev;
884 int flag, fmt;
885 {
886 struct wd_softc *wd;
887 int unit, part;
888 int error;
889
890 unit = WDUNIT(dev);
891 if (unit >= wdcd.cd_ndevs)
892 return ENXIO;
893 wd = wdcd.cd_devs[unit];
894 if (wd == 0)
895 return ENXIO;
896
897 if (error = wdlock(wd))
898 return error;
899
900 if (wd->sc_dk.dk_openmask != 0) {
901 /*
902 * If any partition is open, but the disk has been invalidated,
903 * disallow further opens.
904 */
905 if ((wd->sc_flags & WDF_LOADED) == 0) {
906 error = EIO;
907 goto bad3;
908 }
909 } else {
910 if ((wd->sc_flags & WDF_LOADED) == 0) {
911 wd->sc_flags |= WDF_LOADED;
912
913 /* Load the physical device parameters. */
914 if (wd_get_parms(wd) != 0) {
915 error = ENXIO;
916 goto bad2;
917 }
918
919 /* Load the partition info if not already loaded. */
920 wdgetdisklabel(wd);
921 }
922 }
923
924 part = WDPART(dev);
925
926 /* Check that the partition exists. */
927 if (part != RAW_PART &&
928 (part >= wd->sc_dk.dk_label->d_npartitions ||
929 wd->sc_dk.dk_label->d_partitions[part].p_fstype == FS_UNUSED)) {
930 error = ENXIO;
931 goto bad;
932 }
933
934 /* Insure only one open at a time. */
935 switch (fmt) {
936 case S_IFCHR:
937 wd->sc_dk.dk_copenmask |= (1 << part);
938 break;
939 case S_IFBLK:
940 wd->sc_dk.dk_bopenmask |= (1 << part);
941 break;
942 }
943 wd->sc_dk.dk_openmask = wd->sc_dk.dk_copenmask | wd->sc_dk.dk_bopenmask;
944
945 wdunlock(wd);
946 return 0;
947
948 bad2:
949 wd->sc_flags &= ~WDF_LOADED;
950
951 bad:
952 if (wd->sc_dk.dk_openmask == 0) {
953 }
954
955 bad3:
956 wdunlock(wd);
957 return error;
958 }
959
960 int
961 wdclose(dev, flag, fmt)
962 dev_t dev;
963 int flag, fmt;
964 {
965 struct wd_softc *wd = wdcd.cd_devs[WDUNIT(dev)];
966 int part = WDPART(dev);
967 int error;
968
969 if (error = wdlock(wd))
970 return error;
971
972 switch (fmt) {
973 case S_IFCHR:
974 wd->sc_dk.dk_copenmask &= ~(1 << part);
975 break;
976 case S_IFBLK:
977 wd->sc_dk.dk_bopenmask &= ~(1 << part);
978 break;
979 }
980 wd->sc_dk.dk_openmask = wd->sc_dk.dk_copenmask | wd->sc_dk.dk_bopenmask;
981
982 if (wd->sc_dk.dk_openmask == 0) {
983 /* XXXX Must wait for I/O to complete! */
984 }
985
986 wdunlock(wd);
987 return 0;
988 }
989
990 /*
991 * Fabricate a default disk label, and try to read the correct one.
992 */
993 void
994 wdgetdisklabel(wd)
995 struct wd_softc *wd;
996 {
997 struct disklabel *lp = wd->sc_dk.dk_label;
998 char *errstring;
999
1000 bzero(lp, sizeof(struct disklabel));
1001 bzero(wd->sc_dk.dk_cpulabel, sizeof(struct cpu_disklabel));
1002
1003 lp->d_secsize = DEV_BSIZE;
1004 lp->d_ntracks = wd->sc_params.wdp_heads;
1005 lp->d_nsectors = wd->sc_params.wdp_sectors;
1006 lp->d_ncylinders = wd->sc_params.wdp_cylinders;
1007 lp->d_secpercyl = lp->d_ntracks * lp->d_nsectors;
1008
1009 #if 0
1010 strncpy(lp->d_typename, "ST506 disk", 16);
1011 lp->d_type = DTYPE_ST506;
1012 #endif
1013 strncpy(lp->d_packname, wd->sc_params.wdp_model, 16);
1014 lp->d_secperunit = lp->d_secpercyl * lp->d_ncylinders;
1015 lp->d_rpm = 3600;
1016 lp->d_interleave = 1;
1017 lp->d_flags = 0;
1018
1019 lp->d_partitions[RAW_PART].p_offset = 0;
1020 lp->d_partitions[RAW_PART].p_size =
1021 lp->d_secperunit * (lp->d_secsize / DEV_BSIZE);
1022 lp->d_partitions[RAW_PART].p_fstype = FS_UNUSED;
1023 lp->d_npartitions = RAW_PART + 1;
1024
1025 lp->d_magic = DISKMAGIC;
1026 lp->d_magic2 = DISKMAGIC;
1027 lp->d_checksum = dkcksum(lp);
1028
1029 wd->sc_badsect[0] = -1;
1030
1031 if (wd->sc_state > RECAL)
1032 wd->sc_state = RECAL;
1033 errstring = readdisklabel(MAKEWDDEV(0, wd->sc_dev.dv_unit, RAW_PART),
1034 wdstrategy, lp, wd->sc_dk.dk_cpulabel);
1035 if (errstring) {
1036 /*
1037 * This probably happened because the drive's default
1038 * geometry doesn't match the DOS geometry. We
1039 * assume the DOS geometry is now in the label and try
1040 * again. XXX This is a kluge.
1041 */
1042 if (wd->sc_state > GEOMETRY)
1043 wd->sc_state = GEOMETRY;
1044 errstring = readdisklabel(MAKEWDDEV(0, wd->sc_dev.dv_unit, RAW_PART),
1045 wdstrategy, lp, wd->sc_dk.dk_cpulabel);
1046 }
1047 if (errstring) {
1048 printf("%s: %s\n", wd->sc_dev.dv_xname, errstring);
1049 return;
1050 }
1051
1052 if (wd->sc_state > GEOMETRY)
1053 wd->sc_state = GEOMETRY;
1054 if ((lp->d_flags & D_BADSECT) != 0)
1055 bad144intern(wd);
1056 }
1057
1058 /*
1059 * Implement operations needed before read/write.
1060 * Returns 0 if operation still in progress, 1 if completed.
1061 */
1062 int
1063 wdcontrol(wd)
1064 struct wd_softc *wd;
1065 {
1066 struct wdc_softc *wdc = (void *)wd->sc_dev.dv_parent;
1067
1068 switch (wd->sc_state) {
1069 case RECAL: /* Set SDH, step rate, do recal. */
1070 if (wdcommandshort(wdc, wd->sc_drive, WDCC_RECAL) != 0) {
1071 wderror(wd, NULL, "wdcontrol: recal failed (1)");
1072 goto bad;
1073 }
1074 wd->sc_state = RECAL_WAIT;
1075 break;
1076
1077 case RECAL_WAIT:
1078 if (wdc->sc_status & WDCS_ERR) {
1079 wderror(wd, NULL, "wdcontrol: recal failed (2)");
1080 goto bad;
1081 }
1082 /* fall through */
1083 case GEOMETRY:
1084 if ((wd->sc_params.wdp_capabilities & WD_CAP_LBA) != 0)
1085 goto multimode;
1086 if (wdsetctlr(wd) != 0) {
1087 /* Already printed a message. */
1088 goto bad;
1089 }
1090 wd->sc_state = GEOMETRY_WAIT;
1091 break;
1092
1093 case GEOMETRY_WAIT:
1094 if (wdc->sc_status & WDCS_ERR) {
1095 wderror(wd, NULL, "wdcontrol: geometry failed");
1096 goto bad;
1097 }
1098 /* fall through */
1099 case MULTIMODE:
1100 multimode:
1101 if (wd->sc_mode != WDM_PIOMULTI)
1102 goto open;
1103 outb(wdc->sc_iobase+wd_seccnt, wd->sc_multiple);
1104 if (wdcommandshort(wdc, wd->sc_drive, WDCC_SETMULTI) != 0) {
1105 wderror(wd, NULL, "wdcontrol: setmulti failed (1)");
1106 goto bad;
1107 }
1108 wd->sc_state = MULTIMODE_WAIT;
1109 break;
1110
1111 case MULTIMODE_WAIT:
1112 if (wdc->sc_status & WDCS_ERR) {
1113 wderror(wd, NULL, "wdcontrol: setmulti failed (2)");
1114 goto bad;
1115 }
1116 /* fall through */
1117 case OPEN:
1118 open:
1119 wdc->sc_errors = 0;
1120 wd->sc_state = OPEN;
1121 /*
1122 * The rest of the initialization can be done by normal means.
1123 */
1124 return 1;
1125
1126 bad:
1127 wdcunwedge(wdc);
1128 return 0;
1129 }
1130
1131 wdc->sc_flags |= WDCF_ACTIVE;
1132 timeout(wdctimeout, wdc, WAITTIME);
1133 return 0;
1134 }
1135
1136 /*
1137 * Wait for the drive to become ready and send a command.
1138 * Return -1 if busy for too long or 0 otherwise.
1139 * Assumes interrupts are blocked.
1140 */
1141 int
1142 wdcommand(wd, command, cylin, head, sector, count)
1143 struct wd_softc *wd;
1144 int command;
1145 int cylin, head, sector, count;
1146 {
1147 struct wdc_softc *wdc = (void *)wd->sc_dev.dv_parent;
1148 int iobase = wdc->sc_iobase;
1149 int stat;
1150
1151 /* Select drive, head, and addressing mode. */
1152 outb(iobase+wd_sdh, WDSD_IBM | (wd->sc_drive << 4) | head);
1153
1154 /* Wait for it to become ready to accept a command. */
1155 if (command == WDCC_IDP)
1156 stat = wait_for_unbusy(wdc);
1157 else
1158 stat = wdcwait(wdc, WDCS_DRDY);
1159 if (stat < 0)
1160 return -1;
1161
1162 /* Load parameters. */
1163 if (wd->sc_dk.dk_label->d_type == DTYPE_ST506)
1164 outb(iobase+wd_precomp, wd->sc_dk.dk_label->d_precompcyl / 4);
1165 else
1166 outb(iobase+wd_features, 0);
1167 outb(iobase+wd_cyl_lo, cylin);
1168 outb(iobase+wd_cyl_hi, cylin >> 8);
1169 outb(iobase+wd_sector, sector);
1170 outb(iobase+wd_seccnt, count);
1171
1172 /* Send command. */
1173 outb(iobase+wd_command, command);
1174
1175 return 0;
1176 }
1177
1178 /*
1179 * Simplified version of wdcommand().
1180 */
1181 int
1182 wdcommandshort(wdc, drive, command)
1183 struct wdc_softc *wdc;
1184 int drive;
1185 int command;
1186 {
1187 int iobase = wdc->sc_iobase;
1188
1189 /* Select drive. */
1190 outb(iobase+wd_sdh, WDSD_IBM | (drive << 4));
1191
1192 if (wdcwait(wdc, WDCS_DRDY) < 0)
1193 return -1;
1194
1195 outb(iobase+wd_command, command);
1196
1197 return 0;
1198 }
1199
1200 /*
1201 * Tell the drive what geometry to use.
1202 */
1203 int
1204 wdsetctlr(wd)
1205 struct wd_softc *wd;
1206 {
1207 struct wdc_softc *wdc = (void *)wd->sc_dev.dv_parent;
1208
1209 #ifdef WDDEBUG
1210 printf("wd(%d,%d) C%dH%dS%d\n", wd->sc_dev.dv_unit, wd->sc_drive,
1211 wd->sc_dk.dk_label->d_ncylinders, wd->sc_dk.dk_label->d_ntracks,
1212 wd->sc_dk.dk_label->d_nsectors);
1213 #endif
1214
1215 if (wdcommand(wd, WDCC_IDP, wd->sc_dk.dk_label->d_ncylinders,
1216 wd->sc_dk.dk_label->d_ntracks - 1, 0,
1217 wd->sc_dk.dk_label->d_nsectors) != 0) {
1218 wderror(wd, NULL, "wdsetctlr: geometry upload failed");
1219 return -1;
1220 }
1221
1222 return 0;
1223 }
1224
1225 /*
1226 * Get the drive parameters, if ESDI or ATA, or create fake ones for ST506.
1227 */
1228 int
1229 wd_get_parms(wd)
1230 struct wd_softc *wd;
1231 {
1232 struct wdc_softc *wdc = (void *)wd->sc_dev.dv_parent;
1233 int i;
1234 char tb[DEV_BSIZE];
1235 int s, error;
1236
1237 /*
1238 * XXX
1239 * The locking done here, and the length of time this may keep the rest
1240 * of the system suspended, is a kluge. This should be rewritten to
1241 * set up a transfer and queue it through wdstart(), but it's called
1242 * infrequently enough that this isn't a pressing matter.
1243 */
1244
1245 s = splbio();
1246
1247 while ((wdc->sc_flags & WDCF_ACTIVE) != 0) {
1248 wdc->sc_flags |= WDCF_WANTED;
1249 if ((error = tsleep(wdc, PRIBIO | PCATCH, "wdprm", 0)) != 0) {
1250 splx(s);
1251 return error;
1252 }
1253 }
1254
1255 if (wdcommandshort(wdc, wd->sc_drive, WDCC_IDENTIFY) != 0 ||
1256 wait_for_drq(wdc) != 0) {
1257 /*
1258 * We `know' there's a drive here; just assume it's old.
1259 * This geometry is only used to read the MBR and print a
1260 * (false) attach message.
1261 */
1262 strncpy(wd->sc_dk.dk_label->d_typename, "ST506",
1263 sizeof wd->sc_dk.dk_label->d_typename);
1264 wd->sc_dk.dk_label->d_type = DTYPE_ST506;
1265
1266 strncpy(wd->sc_params.wdp_model, "unknown",
1267 sizeof wd->sc_params.wdp_model);
1268 wd->sc_params.wdp_config = WD_CFG_FIXED;
1269 wd->sc_params.wdp_cylinders = 1024;
1270 wd->sc_params.wdp_heads = 8;
1271 wd->sc_params.wdp_sectors = 17;
1272 wd->sc_params.wdp_maxmulti = 0;
1273 wd->sc_params.wdp_usedmovsd = 0;
1274 wd->sc_params.wdp_capabilities = 0;
1275 } else {
1276 strncpy(wd->sc_dk.dk_label->d_typename, "ESDI/IDE",
1277 sizeof wd->sc_dk.dk_label->d_typename);
1278 wd->sc_dk.dk_label->d_type = DTYPE_ESDI;
1279
1280 /* Read in parameter block. */
1281 insw(wdc->sc_iobase+wd_data, tb, sizeof(tb) / sizeof(short));
1282 bcopy(tb, &wd->sc_params, sizeof(struct wdparams));
1283
1284 /* Shuffle string byte order. */
1285 for (i = 0; i < sizeof(wd->sc_params.wdp_model); i += 2) {
1286 u_short *p;
1287 p = (u_short *)(wd->sc_params.wdp_model + i);
1288 *p = ntohs(*p);
1289 }
1290 }
1291
1292 /* Clear any leftover interrupt. */
1293 (void) inb(wdc->sc_iobase+wd_status);
1294
1295 /* Restart the queue. */
1296 wdcstart(wdc);
1297
1298 splx(s);
1299 return 0;
1300 }
1301
1302 int
1303 wdioctl(dev, cmd, addr, flag, p)
1304 dev_t dev;
1305 u_long cmd;
1306 caddr_t addr;
1307 int flag;
1308 struct proc *p;
1309 {
1310 struct wd_softc *wd = wdcd.cd_devs[WDUNIT(dev)];
1311 int error;
1312
1313 if ((wd->sc_flags & WDF_LOADED) == 0)
1314 return EIO;
1315
1316 switch (cmd) {
1317 case DIOCSBAD:
1318 if ((flag & FWRITE) == 0)
1319 return EBADF;
1320 wd->sc_dk.dk_cpulabel->bad = *(struct dkbad *)addr;
1321 wd->sc_dk.dk_label->d_flags |= D_BADSECT;
1322 bad144intern(wd);
1323 return 0;
1324
1325 case DIOCGDINFO:
1326 *(struct disklabel *)addr = *(wd->sc_dk.dk_label);
1327 return 0;
1328
1329 case DIOCGPART:
1330 ((struct partinfo *)addr)->disklab = wd->sc_dk.dk_label;
1331 ((struct partinfo *)addr)->part =
1332 &wd->sc_dk.dk_label->d_partitions[WDPART(dev)];
1333 return 0;
1334
1335 case DIOCWDINFO:
1336 case DIOCSDINFO:
1337 if ((flag & FWRITE) == 0)
1338 return EBADF;
1339
1340 if (error = wdlock(wd))
1341 return error;
1342 wd->sc_flags |= WDF_LABELLING;
1343
1344 error = setdisklabel(wd->sc_dk.dk_label,
1345 (struct disklabel *)addr, /*wd->sc_dk.dk_openmask : */0,
1346 wd->sc_dk.dk_cpulabel);
1347 if (error == 0) {
1348 if (wd->sc_state > GEOMETRY)
1349 wd->sc_state = GEOMETRY;
1350 if (cmd == DIOCWDINFO)
1351 error = writedisklabel(WDLABELDEV(dev),
1352 wdstrategy, wd->sc_dk.dk_label,
1353 wd->sc_dk.dk_cpulabel);
1354 }
1355
1356 wd->sc_flags &= ~WDF_LABELLING;
1357 wdunlock(wd);
1358 return error;
1359
1360 case DIOCWLABEL:
1361 if ((flag & FWRITE) == 0)
1362 return EBADF;
1363 if (*(int *)addr)
1364 wd->sc_flags |= WDF_WLABEL;
1365 else
1366 wd->sc_flags &= ~WDF_WLABEL;
1367 return 0;
1368
1369 #ifdef notyet
1370 case DIOCWFORMAT:
1371 if ((flag & FWRITE) == 0)
1372 return EBADF;
1373 {
1374 register struct format_op *fop;
1375 struct iovec aiov;
1376 struct uio auio;
1377
1378 fop = (struct format_op *)addr;
1379 aiov.iov_base = fop->df_buf;
1380 aiov.iov_len = fop->df_count;
1381 auio.uio_iov = &aiov;
1382 auio.uio_iovcnt = 1;
1383 auio.uio_resid = fop->df_count;
1384 auio.uio_segflg = 0;
1385 auio.uio_offset =
1386 fop->df_startblk * wd->sc_dk.dk_label->d_secsize;
1387 auio.uio_procp = p;
1388 error = physio(wdformat, NULL, dev, B_WRITE, minphys,
1389 &auio);
1390 fop->df_count -= auio.uio_resid;
1391 fop->df_reg[0] = wdc->sc_status;
1392 fop->df_reg[1] = wdc->sc_error;
1393 return error;
1394 }
1395 #endif
1396
1397 default:
1398 return ENOTTY;
1399 }
1400
1401 #ifdef DIAGNOSTIC
1402 panic("wdioctl: impossible");
1403 #endif
1404 }
1405
1406 #ifdef B_FORMAT
1407 int
1408 wdformat(struct buf *bp)
1409 {
1410
1411 bp->b_flags |= B_FORMAT;
1412 return wdstrategy(bp);
1413 }
1414 #endif
1415
1416 int
1417 wdsize(dev)
1418 dev_t dev;
1419 {
1420 struct wd_softc *wd;
1421 int part;
1422 int size;
1423
1424 if (wdopen(dev, 0, S_IFBLK) != 0)
1425 return -1;
1426 wd = wdcd.cd_devs[WDUNIT(dev)];
1427 part = WDPART(dev);
1428 if (wd->sc_dk.dk_label->d_partitions[part].p_fstype != FS_SWAP)
1429 size = -1;
1430 else
1431 size = wd->sc_dk.dk_label->d_partitions[part].p_size;
1432 if (wdclose(dev, 0, S_IFBLK) != 0)
1433 return -1;
1434 return size;
1435 }
1436
1437
1438 #ifndef __BDEVSW_DUMP_OLD_TYPE
1439 /* #define WD_DUMP_NOT_TRUSTED if you just want to watch */
1440 static int wddoingadump;
1441 static int wddumprecalibrated;
1442
1443 /*
1444 * Dump core after a system crash.
1445 */
1446 int
1447 wddump(dev, blkno, va, size)
1448 dev_t dev;
1449 daddr_t blkno;
1450 caddr_t va;
1451 size_t size;
1452 {
1453 struct wd_softc *wd; /* disk unit to do the I/O */
1454 struct wdc_softc *wdc; /* disk controller to do the I/O */
1455 struct disklabel *lp; /* disk's disklabel */
1456 int unit, part;
1457 int nblks; /* total number of sectors left to write */
1458
1459 /* Check if recursive dump; if so, punt. */
1460 if (wddoingadump)
1461 return EFAULT;
1462 wddoingadump = 1;
1463
1464 unit = WDUNIT(dev);
1465 if (unit >= wdcd.cd_ndevs)
1466 return ENXIO;
1467 wd = wdcd.cd_devs[unit];
1468 if (wd == 0)
1469 return ENXIO;
1470
1471 part = WDPART(dev);
1472
1473 /* Make sure it was initialized. */
1474 if (wd->sc_state < OPEN)
1475 return ENXIO;
1476
1477 wdc = (void *)wd->sc_dev.dv_parent;
1478
1479 /* Convert to disk sectors. Request must be a multiple of size. */
1480 lp = wd->sc_dk.dk_label;
1481 if ((size % lp->d_secsize) != 0)
1482 return EFAULT;
1483 nblks = size / lp->d_secsize;
1484 blkno = blkno / (lp->d_secsize / DEV_BSIZE);
1485
1486 /* Check transfer bounds against partition size. */
1487 if ((blkno < 0) || ((blkno + nblks) > lp->d_partitions[part].p_size))
1488 return EINVAL;
1489
1490 /* Offset block number to start of partition. */
1491 blkno += lp->d_partitions[part].p_offset;
1492
1493 /* Recalibrate, if first dump transfer. */
1494 if (wddumprecalibrated == 0) {
1495 wddumprecalibrated = 1;
1496 if (wdcommandshort(wdc, wd->sc_drive, WDCC_RECAL) != 0 ||
1497 wait_for_ready(wdc) != 0 || wdsetctlr(wd) != 0 ||
1498 wait_for_ready(wdc) != 0) {
1499 wderror(wd, NULL, "wddump: recal failed");
1500 return EIO;
1501 }
1502 }
1503
1504 while (nblks > 0) {
1505 daddr_t xlt_blkno = blkno;
1506 long cylin, head, sector;
1507
1508 if ((lp->d_flags & D_BADSECT) != 0) {
1509 long blkdiff;
1510 int i;
1511
1512 for (i = 0; (blkdiff = wd->sc_badsect[i]) != -1; i++) {
1513 blkdiff -= xlt_blkno;
1514 if (blkdiff < 0)
1515 continue;
1516 if (blkdiff == 0) {
1517 /* Replace current block of transfer. */
1518 xlt_blkno = lp->d_secperunit -
1519 lp->d_nsectors - i - 1;
1520 }
1521 break;
1522 }
1523 /* Tranfer is okay now. */
1524 }
1525
1526 if ((wd->sc_params.wdp_capabilities & WD_CAP_LBA) != 0) {
1527 sector = (xlt_blkno >> 0) & 0xff;
1528 cylin = (xlt_blkno >> 8) & 0xffff;
1529 head = (xlt_blkno >> 24) & 0xf;
1530 head |= WDSD_LBA;
1531 } else {
1532 sector = xlt_blkno % lp->d_nsectors;
1533 sector++; /* Sectors begin with 1, not 0. */
1534 xlt_blkno /= lp->d_nsectors;
1535 head = xlt_blkno % lp->d_ntracks;
1536 xlt_blkno /= lp->d_ntracks;
1537 cylin = xlt_blkno;
1538 head |= WDSD_CHS;
1539 }
1540
1541 #ifndef WD_DUMP_NOT_TRUSTED
1542 if (wdcommand(wd, WDCC_WRITE, cylin, head, sector, 1) != 0 ||
1543 wait_for_drq(wdc) != 0) {
1544 wderror(wd, NULL, "wddump: write failed");
1545 return EIO;
1546 }
1547
1548 outsw(wdc->sc_iobase+wd_data, va, lp->d_secsize >> 1);
1549
1550 /* Check data request (should be done). */
1551 if (wait_for_ready(wdc) != 0) {
1552 wderror(wd, NULL, "wddump: timeout waiting for ready");
1553 return EIO;
1554 }
1555 #else /* WD_DUMP_NOT_TRUSTED */
1556 /* Let's just talk about this first... */
1557 printf("wd%d: dump addr 0x%x, cylin %d, head %d, sector %d\n",
1558 unit, va, cylin, head, sector);
1559 delay(500 * 1000); /* half a second */
1560 #endif
1561
1562 /* update block count */
1563 nblks -= 1;
1564 blkno += 1;
1565 va += lp->d_secsize;
1566 }
1567
1568 wddoingadump = 0;
1569 return 0;
1570 }
1571 #else /* __BDEVSW_DUMP_NEW_TYPE */
1572 int
1573 wddump(dev, blkno, va, size)
1574 dev_t dev;
1575 daddr_t blkno;
1576 caddr_t va;
1577 size_t size;
1578 {
1579
1580 /* Not implemented. */
1581 return ENXIO;
1582 }
1583 #endif /* __BDEVSW_DUMP_NEW_TYPE */
1584
1585 /*
1586 * Internalize the bad sector table.
1587 */
1588 void
1589 bad144intern(wd)
1590 struct wd_softc *wd;
1591 {
1592 struct dkbad *bt = &wd->sc_dk.dk_cpulabel->bad;
1593 struct disklabel *lp = wd->sc_dk.dk_label;
1594 int i = 0;
1595
1596 for (; i < 126; i++) {
1597 if (bt->bt_bad[i].bt_cyl == 0xffff)
1598 break;
1599 wd->sc_badsect[i] =
1600 bt->bt_bad[i].bt_cyl * lp->d_secpercyl +
1601 (bt->bt_bad[i].bt_trksec >> 8) * lp->d_nsectors +
1602 (bt->bt_bad[i].bt_trksec & 0xff);
1603 }
1604 for (; i < 127; i++)
1605 wd->sc_badsect[i] = -1;
1606 }
1607
1608 int
1609 wdcreset(wdc)
1610 struct wdc_softc *wdc;
1611 {
1612 int iobase = wdc->sc_iobase;
1613
1614 /* Reset the device. */
1615 outb(iobase+wd_ctlr, WDCTL_RST | WDCTL_IDS);
1616 delay(1000);
1617 outb(iobase+wd_ctlr, WDCTL_IDS);
1618 delay(1000);
1619 (void) inb(iobase+wd_error);
1620 outb(iobase+wd_ctlr, WDCTL_4BIT);
1621
1622 if (wait_for_unbusy(wdc) < 0) {
1623 printf("%s: reset failed\n", wdc->sc_dev.dv_xname);
1624 return 1;
1625 }
1626
1627 return 0;
1628 }
1629
1630 void
1631 wdcrestart(arg)
1632 void *arg;
1633 {
1634 struct wdc_softc *wdc = arg;
1635 int s;
1636
1637 s = splbio();
1638 wdcstart(wdc);
1639 splx(s);
1640 }
1641
1642 /*
1643 * Unwedge the controller after an unexpected error. We do this by resetting
1644 * it, marking all drives for recalibration, and stalling the queue for a short
1645 * period to give the reset time to finish.
1646 * NOTE: We use a timeout here, so this routine must not be called during
1647 * autoconfig or dump.
1648 */
1649 void
1650 wdcunwedge(wdc)
1651 struct wdc_softc *wdc;
1652 {
1653 int unit;
1654
1655 untimeout(wdctimeout, wdc);
1656 (void) wdcreset(wdc);
1657
1658 /* Schedule recalibrate for all drives on this controller. */
1659 for (unit = 0; unit < wdcd.cd_ndevs; unit++) {
1660 struct wd_softc *wd = wdcd.cd_devs[unit];
1661 if (!wd || (void *)wd->sc_dev.dv_parent != wdc)
1662 continue;
1663 if (wd->sc_state > RECAL)
1664 wd->sc_state = RECAL;
1665 }
1666
1667 wdc->sc_flags |= WDCF_ERROR;
1668 ++wdc->sc_errors;
1669
1670 /* Wake up in a little bit and restart the operation. */
1671 timeout(wdcrestart, wdc, RECOVERYTIME);
1672 }
1673
1674 int
1675 wdcwait(wdc, mask)
1676 struct wdc_softc *wdc;
1677 int mask;
1678 {
1679 int iobase = wdc->sc_iobase;
1680 int timeout = 0;
1681 u_char status;
1682 extern int cold;
1683
1684 for (;;) {
1685 wdc->sc_status = status = inb(iobase+wd_status);
1686 if ((status & WDCS_BSY) == 0 && (status & mask) == mask)
1687 break;
1688 if (++timeout > WDCNDELAY)
1689 return -1;
1690 delay(WDCDELAY);
1691 }
1692 if (status & WDCS_ERR) {
1693 wdc->sc_error = inb(iobase+wd_error);
1694 return WDCS_ERR;
1695 }
1696 #ifdef WDCNDELAY_DEBUG
1697 /* After autoconfig, there should be no long delays. */
1698 if (!cold && timeout > WDCNDELAY_DEBUG)
1699 printf("%s: warning: busy-wait took %dus\n",
1700 wdc->sc_dev.dv_xname, WDCDELAY * timeout);
1701 #endif
1702 return 0;
1703 }
1704
1705 void
1706 wdctimeout(arg)
1707 void *arg;
1708 {
1709 struct wdc_softc *wdc = (struct wdc_softc *)arg;
1710 int s;
1711
1712 s = splbio();
1713 if ((wdc->sc_flags & WDCF_ACTIVE) != 0) {
1714 struct wd_softc *wd = wdc->sc_drives.tqh_first;
1715 struct buf *bp = wd->sc_q.b_actf;
1716
1717 wdc->sc_flags &= ~WDCF_ACTIVE;
1718 wderror(wdc, NULL, "lost interrupt");
1719 printf("%s: lost interrupt: %sing %d@%s:%d\n",
1720 wdc->sc_dev.dv_xname,
1721 (bp->b_flags & B_READ) ? "read" : "writ",
1722 wd->sc_nblks, wd->sc_dev.dv_xname, wd->sc_blkno);
1723 wdcunwedge(wdc);
1724 } else
1725 wderror(wdc, NULL, "missing untimeout");
1726 splx(s);
1727 }
1728
1729 void
1730 wderror(dev, bp, msg)
1731 void *dev;
1732 struct buf *bp;
1733 char *msg;
1734 {
1735 struct wd_softc *wd = dev;
1736 struct wdc_softc *wdc = dev;
1737
1738 if (bp) {
1739 diskerr(bp, "wd", msg, LOG_PRINTF, wd->sc_skip / DEV_BSIZE,
1740 wd->sc_dk.dk_label);
1741 printf("\n");
1742 } else
1743 printf("%s: %s: status %b error %b\n", wdc->sc_dev.dv_xname,
1744 msg, wdc->sc_status, WDCS_BITS, wdc->sc_error, WDERR_BITS);
1745 }
1746