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