xref: /csrg-svn/sys/vax/mba/hp.c (revision 30772)
1 /*
2  * Copyright (c) 1982, 1986 Regents of the University of California.
3  * All rights reserved.  The Berkeley software License Agreement
4  * specifies the terms and conditions for redistribution.
5  *
6  *	@(#)hp.c	7.4 (Berkeley) 04/02/87
7  */
8 
9 #ifdef HPDEBUG
10 int	hpdebug;
11 #endif
12 #ifdef HPBDEBUG
13 int	hpbdebug;
14 #endif
15 
16 #include "hp.h"
17 #if NHP > 0
18 /*
19  * HP disk driver for RP0x+RMxx+ML11
20  *
21  * TODO:
22  *	see if DCLR and/or RELEASE set attention status
23  */
24 #include "param.h"
25 #include "systm.h"
26 #include "dkstat.h"
27 #include "buf.h"
28 #include "conf.h"
29 #include "dir.h"
30 #include "file.h"
31 #include "user.h"
32 #include "map.h"
33 #include "../vax/mtpr.h"
34 #include "vm.h"
35 #include "cmap.h"
36 #include "dkbad.h"
37 #include "disklabel.h"
38 #include "ioctl.h"
39 #include "uio.h"
40 #include "syslog.h"
41 #include "stat.h"
42 
43 #include "../machine/pte.h"
44 #include "../vax/dkio.h"
45 #include "mbareg.h"
46 #include "mbavar.h"
47 #include "hpreg.h"
48 
49 #define	COMPAT_42
50 #define	B_FORMAT	B_XXX
51 
52 /*
53  * Table of supported Massbus drive types.
54  * When using unlabeled packs, slot numbers here
55  * are used as indices into the partition tables.
56  * Slots are left for those drives divined from other means
57  * (e.g. SI, AMPEX, etc.).
58  */
59 short	hptypes[] = {
60 #define	HPDT_RM03	0
61 	MBDT_RM03,
62 #define	HPDT_RM05	1
63 	MBDT_RM05,
64 #define	HPDT_RP06	2
65 	MBDT_RP06,
66 #define	HPDT_RM80	3
67 	MBDT_RM80,
68 #define	HPDT_RP04	4
69 	MBDT_RP04,
70 #define	HPDT_RP05	5
71 	MBDT_RP05,
72 #define	HPDT_RP07	6
73 	MBDT_RP07,
74 #define	HPDT_ML11A	7
75 	MBDT_ML11A,
76 #define	HPDT_ML11B	8
77 	MBDT_ML11B,
78 #define	HPDT_9775	9
79 	-1,
80 #define	HPDT_9730	10
81 	-1,
82 #define	HPDT_CAPRICORN	11
83 	-1,
84 #define HPDT_EAGLE	12
85 	-1,
86 #define	HPDT_9300	13
87 	-1,
88 #define HPDT_RM02	14
89 	MBDT_RM02,		/* beware, actually mapped */
90 #define HPDT_2361	15
91 	-1,
92 	0
93 };
94 
95 struct	mba_device *hpinfo[NHP];
96 int	hpattach(),hpustart(),hpstart(),hpdtint(),hpstrategy();
97 struct	mba_driver hpdriver =
98 	{ hpattach, 0, hpustart, hpstart, hpdtint, 0,
99 	  hptypes, "hp", 0, hpinfo };
100 
101 u_char	hp_offset[16] = {
102     HPOF_P400, HPOF_M400, HPOF_P400, HPOF_M400,
103     HPOF_P800, HPOF_M800, HPOF_P800, HPOF_M800,
104     HPOF_P1200, HPOF_M1200, HPOF_P1200, HPOF_M1200,
105     0, 0, 0, 0,
106 };
107 
108 struct	buf	rhpbuf[NHP];
109 struct	disklabel hplabel[NHP];
110 struct	dkbad	hpbad[NHP];
111 
112 struct	hpsoftc {
113 	u_char	sc_recal;	/* recalibrate state */
114 	u_char	sc_doseeks;	/* perform explicit seeks */
115 	int	sc_state;	/* open fsm */
116 	long	sc_openpart;	/* bit mask of open subunits */
117 	long	sc_copenpart;	/* bit mask of open character subunits */
118 	long	sc_bopenpart;	/* bit mask of open block subunits */
119 	daddr_t	sc_mlsize;	/* ML11 size */
120 	int	sc_blkdone;	/* amount sucessfully transfered */
121 	daddr_t	sc_badbn;	/* replacement block number */
122 } hpsoftc[NHP];
123 
124 /*
125  * Drive states.  Used during steps of open/initialization.
126  * States < OPEN (> 0) are transient, during an open operation.
127  * OPENRAW is used for unlabeled disks,
128  * to inhibit bad-sector forwarding or allow format operations.
129  */
130 #define	CLOSED		0		/* disk is closed. */
131 #define	WANTOPEN	1		/* open requested, not started */
132 #define	WANTOPENRAW	2		/* open requested, no label */
133 #define	RDLABEL		3		/* reading pack label */
134 #define	RDBADTBL	4		/* reading bad-sector table */
135 #define	OPEN		5		/* initialized and ready */
136 #define	OPENRAW		6		/* open, no label or badsect */
137 
138 #define	b_cylin b_resid
139 
140 /* #define ML11 0  to remove ML11 support */
141 #define	ML11(type)	((type) == HPDT_ML11A)
142 #define	RP06(type)	(hptypes[type] <= MBDT_RP06)
143 #define	RM80(type)	((type) == HPDT_RM80)
144 
145 #define hpunit(dev)	(minor(dev) >> 3)
146 #define hppart(dev)	(minor(dev) & 07)
147 #define hpminor(unit, part)	(((unit) << 3) | (part))
148 
149 #define	MASKREG(reg)	((reg)&0xffff)
150 #ifdef lint
151 #define HPWAIT(mi, addr) (hpwait(mi))
152 #else
153 #define HPWAIT(mi, addr) (((addr)->hpds & HPDS_DRY) || hpwait(mi))
154 #endif
155 
156 /*ARGSUSED*/
157 hpattach(mi, slave)
158 	struct mba_device *mi;
159 {
160 	register int unit = mi->mi_unit;
161 
162 	/*
163 	 * Try to initialize device and read pack label.
164 	 */
165 	if (hpinit(hpminor(unit, 0), 0) == 0) {
166 		printf(": %s", hplabel[unit].d_typename);
167 #ifdef notyet
168 		addswap(makedev(HPMAJOR, hpminor(unit, 0)), &hplabel[unit]);
169 #endif
170 	} else
171 		printf(": offline");
172 }
173 
174 hpopen(dev, flags, fmt)
175 	dev_t dev;
176 	int flags, fmt;
177 {
178 	register int unit = hpunit(dev);
179 	register struct hpsoftc *sc;
180 	register struct disklabel *lp;
181 	register struct partition *pp;
182 	struct mba_device *mi;
183 	int s, error, part = hppart(dev), mask = 1 << part;
184 	daddr_t start, end;
185 
186 	if (unit >= NHP || (mi = hpinfo[unit]) == 0 || mi->mi_alive == 0)
187 		return (ENXIO);
188 	sc = &hpsoftc[unit];
189 	lp = &hplabel[unit];
190 
191 	s = spl5();
192 	while (sc->sc_state != OPEN && sc->sc_state != OPENRAW &&
193 	    sc->sc_state != CLOSED)
194 		sleep ((caddr_t)sc, PZERO+1);
195 	splx(s);
196 	if (sc->sc_state != OPEN && sc->sc_state != OPENRAW)
197 		if (error = hpinit(dev, flags))
198 			return (error);
199 	if (part >= lp->d_npartitions)
200 		return (ENXIO);
201 	/*
202 	 * Warn if a partion is opened
203 	 * that overlaps another partition which is open
204 	 * unless one is the "raw" partition (whole disk).
205 	 */
206 #define	RAWPART		2		/* 'c' partition */	/* XXX */
207 	if ((sc->sc_openpart & (1 << part)) == 0 &&
208 	    part != RAWPART) {
209 		pp = &lp->d_partitions[part];
210 		start = pp->p_offset;
211 		end = pp->p_offset + pp->p_size;
212 		for (pp = lp->d_partitions;
213 		     pp < &lp->d_partitions[lp->d_npartitions]; pp++) {
214 			if (pp->p_offset + pp->p_size <= start ||
215 			    pp->p_offset >= end)
216 				continue;
217 			if (pp - lp->d_partitions == RAWPART)
218 				continue;
219 			if (sc->sc_openpart & (1 << (pp - lp->d_partitions)))
220 				log(LOG_WARNING,
221 				    "hp%d%c: overlaps open partition (%c)\n",
222 				    unit, part + 'a',
223 				    pp - lp->d_partitions + 'a');
224 		}
225 	}
226 	switch (fmt) {
227 	case S_IFCHR:
228 		sc->sc_copenpart |= mask;
229 		break;
230 	case S_IFBLK:
231 		sc->sc_bopenpart |= mask;
232 		break;
233 	}
234 	sc->sc_openpart |= mask;
235 	return (0);
236 }
237 
238 hpclose(dev, flags, fmt)
239 	dev_t dev;
240 	int flags, fmt;
241 {
242 	register int unit = hpunit(dev);
243 	register struct hpsoftc *sc;
244 	struct mba_device *mi;
245 	int s, mask = 1 << hppart(dev);
246 
247 	sc = &hpsoftc[unit];
248 	mi = hpinfo[unit];
249 	switch (fmt) {
250 	case S_IFCHR:
251 		sc->sc_copenpart &= ~mask;
252 		break;
253 	case S_IFBLK:
254 		sc->sc_bopenpart &= ~mask;
255 		break;
256 	}
257 	if (((sc->sc_copenpart | sc->sc_bopenpart) & mask) == 0)
258 		sc->sc_openpart &= ~mask;
259 	/*
260 	 * Should wait for I/O to complete on this partition
261 	 * even if others are open, but wait for work on blkflush().
262 	 */
263 	if (sc->sc_openpart == 0) {
264 		s = spl5();
265 		while (mi->mi_tab.b_actf)
266 			sleep((caddr_t)sc, PZERO - 1);
267 		splx(s);
268 		sc->sc_state = CLOSED;
269 	}
270 	return (0);
271 }
272 
273 hpinit(dev, flags)
274 	dev_t dev;
275 	int flags;
276 {
277 	register struct hpsoftc *sc;
278 	register struct buf *bp;
279 	register struct disklabel *lp;
280 	struct mba_device *mi;
281 	struct hpdevice *hpaddr;
282 	struct dkbad *db;
283 	char *msg, *readdisklabel();
284 	int unit, i, error = 0;
285 	extern int cold;
286 
287 	unit = hpunit(dev);
288 	sc = &hpsoftc[unit];
289 	lp = &hplabel[unit];
290 	mi = hpinfo[unit];
291 	hpaddr = (struct hpdevice *)mi->mi_drv;
292 
293 	if (flags & O_NDELAY)
294 		sc->sc_state = WANTOPENRAW;
295 	else
296 		sc->sc_state = WANTOPEN;
297 	/*
298 	 * Use the default sizes until we've read the label,
299 	 * or longer if there isn't one there.
300 	 */
301 	lp->d_secsize = DEV_BSIZE;
302 	lp->d_nsectors = 32;
303 	lp->d_ntracks = 20;
304 	lp->d_secpercyl = 32*20;
305 
306 	/*
307 	 * Map all ML11's to the same type.  Also calculate
308 	 * transfer rates based on device characteristics.
309 	 * Set up dummy label with all that's needed.
310 	 */
311 	if (mi->mi_type == MBDT_ML11A || mi->mi_type == MBDT_ML11B) {
312 		register struct hpsoftc *sc = &hpsoftc[mi->mi_unit];
313 		register int trt;
314 
315 		sc->sc_mlsize = hpaddr->hpmr & HPMR_SZ;
316 		if ((hpaddr->hpmr & HPMR_ARRTYP) == 0)
317 			sc->sc_mlsize >>= 2;
318 		if (mi->mi_dk >= 0) {
319 			trt = (hpaddr->hpmr & HPMR_TRT) >> 8;
320 			dk_mspw[mi->mi_dk] = 1.0 / (1<<(20-trt));
321 		}
322 		mi->mi_type = MBDT_ML11A;
323 		lp->d_partitions[0].p_size = sc->sc_mlsize;
324 		lp->d_secpercyl = sc->sc_mlsize;
325 		sc->sc_state = WANTOPENRAW;
326 	}
327 
328 	/*
329 	 * Preset, pack acknowledge will be done in hpstart
330 	 * during first read operation.
331 	 */
332 	if (msg = readdisklabel(dev, hpstrategy, lp)) {
333 		if (sc->sc_state == OPENRAW)
334 			goto done;
335 		if (cold)
336 			printf(": %s", msg);
337 		else
338 			log(LOG_ERR, "hp%d: %s\n", unit, msg);
339 #ifdef COMPAT_42
340 		mi->mi_type = hpmaptype(mi, lp);
341 #else
342 		sc->sc_state = OPENRAW;
343 		goto done;
344 #endif
345 	}
346 
347 	/*
348 	 * Seconds per word = (60 / rpm) / (nsectors * secsize/2)
349 	 */
350 	if (mi->mi_dk >= 0 && lp->d_rpm)
351 		dk_mspw[mi->mi_dk] = 120.0 /
352 		    (lp->d_rpm * lp->d_nsectors * lp->d_secsize);
353 	/*
354 	 * Read bad sector table into memory.
355 	 */
356 	bp = geteblk(DEV_BSIZE);		/* max sector size */
357 	bp->b_dev = dev;
358 	sc->sc_state = RDBADTBL;
359 	i = 0;
360 	do {
361 		u.u_error = 0;				/* XXX */
362 		bp->b_flags = B_BUSY | B_READ;
363 		bp->b_blkno = lp->d_secperunit - lp->d_nsectors + i;
364 		bp->b_bcount = lp->d_secsize;
365 		bp->b_cylin = lp->d_ncylinders - 1;
366 		hpstrategy(bp);
367 		biowait(bp);
368 	} while ((bp->b_flags & B_ERROR) && (i += 2) < 10 &&
369 	    i < lp->d_nsectors);
370 	db = (struct dkbad *)(bp->b_un.b_addr);
371 	if ((bp->b_flags & B_ERROR) == 0 && db->bt_mbz == 0 &&
372 	    db->bt_flag == 0) {
373 		hpbad[unit] = *db;
374 		sc->sc_state = OPEN;
375 	} else {
376 		log(LOG_ERR, "hp%d: %s bad-sector file\n", unit,
377 		    (bp->b_flags & B_ERROR) ? "can't read" : "format error in");
378 		u.u_error = 0;				/* XXX */
379 		sc->sc_state = OPENRAW;
380 	}
381 	bp->b_flags = B_INVAL | B_AGE;
382 	brelse(bp);
383 done:
384 	wakeup((caddr_t)sc);
385 	return (error);
386 }
387 
388 hpstrategy(bp)
389 	register struct buf *bp;
390 {
391 	register struct mba_device *mi;
392 	register struct disklabel *lp;
393 	register struct hpsoftc *sc;
394 	register int unit;
395 	daddr_t sz, maxsz;
396 	int xunit = hppart(bp->b_dev);
397 	int s;
398 
399 	sz = (bp->b_bcount + DEV_BSIZE - 1) >> DEV_BSHIFT;
400 	unit = hpunit(bp->b_dev);
401 	if (unit >= NHP) {
402 		bp->b_error = ENXIO;
403 		goto bad;
404 	}
405 	mi = hpinfo[unit];
406 	sc = &hpsoftc[unit];
407 	lp = &hplabel[unit];
408 	if (mi == 0 || mi->mi_alive == 0) {
409 		bp->b_error = ENXIO;
410 		goto bad;
411 	}
412 	if (sc->sc_state < OPEN)
413 		goto q;
414 	if ((sc->sc_openpart & (1 << xunit)) == 0) {
415 		bp->b_error = ENODEV;
416 		goto bad;
417 	}
418 	maxsz = lp->d_partitions[xunit].p_size;
419 	if (bp->b_blkno < 0 || bp->b_blkno + sz > maxsz) {
420 		if (bp->b_blkno == maxsz) {
421 			bp->b_resid = bp->b_bcount;
422 			goto done;
423 		}
424 		sz = maxsz - bp->b_blkno;
425 		if (sz <= 0) {
426 			bp->b_error = EINVAL;
427 			goto bad;
428 		}
429 		bp->b_bcount = sz << DEV_BSHIFT;
430 	}
431 	bp->b_cylin = (bp->b_blkno + lp->d_partitions[xunit].p_offset) /
432 	    lp->d_secpercyl;
433 q:
434 	s = spl5();
435 	disksort(&mi->mi_tab, bp);
436 	if (mi->mi_tab.b_active == 0)
437 		mbustart(mi);
438 	splx(s);
439 	return;
440 
441 bad:
442 	bp->b_flags |= B_ERROR;
443 done:
444 	biodone(bp);
445 	return;
446 }
447 
448 hpustart(mi)
449 	register struct mba_device *mi;
450 {
451 	register struct hpdevice *hpaddr = (struct hpdevice *)mi->mi_drv;
452 	register struct buf *bp = mi->mi_tab.b_actf;
453 	register struct disklabel *lp;
454 	struct hpsoftc *sc = &hpsoftc[mi->mi_unit];
455 	daddr_t bn;
456 	int sn, tn, dist;
457 
458 	lp = &hplabel[mi->mi_unit];
459 	hpaddr->hpcs1 = 0;
460 	if ((hpaddr->hpcs1&HP_DVA) == 0)
461 		return (MBU_BUSY);
462 
463 	switch (sc->sc_recal) {
464 
465 	case 1:
466 		(void)HPWAIT(mi, hpaddr);
467 		hpaddr->hpdc = bp->b_cylin;
468 		hpaddr->hpcs1 = HP_SEEK|HP_GO;
469 		sc->sc_recal++;
470 		return (MBU_STARTED);
471 	case 2:
472 		break;
473 	}
474 	sc->sc_recal = 0;
475 	if ((hpaddr->hpds & HPDS_VV) == 0) {
476 		if (sc->sc_state == OPEN && lp->d_flags & D_REMOVABLE) {
477 			if (sc->sc_openpart)
478 				log(LOG_ERR, "hp%d: volume changed\n",
479 				    mi->mi_unit);
480 			sc->sc_openpart = 0;
481 			bp->b_flags |= B_ERROR;
482 			return (MBU_NEXT);
483 		}
484 		hpaddr->hpcs1 = HP_DCLR|HP_GO;
485 		if (mi->mi_mba->mba_drv[0].mbd_as & (1<<mi->mi_drive))
486 			printf("DCLR attn\n");
487 		hpaddr->hpcs1 = HP_PRESET|HP_GO;
488 		if (!ML11(mi->mi_type))
489 			hpaddr->hpof = HPOF_FMT22;
490 		mbclrattn(mi);
491 		if (sc->sc_state == WANTOPENRAW) {
492 			sc->sc_state = OPENRAW;
493 			return (MBU_NEXT);
494 		}
495 		if (sc->sc_state == WANTOPEN)
496 			sc->sc_state = RDLABEL;
497 	}
498 	if (mi->mi_tab.b_active || mi->mi_hd->mh_ndrive == 1) {
499 		if (mi->mi_tab.b_errcnt >= 16 && (bp->b_flags & B_READ)) {
500 			hpaddr->hpof =
501 			    hp_offset[mi->mi_tab.b_errcnt & 017]|HPOF_FMT22;
502 			hpaddr->hpcs1 = HP_OFFSET|HP_GO;
503 			(void)HPWAIT(mi, hpaddr);
504 			mbclrattn(mi);
505 		}
506 		return (MBU_DODATA);
507 	}
508 	if (ML11(mi->mi_type))
509 		return (MBU_DODATA);
510 	if ((hpaddr->hpds & HPDS_DREADY) != HPDS_DREADY)
511 		return (MBU_DODATA);
512 	bn = bp->b_blkno;
513 	sn = bn % lp->d_secpercyl;
514 	tn = sn / lp->d_nsectors;
515 	sn = sn % lp->d_nsectors;
516 	if (bp->b_cylin == MASKREG(hpaddr->hpdc)) {
517 		if (sc->sc_doseeks)
518 			return (MBU_DODATA);
519 		dist = sn - (MASKREG(hpaddr->hpla) >> 6) - 1;
520 		if (dist < 0)
521 			dist += lp->d_nsectors;
522 		if (dist > lp->d_maxdist || dist < lp->d_mindist)
523 			return (MBU_DODATA);
524 	} else
525 		hpaddr->hpdc = bp->b_cylin;
526 	if (sc->sc_doseeks)
527 		hpaddr->hpcs1 = HP_SEEK|HP_GO;
528 	else {
529 		sn = (sn + lp->d_nsectors - lp->d_sdist) % lp->d_nsectors;
530 		hpaddr->hpda = (tn << 8) + sn;
531 		hpaddr->hpcs1 = HP_SEARCH|HP_GO;
532 	}
533 	return (MBU_STARTED);
534 }
535 
536 hpstart(mi)
537 	register struct mba_device *mi;
538 {
539 	register struct hpdevice *hpaddr = (struct hpdevice *)mi->mi_drv;
540 	register struct buf *bp = mi->mi_tab.b_actf;
541 	register struct disklabel *lp = &hplabel[mi->mi_unit];
542 	struct hpsoftc *sc = &hpsoftc[mi->mi_unit];
543 	daddr_t bn;
544 	int sn, tn, cn;
545 
546 	if (ML11(mi->mi_type))
547 		hpaddr->hpda = bp->b_blkno + sc->sc_blkdone;
548 	else {
549 		if (bp->b_flags & B_BAD) {
550 			bn = sc->sc_badbn;
551 			cn = bn / lp->d_secpercyl;
552 		} else {
553 			bn = bp->b_blkno;
554 			cn = bp->b_cylin;
555 		}
556 		sn = bn % lp->d_secpercyl;
557 		if ((bp->b_flags & B_BAD) == 0)
558 			sn += sc->sc_blkdone;
559 		tn = sn / lp->d_nsectors;
560 		sn %= lp->d_nsectors;
561 		cn += tn / lp->d_ntracks;
562 		tn %= lp->d_ntracks;
563 		hpaddr->hpda = (tn << 8) + sn;
564 		hpaddr->hpdc = cn;
565 	}
566 	mi->mi_tab.b_bdone = dbtob(sc->sc_blkdone);
567 	if (bp->b_flags & B_FORMAT) {
568 		if (bp->b_flags & B_READ)
569 			return (HP_RHDR|HP_GO);
570 		else
571 			return (HP_WHDR|HP_GO);
572 	}
573 	return (0);
574 }
575 
576 hpdtint(mi, mbsr)
577 	register struct mba_device *mi;
578 	int mbsr;
579 {
580 	register struct hpdevice *hpaddr = (struct hpdevice *)mi->mi_drv;
581 	register struct buf *bp = mi->mi_tab.b_actf;
582 	register int er1, er2;
583 	struct hpsoftc *sc = &hpsoftc[mi->mi_unit];
584 	int retry = 0;
585 	int npf;
586 	daddr_t bn;
587 	int bcr;
588 
589 	bcr = MASKREG(-mi->mi_mba->mba_bcr);
590 	if (hpaddr->hpds&HPDS_ERR || mbsr&MBSR_EBITS) {
591 		er1 = hpaddr->hper1;
592 		er2 = hpaddr->hper2;
593 		if (bp->b_flags & B_BAD) {
594 			npf = bp->b_error;
595 			bn = sc->sc_badbn;
596 		} else {
597 			npf = btop(bp->b_bcount - bcr);
598 			if (er1 & (HPER1_DCK | HPER1_ECH))
599 				npf--;
600 			bn = bp->b_blkno + npf;
601 		}
602 		if (HPWAIT(mi, hpaddr) == 0)
603 			goto hard;
604 #ifdef HPDEBUG
605 		if (hpdebug) {
606 			int dc = hpaddr->hpdc, da = hpaddr->hpda;
607 
608 			log(LOG_DEBUG,
609 		    "hperr: bp %x cyl %d blk %d blkdone %d as %o dc %x da %x\n",
610 				bp, bp->b_cylin, bn, sc->sc_blkdone,
611 				hpaddr->hpas&0xff, MASKREG(dc), MASKREG(da));
612 			log(LOG_DEBUG,
613 				"errcnt %d mbsr=%b er1=%b er2=%b bcr -%d\n",
614 				mi->mi_tab.b_errcnt, mbsr, mbsr_bits,
615 				MASKREG(er1), HPER1_BITS,
616 				MASKREG(er2), HPER2_BITS, bcr);
617 		}
618 #endif
619 		if (er1 & HPER1_HCRC) {
620 			er1 &= ~(HPER1_HCE|HPER1_FER);
621 			er2 &= ~HPER2_BSE;
622 		}
623 		if (er1 & HPER1_WLE) {
624 			log(LOG_WARNING, "hp%d: write locked\n",
625 			    hpunit(bp->b_dev));
626 			bp->b_flags |= B_ERROR;
627 		} else if (bp->b_flags & B_FORMAT) {
628 			goto hard;
629 		} else if (RM80(mi->mi_type) && er2&HPER2_SSE) {
630 			(void) hpecc(mi, SSE);
631 			return (MBD_RESTARTED);
632 		} else if ((er2 & HPER2_BSE) && !ML11(mi->mi_type)) {
633 			if (hpecc(mi, BSE))
634 				return (MBD_RESTARTED);
635 			goto hard;
636 		} else if (MASKREG(er1) == HPER1_FER && RP06(mi->mi_type)) {
637 			if (hpecc(mi, BSE))
638 				return (MBD_RESTARTED);
639 			goto hard;
640 		} else if ((er1 & (HPER1_DCK | HPER1_ECH)) == HPER1_DCK &&
641 		    mi->mi_tab.b_errcnt >= 3) {
642 			if (hpecc(mi, ECC))
643 				return (MBD_RESTARTED);
644 			/*
645 			 * ECC corrected.  Only log retries below
646 			 * if we got errors other than soft ECC
647 			 * (as indicated by additional retries).
648 			 */
649 			if (mi->mi_tab.b_errcnt == 3)
650 				mi->mi_tab.b_errcnt = 0;
651 		} else if ((er1 & HPER1_HCRC) && !ML11(mi->mi_type) &&
652 		    hpecc(mi, BSE)) {
653  			/*
654  			 * HCRC means the header is screwed up and the sector
655  			 * might well exist in the bad sector table,
656 			 * better check....
657  			 */
658 			return (MBD_RESTARTED);
659 		} else if (++mi->mi_tab.b_errcnt > 27 ||
660 		    (ML11(mi->mi_type) && mi->mi_tab.b_errcnt > 15) ||
661 		    mbsr & MBSR_HARD ||
662 		    er1 & HPER1_HARD ||
663 		    (!ML11(mi->mi_type) && (er2 & HPER2_HARD))) {
664 hard:
665 			bp->b_blkno = bn;		/* XXX */
666 			harderr(bp, "hp");
667 			if (mbsr & (MBSR_EBITS &~ (MBSR_DTABT|MBSR_MBEXC)))
668 				printf("mbsr=%b ", mbsr, mbsr_bits);
669 			printf("er1=%b er2=%b",
670 			    MASKREG(hpaddr->hper1), HPER1_BITS,
671 			    MASKREG(hpaddr->hper2), HPER2_BITS);
672 			if (bp->b_flags & B_FORMAT)
673 				printf(" (hdr i/o)");
674 			printf("\n");
675 			bp->b_flags |= B_ERROR;
676 			bp->b_flags &= ~B_BAD;
677 		} else
678 			retry = 1;
679 		hpaddr->hpcs1 = HP_DCLR|HP_GO;
680 		if (retry && (mi->mi_tab.b_errcnt & 07) == 4) {
681 			hpaddr->hpcs1 = HP_RECAL|HP_GO;
682 			sc->sc_recal = 1;
683 			return (MBD_REPOSITION);
684 		}
685 	}
686 #ifdef HPDEBUG
687 	else
688 		if (hpdebug && sc->sc_recal) {
689 			log(LOG_DEBUG,
690 			    "recal %d errcnt %d mbsr=%b er1=%b er2=%b\n",
691 			    sc->sc_recal, mi->mi_tab.b_errcnt, mbsr, mbsr_bits,
692 			    hpaddr->hper1, HPER1_BITS,
693 			    hpaddr->hper2, HPER2_BITS);
694 		}
695 #endif
696 	(void)HPWAIT(mi, hpaddr);
697 	if (retry)
698 		return (MBD_RETRY);
699 	if (mi->mi_tab.b_errcnt >= 16) {
700 		/*
701 		 * This is fast and occurs rarely; we don't
702 		 * bother with interrupts.
703 		 */
704 		hpaddr->hpcs1 = HP_RTC|HP_GO;
705 		(void)HPWAIT(mi, hpaddr);
706 		mbclrattn(mi);
707 	}
708 	if (mi->mi_tab.b_errcnt && (bp->b_flags & B_ERROR) == 0)
709 		log(LOG_INFO, "hp%d%c: %d retries %sing sn%d\n",
710 		    hpunit(bp->b_dev), 'a'+(minor(bp->b_dev)&07),
711 		    mi->mi_tab.b_errcnt,
712 		    (bp->b_flags & B_READ) ? "read" : "writ",
713 		    (bp->b_flags & B_BAD) ?
714 		    sc->sc_badbn : bp->b_blkno + sc->sc_blkdone);
715 	if ((bp->b_flags & B_BAD) && hpecc(mi, CONT))
716 		return (MBD_RESTARTED);
717 	sc->sc_blkdone = 0;
718 	bp->b_resid = bcr;
719 	if (!ML11(mi->mi_type)) {
720 		hpaddr->hpof = HPOF_FMT22;
721 		hpaddr->hpcs1 = HP_RELEASE|HP_GO;
722 	}
723 	if (sc->sc_openpart == 0)
724 		wakeup((caddr_t)sc);
725 	return (MBD_DONE);
726 }
727 
728 /*
729  * Wait (for a bit) for a drive to come ready;
730  * returns nonzero on success.
731  */
732 hpwait(mi)
733 	register struct mba_device *mi;
734 {
735 	register struct hpdevice *hpaddr = (struct hpdevice *)mi->mi_drv;
736 	register i = 100000;
737 
738 	while ((hpaddr->hpds & HPDS_DRY) == 0 && --i)
739 		DELAY(10);
740 	if (i == 0)
741 		printf("hp%d: intr, not ready\n", mi->mi_unit);
742 	return (i);
743 }
744 
745 hpread(dev, uio)
746 	dev_t dev;
747 	struct uio *uio;
748 {
749 	register int unit = hpunit(dev);
750 
751 	if (unit >= NHP)
752 		return (ENXIO);
753 	return (physio(hpstrategy, &rhpbuf[unit], dev, B_READ, minphys, uio));
754 }
755 
756 hpwrite(dev, uio)
757 	dev_t dev;
758 	struct uio *uio;
759 {
760 	register int unit = hpunit(dev);
761 
762 	if (unit >= NHP)
763 		return (ENXIO);
764 	return (physio(hpstrategy, &rhpbuf[unit], dev, B_WRITE, minphys, uio));
765 }
766 
767 hpioctl(dev, cmd, data, flag)
768 	dev_t dev;
769 	int cmd;
770 	caddr_t data;
771 	int flag;
772 {
773 	int unit = hpunit(dev);
774 	register struct disklabel *lp;
775 	register struct format_op *fop;
776 	int error = 0;
777 	int hpformat();
778 
779 	lp = &hplabel[unit];
780 
781 	switch (cmd) {
782 
783 	case DIOCGDINFO:
784 		*(struct disklabel *)data = *lp;
785 		break;
786 
787 	case DIOCGPART:
788 		((struct partinfo *)data)->disklab = lp;
789 		((struct partinfo *)data)->part =
790 		    &lp->d_partitions[hppart(dev)];
791 		break;
792 
793 	case DIOCSDINFO:
794 		if ((flag & FWRITE) == 0)
795 			error = EBADF;
796 		else
797 			*lp = *(struct disklabel *)data;
798 		break;
799 
800 	case DIOCWDINFO:
801 		if ((flag & FWRITE) == 0) {
802 			error = EBADF;
803 			break;
804 		}
805 		{
806 		struct buf *bp;
807 		struct disklabel *dlp;
808 
809 		*lp = *(struct disklabel *)data;
810 		bp = geteblk(lp->d_secsize);
811 		bp->b_dev = makedev(major(dev), hpminor(hpunit(dev), 0));
812 		bp->b_blkno = LABELSECTOR;
813 		bp->b_bcount = lp->d_secsize;
814 		bp->b_flags = B_READ;
815 		dlp = (struct disklabel *)(bp->b_un.b_addr + LABELOFFSET);
816 		hpstrategy(bp);
817 		biowait(bp);
818 		if (bp->b_flags & B_ERROR) {
819 			error = u.u_error;		/* XXX */
820 			u.u_error = 0;
821 			goto bad;
822 		}
823 		*dlp = *lp;
824 		bp->b_flags = B_WRITE;
825 		hpstrategy(bp);
826 		biowait(bp);
827 		if (bp->b_flags & B_ERROR) {
828 			error = u.u_error;		/* XXX */
829 			u.u_error = 0;
830 		}
831 bad:
832 		brelse(bp);
833 		}
834 		break;
835 
836 #ifdef notyet
837 	case DIOCWFORMAT:
838 		if ((flag & FWRITE) == 0) {
839 			error = EBADF;
840 			break;
841 		}
842 		{
843 		struct uio auio;
844 		struct iovec aiov;
845 
846 		fop = (struct format_op *)data;
847 		aiov.iov_base = fop->df_buf;
848 		aiov.iov_len = fop->df_count;
849 		auio.uio_iov = &aiov;
850 		auio.uio_iovcnt = 1;
851 		auio.uio_resid = fop->df_count;
852 		auio.uio_segflg = 0;
853 		auio.uio_offset = fop->df_startblk * lp->d_secsize;
854 		error = physio(hpformat, &rhpbuf[unit], dev, B_WRITE,
855 			minphys, &auio);
856 		fop->df_count -= auio.uio_resid;
857 		fop->df_reg[0] = sc->sc_status;
858 		fop->df_reg[1] = sc->sc_error;
859 		}
860 		break;
861 #endif
862 
863 	default:
864 		error = ENOTTY;
865 		break;
866 	}
867 	return (0);
868 }
869 
870 hpformat(bp)
871 	struct buf *bp;
872 {
873 
874 	bp->b_flags |= B_FORMAT;
875 	return (hpstrategy(bp));
876 }
877 
878 hpecc(mi, flag)
879 	register struct mba_device *mi;
880 	int flag;
881 {
882 	register struct mba_regs *mbp = mi->mi_mba;
883 	register struct hpdevice *rp = (struct hpdevice *)mi->mi_drv;
884 	register struct buf *bp = mi->mi_tab.b_actf;
885 	register struct disklabel *lp = &hplabel[mi->mi_unit];
886 	struct hpsoftc *sc = &hpsoftc[mi->mi_unit];
887 	int npf, o;
888 	int bn, cn, tn, sn;
889 	int bcr;
890 
891 	bcr = MASKREG(-mbp->mba_bcr);
892 	if (bp->b_flags & B_BAD)
893 		npf = bp->b_error;
894 	else {
895 		npf = bp->b_bcount - bcr;
896 		/*
897 		 * Watch out for fractional sector at end of transfer;
898 		 * want to round up if finished, otherwise round down.
899 		 */
900 		if (bcr == 0)
901 			npf += 511;
902 		npf = btodb(npf);
903 	}
904 	o = (int)bp->b_un.b_addr & PGOFSET;
905 	bn = bp->b_blkno;
906 	cn = bp->b_cylin;
907 	sn = bn % lp->d_secpercyl + npf;
908 	tn = sn / lp->d_nsectors;
909 	sn %= lp->d_nsectors;
910 	cn += tn / lp->d_ntracks;
911 	tn %= lp->d_ntracks;
912 	bn += npf;
913 	switch (flag) {
914 	case ECC: {
915 		register int i;
916 		caddr_t addr;
917 		struct pte mpte;
918 		int bit, byte, mask;
919 
920 		npf--;		/* because block in error is previous block */
921 		bn--;
922 		if (bp->b_flags & B_BAD)
923 			bn = sc->sc_badbn;
924 		log(LOG_WARNING, "hp%d%c: soft ecc sn%d\n", hpunit(bp->b_dev),
925 		    'a'+(minor(bp->b_dev)&07), bn);
926 		mask = MASKREG(rp->hpec2);
927 		i = MASKREG(rp->hpec1) - 1;		/* -1 makes 0 origin */
928 		bit = i&07;
929 		i = (i&~07)>>3;
930 		byte = i + o;
931 		while (i < 512 && (int)dbtob(npf)+i < bp->b_bcount && bit > -11) {
932 			mpte = mbp->mba_map[npf+btop(byte)];
933 			addr = ptob(mpte.pg_pfnum) + (byte & PGOFSET);
934 			putmemc(addr, getmemc(addr)^(mask<<bit));
935 			byte++;
936 			i++;
937 			bit -= 8;
938 		}
939 		if (bcr == 0)
940 			return (0);
941 		npf++;
942 		break;
943 		}
944 
945 	case SSE:
946 		rp->hpof |= HPOF_SSEI;
947 		if (bp->b_flags & B_BAD) {
948 			bn = sc->sc_badbn;
949 			goto fixregs;
950 		}
951 		mbp->mba_bcr = -(bp->b_bcount - (int)ptob(npf));
952 		break;
953 
954 	case BSE:
955 		if (sc->sc_state == OPENRAW)
956 			return (0);
957  		if (rp->hpof & HPOF_SSEI)
958  			sn++;
959 #ifdef HPBDEBUG
960 		if (hpbdebug)
961 		log(LOG_DEBUG, "hpecc, BSE: bn %d cn %d tn %d sn %d\n", bn, cn, tn, sn);
962 #endif
963 		if (bp->b_flags & B_BAD)
964 			return (0);
965 		if ((bn = isbad(&hpbad[mi->mi_unit], cn, tn, sn)) < 0)
966 			return (0);
967 		bp->b_flags |= B_BAD;
968 		bp->b_error = npf + 1;
969  		rp->hpof &= ~HPOF_SSEI;
970 		bn = lp->d_ncylinders * lp->d_secpercyl -
971 		    lp->d_nsectors - 1 - bn;
972 		sc->sc_badbn = bn;
973 	fixregs:
974 		cn = bn / lp->d_secpercyl;
975 		sn = bn % lp->d_secpercyl;
976 		tn = sn / lp->d_nsectors;
977 		sn %= lp->d_nsectors;
978 		bcr = bp->b_bcount - (int)ptob(npf);
979 		bcr = MIN(bcr, 512);
980 		mbp->mba_bcr = -bcr;
981 #ifdef HPBDEBUG
982 		if (hpbdebug)
983 		log(LOG_DEBUG, "revector to cn %d tn %d sn %d\n", cn, tn, sn);
984 #endif
985 		break;
986 
987 	case CONT:
988 #ifdef HPBDEBUG
989 		if (hpbdebug)
990 		log(LOG_DEBUG, "hpecc, CONT: bn %d cn %d tn %d sn %d\n", bn,cn,tn,sn);
991 #endif
992 		bp->b_flags &= ~B_BAD;
993 		if ((int)ptob(npf) >= bp->b_bcount)
994 			return (0);
995 		mbp->mba_bcr = -(bp->b_bcount - (int)ptob(npf));
996 		break;
997 	}
998 	rp->hpcs1 = HP_DCLR|HP_GO;
999 	if (rp->hpof & HPOF_SSEI)
1000 		sn++;
1001 	rp->hpdc = cn;
1002 	rp->hpda = (tn<<8) + sn;
1003 	mbp->mba_sr = -1;
1004 	mbp->mba_var = (int)ptob(npf) + o;
1005 	rp->hpcs1 = bp->b_flags&B_READ ? HP_RCOM|HP_GO : HP_WCOM|HP_GO;
1006 	mi->mi_tab.b_errcnt = 0;	/* error has been corrected */
1007 	sc->sc_blkdone = npf;
1008 	return (1);
1009 }
1010 
1011 #define	DBSIZE	20
1012 
1013 hpdump(dev)
1014 	dev_t dev;
1015 {
1016 	register struct mba_device *mi;
1017 	register struct mba_regs *mba;
1018 	struct hpdevice *hpaddr;
1019 	char *start;
1020 	int num, unit;
1021 	register struct disklabel *lp;
1022 
1023 	num = maxfree;
1024 	start = 0;
1025 	unit = hpunit(dev);
1026 	if (unit >= NHP)
1027 		return (ENXIO);
1028 #define	phys(a,b)	((b)((int)(a)&0x7fffffff))
1029 	mi = phys(hpinfo[unit],struct mba_device *);
1030 	if (mi == 0 || mi->mi_alive == 0)
1031 		return (ENXIO);
1032 	lp = &hplabel[unit];
1033 	mba = phys(mi->mi_hd, struct mba_hd *)->mh_physmba;
1034 	mba->mba_cr = MBCR_INIT;
1035 	hpaddr = (struct hpdevice *)&mba->mba_drv[mi->mi_drive];
1036 	if ((hpaddr->hpds & HPDS_VV) == 0) {
1037 		hpaddr->hpcs1 = HP_DCLR|HP_GO;
1038 		hpaddr->hpcs1 = HP_PRESET|HP_GO;
1039 		hpaddr->hpof = HPOF_FMT22;
1040 	}
1041 	if (dumplo < 0)
1042 		return (EINVAL);
1043 	if (dumplo + num >= lp->d_partitions[hppart(dev)].p_size)
1044 		num = lp->d_partitions[hppart(dev)].p_size - dumplo;
1045 	while (num > 0) {
1046 		register struct pte *hpte = mba->mba_map;
1047 		register int i;
1048 		int blk, cn, sn, tn;
1049 		daddr_t bn;
1050 
1051 		blk = num > DBSIZE ? DBSIZE : num;
1052 		bn = dumplo + btop(start);
1053 		cn = (bn + lp->d_partitions[hppart(dev)].p_offset) /
1054 		    lp->d_secpercyl;
1055 		sn = bn % lp->d_secpercyl;
1056 		tn = sn / lp->d_nsectors;
1057 		sn = sn % lp->d_nsectors;
1058 		hpaddr->hpdc = cn;
1059 		hpaddr->hpda = (tn << 8) + sn;
1060 		for (i = 0; i < blk; i++)
1061 			*(int *)hpte++ = (btop(start)+i) | PG_V;
1062 		mba->mba_sr = -1;
1063 		mba->mba_bcr = -(blk*NBPG);
1064 		mba->mba_var = 0;
1065 		hpaddr->hpcs1 = HP_WCOM | HP_GO;
1066 		while ((hpaddr->hpds & HPDS_DRY) == 0)
1067 			DELAY(10);
1068 		if (hpaddr->hpds&HPDS_ERR)
1069 			return (EIO);
1070 		start += blk*NBPG;
1071 		num -= blk;
1072 	}
1073 	return (0);
1074 }
1075 
1076 hpsize(dev)
1077 	dev_t dev;
1078 {
1079 	register int unit = hpunit(dev);
1080 	struct mba_device *mi;
1081 
1082 	if (unit >= NHP || (mi = hpinfo[unit]) == 0 || mi->mi_alive == 0 ||
1083 	    hpsoftc[unit].sc_state != OPEN)
1084 		return (-1);
1085 	return ((int)hplabel[unit].d_partitions[hppart(dev)].p_size);
1086 }
1087 
1088 #ifdef COMPAT_42
1089 /*
1090  * Compatibility code to fake up pack label
1091  * for unlabeled disks.
1092  */
1093 struct	size {
1094 	daddr_t	nblocks;
1095 	int	cyloff;
1096 } rp06_sizes[8] = {
1097 	15884,	0,		/* A=cyl 0 thru 37 */
1098 	33440,	38,		/* B=cyl 38 thru 117 */
1099 	340670,	0,		/* C=cyl 0 thru 814 */
1100 	15884,	118,		/* D=cyl 118 thru 155 */
1101 	55936,	156,		/* E=cyl 156 thru 289 */
1102 	219384,	290,		/* F=cyl 290 thru 814 */
1103 	291280,	118,		/* G=cyl 118 thru 814 */
1104 	0,	0,
1105 }, rp05_sizes[8] = {
1106 	15884,	0,		/* A=cyl 0 thru 37 */
1107 	33440,	38,		/* B=cyl 38 thru 117 */
1108 	171798,	0,		/* C=cyl 0 thru 410 */
1109 	15884,	118,		/* D=cyl 118 thru 155 */
1110 	55936,	156,		/* E=cyl 156 thru 289 */
1111 	50512,	290,		/* F=cyl 290 thru 410 */
1112 	122408,	118,		/* G=cyl 118 thru 410 */
1113 	0,	0,
1114 }, rm03_sizes[8] = {
1115 	15884,	0,		/* A=cyl 0 thru 99 */
1116 	33440,	100,		/* B=cyl 100 thru 308 */
1117 	131680,	0,		/* C=cyl 0 thru 822 */
1118 	15884,	309,		/* D=cyl 309 thru 408 */
1119 	55936,	409,		/* E=cyl 409 thru 758 */
1120 	10144,	759,		/* F=cyl 759 thru 822 */
1121 	82144,	309,		/* G=cyl 309 thru 822 */
1122 	0,	0,
1123 }, rm05_sizes[8] = {
1124 	15884,	0,		/* A=cyl 0 thru 26 */
1125 	33440,	27,		/* B=cyl 27 thru 81 */
1126 	500384,	0,		/* C=cyl 0 thru 822 */
1127 	15884,	562,		/* D=cyl 562 thru 588 */
1128 	55936,	589,		/* E=cyl 589 thru 680 */
1129 	86240,	681,		/* F=cyl 681 thru 822 */
1130 	158592,	562,		/* G=cyl 562 thru 822 */
1131 	291346,	82,		/* H=cyl 82 thru 561 */
1132 }, rm80_sizes[8] = {
1133 	15884,	0,		/* A=cyl 0 thru 36 */
1134 	33440,	37,		/* B=cyl 37 thru 114 */
1135 	242606,	0,		/* C=cyl 0 thru 558 */
1136 	15884,	115,		/* D=cyl 115 thru 151 */
1137 	55936,	152,		/* E=cyl 152 thru 280 */
1138 	120559,	281,		/* F=cyl 281 thru 558 */
1139 	192603,	115,		/* G=cyl 115 thru 558 */
1140 	0,	0,
1141 }, rp07_sizes[8] = {
1142 	15884,	0,		/* A=cyl 0 thru 9 */
1143 	66880,	10,		/* B=cyl 10 thru 51 */
1144 	1008000, 0,		/* C=cyl 0 thru 629 */
1145 	15884,	235,		/* D=cyl 235 thru 244 */
1146 	307200,	245,		/* E=cyl 245 thru 436 */
1147 	308650,	437,		/* F=cyl 437 thru 629 */
1148 	631850,	235,		/* G=cyl 235 thru 629 */
1149 	291346,	52,		/* H=cyl 52 thru 234 */
1150 }, cdc9775_sizes[8] = {
1151 	15884,	0,		/* A=cyl 0 thru 12 */
1152 	66880,	13,		/* B=cyl 13 thru 65 */
1153 	1077760, 0,		/* C=cyl 0 thru 841 */
1154 	15884,	294,		/* D=cyl 294 thru 306 */
1155 	307200,	307,		/* E=cyl 307 thru 546 */
1156 	377440,	547,		/* F=cyl 547 thru 841 */
1157 	701280,	294,		/* G=cyl 294 thru 841 */
1158 	291346,	66,		/* H=cyl 66 thru 293 */
1159 }, cdc9730_sizes[8] = {
1160 	15884,	0,		/* A=cyl 0 thru 49 */
1161 	33440,	50,		/* B=cyl 50 thru 154 */
1162 	263360,	0,		/* C=cyl 0 thru 822 */
1163 	15884,	155,		/* D=cyl 155 thru 204 */
1164 	55936,	205,		/* E=cyl 205 thru 379 */
1165 	141664,	380,		/* F=cyl 380 thru 822 */
1166 	213664,	155,		/* G=cyl 155 thru 822 */
1167 	0,	0,
1168 }, capricorn_sizes[8] = {
1169 	15884,	0,		/* A=cyl 0 thru 31 */
1170 	33440,	32,		/* B=cyl 32 thru 97 */
1171 	524288,	0,		/* C=cyl 0 thru 1023 */
1172 	15884,	668,		/* D=cyl 668 thru 699 */
1173 	55936,	700,		/* E=cyl 700 thru 809 */
1174 	109472,	810,		/* F=cyl 810 thru 1023 */
1175 	182176,	668,		/* G=cyl 668 thru 1023 */
1176 	291346,	98,		/* H=cyl 98 thru 667 */
1177 }, eagle_sizes[8] = {
1178 	15884,	0,		/* A=cyl 0 thru 16 */
1179 	66880,	17,		/* B=cyl 17 thru 86 */
1180 	808320,	0,		/* C=cyl 0 thru 841 */
1181 	15884,	391,		/* D=cyl 391 thru 407 */
1182 	307200,	408,		/* E=cyl 408 thru 727 */
1183 	109296,	728,		/* F=cyl 728 thru 841 */
1184 	432816,	391,		/* G=cyl 391 thru 841 */
1185 	291346,	87,		/* H=cyl 87 thru 390 */
1186 }, ampex_sizes[8] = {
1187 	15884,	0,		/* A=cyl 0 thru 26 */
1188 	33440,	27,		/* B=cyl 27 thru 81 */
1189 	495520,	0,		/* C=cyl 0 thru 814 */
1190 	15884,	562,		/* D=cyl 562 thru 588 */
1191 	55936,	589,		/* E=cyl 589 thru 680 */
1192 	81312,	681,		/* F=cyl 681 thru 814 */
1193 	153664,	562,		/* G=cyl 562 thru 814 */
1194 	291346,	82,		/* H=cyl 82 thru 561 */
1195 }, fj2361_sizes[8] = {
1196 	15884,	0,		/* A=cyl 0 thru 12 */
1197 	66880,	13,		/* B=cyl 13 thru 65 */
1198 	1077760, 0,		/* C=cyl 0 thru 841 */
1199 	15884,	294,		/* D=cyl 294 thru 306 */
1200 	307200,	307,		/* E=cyl 307 thru 546 */
1201 	377408,	547,		/* F=cyl 547 thru 841 */
1202 	701248,	294,		/* G=cyl 294 thru 841 */
1203 	291346,	66,		/* H=cyl 66 thru 293 */
1204 };
1205 
1206 /*
1207  * These variable are all measured in sectors.
1208  * Sdist is how much to "lead" in the search for a desired sector
1209  * (i.e. if want N, search for N-sdist.)
1210  * Maxdist and mindist define the region right before our desired sector within
1211  * which we don't bother searching.  We don't search when we are already less
1212  * then maxdist and more than mindist sectors "before" our desired sector.
1213  * Maxdist should be >= sdist.
1214  *
1215  * Beware, sdist, mindist and maxdist are not well tuned
1216  * for many of the drives listed in this table.
1217  * Try patching things with something i/o intensive
1218  * running and watch iostat.
1219  */
1220 struct hpst {
1221 	short	nsect;		/* # sectors/track */
1222 	short	ntrak;		/* # tracks/cylinder */
1223 	short	nspc;		/* # sector/cylinders */
1224 	short	ncyl;		/* # cylinders */
1225 	struct	size *sizes;	/* partition tables */
1226 	short	sdist;		/* seek distance metric */
1227 	short	maxdist;	/* boundaries of non-searched area */
1228 	short	mindist;	/* preceding the target sector */
1229 	char	*name;		/* name of disk type */
1230 } hpst[] = {
1231     { 32, 5,	32*5,	823,	rm03_sizes,	7, 4, 1, "RM03" },
1232     { 32, 19,	32*19,	823,	rm05_sizes,	7, 4, 1, "RM05" },
1233     { 22,19,	22*19,	815,	rp06_sizes,	7, 4, 1, "RP06"},
1234     { 31, 14, 	31*14,	559,	rm80_sizes,	7, 4, 1, "RM80"},
1235     { 22, 19,	22*19,	411,	rp05_sizes,	7, 4, 1, "RP04"},
1236     { 22, 19,	22*19,	411,	rp05_sizes,	7, 4, 1, "RP05"},
1237     { 50, 32,	50*32,	630,	rp07_sizes,    15, 8, 3, "RP07"},
1238     { 1, 1,	1,	1,	0,		0, 0, 0, "ML11A"},
1239     { 1, 1,	1,	1,	0,		0, 0, 0, "ML11B" },
1240     { 32, 40,	32*40,	843,	cdc9775_sizes,	7, 4, 1, "9775" },
1241     { 32, 10,	32*10,	823,	cdc9730_sizes,	7, 4, 1, "9730-160" },
1242     { 32, 16,	32*16,	1024,	capricorn_sizes,10,4, 3, "capricorn" },
1243     { 48, 20,	48*20,	842,	eagle_sizes,   15, 8, 3, "eagle" },
1244     { 32, 19,	32*19,	815,	ampex_sizes,	7, 4, 1, "9300" },
1245     { 64, 20,	64*20,	842,	fj2361_sizes,  15, 8, 3, "2361" },
1246 };
1247 
1248 /*
1249  * Map apparent MASSBUS drive type into manufacturer
1250  * specific configuration.  For SI controllers this is done
1251  * based on codes in the serial number register.  For
1252  * EMULEX controllers, the track and sector attributes are
1253  * used when the drive type is an RM02 (not supported by DEC).
1254  */
1255 hpmaptype(mi, lp)
1256 	register struct mba_device *mi;
1257 	register struct disklabel *lp;
1258 {
1259 	register struct hpdevice *hpaddr = (struct hpdevice *)mi->mi_drv;
1260 	register int type = mi->mi_type;
1261 	register struct hpst *st;
1262 	register i;
1263 
1264 	/*
1265 	 * Model-byte processing for SI controllers.
1266 	 * NB:  Only deals with RM03 and RM05 emulations.
1267 	 */
1268 	if (type == HPDT_RM03 || type == HPDT_RM05) {
1269 		int hpsn = hpaddr->hpsn;
1270 
1271 		if ((hpsn & SIMB_LU) == mi->mi_drive)
1272 		switch ((hpsn & SIMB_MB) & ~(SIMB_S6|SIRM03|SIRM05)) {
1273 
1274 		case SI9775D:
1275 			type = HPDT_9775;
1276 			break;
1277 
1278 		case SI9730D:
1279 			type = HPDT_9730;
1280 			break;
1281 
1282 		case SI9766:
1283 			type = HPDT_RM05;
1284 			break;
1285 
1286 		case SI9762:
1287 			type = HPDT_RM03;
1288 			break;
1289 
1290 		case SICAPD:
1291 			type = HPDT_CAPRICORN;
1292 			break;
1293 
1294 		case SI9751D:
1295 			type = HPDT_EAGLE;
1296 			break;
1297 		}
1298 	}
1299 
1300 	/*
1301 	 * EMULEX SC750 or SC780.  Poke the holding register.
1302 	 */
1303 	if (type == HPDT_RM02) {
1304 		int nsectors, ntracks, ncyl;
1305 
1306 		hpaddr->hpof = HPOF_FMT22;
1307 		mbclrattn(mi);
1308 		hpaddr->hpcs1 = HP_NOP;
1309 		hpaddr->hphr = HPHR_MAXTRAK;
1310 		ntracks = MASKREG(hpaddr->hphr) + 1;
1311 		DELAY(100);
1312 		hpaddr->hpcs1 = HP_NOP;
1313 		hpaddr->hphr = HPHR_MAXSECT;
1314 		nsectors = MASKREG(hpaddr->hphr) + 1;
1315 		DELAY(100);
1316 		hpaddr->hpcs1 = HP_NOP;
1317 		hpaddr->hphr = HPHR_MAXCYL;
1318 		ncyl = MASKREG(hpaddr->hphr) + 1;
1319 		for (type = 0; hptypes[type] != 0; type++)
1320 			if (hpst[type].nsect == nsectors &&
1321 			    hpst[type].ntrak == ntracks &&
1322 			    hpst[type].ncyl == ncyl)
1323 				break;
1324 
1325 		if (hptypes[type] == 0) {
1326 	printf("hp%d: %d sectors, %d tracks, %d cylinders: unknown device\n",
1327 				mi->mi_unit, nsectors, ntracks, ncyl);
1328 			type = HPDT_RM02;
1329 		}
1330 		hpaddr->hpcs1 = HP_DCLR|HP_GO;
1331 		mbclrattn(mi);		/* conservative */
1332 	}
1333 
1334 	/*
1335 	 * set up minimal disk label.
1336 	 */
1337 	st = &hpst[type];
1338 	lp->d_secsize = 512;
1339 	lp->d_nsectors = st->nsect;
1340 	lp->d_ntracks = st->ntrak;
1341 	lp->d_secpercyl = st->nspc;
1342 	lp->d_ncylinders = st->ncyl;
1343 	lp->d_secperunit = st->nspc * st->ncyl;
1344 	lp->d_sdist = st->sdist;
1345 	lp->d_mindist = st->mindist;
1346 	lp->d_maxdist = st->maxdist;
1347 	bcopy(hpst[type].name, lp->d_typename, sizeof(lp->d_typename));
1348 	lp->d_npartitions = 8;
1349 	for (i = 0; i < 8; i++) {
1350 		lp->d_partitions[i].p_offset = st->sizes[i].cyloff *
1351 		    lp->d_secpercyl;
1352 		lp->d_partitions[i].p_size = st->sizes[i].nblocks;
1353 	}
1354 	return (type);
1355 }
1356 #endif COMPAT_42
1357 #endif
1358