1 /*
2 * Copyright (c) 1988 The Regents of the University of California.
3 * All rights reserved.
4 *
5 * This code is derived from software contributed to Berkeley by
6 * Harris Corp.
7 *
8 * %sccs.include.redist.c%
9 *
10 * @(#)hd.c 7.12 (Berkeley) 12/16/90
11 */
12
13 #include "hd.h"
14
15 #if NHD > 0
16 #include "sys/param.h"
17 #include "sys/buf.h"
18 #include "sys/conf.h"
19 #include "sys/dkstat.h"
20 #include "sys/disklabel.h"
21 #include "sys/file.h"
22 #include "sys/systm.h"
23 #include "sys/vmmac.h"
24 #include "sys/time.h"
25 #include "sys/proc.h"
26 #include "sys/uio.h"
27 #include "sys/syslog.h"
28 #include "sys/kernel.h"
29 #include "sys/ioctl.h"
30 #include "sys/stat.h"
31 #include "sys/errno.h"
32
33 #include "../include/cpu.h"
34 #include "../include/mtpr.h"
35
36 #include "../vba/vbavar.h"
37 #include "../vba/hdreg.h"
38
39 #define b_cylin b_resid
40
41 #define hdunit(dev) (minor(dev)>>3)
42 #define hdpart(dev) (minor(dev)&0x07)
43 #define hdminor(unit, part) (((unit)<<3)|(part))
44
45 struct vba_ctlr *hdcminfo[NHDC];
46 struct vba_device *hddinfo[NHD];
47 int hdcprobe(), hdslave(), hdattach(), hddgo(), hdstrategy();
48 long hdstd[] = { 0 };
49 struct vba_driver hdcdriver =
50 { hdcprobe, hdslave, hdattach, hddgo, hdstd, "hd", hddinfo, "hdc", hdcminfo };
51
52 /*
53 * Per-controller state.
54 */
55 struct hdcsoftc {
56 u_short hdc_flags;
57 #define HDC_INIT 0x01 /* controller initialized */
58 #define HDC_STARTED 0x02 /* start command issued */
59 #define HDC_LOCKED 0x04 /* locked for direct controller access */
60 #define HDC_WAIT 0x08 /* someone needs direct controller access */
61 u_short hdc_wticks; /* timeout */
62 struct master_mcb *hdc_mcbp; /* address of controller mcb */
63 struct registers *hdc_reg; /* base address of i/o regs */
64 struct vb_buf hdc_rbuf; /* vba resources */
65 struct master_mcb hdc_mcb; /* controller mcb */
66 } hdcsoftc[NHDC];
67
68 #define HDCMAXTIME 20 /* max time for operation, sec. */
69 #define HDCINTERRUPT 0xf0 /* interrupt vector */
70
71 /*
72 * Per-drive state; probably everything should be "hd_", not "dk_",
73 * but it's not worth it, and dk is a better mnemonic for disk anyway.
74 */
75 struct dksoftc {
76 #ifdef COMPAT_42
77 u_short dk_def_cyl; /* definition track cylinder address */
78 #endif
79 int dk_state; /* open fsm */
80 u_short dk_bshift; /* shift for * (DEV_BSIZE / sectorsize) XXX */
81 int dk_wlabel; /* if label sector is writeable */
82 u_long dk_copenpart; /* character units open on this drive */
83 u_long dk_bopenpart; /* block units open on this drive */
84 u_long dk_openpart; /* all units open on this drive */
85 int dk_unit; /* unit# */
86 int dk_ctlr; /* controller# */
87 int dk_format; /* if format program is using disk */
88 struct buf dk_utab; /* i/o queue header */
89 struct disklabel dk_label; /* disklabel for this disk */
90 struct mcb dk_mcb; /* disk mcb */
91 } dksoftc[NHD];
92
93 /*
94 * Drive states. Used during steps of open/initialization.
95 * States < OPEN (> 0) are transient, during an open operation.
96 * OPENRAW is used for unlabeled disks, to allow format operations.
97 */
98 #define CLOSED 0 /* disk is closed */
99 #define WANTOPEN 1 /* open requested, not started */
100 #define WANTOPENRAW 2 /* open requested, no label */
101 #define RDLABEL 3 /* reading pack label */
102 #define OPEN 4 /* intialized and ready */
103 #define OPENRAW 5 /* open, no label */
104
105 int hdcwstart, hdcwatch();
106
107 /* see if the controller is really there, if so, init it. */
108 /* ARGSUSED */
hdcprobe(reg,vm)109 hdcprobe(reg, vm)
110 caddr_t reg;
111 /* register */ struct vba_ctlr *vm;
112 {
113 register int br, cvec; /* must be r12, r11 */
114 register struct hdcsoftc *hdc;
115 static struct module_id id;
116 struct pte *dummypte;
117 caddr_t putl;
118
119 /* initialize the hdc controller structure. */
120 hdc = &hdcsoftc[vm->um_ctlr];
121 if (!vbmemalloc(1, reg, &dummypte, &putl)) {
122 printf("hdc%d: vbmemalloc failed.\n", vm->um_ctlr);
123 return(0);
124 }
125 hdc->hdc_reg = (struct registers *)putl;
126
127 /*
128 * try and ping the MID register; side effect of wbadaddr is to read
129 * the module id; the controller is bad if it's not an hdc, the hdc's
130 * writeable control store is not loaded, or the hdc failed the
131 * functional integrity test;
132 */
133 if (wbadaddr(&hdc->hdc_reg->module_id, 4,
134 vtoph((struct process *)NULL, &id)))
135 return(0);
136 DELAY(10000);
137 mtpr(PADC, 0);
138 if (id.module_id != (u_char)HDC_MID) {
139 printf("hdc%d: bad module id; id = %x.\n",
140 vm->um_ctlr, id.module_id);
141 return(0);
142 }
143 if (id.code_rev == (u_char)0xff) {
144 printf("hdc%d: micro-code not loaded.\n", vm->um_ctlr);
145 return(0);
146 }
147 if (id.fit != (u_char)0xff) {
148 printf("hdc%d: FIT test failed.\n", vm->um_ctlr);
149 return(0);
150 }
151
152 /* reset that pup; flag as inited */
153 hdc->hdc_reg->soft_reset = 0;
154 DELAY(1000000);
155 hdc->hdc_flags |= HDC_INIT;
156
157 /* allocate page tables and i/o buffer. */
158 if (!vbainit(&hdc->hdc_rbuf, MAXPHYS, VB_32BIT|VB_SCATTER)) {
159 printf("hdc%d: vbainit failed\n", vm->um_ctlr);
160 return (0);
161 }
162
163 /* set pointer to master control block */
164 hdc->hdc_mcbp =
165 (struct master_mcb *)vtoph((struct proc *)NULL, &hdc->hdc_mcb);
166
167 br = 0x17, cvec = HDCINTERRUPT + vm->um_ctlr; /* XXX */
168 return(sizeof(struct registers));
169 }
170
171 /* ARGSUSED */
172 hdslave(vi, vdaddr)
173 struct vba_device *vi;
174 struct vddevice *vdaddr;
175 {
176 register struct mcb *mcb;
177 register struct disklabel *lp;
178 register struct dksoftc *dk;
179 static struct status status;
180
181 dk = &dksoftc[vi->ui_unit];
182 dk->dk_unit = vi->ui_unit;
183 dk->dk_ctlr = vi->ui_ctlr;
184
185 mcb = &dk->dk_mcb;
186 mcb->command = HCMD_STATUS;
187 mcb->chain[0].wcount = sizeof(struct status) / sizeof(long);
188 mcb->chain[0].memadr = (u_long)vtoph((struct process *)0, &status);
189 if (hdimcb(dk)) {
190 printf(" (no status)\n");
191 return(0);
192 }
193
194 /*
195 * Report the drive down if anything in the drive status looks bad.
196 * If the drive is offline and it is not on cylinder, then the drive
197 * is not there. If there is a fault condition, the hdc will try to
198 * clear it when we read the disklabel information.
199 */
200 if (!(status.drs&DRS_ONLINE)) {
201 if (status.drs&DRS_ON_CYLINDER)
202 printf(" (not online)\n");
203 return(0);
204 }
205 if (status.drs&DRS_FAULT)
206 printf(" (clearing fault)");
207
208 lp = &dk->dk_label;
209 #ifdef RAW_SIZE
210 lp->d_secsize = status.bytes_per_sec;
211 #else
212 lp->d_secsize = 512;
213 #endif
214 lp->d_nsectors = status.max_sector + 1;
215 lp->d_ntracks = status.max_head + 1;
216 lp->d_ncylinders = status.max_cyl + 1;
217 lp->d_secpercyl = lp->d_ntracks * lp->d_nsectors;
218 lp->d_npartitions = 1;
219 lp->d_partitions[0].p_offset = 0;
220 lp->d_partitions[0].p_size = LABELSECTOR + 1;
221 lp->d_rpm = status.rpm;
222 lp->d_typename[0] = 'h';
223 lp->d_typename[1] = 'd';
224 lp->d_typename[2] = '\0';
225 #ifdef COMPAT_42
226 dk->dk_def_cyl = status.def_cyl;
227 #endif
228 return(1);
229 }
230
hdattach(vi)231 hdattach(vi)
232 register struct vba_device *vi;
233 {
234 register struct dksoftc *dk;
235 register struct disklabel *lp;
236 register int unit;
237
238 unit = vi->ui_unit;
239 if (hdinit(hdminor(unit, 0), 0)) {
240 printf(": unknown drive type");
241 return;
242 }
243 dk = &dksoftc[unit];
244 lp = &dk->dk_label;
245 hd_setsecsize(dk, lp);
246 if (dk->dk_state == OPEN)
247 printf(": %s <secsize %d, ntrak %d, ncyl %d, nsec %d>",
248 lp->d_typename, lp->d_secsize, lp->d_ntracks,
249 lp->d_ncylinders, lp->d_nsectors);
250
251 /*
252 * (60 / rpm) / (sectors per track * (bytes per sector / 2))
253 */
254 if (vi->ui_dk >= 0)
255 dk_wpms[vi->ui_dk] =
256 (lp->d_rpm * lp->d_nsectors * lp->d_secsize) / 120;
257 #ifdef notyet
258 addswap(makedev(HDMAJOR, hdminor(unit, 0)), lp);
259 #endif
260 }
261
hdopen(dev,flags,fmt)262 hdopen(dev, flags, fmt)
263 dev_t dev;
264 int flags, fmt;
265 {
266 register struct disklabel *lp;
267 register struct dksoftc *dk;
268 register struct partition *pp;
269 register int unit;
270 struct vba_device *vi;
271 int s, error, part = hdpart(dev), mask = 1 << part;
272 daddr_t start, end;
273
274 unit = hdunit(dev);
275 if (unit >= NHD || (vi = hddinfo[unit]) == 0 || vi->ui_alive == 0)
276 return(ENXIO);
277 dk = &dksoftc[unit];
278 lp = &dk->dk_label;
279 s = spl7();
280 while (dk->dk_state != OPEN && dk->dk_state != OPENRAW &&
281 dk->dk_state != CLOSED)
282 if (error = tsleep((caddr_t)dk, (PZERO+1) | PCATCH,
283 devopn, 0)) {
284 splx(s);
285 return (error);
286 }
287 splx(s);
288 if (dk->dk_state != OPEN && dk->dk_state != OPENRAW)
289 if (error = hdinit(dev, flags))
290 return(error);
291
292 if (hdcwstart == 0) {
293 timeout(hdcwatch, (caddr_t)0, hz);
294 hdcwstart++;
295 }
296 /*
297 * Warn if a partion is opened that overlaps another partition
298 * which is open unless one is the "raw" partition (whole disk).
299 */
300 #define RAWPART 8 /* 'x' partition */ /* XXX */
301 if ((dk->dk_openpart & mask) == 0 && part != RAWPART) {
302 pp = &lp->d_partitions[part];
303 start = pp->p_offset;
304 end = pp->p_offset + pp->p_size;
305 for (pp = lp->d_partitions;
306 pp < &lp->d_partitions[lp->d_npartitions]; pp++) {
307 if (pp->p_offset + pp->p_size <= start ||
308 pp->p_offset >= end)
309 continue;
310 if (pp - lp->d_partitions == RAWPART)
311 continue;
312 if (dk->dk_openpart & (1 << (pp - lp->d_partitions)))
313 log(LOG_WARNING,
314 "hd%d%c: overlaps open partition (%c)\n",
315 unit, part + 'a',
316 pp - lp->d_partitions + 'a');
317 }
318 }
319 if (part >= lp->d_npartitions)
320 return(ENXIO);
321 dk->dk_openpart |= mask;
322 switch (fmt) {
323 case S_IFCHR:
324 dk->dk_copenpart |= mask;
325 break;
326 case S_IFBLK:
327 dk->dk_bopenpart |= mask;
328 break;
329 }
330 return(0);
331 }
332
333 /* ARGSUSED */
hdclose(dev,flags,fmt)334 hdclose(dev, flags, fmt)
335 dev_t dev;
336 int flags, fmt;
337 {
338 register struct dksoftc *dk;
339 int mask;
340
341 dk = &dksoftc[hdunit(dev)];
342 mask = 1 << hdpart(dev);
343 switch (fmt) {
344 case S_IFCHR:
345 dk->dk_copenpart &= ~mask;
346 break;
347 case S_IFBLK:
348 dk->dk_bopenpart &= ~mask;
349 break;
350 }
351 if (((dk->dk_copenpart | dk->dk_bopenpart) & mask) == 0)
352 dk->dk_openpart &= ~mask;
353 /*
354 * Should wait for i/o to complete on this partition
355 * even if others are open, but wait for work on blkflush().
356 */
357 if (dk->dk_openpart == 0) {
358 int s = spl7();
359 while (dk->dk_utab.b_actf)
360 sleep((caddr_t)dk, PZERO-1);
361 splx(s);
362 dk->dk_state = CLOSED;
363 dk->dk_wlabel = 0;
364 }
365 return(0);
366 }
367
hdinit(dev,flags)368 hdinit(dev, flags)
369 dev_t dev;
370 int flags;
371 {
372 register struct dksoftc *dk;
373 register struct disklabel *lp;
374 struct vba_device *vi;
375 int error, unit;
376 char *msg, *readdisklabel();
377 extern int cold;
378
379 vi = hddinfo[unit = hdunit(dev)];
380 dk = &dksoftc[unit];
381 dk->dk_unit = vi->ui_slave;
382 dk->dk_ctlr = vi->ui_ctlr;
383
384 if (flags & O_NDELAY) {
385 dk->dk_state = OPENRAW;
386 return(0);
387 }
388
389 error = 0;
390 lp = &dk->dk_label;
391 dk->dk_state = RDLABEL;
392 if (msg = readdisklabel(dev, hdstrategy, lp)) {
393 if (cold) {
394 printf(": %s\n", msg);
395 dk->dk_state = CLOSED;
396 } else {
397 log(LOG_ERR, "hd%d: %s\n", unit, msg);
398 dk->dk_state = OPENRAW;
399 }
400 #ifdef COMPAT_42
401 hdclock(vi->ui_ctlr);
402 if (!(error = hdreadgeometry(dk)))
403 dk->dk_state = OPEN;
404 hdcunlock(vi->ui_ctlr);
405 #endif
406 } else
407 dk->dk_state = OPEN;
408 wakeup((caddr_t)dk);
409 return(error);
410 }
411
hd_setsecsize(dk,lp)412 hd_setsecsize(dk, lp)
413 register struct dksoftc *dk;
414 struct disklabel *lp;
415 {
416 register int mul;
417
418 /*
419 * Calculate scaling shift for mapping
420 * DEV_BSIZE blocks to drive sectors.
421 */
422 mul = DEV_BSIZE / lp->d_secsize;
423 dk->dk_bshift = 0;
424 while ((mul >>= 1) > 0)
425 dk->dk_bshift++;
426 }
427
428 /* ARGSUSED */
429 hddgo(vm)
430 struct vba_device *vm;
431 {}
432
433 extern int name_ext;
hdstrategy(bp)434 hdstrategy(bp)
435 register struct buf *bp;
436 {
437 register struct vba_device *vi;
438 register struct disklabel *lp;
439 register struct dksoftc *dk;
440 struct buf *dp;
441 register int unit;
442 daddr_t sn, sz, maxsz;
443 int part, s;
444
445 vi = hddinfo[unit = hdunit(bp->b_dev)];
446 if (unit >= NHD || vi == 0 || vi->ui_alive == 0) {
447 bp->b_error = ENXIO;
448 goto bad;
449 }
450 dk = &dksoftc[unit];
451 if (dk->dk_state < OPEN)
452 goto q;
453 if (dk->dk_state != OPEN && (bp->b_flags & B_READ) == 0) {
454 bp->b_error = EROFS;
455 goto bad;
456 }
457 part = hdpart(bp->b_dev);
458 if ((dk->dk_openpart & (1 << part)) == 0) {
459 bp->b_error = ENODEV;
460 goto bad;
461 }
462 lp = &dk->dk_label;
463 sz = (bp->b_bcount + lp->d_secsize - 1) / lp->d_secsize;
464 maxsz = lp->d_partitions[part].p_size;
465 sn = bp->b_blkno << dk->dk_bshift;
466 if (sn + lp->d_partitions[part].p_offset <= LABELSECTOR &&
467 #if LABELSECTOR != 0
468 sn + lp->d_partitions[part].p_offset + sz > LABELSECTOR &&
469 #endif
470 (bp->b_flags & B_READ) == 0 && dk->dk_wlabel == 0) {
471 bp->b_error = EROFS;
472 goto bad;
473 }
474 if (sn < 0 || sn + sz > maxsz) {
475 if (sn == maxsz) {
476 bp->b_resid = bp->b_bcount;
477 goto done;
478 }
479 sz = maxsz - sn;
480 if (sz <= 0) {
481 bp->b_error = EINVAL;
482 goto bad;
483 }
484 bp->b_bcount = sz * lp->d_secsize;
485 }
486 bp->b_cylin = (sn + lp->d_partitions[part].p_offset) / lp->d_secpercyl;
487
488 q: s = spl7();
489 dp = &dk->dk_utab;
490 disksort(dp, bp);
491 if (!dp->b_active) {
492 (void)hdustart(vi);
493 if (!vi->ui_mi->um_tab.b_active)
494 hdcstart(vi->ui_mi);
495 }
496 splx(s);
497 return;
498 bad:
499 bp->b_flags |= B_ERROR;
500 done:
501 biodone(bp);
502 }
503
hdustart(vi)504 hdustart(vi)
505 register struct vba_device *vi;
506 {
507 register struct buf *bp, *dp;
508 register struct vba_ctlr *vm;
509 register struct dksoftc *dk;
510
511 dk = &dksoftc[vi->ui_unit];
512 dp = &dk->dk_utab;
513
514 /* if queue empty, nothing to do. impossible? */
515 if (dp->b_actf == NULL)
516 return;
517
518 /* place on controller transfer queue */
519 vm = vi->ui_mi;
520 if (vm->um_tab.b_actf == NULL)
521 vm->um_tab.b_actf = dp;
522 else
523 vm->um_tab.b_actl->b_forw = dp;
524 vm->um_tab.b_actl = dp;
525 dp->b_forw = NULL;
526 dp->b_active++;
527 }
528
hdcstart(vm)529 hdcstart(vm)
530 register struct vba_ctlr *vm;
531 {
532 register struct buf *bp;
533 register struct dksoftc *dk;
534 register struct disklabel *lp;
535 register struct master_mcb *master;
536 register struct mcb *mcb;
537 struct vba_device *vi;
538 struct hdcsoftc *hdc;
539 struct buf *dp;
540 int sn;
541
542 /* pull a request off the controller queue */
543 for (;;) {
544 if ((dp = vm->um_tab.b_actf) == NULL)
545 return;
546 if (bp = dp->b_actf)
547 break;
548 vm->um_tab.b_actf = dp->b_forw;
549 }
550
551 /* mark controller active */
552 vm->um_tab.b_active++;
553
554 vi = hddinfo[hdunit(bp->b_dev)];
555 dk = &dksoftc[vi->ui_unit];
556 lp = &dk->dk_label;
557 sn = bp->b_blkno << dk->dk_bshift;
558
559 /* fill in mcb */
560 mcb = &dk->dk_mcb;
561 mcb->forw_phaddr = 0;
562 /* mcb->priority = 0; */
563 mcb->interrupt = 1;
564 mcb->command = (bp->b_flags & B_READ) ? HCMD_READ:HCMD_WRITE;
565 mcb->cyl = bp->b_cylin;
566 /* assumes partition starts on cylinder boundary */
567 mcb->head = (sn / lp->d_nsectors) % lp->d_ntracks;
568 mcb->sector = sn % lp->d_nsectors;
569 mcb->drive = vi->ui_slave;
570 /* mcb->context = 0; /* what do we want on interrupt? */
571
572 hdc = &hdcsoftc[vm->um_ctlr];
573 if (!hd_sgsetup(bp, &hdc->hdc_rbuf, mcb->chain)) {
574 mcb->chain[0].wcount = (bp->b_bcount+3) >> 2;
575 mcb->chain[0].memadr =
576 vbasetup(bp, &hdc->hdc_rbuf, (int)lp->d_secsize);
577 }
578
579 if (vi->ui_dk >= 0) {
580 dk_busy |= 1<<vi->ui_dk;
581 dk_xfer[vi->ui_dk]++;
582 dk_wds[vi->ui_dk] += bp->b_bcount>>6;
583 }
584
585 master = &hdc->hdc_mcb;
586 master->mcw = MCL_QUEUED;
587 master->interrupt = HDCINTERRUPT + vm->um_ctlr;
588 master->forw_phaddr = (u_long)vtoph((struct proc *)NULL, mcb);
589 hdc->hdc_reg->master_mcb = (u_long)hdc->hdc_mcbp;
590 }
591
592 /*
593 * Wait for controller to finish current operation
594 * so that direct controller accesses can be done.
595 */
hdclock(ctlr)596 hdclock(ctlr)
597 int ctlr;
598 {
599 register struct vba_ctlr *vm = hdcminfo[ctlr];
600 register struct hdcsoftc *hdc;
601 int s;
602
603 hdc = &hdcsoftc[ctlr];
604 s = spl7();
605 while (vm->um_tab.b_active || hdc->hdc_flags & HDC_LOCKED) {
606 hdc->hdc_flags |= HDC_WAIT;
607 sleep((caddr_t)hdc, PRIBIO);
608 }
609 hdc->hdc_flags |= HDC_LOCKED;
610 splx(s);
611 }
612
613 /*
614 * Continue normal operations after pausing for
615 * munging the controller directly.
616 */
hdcunlock(ctlr)617 hdcunlock(ctlr)
618 int ctlr;
619 {
620 register struct vba_ctlr *vm;
621 register struct hdcsoftc *hdc = &hdcsoftc[ctlr];
622
623 hdc->hdc_flags &= ~HDC_LOCKED;
624 if (hdc->hdc_flags & HDC_WAIT) {
625 hdc->hdc_flags &= ~HDC_WAIT;
626 wakeup((caddr_t)hdc);
627 } else {
628 vm = hdcminfo[ctlr];
629 if (vm->um_tab.b_actf)
630 hdcstart(vm);
631 }
632 }
633
hdintr(ctlr)634 hdintr(ctlr)
635 int ctlr;
636 {
637 register struct buf *bp, *dp;
638 register struct vba_ctlr *vm;
639 register struct vba_device *vi;
640 register struct hdcsoftc *hdc;
641 register struct mcb *mcb;
642 struct master_mcb *master;
643 register int status;
644 int timedout;
645 struct dksoftc *dk;
646
647 hdc = &hdcsoftc[ctlr];
648 master = &hdc->hdc_mcb;
649 uncache(&master->mcs);
650 uncache(&master->context);
651
652 vm = hdcminfo[ctlr];
653 if (!vm->um_tab.b_active || !(master->mcs&MCS_DONE)) {
654 printf("hd%d: stray interrupt\n", ctlr);
655 return;
656 }
657
658 dp = vm->um_tab.b_actf;
659 bp = dp->b_actf;
660 vi = hddinfo[hdunit(bp->b_dev)];
661 dk = &dksoftc[vi->ui_unit];
662 if (vi->ui_dk >= 0)
663 dk_busy &= ~(1<<vi->ui_dk);
664 timedout = (hdc->hdc_wticks >= HDCMAXTIME);
665
666 mcb = &dk->dk_mcb;
667
668 if (master->mcs & (MCS_SOFTERROR | MCS_FATALERROR) || timedout)
669 hdcerror(ctlr, *(u_long *)master->xstatus);
670 else
671 hdc->hdc_wticks = 0;
672 if (vm->um_tab.b_active) {
673 vm->um_tab.b_active = 0;
674 vm->um_tab.b_actf = dp->b_forw;
675 dp->b_active = 0;
676 dp->b_errcnt = 0;
677 dp->b_actf = bp->av_forw;
678 bp->b_resid = 0;
679 vbadone(bp, &hdc->hdc_rbuf);
680 biodone(bp);
681 /* start up now, if more work to do */
682 if (dp->b_actf)
683 hdustart(vi);
684 else if (dk->dk_openpart == 0)
685 wakeup((caddr_t)dk);
686 }
687 /* if there are devices ready to transfer, start the controller. */
688 if (hdc->hdc_flags & HDC_WAIT) {
689 hdc->hdc_flags &= ~HDC_WAIT;
690 wakeup((caddr_t)hdc);
691 } else if (vm->um_tab.b_actf)
692 hdcstart(vm);
693 }
694
hdioctl(dev,cmd,data,flag)695 hdioctl(dev, cmd, data, flag)
696 dev_t dev;
697 int cmd, flag;
698 caddr_t data;
699 {
700 register int unit;
701 register struct dksoftc *dk;
702 register struct disklabel *lp;
703 int error;
704
705 unit = hdunit(dev);
706 dk = &dksoftc[unit];
707 lp = &dk->dk_label;
708 error = 0;
709 switch (cmd) {
710 case DIOCGDINFO:
711 *(struct disklabel *)data = *lp;
712 break;
713 case DIOCGPART:
714 ((struct partinfo *)data)->disklab = lp;
715 ((struct partinfo *)data)->part =
716 &lp->d_partitions[hdpart(dev)];
717 break;
718 case DIOCSDINFO:
719 if ((flag & FWRITE) == 0)
720 error = EBADF;
721 else
722 error = setdisklabel(lp, (struct disklabel *)data,
723 (dk->dk_state == OPENRAW) ? 0 : dk->dk_openpart);
724 if (error == 0 && dk->dk_state == OPENRAW)
725 dk->dk_state = OPEN;
726 break;
727 case DIOCWLABEL:
728 if ((flag & FWRITE) == 0)
729 error = EBADF;
730 else
731 dk->dk_wlabel = *(int *)data;
732 break;
733 case DIOCWDINFO:
734 if ((flag & FWRITE) == 0)
735 error = EBADF;
736 else if ((error = setdisklabel(lp, (struct disklabel *)data,
737 (dk->dk_state == OPENRAW) ? 0 : dk->dk_openpart)) == 0) {
738 int wlab;
739
740 if (error == 0 && dk->dk_state == OPENRAW)
741 dk->dk_state = OPEN;
742 /* simulate opening partition 0 so write succeeds */
743 dk->dk_openpart |= (1 << 0); /* XXX */
744 wlab = dk->dk_wlabel;
745 dk->dk_wlabel = 1;
746 error = writedisklabel(dev, hdstrategy, lp);
747 dk->dk_openpart = dk->dk_copenpart | dk->dk_bopenpart;
748 dk->dk_wlabel = wlab;
749 }
750 break;
751 default:
752 error = ENOTTY;
753 break;
754 }
755 return (error);
756 }
757
758 /*
759 * Watch for lost interrupts.
760 */
hdcwatch()761 hdcwatch()
762 {
763 register struct hdcsoftc *hdc;
764 register struct vba_ctlr **vmp;
765 register int ctlr;
766 int s;
767
768 timeout(hdcwatch, (caddr_t)0, hz);
769 for (vmp = hdcminfo, hdc = hdcsoftc, ctlr = 0; ctlr < NHDC;
770 ++ctlr, ++vmp, ++hdc) {
771 if (*vmp == 0 || (*vmp)->um_alive == 0)
772 continue;
773 s = spl7();
774 if ((*vmp)->um_tab.b_active &&
775 hdc->hdc_wticks++ >= HDCMAXTIME) {
776 printf("hd%d: lost interrupt\n", ctlr);
777 hdintr(ctlr);
778 }
779 splx(s);
780 }
781 }
782
hddump(dev)783 hddump(dev)
784 dev_t dev;
785 {
786 return(ENXIO);
787 }
788
hdsize(dev)789 hdsize(dev)
790 dev_t dev;
791 {
792 register int unit = hdunit(dev);
793 register struct dksoftc *dk;
794 struct vba_device *vi;
795 struct disklabel *lp;
796
797 if (unit >= NHD || (vi = hddinfo[unit]) == 0 || vi->ui_alive == 0 ||
798 (dk = &dksoftc[unit])->dk_state != OPEN)
799 return (-1);
800 lp = &dk->dk_label;
801 return ((int)lp->d_partitions[hdpart(dev)].p_size >> dk->dk_bshift);
802 }
803
hdimcb(dk)804 hdimcb(dk)
805 register struct dksoftc *dk;
806 {
807 register struct master_mcb *master;
808 register struct mcb *mcb;
809 register struct hdcsoftc *hdc;
810 int timeout;
811
812 /* fill in mcb */
813 mcb = &dk->dk_mcb;
814 mcb->interrupt = 0;
815 mcb->forw_phaddr = 0;
816 mcb->drive = dk->dk_unit;
817
818 hdc = &hdcsoftc[dk->dk_ctlr];
819 master = &hdc->hdc_mcb;
820
821 /* fill in master mcb */
822 master->mcw = MCL_IMMEDIATE;
823 master->forw_phaddr = (u_long)vtoph((struct proc *)NULL, mcb);
824 master->mcs = 0;
825
826 /* kick controller and wait */
827 hdc->hdc_reg->master_mcb = (u_long)hdc->hdc_mcbp;
828 for (timeout = 15000; timeout; --timeout) {
829 DELAY(1000);
830 mtpr(PADC, 0);
831 if (master->mcs&MCS_FATALERROR) {
832 printf("hdc%d: fatal error\n", dk->dk_ctlr);
833 hdcerror(dk->dk_ctlr, *(u_long *)master->xstatus);
834 return(1);
835 }
836 if (master->mcs&MCS_DONE)
837 return(0);
838 }
839 printf("hdc%d: timed out\n", dk->dk_ctlr);
840 return(1);
841 }
842
hdcerror(ctlr,code)843 hdcerror(ctlr, code)
844 int ctlr;
845 u_long code;
846 {
847 printf("hd%d: error %lx\n", ctlr, code);
848 }
849
850 #ifdef COMPAT_42
851 hdreadgeometry(dk)
852 struct dksoftc *dk;
853 {
854 static geometry_sector geometry;
855 register struct mcb *mcb;
856 register struct disklabel *lp;
857 geometry_block *geo;
858 int cnt;
859
860 /*
861 * Read the geometry block (at head = 0 sector = 0 of the drive
862 * definition cylinder), validate it (must have the correct version
863 * number, header, and checksum).
864 */
865 mcb = &dk->dk_mcb;
866 mcb->command = HCMD_READ;
867 mcb->cyl = dk->dk_def_cyl;
868 mcb->head = 0;
869 mcb->sector = 0;
870 mcb->chain[0].wcount = sizeof(geometry_sector) / sizeof(long);
871 mcb->chain[0].memadr = (u_long)vtoph((struct process *)0, &geometry);
872 /* mcb->chain[0].memadr = (long)&geometry; */
873 if (hdimcb(dk)) {
874 printf("hd%d: can't read default geometry.\n", dk->dk_unit);
875 return(1);
876 }
877 geo = &geometry.geometry_block;
878 if (geo->version > 64000 || geo->version < 0) {
879 printf("hd%d: bad default geometry version#.\n", dk->dk_unit);
880 return(1);
881 }
882 if (bcmp(&geo->id[0], GB_ID, GB_ID_LEN)) {
883 printf("hd%d: bad default geometry header.\n", dk->dk_unit);
884 return(1);
885 }
886 GB_CHECKSUM(geo, cnt);
887 if (geometry.checksum != cnt) {
888 printf("hd%d: bad default geometry checksum.\n", dk->dk_unit);
889 return(1);
890 }
891 lp = &dk->dk_label;
892
893 /* 1K block in Harris geometry; convert to sectors for disklabels */
894 for (cnt = 0; cnt < GB_MAXPART; cnt++) {
895 lp->d_partitions[cnt].p_offset =
896 geo->partition[cnt].start * (1024 / lp->d_secsize);
897 lp->d_partitions[cnt].p_size =
898 geo->partition[cnt].length * (1024 / lp->d_secsize);
899 }
900 lp->d_npartitions = GB_MAXPART;
901 return(0);
902 }
903 #endif /* COMPAT_42 */
904 #endif /* NHD */
905