xref: /netbsd-src/sys/arch/hp300/dev/rd.c (revision ce0bb6e8d2e560ecacbe865a848624f94498063b)
1 /*	$NetBSD: rd.c,v 1.11 1995/04/10 13:09:56 mycroft Exp $	*/
2 
3 /*
4  * Copyright (c) 1988 University of Utah.
5  * Copyright (c) 1982, 1990, 1993
6  *	The Regents of the University of California.  All rights reserved.
7  *
8  * This code is derived from software contributed to Berkeley by
9  * the Systems Programming Group of the University of Utah Computer
10  * Science Department.
11  *
12  * Redistribution and use in source and binary forms, with or without
13  * modification, are permitted provided that the following conditions
14  * are met:
15  * 1. Redistributions of source code must retain the above copyright
16  *    notice, this list of conditions and the following disclaimer.
17  * 2. Redistributions in binary form must reproduce the above copyright
18  *    notice, this list of conditions and the following disclaimer in the
19  *    documentation and/or other materials provided with the distribution.
20  * 3. All advertising materials mentioning features or use of this software
21  *    must display the following acknowledgement:
22  *	This product includes software developed by the University of
23  *	California, Berkeley and its contributors.
24  * 4. Neither the name of the University nor the names of its contributors
25  *    may be used to endorse or promote products derived from this software
26  *    without specific prior written permission.
27  *
28  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
29  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
30  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
31  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
32  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
33  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
34  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
35  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
36  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
37  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
38  * SUCH DAMAGE.
39  *
40  * from: Utah $Hdr: rd.c 1.44 92/12/26$
41  *
42  *	@(#)rd.c	8.2 (Berkeley) 5/19/94
43  */
44 
45 /*
46  * CS80/SS80 disk driver
47  */
48 #include "rd.h"
49 #if NRD > 0
50 
51 #include <sys/param.h>
52 #include <sys/systm.h>
53 #include <sys/buf.h>
54 #include <sys/stat.h>
55 #include <sys/dkstat.h>
56 #include <sys/disklabel.h>
57 #include <sys/ioctl.h>
58 #include <sys/fcntl.h>
59 
60 #include <hp300/dev/device.h>
61 #include <hp300/dev/rdreg.h>
62 #include <hp300/dev/rdvar.h>
63 #ifdef USELEDS
64 #include <hp300/hp300/led.h>
65 #endif
66 
67 #include <vm/vm_param.h>
68 #include <vm/lock.h>
69 #include <vm/vm_prot.h>
70 #include <vm/pmap.h>
71 
72 int	rdinit(), rdstart(), rdgo(), rdintr();
73 void	rdstrategy();
74 struct	driver rddriver = {
75 	rdinit, "rd", rdstart, rdgo, rdintr,
76 };
77 
78 struct	rd_softc rd_softc[NRD];
79 struct	buf rdtab[NRD];
80 int	rderrthresh = RDRETRY-1;	/* when to start reporting errors */
81 
82 #ifdef DEBUG
83 /* error message tables */
84 char *err_reject[] = {
85 	0, 0,
86 	"channel parity error",		/* 0x2000 */
87 	0, 0,
88 	"illegal opcode",		/* 0x0400 */
89 	"module addressing",		/* 0x0200 */
90 	"address bounds",		/* 0x0100 */
91 	"parameter bounds",		/* 0x0080 */
92 	"illegal parameter",		/* 0x0040 */
93 	"message sequence",		/* 0x0020 */
94 	0,
95 	"message length",		/* 0x0008 */
96 	0, 0, 0
97 };
98 
99 char *err_fault[] = {
100 	0,
101 	"cross unit",			/* 0x4000 */
102 	0,
103 	"controller fault",		/* 0x1000 */
104 	0, 0,
105 	"unit fault",			/* 0x0200 */
106 	0,
107 	"diagnostic result",		/* 0x0080 */
108 	0,
109 	"operator release request",	/* 0x0020 */
110 	"diagnostic release request",	/* 0x0010 */
111 	"internal maintenance release request",	/* 0x0008 */
112 	0,
113 	"power fail",			/* 0x0002 */
114 	"retransmit"			/* 0x0001 */
115 };
116 
117 char *err_access[] = {
118 	"illegal parallel operation",	/* 0x8000 */
119 	"uninitialized media",		/* 0x4000 */
120 	"no spares available",		/* 0x2000 */
121 	"not ready",			/* 0x1000 */
122 	"write protect",		/* 0x0800 */
123 	"no data found",		/* 0x0400 */
124 	0, 0,
125 	"unrecoverable data overflow",	/* 0x0080 */
126 	"unrecoverable data",		/* 0x0040 */
127 	0,
128 	"end of file",			/* 0x0010 */
129 	"end of volume",		/* 0x0008 */
130 	0, 0, 0
131 };
132 
133 char *err_info[] = {
134 	"operator release request",	/* 0x8000 */
135 	"diagnostic release request",	/* 0x4000 */
136 	"internal maintenance release request",	/* 0x2000 */
137 	"media wear",			/* 0x1000 */
138 	"latency induced",		/* 0x0800 */
139 	0, 0,
140 	"auto sparing invoked",		/* 0x0100 */
141 	0,
142 	"recoverable data overflow",	/* 0x0040 */
143 	"marginal data",		/* 0x0020 */
144 	"recoverable data",		/* 0x0010 */
145 	0,
146 	"maintenance track overflow",	/* 0x0004 */
147 	0, 0
148 };
149 
150 struct	rdstats rdstats[NRD];
151 int	rddebug = 0x80;
152 #define RDB_FOLLOW	0x01
153 #define RDB_STATUS	0x02
154 #define RDB_IDENT	0x04
155 #define RDB_IO		0x08
156 #define RDB_ASYNC	0x10
157 #define RDB_ERROR	0x80
158 #endif
159 
160 /*
161  * Misc. HW description, indexed by sc_type.
162  * Nothing really critical here, could do without it.
163  */
164 struct rdidentinfo rdidentinfo[] = {
165 	{ RD7946AID,	0,	"7945A",	 108416 },
166 	{ RD9134DID,	1,	"9134D",	  29088 },
167 	{ RD9134LID,	1,	"9122S",	   1232 },
168 	{ RD7912PID,	0,	"7912P",	 128128 },
169 	{ RD7914PID,	0,	"7914P",	 258048 },
170 	{ RD7958AID,	0,	"7958A",	 255276 },
171 	{ RD7957AID,	0,	"7957A",	 159544 },
172 	{ RD7933HID,	0,	"7933H",	 789958 },
173 	{ RD9134LID,	1,	"9134L",	  77840 },
174 	{ RD7936HID,	0,	"7936H",	 600978 },
175 	{ RD7937HID,	0,	"7937H",	1116102 },
176 	{ RD7914CTID,	0,	"7914CT",	 258048 },
177 	{ RD7946AID,	0,	"7946A",	 108416 },
178 	{ RD9134LID,	1,	"9122D",	   1232 },
179 	{ RD7957BID,	0,	"7957B",	 159894 },
180 	{ RD7958BID,	0,	"7958B",	 297108 },
181 	{ RD7959BID,	0,	"7959B",	 594216 },
182 	{ RD2200AID,	0,	"2200A",	 654948 },
183 	{ RD2203AID,	0,	"2203A",	1309896 }
184 };
185 int numrdidentinfo = sizeof(rdidentinfo) / sizeof(rdidentinfo[0]);
186 
187 rdinit(hd)
188 	register struct hp_device *hd;
189 {
190 	register struct rd_softc *rs = &rd_softc[hd->hp_unit];
191 
192 	rs->sc_hd = hd;
193 	rs->sc_punit = rdpunit(hd->hp_flags);
194 	rs->sc_type = rdident(rs, hd);
195 	if (rs->sc_type < 0)
196 		return(0);
197 	rs->sc_dq.dq_ctlr = hd->hp_ctlr;
198 	rs->sc_dq.dq_unit = hd->hp_unit;
199 	rs->sc_dq.dq_slave = hd->hp_slave;
200 	rs->sc_dq.dq_driver = &rddriver;
201 	rs->sc_flags = RDF_ALIVE;
202 #ifdef DEBUG
203 	/* always report errors */
204 	if (rddebug & RDB_ERROR)
205 		rderrthresh = 0;
206 #endif
207 	return(1);
208 }
209 
210 rdident(rs, hd)
211 	struct rd_softc *rs;
212 	struct hp_device *hd;
213 {
214 	struct rd_describe desc;
215 	u_char stat, cmd[3];
216 	int unit, lunit;
217 	char name[7];
218 	register int ctlr, slave, id, i;
219 
220 	ctlr = hd->hp_ctlr;
221 	slave = hd->hp_slave;
222 	unit = rs->sc_punit;
223 	lunit = hd->hp_unit;
224 
225 	/*
226 	 * Grab device id and make sure:
227 	 * 1. It is a CS80 device.
228 	 * 2. It is one of the types we support.
229 	 * 3. If it is a 7946, we are accessing the disk unit (0)
230 	 */
231 	id = hpibid(ctlr, slave);
232 #ifdef DEBUG
233 	if (rddebug & RDB_IDENT)
234 		printf("hpibid(%d, %d) -> %x\n", ctlr, slave, id);
235 #endif
236 	if ((id & 0x200) == 0)
237 		return(-1);
238 	for (i = 0; i < numrdidentinfo; i++)
239 		if (id == rdidentinfo[i].ri_hwid)
240 			break;
241 	if (i == numrdidentinfo || unit > rdidentinfo[i].ri_maxunum)
242 		return(-1);
243 	id = i;
244 
245 	/*
246 	 * Reset drive and collect device description.
247 	 * Don't really use the description info right now but
248 	 * might come in handy in the future (for disk labels).
249 	 */
250 	rdreset(rs, hd);
251 	cmd[0] = C_SUNIT(unit);
252 	cmd[1] = C_SVOL(0);
253 	cmd[2] = C_DESC;
254 	hpibsend(ctlr, slave, C_CMD, cmd, sizeof(cmd));
255 	hpibrecv(ctlr, slave, C_EXEC, &desc, 37);
256 	hpibrecv(ctlr, slave, C_QSTAT, &stat, sizeof(stat));
257 	bzero(name, sizeof(name));
258 	if (!stat) {
259 		register int n = desc.d_name;
260 		for (i = 5; i >= 0; i--) {
261 			name[i] = (n & 0xf) + '0';
262 			n >>= 4;
263 		}
264 		/* use drive characteristics to calculate xfer rate */
265 		rs->sc_wpms = 1000000 * (desc.d_sectsize/2) / desc.d_blocktime;
266 	}
267 #ifdef DEBUG
268 	if (rddebug & RDB_IDENT) {
269 		printf("rd%d: name: %x ('%s')\n",
270 		       lunit, desc.d_name, name);
271 		printf("  iuw %x, maxxfr %d, ctype %d\n",
272 		       desc.d_iuw, desc.d_cmaxxfr, desc.d_ctype);
273 		printf("  utype %d, bps %d, blkbuf %d, burst %d, blktime %d\n",
274 		       desc.d_utype, desc.d_sectsize,
275 		       desc.d_blkbuf, desc.d_burstsize, desc.d_blocktime);
276 		printf("  avxfr %d, ort %d, atp %d, maxint %d, fv %x, rv %x\n",
277 		       desc.d_uavexfr, desc.d_retry, desc.d_access,
278 		       desc.d_maxint, desc.d_fvbyte, desc.d_rvbyte);
279 		printf("  maxcyl/head/sect %d/%d/%d, maxvsect %d, inter %d\n",
280 		       desc.d_maxcyl, desc.d_maxhead, desc.d_maxsect,
281 		       desc.d_maxvsectl, desc.d_interleave);
282 	}
283 #endif
284 	/*
285 	 * Take care of a couple of anomolies:
286 	 * 1. 7945A and 7946A both return same HW id
287 	 * 2. 9122S and 9134D both return same HW id
288 	 * 3. 9122D and 9134L both return same HW id
289 	 */
290 	switch (rdidentinfo[id].ri_hwid) {
291 	case RD7946AID:
292 		if (bcmp(name, "079450", 6) == 0)
293 			id = RD7945A;
294 		else
295 			id = RD7946A;
296 		break;
297 
298 	case RD9134LID:
299 		if (bcmp(name, "091340", 6) == 0)
300 			id = RD9134L;
301 		else
302 			id = RD9122D;
303 		break;
304 
305 	case RD9134DID:
306 		if (bcmp(name, "091220", 6) == 0)
307 			id = RD9122S;
308 		else
309 			id = RD9134D;
310 		break;
311 	}
312 	printf("rd%d: %s\n", lunit, rdidentinfo[id].ri_desc);
313 	return(id);
314 }
315 
316 rdreset(rs, hd)
317 	register struct rd_softc *rs;
318 	register struct hp_device *hd;
319 {
320 	u_char stat;
321 
322 	rs->sc_clear.c_unit = C_SUNIT(rs->sc_punit);
323 	rs->sc_clear.c_cmd = C_CLEAR;
324 	hpibsend(hd->hp_ctlr, hd->hp_slave, C_TCMD, &rs->sc_clear,
325 		sizeof(rs->sc_clear));
326 	hpibswait(hd->hp_ctlr, hd->hp_slave);
327 	hpibrecv(hd->hp_ctlr, hd->hp_slave, C_QSTAT, &stat, sizeof(stat));
328 	rs->sc_src.c_unit = C_SUNIT(RDCTLR);
329 	rs->sc_src.c_nop = C_NOP;
330 	rs->sc_src.c_cmd = C_SREL;
331 	rs->sc_src.c_param = C_REL;
332 	hpibsend(hd->hp_ctlr, hd->hp_slave, C_CMD, &rs->sc_src,
333 		sizeof(rs->sc_src));
334 	hpibswait(hd->hp_ctlr, hd->hp_slave);
335 	hpibrecv(hd->hp_ctlr, hd->hp_slave, C_QSTAT, &stat, sizeof(stat));
336 	rs->sc_ssmc.c_unit = C_SUNIT(rs->sc_punit);
337 	rs->sc_ssmc.c_cmd = C_SSM;
338 	rs->sc_ssmc.c_refm = REF_MASK;
339 	rs->sc_ssmc.c_fefm = FEF_MASK;
340 	rs->sc_ssmc.c_aefm = AEF_MASK;
341 	rs->sc_ssmc.c_iefm = IEF_MASK;
342 	hpibsend(hd->hp_ctlr, hd->hp_slave, C_CMD, &rs->sc_ssmc,
343 		sizeof(rs->sc_ssmc));
344 	hpibswait(hd->hp_ctlr, hd->hp_slave);
345 	hpibrecv(hd->hp_ctlr, hd->hp_slave, C_QSTAT, &stat, sizeof(stat));
346 #ifdef DEBUG
347 	rdstats[hd->hp_unit].rdresets++;
348 #endif
349 }
350 
351 /*
352  * Read or constuct a disklabel
353  */
354 int
355 rdgetinfo(dev)
356 	dev_t dev;
357 {
358 	int unit = rdunit(dev);
359 	register struct rd_softc *rs = &rd_softc[unit];
360 	register struct disklabel *lp = &rs->sc_info.ri_label;
361 	register struct partition *pi;
362 	char *msg, *readdisklabel();
363 
364 	/*
365 	 * Set some default values to use while reading the label
366 	 * or to use if there isn't a label.
367 	 */
368 	bzero((caddr_t)lp, sizeof *lp);
369 	lp->d_type = DTYPE_HPIB;
370 	lp->d_secsize = DEV_BSIZE;
371 	lp->d_nsectors = 32;
372 	lp->d_ntracks = 20;
373 	lp->d_ncylinders = 1;
374 	lp->d_secpercyl = 32*20;
375 	lp->d_npartitions = 3;
376 	lp->d_partitions[2].p_offset = 0;
377 	lp->d_partitions[2].p_size = LABELSECTOR+1;
378 
379 	/*
380 	 * Now try to read the disklabel
381 	 */
382 	msg = readdisklabel(rdlabdev(dev), rdstrategy, lp);
383 	if (msg == NULL)
384 		return(0);
385 
386 	pi = lp->d_partitions;
387 	printf("rd%d: WARNING: %s, ", unit, msg);
388 #ifdef COMPAT_NOLABEL
389 	printf("using old default partitioning\n");
390 	rdmakedisklabel(unit, lp);
391 #else
392 	printf("defining `c' partition as entire disk\n");
393 	pi[2].p_size = rdidentinfo[rs->sc_type].ri_nblocks;
394 	/* XXX reset other info since readdisklabel screws with it */
395 	lp->d_npartitions = 3;
396 	pi[0].p_size = 0;
397 #endif
398 	return(0);
399 }
400 
401 int
402 rdopen(dev, flags, mode, p)
403 	dev_t dev;
404 	int flags, mode;
405 	struct proc *p;
406 {
407 	register int unit = rdunit(dev);
408 	register struct rd_softc *rs = &rd_softc[unit];
409 	int error, mask;
410 
411 	if (unit >= NRD || (rs->sc_flags & RDF_ALIVE) == 0)
412 		return(ENXIO);
413 
414 	/*
415 	 * Wait for any pending opens/closes to complete
416 	 */
417 	while (rs->sc_flags & (RDF_OPENING|RDF_CLOSING))
418 		sleep((caddr_t)rs, PRIBIO);
419 
420 	/*
421 	 * On first open, get label and partition info.
422 	 * We may block reading the label, so be careful
423 	 * to stop any other opens.
424 	 */
425 	if (rs->sc_info.ri_open == 0) {
426 		rs->sc_flags |= RDF_OPENING;
427 		error = rdgetinfo(dev);
428 		rs->sc_flags &= ~RDF_OPENING;
429 		wakeup((caddr_t)rs);
430 		if (error)
431 			return(error);
432 	}
433 	if (rs->sc_hd->hp_dk >= 0) {
434 		/* guess at xfer rate based on 3600 rpm (60 rps) */
435 		if (rs->sc_wpms == 0)
436 			rs->sc_wpms = 60 * rs->sc_info.ri_label.d_nsectors
437 				* DEV_BSIZE / 2;
438 		dk_wpms[rs->sc_hd->hp_dk] = rs->sc_wpms;
439 	}
440 
441 	mask = 1 << rdpart(dev);
442 	if (mode == S_IFCHR)
443 		rs->sc_info.ri_copen |= mask;
444 	else
445 		rs->sc_info.ri_bopen |= mask;
446 	rs->sc_info.ri_open |= mask;
447 	return(0);
448 }
449 
450 int
451 rdclose(dev, flag, mode, p)
452 	dev_t dev;
453 	int flag, mode;
454 	struct proc *p;
455 {
456 	int unit = rdunit(dev);
457 	register struct rd_softc *rs = &rd_softc[unit];
458 	register struct rdinfo *ri = &rs->sc_info;
459 	int mask, s;
460 
461 	mask = 1 << rdpart(dev);
462 	if (mode == S_IFCHR)
463 		ri->ri_copen &= ~mask;
464 	else
465 		ri->ri_bopen &= ~mask;
466 	ri->ri_open = ri->ri_bopen | ri->ri_copen;
467 	/*
468 	 * On last close, we wait for all activity to cease since
469 	 * the label/parition info will become invalid.  Since we
470 	 * might sleep, we must block any opens while we are here.
471 	 * Note we don't have to about other closes since we know
472 	 * we are the last one.
473 	 */
474 	if (ri->ri_open == 0) {
475 		rs->sc_flags |= RDF_CLOSING;
476 		s = splbio();
477 		while (rdtab[unit].b_active) {
478 			rs->sc_flags |= RDF_WANTED;
479 			sleep((caddr_t)&rdtab[unit], PRIBIO);
480 		}
481 		splx(s);
482 		rs->sc_flags &= ~(RDF_CLOSING|RDF_WLABEL);
483 		wakeup((caddr_t)rs);
484 	}
485 	return(0);
486 }
487 
488 void
489 rdstrategy(bp)
490 	register struct buf *bp;
491 {
492 	int unit = rdunit(bp->b_dev);
493 	register struct rd_softc *rs = &rd_softc[unit];
494 	register struct buf *dp = &rdtab[unit];
495 	register struct partition *pinfo;
496 	register daddr_t bn;
497 	register int sz, s;
498 
499 #ifdef DEBUG
500 	if (rddebug & RDB_FOLLOW)
501 		printf("rdstrategy(%x): dev %x, bn %x, bcount %x, %c\n",
502 		       bp, bp->b_dev, bp->b_blkno, bp->b_bcount,
503 		       (bp->b_flags & B_READ) ? 'R' : 'W');
504 #endif
505 	bn = bp->b_blkno;
506 	sz = howmany(bp->b_bcount, DEV_BSIZE);
507 	pinfo = &rs->sc_info.ri_label.d_partitions[rdpart(bp->b_dev)];
508 	if (bn < 0 || bn + sz > pinfo->p_size) {
509 		sz = pinfo->p_size - bn;
510 		if (sz == 0) {
511 			bp->b_resid = bp->b_bcount;
512 			goto done;
513 		}
514 		if (sz < 0) {
515 			bp->b_error = EINVAL;
516 			goto bad;
517 		}
518 		bp->b_bcount = dbtob(sz);
519 	}
520 	/*
521 	 * Check for write to write protected label
522 	 */
523 	if (bn + pinfo->p_offset <= LABELSECTOR &&
524 #if LABELSECTOR != 0
525 	    bn + pinfo->p_offset + sz > LABELSECTOR &&
526 #endif
527 	    !(bp->b_flags & B_READ) && !(rs->sc_flags & RDF_WLABEL)) {
528 		bp->b_error = EROFS;
529 		goto bad;
530 	}
531 	bp->b_cylin = bn + pinfo->p_offset;
532 	s = splbio();
533 	disksort(dp, bp);
534 	if (dp->b_active == 0) {
535 		dp->b_active = 1;
536 		rdustart(unit);
537 	}
538 	splx(s);
539 	return;
540 bad:
541 	bp->b_flags |= B_ERROR;
542 done:
543 	biodone(bp);
544 }
545 
546 /*
547  * Called from timeout() when handling maintenance releases
548  */
549 void
550 rdrestart(arg)
551 	void *arg;
552 {
553 	int s = splbio();
554 	rdustart((int)arg);
555 	splx(s);
556 }
557 
558 rdustart(unit)
559 	register int unit;
560 {
561 	register struct buf *bp;
562 	register struct rd_softc *rs = &rd_softc[unit];
563 
564 	bp = rdtab[unit].b_actf;
565 	rs->sc_addr = bp->b_un.b_addr;
566 	rs->sc_resid = bp->b_bcount;
567 	if (hpibreq(&rs->sc_dq))
568 		rdstart(unit);
569 }
570 
571 struct buf *
572 rdfinish(unit, rs, bp)
573 	int unit;
574 	register struct rd_softc *rs;
575 	register struct buf *bp;
576 {
577 	register struct buf *dp = &rdtab[unit];
578 
579 	dp->b_errcnt = 0;
580 	dp->b_actf = bp->b_actf;
581 	bp->b_resid = 0;
582 	biodone(bp);
583 	hpibfree(&rs->sc_dq);
584 	if (dp->b_actf)
585 		return(dp->b_actf);
586 	dp->b_active = 0;
587 	if (rs->sc_flags & RDF_WANTED) {
588 		rs->sc_flags &= ~RDF_WANTED;
589 		wakeup((caddr_t)dp);
590 	}
591 	return(NULL);
592 }
593 
594 rdstart(unit)
595 	register int unit;
596 {
597 	register struct rd_softc *rs = &rd_softc[unit];
598 	register struct buf *bp = rdtab[unit].b_actf;
599 	register struct hp_device *hp = rs->sc_hd;
600 	register int part;
601 
602 again:
603 #ifdef DEBUG
604 	if (rddebug & RDB_FOLLOW)
605 		printf("rdstart(%d): bp %x, %c\n", unit, bp,
606 		       (bp->b_flags & B_READ) ? 'R' : 'W');
607 #endif
608 	part = rdpart(bp->b_dev);
609 	rs->sc_flags |= RDF_SEEK;
610 	rs->sc_ioc.c_unit = C_SUNIT(rs->sc_punit);
611 	rs->sc_ioc.c_volume = C_SVOL(0);
612 	rs->sc_ioc.c_saddr = C_SADDR;
613 	rs->sc_ioc.c_hiaddr = 0;
614 	rs->sc_ioc.c_addr = RDBTOS(bp->b_cylin);
615 	rs->sc_ioc.c_nop2 = C_NOP;
616 	rs->sc_ioc.c_slen = C_SLEN;
617 	rs->sc_ioc.c_len = rs->sc_resid;
618 	rs->sc_ioc.c_cmd = bp->b_flags & B_READ ? C_READ : C_WRITE;
619 #ifdef DEBUG
620 	if (rddebug & RDB_IO)
621 		printf("rdstart: hpibsend(%x, %x, %x, %x, %x)\n",
622 		       hp->hp_ctlr, hp->hp_slave, C_CMD,
623 		       &rs->sc_ioc.c_unit, sizeof(rs->sc_ioc)-2);
624 #endif
625 	if (hpibsend(hp->hp_ctlr, hp->hp_slave, C_CMD, &rs->sc_ioc.c_unit,
626 		     sizeof(rs->sc_ioc)-2) == sizeof(rs->sc_ioc)-2) {
627 		if (hp->hp_dk >= 0) {
628 			dk_busy |= 1 << hp->hp_dk;
629 			dk_seek[hp->hp_dk]++;
630 		}
631 #ifdef DEBUG
632 		if (rddebug & RDB_IO)
633 			printf("rdstart: hpibawait(%x)\n", hp->hp_ctlr);
634 #endif
635 		hpibawait(hp->hp_ctlr);
636 		return;
637 	}
638 	/*
639 	 * Experience has shown that the hpibwait in this hpibsend will
640 	 * occasionally timeout.  It appears to occur mostly on old 7914
641 	 * drives with full maintenance tracks.  We should probably
642 	 * integrate this with the backoff code in rderror.
643 	 */
644 #ifdef DEBUG
645 	if (rddebug & RDB_ERROR)
646 		printf("rd%d: rdstart: cmd %x adr %d blk %d len %d ecnt %d\n",
647 		       unit, rs->sc_ioc.c_cmd, rs->sc_ioc.c_addr,
648 		       bp->b_blkno, rs->sc_resid, rdtab[unit].b_errcnt);
649 	rdstats[unit].rdretries++;
650 #endif
651 	rs->sc_flags &= ~RDF_SEEK;
652 	rdreset(rs, hp);
653 	if (rdtab[unit].b_errcnt++ < RDRETRY)
654 		goto again;
655 	printf("rd%d: rdstart err: cmd 0x%x sect %d blk %d len %d\n",
656 	       unit, rs->sc_ioc.c_cmd, rs->sc_ioc.c_addr,
657 	       bp->b_blkno, rs->sc_resid);
658 	bp->b_flags |= B_ERROR;
659 	bp->b_error = EIO;
660 	bp = rdfinish(unit, rs, bp);
661 	if (bp) {
662 		rs->sc_addr = bp->b_un.b_addr;
663 		rs->sc_resid = bp->b_bcount;
664 		if (hpibreq(&rs->sc_dq))
665 			goto again;
666 	}
667 }
668 
669 rdgo(unit)
670 	register int unit;
671 {
672 	register struct rd_softc *rs = &rd_softc[unit];
673 	register struct hp_device *hp = rs->sc_hd;
674 	struct buf *bp = rdtab[unit].b_actf;
675 
676 	if (hp->hp_dk >= 0) {
677 		dk_busy |= 1 << hp->hp_dk;
678 		dk_xfer[hp->hp_dk]++;
679 		dk_wds[hp->hp_dk] += rs->sc_resid >> 6;
680 	}
681 #ifdef USELEDS
682 	if (inledcontrol == 0)
683 		ledcontrol(0, 0, LED_DISK);
684 #endif
685 	hpibgo(hp->hp_ctlr, hp->hp_slave, C_EXEC,
686 	       rs->sc_addr, rs->sc_resid, bp->b_flags & B_READ);
687 }
688 
689 rdintr(unit)
690 	register int unit;
691 {
692 	register struct rd_softc *rs = &rd_softc[unit];
693 	register struct buf *bp = rdtab[unit].b_actf;
694 	register struct hp_device *hp = rs->sc_hd;
695 	u_char stat = 13;	/* in case hpibrecv fails */
696 	int rv, restart;
697 
698 #ifdef DEBUG
699 	if (rddebug & RDB_FOLLOW)
700 		printf("rdintr(%d): bp %x, %c, flags %x\n", unit, bp,
701 		       (bp->b_flags & B_READ) ? 'R' : 'W', rs->sc_flags);
702 	if (bp == NULL) {
703 		printf("rd%d: bp == NULL\n", unit);
704 		return;
705 	}
706 #endif
707 	if (hp->hp_dk >= 0)
708 		dk_busy &= ~(1 << hp->hp_dk);
709 	if (rs->sc_flags & RDF_SEEK) {
710 		rs->sc_flags &= ~RDF_SEEK;
711 		if (hpibustart(hp->hp_ctlr))
712 			rdgo(unit);
713 		return;
714 	}
715 	if ((rs->sc_flags & RDF_SWAIT) == 0) {
716 #ifdef DEBUG
717 		rdstats[unit].rdpolltries++;
718 #endif
719 		if (hpibpptest(hp->hp_ctlr, hp->hp_slave) == 0) {
720 #ifdef DEBUG
721 			rdstats[unit].rdpollwaits++;
722 #endif
723 			if (hp->hp_dk >= 0)
724 				dk_busy |= 1 << hp->hp_dk;
725 			rs->sc_flags |= RDF_SWAIT;
726 			hpibawait(hp->hp_ctlr);
727 			return;
728 		}
729 	} else
730 		rs->sc_flags &= ~RDF_SWAIT;
731 	rv = hpibrecv(hp->hp_ctlr, hp->hp_slave, C_QSTAT, &stat, 1);
732 	if (rv != 1 || stat) {
733 #ifdef DEBUG
734 		if (rddebug & RDB_ERROR)
735 			printf("rdintr: recv failed or bad stat %d\n", stat);
736 #endif
737 		restart = rderror(unit);
738 #ifdef DEBUG
739 		rdstats[unit].rdretries++;
740 #endif
741 		if (rdtab[unit].b_errcnt++ < RDRETRY) {
742 			if (restart)
743 				rdstart(unit);
744 			return;
745 		}
746 		bp->b_flags |= B_ERROR;
747 		bp->b_error = EIO;
748 	}
749 	if (rdfinish(unit, rs, bp))
750 		rdustart(unit);
751 }
752 
753 rdstatus(rs)
754 	register struct rd_softc *rs;
755 {
756 	register int c, s;
757 	u_char stat;
758 	int rv;
759 
760 	c = rs->sc_hd->hp_ctlr;
761 	s = rs->sc_hd->hp_slave;
762 	rs->sc_rsc.c_unit = C_SUNIT(rs->sc_punit);
763 	rs->sc_rsc.c_sram = C_SRAM;
764 	rs->sc_rsc.c_ram = C_RAM;
765 	rs->sc_rsc.c_cmd = C_STATUS;
766 	bzero((caddr_t)&rs->sc_stat, sizeof(rs->sc_stat));
767 	rv = hpibsend(c, s, C_CMD, &rs->sc_rsc, sizeof(rs->sc_rsc));
768 	if (rv != sizeof(rs->sc_rsc)) {
769 #ifdef DEBUG
770 		if (rddebug & RDB_STATUS)
771 			printf("rdstatus: send C_CMD failed %d != %d\n",
772 			       rv, sizeof(rs->sc_rsc));
773 #endif
774 		return(1);
775 	}
776 	rv = hpibrecv(c, s, C_EXEC, &rs->sc_stat, sizeof(rs->sc_stat));
777 	if (rv != sizeof(rs->sc_stat)) {
778 #ifdef DEBUG
779 		if (rddebug & RDB_STATUS)
780 			printf("rdstatus: send C_EXEC failed %d != %d\n",
781 			       rv, sizeof(rs->sc_stat));
782 #endif
783 		return(1);
784 	}
785 	rv = hpibrecv(c, s, C_QSTAT, &stat, 1);
786 	if (rv != 1 || stat) {
787 #ifdef DEBUG
788 		if (rddebug & RDB_STATUS)
789 			printf("rdstatus: recv failed %d or bad stat %d\n",
790 			       rv, stat);
791 #endif
792 		return(1);
793 	}
794 	return(0);
795 }
796 
797 /*
798  * Deal with errors.
799  * Returns 1 if request should be restarted,
800  * 0 if we should just quietly give up.
801  */
802 rderror(unit)
803 	int unit;
804 {
805 	struct rd_softc *rs = &rd_softc[unit];
806 	register struct rd_stat *sp;
807 	struct buf *bp;
808 	daddr_t hwbn, pbn;
809 
810 	if (rdstatus(rs)) {
811 #ifdef DEBUG
812 		printf("rd%d: couldn't get status\n", unit);
813 #endif
814 		rdreset(rs, rs->sc_hd);
815 		return(1);
816 	}
817 	sp = &rs->sc_stat;
818 	if (sp->c_fef & FEF_REXMT)
819 		return(1);
820 	if (sp->c_fef & FEF_PF) {
821 		rdreset(rs, rs->sc_hd);
822 		return(1);
823 	}
824 	/*
825 	 * Unit requests release for internal maintenance.
826 	 * We just delay awhile and try again later.  Use expontially
827 	 * increasing backoff ala ethernet drivers since we don't really
828 	 * know how long the maintenance will take.  With RDWAITC and
829 	 * RDRETRY as defined, the range is 1 to 32 seconds.
830 	 */
831 	if (sp->c_fef & FEF_IMR) {
832 		extern int hz;
833 		int rdtimo = RDWAITC << rdtab[unit].b_errcnt;
834 #ifdef DEBUG
835 		printf("rd%d: internal maintenance, %d second timeout\n",
836 		       unit, rdtimo);
837 		rdstats[unit].rdtimeouts++;
838 #endif
839 		hpibfree(&rs->sc_dq);
840 		timeout(rdrestart, (void *)unit, rdtimo * hz);
841 		return(0);
842 	}
843 	/*
844 	 * Only report error if we have reached the error reporting
845 	 * threshhold.  By default, this will only report after the
846 	 * retry limit has been exceeded.
847 	 */
848 	if (rdtab[unit].b_errcnt < rderrthresh)
849 		return(1);
850 
851 	/*
852 	 * First conjure up the block number at which the error occured.
853 	 * Note that not all errors report a block number, in that case
854 	 * we just use b_blkno.
855  	 */
856 	bp = rdtab[unit].b_actf;
857 	pbn = rs->sc_info.ri_label.d_partitions[rdpart(bp->b_dev)].p_offset;
858 	if ((sp->c_fef & FEF_CU) || (sp->c_fef & FEF_DR) ||
859 	    (sp->c_ief & IEF_RRMASK)) {
860 		hwbn = RDBTOS(pbn + bp->b_blkno);
861 		pbn = bp->b_blkno;
862 	} else {
863 		hwbn = sp->c_blk;
864 		pbn = RDSTOB(hwbn) - pbn;
865 	}
866 	/*
867 	 * Now output a generic message suitable for badsect.
868 	 * Note that we don't use harderr cuz it just prints
869 	 * out b_blkno which is just the beginning block number
870 	 * of the transfer, not necessary where the error occured.
871 	 */
872 	printf("rd%d%c: hard error sn%d\n",
873 	       rdunit(bp->b_dev), 'a'+rdpart(bp->b_dev), pbn);
874 	/*
875 	 * Now report the status as returned by the hardware with
876 	 * attempt at interpretation (unless debugging).
877 	 */
878 	printf("rd%d %s error:",
879 	       unit, (bp->b_flags & B_READ) ? "read" : "write");
880 #ifdef DEBUG
881 	if (rddebug & RDB_ERROR) {
882 		/* status info */
883 		printf("\n    volume: %d, unit: %d\n",
884 		       (sp->c_vu>>4)&0xF, sp->c_vu&0xF);
885 		rdprinterr("reject", sp->c_ref, err_reject);
886 		rdprinterr("fault", sp->c_fef, err_fault);
887 		rdprinterr("access", sp->c_aef, err_access);
888 		rdprinterr("info", sp->c_ief, err_info);
889 		printf("    block: %d, P1-P10: ", hwbn);
890 		printf("%s", hexstr(*(u_int *)&sp->c_raw[0], 8));
891 		printf("%s", hexstr(*(u_int *)&sp->c_raw[4], 8));
892 		printf("%s\n", hexstr(*(u_short *)&sp->c_raw[8], 4));
893 		/* command */
894 		printf("    ioc: ");
895 		printf("%s", hexstr(*(u_int *)&rs->sc_ioc.c_pad, 8));
896 		printf("%s", hexstr(*(u_short *)&rs->sc_ioc.c_hiaddr, 4));
897 		printf("%s", hexstr(*(u_int *)&rs->sc_ioc.c_addr, 8));
898 		printf("%s", hexstr(*(u_short *)&rs->sc_ioc.c_nop2, 4));
899 		printf("%s", hexstr(*(u_int *)&rs->sc_ioc.c_len, 8));
900 		printf("%s\n", hexstr(*(u_short *)&rs->sc_ioc.c_cmd, 4));
901 		return(1);
902 	}
903 #endif
904 	printf(" v%d u%d, R0x%x F0x%x A0x%x I0x%x\n",
905 	       (sp->c_vu>>4)&0xF, sp->c_vu&0xF,
906 	       sp->c_ref, sp->c_fef, sp->c_aef, sp->c_ief);
907 	printf("P1-P10: ");
908 	printf("%s", hexstr(*(u_int *)&sp->c_raw[0], 8));
909 	printf("%s", hexstr(*(u_int *)&sp->c_raw[4], 8));
910 	printf("%s\n", hexstr(*(u_short *)&sp->c_raw[8], 4));
911 	return(1);
912 }
913 
914 int
915 rdioctl(dev, cmd, data, flag, p)
916 	dev_t dev;
917 	int cmd;
918 	caddr_t data;
919 	int flag;
920 	struct proc *p;
921 {
922 	int unit = rdunit(dev);
923 	register struct rd_softc *sc = &rd_softc[unit];
924 	register struct disklabel *lp = &sc->sc_info.ri_label;
925 	int error, flags;
926 
927 	switch (cmd) {
928 	case DIOCGDINFO:
929 		*(struct disklabel *)data = *lp;
930 		return (0);
931 
932 	case DIOCGPART:
933 		((struct partinfo *)data)->disklab = lp;
934 		((struct partinfo *)data)->part =
935 			&lp->d_partitions[rdpart(dev)];
936 		return (0);
937 
938 	case DIOCWLABEL:
939 		if ((flag & FWRITE) == 0)
940 			return (EBADF);
941 		if (*(int *)data)
942 			sc->sc_flags |= RDF_WLABEL;
943 		else
944 			sc->sc_flags &= ~RDF_WLABEL;
945 		return (0);
946 
947 	case DIOCSDINFO:
948 		if ((flag & FWRITE) == 0)
949 			return (EBADF);
950 		return (setdisklabel(lp, (struct disklabel *)data,
951 				     (sc->sc_flags & RDF_WLABEL) ? 0
952 				     : sc->sc_info.ri_open,
953 				     (struct cpu_disklabel *)0));
954 
955 	case DIOCWDINFO:
956 		if ((flag & FWRITE) == 0)
957 			return (EBADF);
958 		error = setdisklabel(lp, (struct disklabel *)data,
959 				     (sc->sc_flags & RDF_WLABEL) ? 0
960 				     : sc->sc_info.ri_open,
961 				     (struct cpu_disklabel *)0);
962 		if (error)
963 			return (error);
964 		flags = sc->sc_flags;
965 		sc->sc_flags = RDF_ALIVE | RDF_WLABEL;
966 		error = writedisklabel(rdlabdev(dev), rdstrategy, lp,
967 				       (struct cpu_disklabel *)0);
968 		sc->sc_flags = flags;
969 		return (error);
970 	}
971 	return(EINVAL);
972 }
973 
974 int
975 rdsize(dev)
976 	dev_t dev;
977 {
978 	register int unit = rdunit(dev);
979 	register struct rd_softc *rs = &rd_softc[unit];
980 	int psize, didopen = 0;
981 
982 	if (unit >= NRD || (rs->sc_flags & RDF_ALIVE) == 0)
983 		return(-1);
984 
985 	/*
986 	 * We get called very early on (via swapconf)
987 	 * without the device being open so we may need
988 	 * to handle it here.
989 	 */
990 	if (rs->sc_info.ri_open == 0) {
991 		if (rdopen(dev, FREAD|FWRITE, S_IFBLK, NULL))
992 			return(-1);
993 		didopen = 1;
994 	}
995 	psize = rs->sc_info.ri_label.d_partitions[rdpart(dev)].p_size;
996 	if (didopen)
997 		(void) rdclose(dev, FREAD|FWRITE, S_IFBLK, NULL);
998 	return (psize);
999 }
1000 
1001 #ifdef DEBUG
1002 rdprinterr(str, err, tab)
1003 	char *str;
1004 	short err;
1005 	char *tab[];
1006 {
1007 	register int i;
1008 	int printed;
1009 
1010 	if (err == 0)
1011 		return;
1012 	printf("    %s error field:", str, err);
1013 	printed = 0;
1014 	for (i = 0; i < 16; i++)
1015 		if (err & (0x8000 >> i))
1016 			printf("%s%s", printed++ ? " + " : " ", tab[i]);
1017 	printf("\n");
1018 }
1019 #endif
1020 
1021 /*
1022  * Non-interrupt driven, non-dma dump routine.
1023  */
1024 int
1025 rddump(dev)
1026 	dev_t dev;
1027 {
1028 	int part = rdpart(dev);
1029 	int unit = rdunit(dev);
1030 	register struct rd_softc *rs = &rd_softc[unit];
1031 	register struct hp_device *hp = rs->sc_hd;
1032 	register struct partition *pinfo;
1033 	register daddr_t baddr;
1034 	register int maddr, pages, i;
1035 	char stat;
1036 	extern int lowram, dumpsize;
1037 #ifdef DEBUG
1038 	extern int pmapdebug;
1039 	pmapdebug = 0;
1040 #endif
1041 
1042 	/* is drive ok? */
1043 	if (unit >= NRD || (rs->sc_flags & RDF_ALIVE) == 0)
1044 		return (ENXIO);
1045 	pinfo = &rs->sc_info.ri_label.d_partitions[part];
1046 	/* dump parameters in range? */
1047 	if (dumplo < 0 || dumplo >= pinfo->p_size ||
1048 	    pinfo->p_fstype != FS_SWAP)
1049 		return (EINVAL);
1050 	pages = dumpsize;
1051 	if (dumplo + ctod(pages) > pinfo->p_size)
1052 		pages = dtoc(pinfo->p_size - dumplo);
1053 	maddr = lowram;
1054 	baddr = dumplo + pinfo->p_offset;
1055 	/* HPIB idle? */
1056 	if (!hpibreq(&rs->sc_dq)) {
1057 		hpibreset(hp->hp_ctlr);
1058 		rdreset(rs, rs->sc_hd);
1059 		printf("[ drive %d reset ] ", unit);
1060 	}
1061 	for (i = 0; i < pages; i++) {
1062 #define NPGMB	(1024*1024/NBPG)
1063 		/* print out how many Mbs we have dumped */
1064 		if (i && (i % NPGMB) == 0)
1065 			printf("%d ", i / NPGMB);
1066 #undef NPBMG
1067 		rs->sc_ioc.c_unit = C_SUNIT(rs->sc_punit);
1068 		rs->sc_ioc.c_volume = C_SVOL(0);
1069 		rs->sc_ioc.c_saddr = C_SADDR;
1070 		rs->sc_ioc.c_hiaddr = 0;
1071 		rs->sc_ioc.c_addr = RDBTOS(baddr);
1072 		rs->sc_ioc.c_nop2 = C_NOP;
1073 		rs->sc_ioc.c_slen = C_SLEN;
1074 		rs->sc_ioc.c_len = NBPG;
1075 		rs->sc_ioc.c_cmd = C_WRITE;
1076 		hpibsend(hp->hp_ctlr, hp->hp_slave, C_CMD,
1077 			 &rs->sc_ioc.c_unit, sizeof(rs->sc_ioc)-2);
1078 		if (hpibswait(hp->hp_ctlr, hp->hp_slave))
1079 			return (EIO);
1080 		pmap_enter(pmap_kernel(), (vm_offset_t)vmmap, maddr,
1081 		    VM_PROT_READ, TRUE);
1082 		hpibsend(hp->hp_ctlr, hp->hp_slave, C_EXEC, vmmap, NBPG);
1083 		(void) hpibswait(hp->hp_ctlr, hp->hp_slave);
1084 		hpibrecv(hp->hp_ctlr, hp->hp_slave, C_QSTAT, &stat, 1);
1085 		if (stat)
1086 			return (EIO);
1087 		maddr += NBPG;
1088 		baddr += ctod(1);
1089 	}
1090 	return (0);
1091 }
1092 #endif
1093