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