1/*	$NetBSD: rd.c,v 1.126 2023/04/21 23:01:59 tsutsui Exp $	*/
2
3/*-
4 * Copyright (c) 1996, 1997 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Jason R. Thorpe.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 *    notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 *    notice, this list of conditions and the following disclaimer in the
17 *    documentation and/or other materials provided with the distribution.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 */
31
32/*
33 * Copyright (c) 1988 University of Utah.
34 * Copyright (c) 1982, 1990, 1993
35 *	The Regents of the University of California.  All rights reserved.
36 *
37 * This code is derived from software contributed to Berkeley by
38 * the Systems Programming Group of the University of Utah Computer
39 * Science Department.
40 *
41 * Redistribution and use in source and binary forms, with or without
42 * modification, are permitted provided that the following conditions
43 * are met:
44 * 1. Redistributions of source code must retain the above copyright
45 *    notice, this list of conditions and the following disclaimer.
46 * 2. Redistributions in binary form must reproduce the above copyright
47 *    notice, this list of conditions and the following disclaimer in the
48 *    documentation and/or other materials provided with the distribution.
49 * 3. Neither the name of the University nor the names of its contributors
50 *    may be used to endorse or promote products derived from this software
51 *    without specific prior written permission.
52 *
53 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
54 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
55 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
56 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
57 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
58 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
59 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
60 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
61 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
62 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
63 * SUCH DAMAGE.
64 *
65 * from: Utah $Hdr: rd.c 1.44 92/12/26$
66 *
67 *	@(#)rd.c	8.2 (Berkeley) 5/19/94
68 */
69
70/*
71 * CS80/SS80 disk driver
72 */
73
74#include <sys/cdefs.h>
75__KERNEL_RCSID(0, "$NetBSD: rd.c,v 1.126 2023/04/21 23:01:59 tsutsui Exp $");
76
77#include "opt_useleds.h"
78
79#include <sys/param.h>
80#include <sys/systm.h>
81#include <sys/kernel.h>
82#include <sys/buf.h>
83#include <sys/bufq.h>
84#include <sys/conf.h>
85#include <sys/device.h>
86#include <sys/disk.h>
87#include <sys/disklabel.h>
88#include <sys/fcntl.h>
89#include <sys/ioctl.h>
90#include <sys/proc.h>
91#include <sys/stat.h>
92
93#include <sys/rndsource.h>
94
95#include <hp300/dev/hpibvar.h>
96
97#include <hp300/dev/rdreg.h>
98#include <hp300/dev/rdvar.h>
99
100#ifdef USELEDS
101#include <hp300/hp300/leds.h>
102#endif
103
104#include "ioconf.h"
105
106int	rderrthresh = RDRETRY - 1;	/* when to start reporting errors */
107
108#ifdef DEBUG
109/* error message tables */
110static const char *err_reject[] = {
111	0, 0,
112	"channel parity error",		/* 0x2000 */
113	0, 0,
114	"illegal opcode",		/* 0x0400 */
115	"module addressing",		/* 0x0200 */
116	"address bounds",		/* 0x0100 */
117	"parameter bounds",		/* 0x0080 */
118	"illegal parameter",		/* 0x0040 */
119	"message sequence",		/* 0x0020 */
120	0,
121	"message length",		/* 0x0008 */
122	0, 0, 0
123};
124
125static const char *err_fault[] = {
126	0,
127	"cross unit",			/* 0x4000 */
128	0,
129	"controller fault",		/* 0x1000 */
130	0, 0,
131	"unit fault",			/* 0x0200 */
132	0,
133	"diagnostic result",		/* 0x0080 */
134	0,
135	"operator release request",	/* 0x0020 */
136	"diagnostic release request",	/* 0x0010 */
137	"internal maintenance release request",	/* 0x0008 */
138	0,
139	"power fail",			/* 0x0002 */
140	"retransmit"			/* 0x0001 */
141};
142
143static const char *err_access[] = {
144	"illegal parallel operation",	/* 0x8000 */
145	"uninitialized media",		/* 0x4000 */
146	"no spares available",		/* 0x2000 */
147	"not ready",			/* 0x1000 */
148	"write protect",		/* 0x0800 */
149	"no data found",		/* 0x0400 */
150	0, 0,
151	"unrecoverable data overflow",	/* 0x0080 */
152	"unrecoverable data",		/* 0x0040 */
153	0,
154	"end of file",			/* 0x0010 */
155	"end of volume",		/* 0x0008 */
156	0, 0, 0
157};
158
159static const char *err_info[] = {
160	"operator release request",	/* 0x8000 */
161	"diagnostic release request",	/* 0x4000 */
162	"internal maintenance release request",	/* 0x2000 */
163	"media wear",			/* 0x1000 */
164	"latency induced",		/* 0x0800 */
165	0, 0,
166	"auto sparing invoked",		/* 0x0100 */
167	0,
168	"recoverable data overflow",	/* 0x0040 */
169	"marginal data",		/* 0x0020 */
170	"recoverable data",		/* 0x0010 */
171	0,
172	"maintenance track overflow",	/* 0x0004 */
173	0, 0
174};
175
176#define RDB_FOLLOW	0x01
177#define RDB_STATUS	0x02
178#define RDB_IDENT	0x04
179#define RDB_IO		0x08
180#define RDB_ASYNC	0x10
181#define RDB_ERROR	0x80
182int	rddebug = RDB_ERROR | RDB_IDENT;
183#endif
184
185/*
186 * Misc. HW description, indexed by sc_type.
187 * Nothing really critical here, could do without it.
188 */
189static const struct rdidentinfo rdidentinfo[] = {
190	[RD7945A] = {
191		.ri_hwid = RD7946AID,
192		.ri_desc = "7945A",
193		.ri_nbpt = NRD7945ABPT,
194		.ri_ntpc = NRD7945ATRK,
195		.ri_ncyl = NRD7945ACYL,
196		.ri_nblocks = NRD7945ABLK
197	},
198
199	[RD9134D] = {
200		.ri_hwid = RD9134DID,
201		.ri_desc = "9134D",
202		.ri_nbpt = NRD9134DBPT,
203		.ri_ntpc = NRD9134DTRK,
204		.ri_ncyl = NRD9134DCYL,
205		.ri_nblocks = NRD9134DBLK
206	},
207
208	[RD9122S] = {
209		.ri_hwid = RD9134LID,
210		.ri_desc = "9122S",
211		.ri_nbpt = NRD9122SBPT,
212		.ri_ntpc = NRD9122STRK,
213		.ri_ncyl = NRD9122SCYL,
214		.ri_nblocks = NRD9122SBLK
215	},
216
217	[RD7912P] = {
218		.ri_hwid = RD7912PID,
219		.ri_desc = "7912P",
220		.ri_nbpt = NRD7912PBPT,
221		.ri_ntpc = NRD7912PTRK,
222		.ri_ncyl = NRD7912PCYL,
223		.ri_nblocks = NRD7912PBLK
224	},
225
226	[RD7914P] = {
227		.ri_hwid = RD7914PID,
228		.ri_desc = "7914P",
229		.ri_nbpt = NRD7914PBPT,
230		.ri_ntpc = NRD7914PTRK,
231		.ri_ncyl = NRD7914PCYL,
232		.ri_nblocks = NRD7914PBLK
233	},
234
235	[RD7958A] = {
236		.ri_hwid = RD7958AID,
237		.ri_desc = "7958A",
238		.ri_nbpt = NRD7958ABPT,
239		.ri_ntpc = NRD7958ATRK,
240		.ri_ncyl = NRD7958ACYL,
241		.ri_nblocks = NRD7958ABLK
242	},
243
244	[RD7957A] = {
245		.ri_hwid = RD7957AID,
246		.ri_desc = "7957A",
247		.ri_nbpt = NRD7957ABPT,
248		.ri_ntpc = NRD7957ATRK,
249		.ri_ncyl = NRD7957ACYL,
250		.ri_nblocks = NRD7957ABLK
251	},
252
253	[RD7933H] = {
254		.ri_hwid = RD7933HID,
255		.ri_desc = "7933H",
256		.ri_nbpt = NRD7933HBPT,
257		.ri_ntpc = NRD7933HTRK,
258		.ri_ncyl = NRD7933HCYL,
259		.ri_nblocks = NRD7933HBLK
260	},
261
262	[RD9134L] = {
263		.ri_hwid = RD9134LID,
264		.ri_desc = "9134L",
265		.ri_nbpt = NRD9134LBPT,
266		.ri_ntpc = NRD9134LTRK,
267		.ri_ncyl = NRD9134LCYL,
268		.ri_nblocks = NRD9134LBLK
269	},
270
271	[RD7936H] = {
272		.ri_hwid = RD7936HID,
273		.ri_desc = "7936H",
274		.ri_nbpt = NRD7936HBPT,
275		.ri_ntpc = NRD7936HTRK,
276		.ri_ncyl = NRD7936HCYL,
277		.ri_nblocks = NRD7936HBLK
278	},
279
280	[RD7937H] = {
281		.ri_hwid = RD7937HID,
282		.ri_desc = "7937H",
283		.ri_nbpt = NRD7937HBPT,
284		.ri_ntpc = NRD7937HTRK,
285		.ri_ncyl = NRD7937HCYL,
286		.ri_nblocks = NRD7937HBLK
287	},
288
289	[RD7914CT] = {
290		.ri_hwid = RD7914CTID,
291		.ri_desc = "7914CT",
292		.ri_nbpt = NRD7914PBPT,
293		.ri_ntpc = NRD7914PTRK,
294		.ri_ncyl = NRD7914PCYL,
295		.ri_nblocks = NRD7914PBLK
296	},
297
298	[RD7946A] = {
299		.ri_hwid = RD7946AID,
300		.ri_desc = "7946A",
301		.ri_nbpt = NRD7945ABPT,
302		.ri_ntpc = NRD7945ATRK,
303		.ri_ncyl = NRD7945ACYL,
304		.ri_nblocks = NRD7945ABLK
305	},
306
307	[RD9122D] = {
308		.ri_hwid = RD9134LID,
309		.ri_desc = "9122D",
310		.ri_nbpt = NRD9122SBPT,
311		.ri_ntpc = NRD9122STRK,
312		.ri_ncyl = NRD9122SCYL,
313		.ri_nblocks = NRD9122SBLK
314	},
315
316	[RD7957B] = {
317		.ri_hwid = RD7957BID,
318		.ri_desc = "7957B",
319		.ri_nbpt = NRD7957BBPT,
320		.ri_ntpc = NRD7957BTRK,
321		.ri_ncyl = NRD7957BCYL,
322		.ri_nblocks = NRD7957BBLK
323	},
324
325	[RD7958B] = {
326		.ri_hwid = RD7958BID,
327		.ri_desc = "7958B",
328		.ri_nbpt = NRD7958BBPT,
329		.ri_ntpc = NRD7958BTRK,
330		.ri_ncyl = NRD7958BCYL,
331		.ri_nblocks = NRD7958BBLK
332	},
333
334	[RD7959B] = {
335		.ri_hwid = RD7959BID,
336		.ri_desc = "7959B",
337		.ri_nbpt = NRD7959BBPT,
338		.ri_ntpc = NRD7959BTRK,
339		.ri_ncyl = NRD7959BCYL,
340		.ri_nblocks = NRD7959BBLK
341	},
342
343	[RD2200A] = {
344		.ri_hwid = RD2200AID,
345		.ri_desc = "2200A",
346		.ri_nbpt = NRD2200ABPT,
347		.ri_ntpc = NRD2200ATRK,
348		.ri_ncyl = NRD2200ACYL,
349		.ri_nblocks = NRD2200ABLK
350	},
351
352	[RD2203A] = {
353		.ri_hwid = RD2203AID,
354		.ri_desc = "2203A",
355		.ri_nbpt = NRD2203ABPT,
356		.ri_ntpc = NRD2203ATRK,
357		.ri_ncyl = NRD2203ACYL,
358		.ri_nblocks = NRD2203ABLK
359	},
360
361	[RD2202A] = {
362		.ri_hwid = RD2202AID,
363		.ri_desc = "2202A",
364		.ri_nbpt = NRD2202ABPT,
365		.ri_ntpc = NRD2202ATRK,
366		.ri_ncyl = NRD2202ACYL,
367		.ri_nblocks = NRD2202ABLK
368	},
369
370	[RD7908A] = {
371		.ri_hwid = RD7908AID,
372		.ri_desc = "7908A",
373		.ri_nbpt = NRD7908ABPT,
374		.ri_ntpc = NRD7908ATRK,
375		.ri_ncyl = NRD7908ACYL,
376		.ri_nblocks = NRD7908ABLK
377	},
378
379	[RD7911A] = {
380		.ri_hwid = RD7911AID,
381		.ri_desc = "7911A",
382		.ri_nbpt = NRD7911ABPT,
383		.ri_ntpc = NRD7911ATRK,
384		.ri_ncyl = NRD7911ACYL,
385		.ri_nblocks = NRD7911ABLK
386	},
387
388	[RD7941A] = {
389		.ri_hwid = RD7946AID,
390		.ri_desc = "7941A",
391		.ri_nbpt = NRD7941ABPT,
392		.ri_ntpc = NRD7941ATRK,
393		.ri_ncyl = NRD7941ACYL,
394		.ri_nblocks = NRD7941ABLK
395	}
396};
397static const int numrdidentinfo = __arraycount(rdidentinfo);
398
399struct rdname2id {
400	const char *rn_name;
401	int rn_id;
402};
403static const struct rdname2id rdname2id[] = {
404	{ RD7945ANAME,	RD7945A },
405	{ RD9134DNAME,	RD9134D },
406	{ RD7912PNAME,	RD7912P },
407	{ RD7914PNAME,	RD7914P },
408	{ RD7958ANAME,	RD7958A },
409	{ RD7957ANAME,	RD7957A },
410	{ RD7933HNAME,	RD7933H },
411	{ RD9134LNAME,	RD9134L },
412	{ RD7936HNAME,	RD7936H },
413	{ RD7937HNAME,	RD7937H },
414	{ RD7914CTNAME,	RD7914CT },
415	{ RD9122DNAME,	RD9122D },
416	{ RD7957BNAME,	RD7957B },
417	{ RD7958BNAME,	RD7958B },
418	{ RD7959BNAME,	RD7959B },
419	{ RD2200ANAME,	RD2200A },
420	{ RD2203ANAME,	RD2203A },
421	{ RD2202ANAME,	RD2202A },
422	{ RD7908ANAME,	RD7908A },
423	{ RD7911ANAME,	RD7911A },
424	{ RD7941ANAME,	RD7941A }
425};
426static const int numrdname2id = __arraycount(rdname2id);
427
428static int	rdident(device_t, struct rd_softc *,
429		    struct hpibbus_attach_args *);
430static void	rdreset(struct rd_softc *);
431static void	rdreset_unit(int, int, int);
432static void	rd_set_geom(struct rd_softc *);
433static int	rdgetinfo(dev_t);
434
435static void	rdgetdefaultlabel(struct rd_softc *, struct disklabel *);
436static void	rdrestart(void *);
437static void	rdustart(struct rd_softc *);
438static struct buf *rdfinish(struct rd_softc *, struct buf *);
439static void	rdstart(void *);
440static void	rdgo(void *);
441static void	rdintr(void *);
442static int	rdstatus(struct rd_softc *);
443static int	rderror(int);
444#ifdef DEBUG
445static void	rdprinterr(const char *, short, const char **);
446#endif
447
448static int	rdmatch(device_t, cfdata_t, void *);
449static void	rdattach(device_t, device_t, void *);
450
451CFATTACH_DECL_NEW(rd, sizeof(struct rd_softc),
452    rdmatch, rdattach, NULL, NULL);
453
454static dev_type_open(rdopen);
455static dev_type_close(rdclose);
456static dev_type_read(rdread);
457static dev_type_write(rdwrite);
458static dev_type_ioctl(rdioctl);
459static dev_type_strategy(rdstrategy);
460static dev_type_dump(rddump);
461static dev_type_size(rdsize);
462
463const struct bdevsw rd_bdevsw = {
464	.d_open = rdopen,
465	.d_close = rdclose,
466	.d_strategy = rdstrategy,
467	.d_ioctl = rdioctl,
468	.d_dump = rddump,
469	.d_psize = rdsize,
470	.d_discard = nodiscard,
471	.d_flag = D_DISK
472};
473
474const struct cdevsw rd_cdevsw = {
475	.d_open = rdopen,
476	.d_close = rdclose,
477	.d_read = rdread,
478	.d_write = rdwrite,
479	.d_ioctl = rdioctl,
480	.d_stop = nostop,
481	.d_tty = notty,
482	.d_poll = nopoll,
483	.d_mmap = nommap,
484	.d_kqfilter = nokqfilter,
485	.d_discard = nodiscard,
486	.d_flag = D_DISK
487};
488
489static int
490rdmatch(device_t parent, cfdata_t cf, void *aux)
491{
492	struct hpibbus_attach_args *ha = aux;
493
494	return rdident(parent, NULL, ha);
495}
496
497static void
498rdattach(device_t parent, device_t self, void *aux)
499{
500	struct rd_softc *sc = device_private(self);
501	struct hpibbus_attach_args *ha = aux;
502	int id;
503	char pbuf[9];
504
505	sc->sc_dev = self;
506	bufq_alloc(&sc->sc_tab, "disksort", BUFQ_SORT_RAWBLOCK);
507
508	if (rdident(parent, sc, ha) == 0) {
509		aprint_error(": didn't respond to describe command!\n");
510		return;
511	}
512
513	/*
514	 * XXX We use DEV_BSIZE instead of the sector size value pulled
515	 * XXX off the driver because all of this code assumes 512 byte
516	 * XXX blocks.  ICK!
517	 */
518	id = sc->sc_type;
519	aprint_normal(": %s\n", rdidentinfo[id].ri_desc);
520	format_bytes(pbuf, sizeof(pbuf),
521	    rdidentinfo[id].ri_nblocks * DEV_BSIZE);
522	aprint_normal_dev(sc->sc_dev, "%s, %d cyl, %d head, %d sec,"
523	    " %d bytes/block x %u blocks\n",
524	    pbuf, rdidentinfo[id].ri_ncyl, rdidentinfo[id].ri_ntpc,
525	    rdidentinfo[id].ri_nbpt,
526	    DEV_BSIZE, rdidentinfo[id].ri_nblocks);
527
528	/*
529	 * Initialize and attach the disk structure.
530	 */
531	memset(&sc->sc_dkdev, 0, sizeof(sc->sc_dkdev));
532	disk_init(&sc->sc_dkdev, device_xname(sc->sc_dev), NULL);
533	disk_attach(&sc->sc_dkdev);
534	rd_set_geom(sc);
535
536	sc->sc_slave = ha->ha_slave;
537	sc->sc_punit = ha->ha_punit;
538
539	callout_init(&sc->sc_restart_ch, 0);
540
541	/* Initialize the hpib job queue entry */
542	sc->sc_hq.hq_softc = sc;
543	sc->sc_hq.hq_slave = sc->sc_slave;
544	sc->sc_hq.hq_start = rdstart;
545	sc->sc_hq.hq_go = rdgo;
546	sc->sc_hq.hq_intr = rdintr;
547
548	sc->sc_flags = RDF_ALIVE;
549#ifdef DEBUG
550	/* always report errors */
551	if ((rddebug & RDB_ERROR) != 0)
552		rderrthresh = 0;
553#endif
554	/*
555	 * attach the device into the random source list
556	 */
557	rnd_attach_source(&sc->rnd_source, device_xname(sc->sc_dev),
558	    RND_TYPE_DISK, RND_FLAG_DEFAULT);
559}
560
561static int
562rdident(device_t parent, struct rd_softc *sc, struct hpibbus_attach_args *ha)
563{
564	struct cs80_describe desc;
565	uint8_t stat, cmd[3];
566	char name[7];
567	int i, id, n, ctlr, slave;
568
569	ctlr = device_unit(parent);
570	slave = ha->ha_slave;
571
572	/* Verify that we have a CS80 device. */
573	if ((ha->ha_id & 0x200) == 0)
574		return 0;
575
576	/* Is it one of the disks we support? */
577	for (id = 0; id < numrdidentinfo; id++)
578		if (ha->ha_id == rdidentinfo[id].ri_hwid)
579			break;
580	if (id == numrdidentinfo)
581		return 0;
582
583	/*
584	 * The supported device ID is probed.
585	 * Check if the specified physical unit is actually supported
586	 * by brand-new HP-IB emulator devices like HPDisk and HPDrive etc.
587	 */
588	/*
589	 * Reset device and collect description
590	 */
591	memset(&desc, 0, sizeof(desc));
592	stat = 0;
593	rdreset_unit(ctlr, slave, ha->ha_punit);
594	cmd[0] = C_SUNIT(ha->ha_punit);
595	cmd[1] = C_SVOL(0);
596	cmd[2] = C_DESC;
597	hpibsend(ctlr, slave, C_CMD, cmd, sizeof(cmd));
598	hpibrecv(ctlr, slave, C_EXEC, &desc, sizeof(desc));
599	hpibrecv(ctlr, slave, C_QSTAT, &stat, sizeof(stat));
600
601	if (stat != 0 || desc.d_name == 0) {
602		/*
603		 * No valid response from the specified punit.
604		 *
605		 * Note it looks HPDisk responds to commands against
606		 * supported but not-configured punits at 1 to 3.
607		 */
608		return 0;
609	}
610
611	/*
612	 * If we're just probing for the device, that's all the
613	 * work we need to do.
614	 */
615	if (sc == NULL)
616		return 1;
617
618	memset(name, 0, sizeof(name));
619	n = desc.d_name;
620	for (i = 5; i >= 0; i--) {
621		name[i] = (n & 0xf) + '0';
622		n >>= 4;
623	}
624
625#ifdef DEBUG
626	if (rddebug & RDB_IDENT) {
627		aprint_normal("\n");
628		aprint_normal_dev(sc->sc_dev, "id: 0x%04x, name: %x ('%s')\n",
629		    ha->ha_id, desc.d_name, name);
630		aprint_normal("  iuw %x, maxxfr %d, ctype %d\n",
631		    desc.d_iuw, desc.d_cmaxxfr, desc.d_ctype);
632		aprint_normal("  utype %d, bps %d, blkbuf %d, burst %d,"
633		    " blktime %d\n",
634		    desc.d_utype, desc.d_sectsize,
635		    desc.d_blkbuf, desc.d_burstsize, desc.d_blocktime);
636		aprint_normal("  avxfr %d, ort %d, atp %d, maxint %d, fv %x"
637		    ", rv %x\n",
638		    desc.d_uavexfr, desc.d_retry, desc.d_access,
639		    desc.d_maxint, desc.d_fvbyte, desc.d_rvbyte);
640		aprint_normal("  maxcyl/head/sect %d/%d/%d, maxvsect %d,"
641		    " inter %d\n",
642		    desc.d_maxcyl, desc.d_maxhead, desc.d_maxsect,
643		    desc.d_maxvsectl, desc.d_interleave);
644		aprint_normal("%s", device_xname(sc->sc_dev));
645	}
646#endif
647
648	/*
649	 * Take care of a couple of anomalies:
650	 * 1. 7945A, 7946A, and 7941A all return same HW id
651	 * 2. 9122S and 9134D both return same HW id
652	 * 3. 9122D and 9134L both return same HW id
653	 */
654	switch (ha->ha_id) {
655	case RD7946AID:
656		if (memcmp(name, RD7945ANAME, RDNAMELEN) == 0)
657			id = RD7945A;
658		else if (memcmp(name, RD7941ANAME, RDNAMELEN) == 0)
659			id = RD7941A;
660		else
661			id = RD7946A;
662		break;
663
664	case RD9134LID:
665		if (memcmp(name, RD9134LNAME, RDNAMELEN) == 0)
666			id = RD9134L;
667		else
668			id = RD9122D;
669		break;
670
671	case RD9134DID:
672		if (memcmp(name, RD9122SNAME, RDNAMELEN) == 0)
673			id = RD9122S;
674		else
675			id = RD9134D;
676		break;
677	}
678
679	/*
680	 * HPDisk can have independent physical units that are not
681	 * corresponding to device IDs.
682	 * To handle this, we have to check names in the drive description
683	 * data for punit >= 1.
684	 */
685	if (ha->ha_punit >= 1) {
686		for (i = 0; i < numrdname2id; i++) {
687			if (memcmp(name, rdname2id[i].rn_name,
688			    RDNAMELEN) == 0) {
689				id = rdname2id[i].rn_id;
690				break;
691			}
692		}
693	}
694
695	sc->sc_type = id;
696
697	return 1;
698}
699
700static void
701rdreset(struct rd_softc *sc)
702{
703	int ctlr, slave, punit;
704
705	ctlr = device_unit(device_parent(sc->sc_dev));
706	slave = sc->sc_slave;
707	punit = sc->sc_punit;
708	rdreset_unit(ctlr, slave, punit);
709#ifdef DEBUG
710	sc->sc_stats.rdresets++;
711#endif
712}
713
714static void
715rdreset_unit(int ctlr, int slave, int punit)
716{
717	struct rd_ssmcmd ssmc;
718	struct rd_srcmd src;
719	struct rd_clearcmd clear;
720	uint8_t stat;
721
722	clear.c_unit = C_SUNIT(punit);
723	clear.c_cmd = C_CLEAR;
724	hpibsend(ctlr, slave, C_TCMD, &clear, sizeof(clear));
725	hpibswait(ctlr, slave);
726	hpibrecv(ctlr, slave, C_QSTAT, &stat, sizeof(stat));
727
728	src.c_unit = C_SUNIT(RDCTLR);
729	src.c_nop = C_NOP;
730	src.c_cmd = C_SREL;
731	src.c_param = C_REL;
732	hpibsend(ctlr, slave, C_CMD, &src, sizeof(src));
733	hpibswait(ctlr, slave);
734	hpibrecv(ctlr, slave, C_QSTAT, &stat, sizeof(stat));
735
736	ssmc.c_unit = C_SUNIT(punit);
737	ssmc.c_cmd = C_SSM;
738	ssmc.c_refm = REF_MASK;
739	ssmc.c_fefm = FEF_MASK;
740	ssmc.c_aefm = AEF_MASK;
741	ssmc.c_iefm = IEF_MASK;
742	hpibsend(ctlr, slave, C_CMD, &ssmc, sizeof(ssmc));
743	hpibswait(ctlr, slave);
744	hpibrecv(ctlr, slave, C_QSTAT, &stat, sizeof(stat));
745}
746
747static void
748rd_set_geom(struct rd_softc *sc)
749{
750	struct disk_geom *dg = &sc->sc_dkdev.dk_geom;
751	const struct rdidentinfo *ri = &rdidentinfo[sc->sc_type];
752
753	memset(dg, 0, sizeof(*dg));
754
755	dg->dg_secsize = DEV_BSIZE;
756	dg->dg_nsectors = ri->ri_nbpt;
757	dg->dg_ntracks = ri->ri_ntpc;
758	dg->dg_ncylinders = ri->ri_ncyl;
759	dg->dg_secperunit = ri->ri_nblocks;
760
761	disk_set_info(sc->sc_dev, &sc->sc_dkdev, ri->ri_desc);
762}
763
764/*
765 * Read or construct a disklabel
766 */
767static int
768rdgetinfo(dev_t dev)
769{
770	struct rd_softc *sc = device_lookup_private(&rd_cd, rdunit(dev));
771	struct disklabel *lp = sc->sc_dkdev.dk_label;
772	struct partition *pi;
773	const char *msg;
774
775	/*
776	 * Set some default values to use while reading the label
777	 * or to use if there isn't a label.
778	 */
779	memset((void *)lp, 0, sizeof *lp);
780	rdgetdefaultlabel(sc, lp);
781
782	/*
783	 * Now try to read the disklabel
784	 */
785	msg = readdisklabel(rdlabdev(dev), rdstrategy, lp, NULL);
786	if (msg == NULL)
787		return 0;
788
789	pi = lp->d_partitions;
790	printf("%s: WARNING: %s\n", device_xname(sc->sc_dev), msg);
791
792	pi[RAW_PART].p_size = rdidentinfo[sc->sc_type].ri_nblocks;
793	/* XXX reset other info since readdisklabel screws with it */
794	lp->d_npartitions = 3;
795	pi[0].p_size = 0;
796
797	return 0;
798}
799
800static int
801rdopen(dev_t dev, int flags, int mode, struct lwp *l)
802{
803	struct rd_softc *sc;
804	int error, mask, part;
805
806	sc = device_lookup_private(&rd_cd, rdunit(dev));
807	if (sc == NULL)
808		return ENXIO;
809
810	if ((sc->sc_flags & RDF_ALIVE) == 0)
811		return ENXIO;
812
813	/*
814	 * Wait for any pending opens/closes to complete
815	 */
816	while ((sc->sc_flags & (RDF_OPENING | RDF_CLOSING)) != 0)
817		(void)tsleep(sc, PRIBIO, "rdopen", 0);
818
819	/*
820	 * On first open, get label and partition info.
821	 * We may block reading the label, so be careful
822	 * to stop any other opens.
823	 */
824	if (sc->sc_dkdev.dk_openmask == 0) {
825		sc->sc_flags |= RDF_OPENING;
826		error = rdgetinfo(dev);
827		sc->sc_flags &= ~RDF_OPENING;
828		wakeup((void *)sc);
829		if (error)
830			return error;
831	}
832
833	part = rdpart(dev);
834	mask = 1 << part;
835
836	/* Check that the partition exists. */
837	if (part != RAW_PART &&
838	    (part > sc->sc_dkdev.dk_label->d_npartitions ||
839	     sc->sc_dkdev.dk_label->d_partitions[part].p_fstype == FS_UNUSED))
840		return ENXIO;
841
842	/* Ensure only one open at a time. */
843	switch (mode) {
844	case S_IFCHR:
845		sc->sc_dkdev.dk_copenmask |= mask;
846		break;
847	case S_IFBLK:
848		sc->sc_dkdev.dk_bopenmask |= mask;
849		break;
850	}
851	sc->sc_dkdev.dk_openmask =
852	    sc->sc_dkdev.dk_copenmask | sc->sc_dkdev.dk_bopenmask;
853
854	return 0;
855}
856
857static int
858rdclose(dev_t dev, int flag, int mode, struct lwp *l)
859{
860	struct rd_softc *sc = device_lookup_private(&rd_cd, rdunit(dev));
861	struct disk *dk = &sc->sc_dkdev;
862	int mask, s;
863
864	mask = 1 << rdpart(dev);
865	if (mode == S_IFCHR)
866		dk->dk_copenmask &= ~mask;
867	else
868		dk->dk_bopenmask &= ~mask;
869	dk->dk_openmask = dk->dk_copenmask | dk->dk_bopenmask;
870	/*
871	 * On last close, we wait for all activity to cease since
872	 * the label/partition info will become invalid.  Since we
873	 * might sleep, we must block any opens while we are here.
874	 * Note we don't have to about other closes since we know
875	 * we are the last one.
876	 */
877	if (dk->dk_openmask == 0) {
878		sc->sc_flags |= RDF_CLOSING;
879		s = splbio();
880		while (sc->sc_active) {
881			sc->sc_flags |= RDF_WANTED;
882			(void)tsleep(&sc->sc_tab, PRIBIO, "rdclose", 0);
883		}
884		splx(s);
885		sc->sc_flags &= ~(RDF_CLOSING | RDF_WLABEL);
886		wakeup((void *)sc);
887	}
888	return 0;
889}
890
891static void
892rdstrategy(struct buf *bp)
893{
894	struct rd_softc *sc = device_lookup_private(&rd_cd, rdunit(bp->b_dev));
895	struct partition *pinfo;
896	daddr_t bn;
897	int s;
898	int offset;
899
900#ifdef DEBUG
901	if ((rddebug & RDB_FOLLOW) != 0)
902		printf("rdstrategy(%p): dev %" PRIx64
903		    ", bn %llx, bcount %x, %c\n",
904		    bp, bp->b_dev, bp->b_blkno, bp->b_bcount,
905		    (bp->b_flags & B_READ) != 0 ? 'R' : 'W');
906#endif
907	bn = bp->b_blkno;
908	pinfo = &sc->sc_dkdev.dk_label->d_partitions[rdpart(bp->b_dev)];
909
910	/* Don't perform partition translation on RAW_PART. */
911	offset = (rdpart(bp->b_dev) == RAW_PART) ? 0 : pinfo->p_offset;
912
913	if (rdpart(bp->b_dev) == RAW_PART) {
914		if (bounds_check_with_mediasize(bp, DEV_BSIZE,
915		    rdidentinfo[sc->sc_type].ri_nblocks) <= 0)
916			goto done;
917	} else {
918		if (bounds_check_with_label(&sc->sc_dkdev, bp,
919		    (sc->sc_flags & RDF_WLABEL) != 0) <= 0)
920			goto done;
921	}
922	bp->b_rawblkno = bn + offset;
923	s = splbio();
924	bufq_put(sc->sc_tab, bp);
925	if (sc->sc_active == 0) {
926		sc->sc_active = 1;
927		rdustart(sc);
928	}
929	splx(s);
930	return;
931 done:
932	biodone(bp);
933}
934
935/*
936 * Called from timeout() when handling maintenance releases
937 */
938static void
939rdrestart(void *arg)
940{
941	struct rd_softc *sc = arg;
942	int s;
943
944	s = splbio();
945	rdustart(sc);
946	splx(s);
947}
948
949static void
950rdustart(struct rd_softc *sc)
951{
952	struct buf *bp;
953
954	bp = bufq_peek(sc->sc_tab);
955	sc->sc_addr = bp->b_data;
956	sc->sc_resid = bp->b_bcount;
957	if (hpibreq(device_parent(sc->sc_dev), &sc->sc_hq))
958		rdstart(sc);
959}
960
961static struct buf *
962rdfinish(struct rd_softc *sc, struct buf *bp)
963{
964
965	sc->sc_errcnt = 0;
966	(void)bufq_get(sc->sc_tab);
967	bp->b_resid = 0;
968	biodone(bp);
969	hpibfree(device_parent(sc->sc_dev), &sc->sc_hq);
970	if ((bp = bufq_peek(sc->sc_tab)) != NULL)
971		return bp;
972	sc->sc_active = 0;
973	if ((sc->sc_flags & RDF_WANTED) != 0) {
974		sc->sc_flags &= ~RDF_WANTED;
975		wakeup((void *)&sc->sc_tab);
976	}
977	return NULL;
978}
979
980static void
981rdstart(void *arg)
982{
983	struct rd_softc *sc = arg;
984	struct buf *bp = bufq_peek(sc->sc_tab);
985	int ctlr, slave;
986
987	ctlr = device_unit(device_parent(sc->sc_dev));
988	slave = sc->sc_slave;
989
990 again:
991#ifdef DEBUG
992	if (rddebug & RDB_FOLLOW)
993		printf("rdstart(%s): bp %p, %c\n", device_xname(sc->sc_dev), bp,
994		    (bp->b_flags & B_READ) ? 'R' : 'W');
995#endif
996	sc->sc_flags |= RDF_SEEK;
997	sc->sc_ioc.c_unit = C_SUNIT(sc->sc_punit);
998	sc->sc_ioc.c_volume = C_SVOL(0);
999	sc->sc_ioc.c_saddr = C_SADDR;
1000	sc->sc_ioc.c_hiaddr = 0;
1001	sc->sc_ioc.c_addr = RDBTOS(bp->b_rawblkno);
1002	sc->sc_ioc.c_nop2 = C_NOP;
1003	sc->sc_ioc.c_slen = C_SLEN;
1004	sc->sc_ioc.c_len = sc->sc_resid;
1005	sc->sc_ioc.c_cmd = (bp->b_flags & B_READ) != 0 ? C_READ : C_WRITE;
1006#ifdef DEBUG
1007	if ((rddebug & RDB_IO) != 0)
1008		printf("rdstart: hpibsend(%x, %x, %x, %p, %x)\n",
1009		    ctlr, slave, C_CMD,
1010		    &sc->sc_ioc.c_unit, sizeof(sc->sc_ioc) - 2);
1011#endif
1012	if (hpibsend(ctlr, slave, C_CMD, &sc->sc_ioc.c_unit,
1013	    sizeof(sc->sc_ioc) - 2) == sizeof(sc->sc_ioc) - 2) {
1014
1015		/* Instrumentation. */
1016		disk_busy(&sc->sc_dkdev);
1017		iostat_seek(sc->sc_dkdev.dk_stats);
1018
1019#ifdef DEBUG
1020		if ((rddebug & RDB_IO) != 0)
1021			printf("rdstart: hpibawait(%x)\n", ctlr);
1022#endif
1023		hpibawait(ctlr);
1024		return;
1025	}
1026	/*
1027	 * Experience has shown that the hpibwait in this hpibsend will
1028	 * occasionally timeout.  It appears to occur mostly on old 7914
1029	 * drives with full maintenance tracks.  We should probably
1030	 * integrate this with the backoff code in rderror.
1031	 */
1032#ifdef DEBUG
1033	if ((rddebug & RDB_ERROR) != 0)
1034		printf("%s: rdstart: cmd %x adr %x blk %lld len %d ecnt %d\n",
1035		    device_xname(sc->sc_dev),
1036		    sc->sc_ioc.c_cmd, sc->sc_ioc.c_addr,
1037		    bp->b_blkno, sc->sc_resid, sc->sc_errcnt);
1038	sc->sc_stats.rdretries++;
1039#endif
1040	sc->sc_flags &= ~RDF_SEEK;
1041	rdreset(sc);
1042	if (sc->sc_errcnt++ < RDRETRY)
1043		goto again;
1044	printf("%s: rdstart err: cmd 0x%x sect %u blk %" PRId64 " len %d\n",
1045	    device_xname(sc->sc_dev), sc->sc_ioc.c_cmd, sc->sc_ioc.c_addr,
1046	    bp->b_blkno, sc->sc_resid);
1047	bp->b_error = EIO;
1048	bp = rdfinish(sc, bp);
1049	if (bp != NULL) {
1050		sc->sc_addr = bp->b_data;
1051		sc->sc_resid = bp->b_bcount;
1052		if (hpibreq(device_parent(sc->sc_dev), &sc->sc_hq))
1053			goto again;
1054	}
1055}
1056
1057static void
1058rdgo(void *arg)
1059{
1060	struct rd_softc *sc = arg;
1061	struct buf *bp = bufq_peek(sc->sc_tab);
1062	int rw, ctlr, slave;
1063
1064	ctlr = device_unit(device_parent(sc->sc_dev));
1065	slave = sc->sc_slave;
1066
1067	rw = bp->b_flags & B_READ;
1068
1069	/* Instrumentation. */
1070	disk_busy(&sc->sc_dkdev);
1071
1072#ifdef USELEDS
1073	ledcontrol(0, 0, LED_DISK);
1074#endif
1075	hpibgo(ctlr, slave, C_EXEC, sc->sc_addr, sc->sc_resid, rw, rw != 0);
1076}
1077
1078static void
1079rdintr(void *arg)
1080{
1081	struct rd_softc *sc = arg;
1082	int unit = device_unit(sc->sc_dev);
1083	struct buf *bp = bufq_peek(sc->sc_tab);
1084	uint8_t stat = 13;	/* in case hpibrecv fails */
1085	int rv, restart, ctlr, slave;
1086
1087	ctlr = device_unit(device_parent(sc->sc_dev));
1088	slave = sc->sc_slave;
1089
1090#ifdef DEBUG
1091	if ((rddebug & RDB_FOLLOW) != 0)
1092		printf("rdintr(%d): bp %p, %c, flags %x\n", unit, bp,
1093		    (bp->b_flags & B_READ) ? 'R' : 'W', sc->sc_flags);
1094	if (bp == NULL) {
1095		printf("%s: bp == NULL\n", device_xname(sc->sc_dev));
1096		return;
1097	}
1098#endif
1099	disk_unbusy(&sc->sc_dkdev, (bp->b_bcount - bp->b_resid),
1100	    (bp->b_flags & B_READ));
1101
1102	if ((sc->sc_flags & RDF_SEEK) != 0) {
1103		sc->sc_flags &= ~RDF_SEEK;
1104		if (hpibustart(ctlr))
1105			rdgo(sc);
1106		return;
1107	}
1108	if ((sc->sc_flags & RDF_SWAIT) == 0) {
1109#ifdef DEBUG
1110		sc->sc_stats.rdpolltries++;
1111#endif
1112		if (hpibpptest(ctlr, slave) == 0) {
1113#ifdef DEBUG
1114			sc->sc_stats.rdpollwaits++;
1115#endif
1116
1117			/* Instrumentation. */
1118			disk_busy(&sc->sc_dkdev);
1119			sc->sc_flags |= RDF_SWAIT;
1120			hpibawait(ctlr);
1121			return;
1122		}
1123	} else
1124		sc->sc_flags &= ~RDF_SWAIT;
1125	rv = hpibrecv(ctlr, slave, C_QSTAT, &stat, 1);
1126	if (rv != 1 || stat != 0) {
1127#ifdef DEBUG
1128		if (rddebug & RDB_ERROR)
1129			printf("rdintr: recv failed or bad stat %d\n", stat);
1130#endif
1131		restart = rderror(unit);
1132#ifdef DEBUG
1133		sc->sc_stats.rdretries++;
1134#endif
1135		if (sc->sc_errcnt++ < RDRETRY) {
1136			if (restart)
1137				rdstart(sc);
1138			return;
1139		}
1140		bp->b_error = EIO;
1141	}
1142	if (rdfinish(sc, bp))
1143		rdustart(sc);
1144	rnd_add_uint32(&sc->rnd_source, bp->b_blkno);
1145}
1146
1147static int
1148rdstatus(struct rd_softc *sc)
1149{
1150	int c, s;
1151	uint8_t stat;
1152	int rv;
1153
1154	c = device_unit(device_parent(sc->sc_dev));
1155	s = sc->sc_slave;
1156	sc->sc_rsc.c_unit = C_SUNIT(sc->sc_punit);
1157	sc->sc_rsc.c_sram = C_SRAM;
1158	sc->sc_rsc.c_ram = C_RAM;
1159	sc->sc_rsc.c_cmd = C_STATUS;
1160	memset((void *)&sc->sc_stat, 0, sizeof(sc->sc_stat));
1161	rv = hpibsend(c, s, C_CMD, &sc->sc_rsc, sizeof(sc->sc_rsc));
1162	if (rv != sizeof(sc->sc_rsc)) {
1163#ifdef DEBUG
1164		if ((rddebug & RDB_STATUS) != 0)
1165			printf("rdstatus: send C_CMD failed %d != %d\n",
1166			    rv, sizeof(sc->sc_rsc));
1167#endif
1168		return 1;
1169	}
1170	rv = hpibrecv(c, s, C_EXEC, &sc->sc_stat, sizeof(sc->sc_stat));
1171	if (rv != sizeof(sc->sc_stat)) {
1172#ifdef DEBUG
1173		if ((rddebug & RDB_STATUS) != 0)
1174			printf("rdstatus: send C_EXEC failed %d != %d\n",
1175			    rv, sizeof(sc->sc_stat));
1176#endif
1177		return 1;
1178	}
1179	rv = hpibrecv(c, s, C_QSTAT, &stat, 1);
1180	if (rv != 1 || stat != 0) {
1181#ifdef DEBUG
1182		if ((rddebug & RDB_STATUS) != 0)
1183			printf("rdstatus: recv failed %d or bad stat %d\n",
1184			    rv, stat);
1185#endif
1186		return 1;
1187	}
1188	return 0;
1189}
1190
1191/*
1192 * Deal with errors.
1193 * Returns 1 if request should be restarted,
1194 * 0 if we should just quietly give up.
1195 */
1196static int
1197rderror(int unit)
1198{
1199	struct rd_softc *sc = device_lookup_private(&rd_cd, unit);
1200	struct rd_stat *sp;
1201	struct buf *bp;
1202	daddr_t hwbn, pbn;
1203
1204	if (rdstatus(sc) != 0) {
1205#ifdef DEBUG
1206		printf("%s: couldn't get status\n", device_xname(sc->sc_dev));
1207#endif
1208		rdreset(sc);
1209		return 1;
1210	}
1211	sp = &sc->sc_stat;
1212	if ((sp->c_fef & FEF_REXMT) != 0)
1213		return 1;
1214	if ((sp->c_fef & FEF_PF) != 0) {
1215		rdreset(sc);
1216		return 1;
1217	}
1218	/*
1219	 * Unit requests release for internal maintenance.
1220	 * We just delay awhile and try again later.  Use exponentially
1221	 * increasing backoff ala ethernet drivers since we don't really
1222	 * know how long the maintenance will take.  With RDWAITC and
1223	 * RDRETRY as defined, the range is 1 to 32 seconds.
1224	 */
1225	if ((sp->c_fef & FEF_IMR) != 0) {
1226		int rdtimo = RDWAITC << sc->sc_errcnt;
1227#ifdef DEBUG
1228		printf("%s: internal maintenance, %d second timeout\n",
1229		    device_xname(sc->sc_dev), rdtimo);
1230		sc->sc_stats.rdtimeouts++;
1231#endif
1232		hpibfree(device_parent(sc->sc_dev), &sc->sc_hq);
1233		callout_reset(&sc->sc_restart_ch, rdtimo * hz, rdrestart, sc);
1234		return 0;
1235	}
1236	/*
1237	 * Only report error if we have reached the error reporting
1238	 * threshold.  By default, this will only report after the
1239	 * retry limit has been exceeded.
1240	 */
1241	if (sc->sc_errcnt < rderrthresh)
1242		return 1;
1243
1244	/*
1245	 * First conjure up the block number at which the error occurred.
1246	 * Note that not all errors report a block number, in that case
1247	 * we just use b_blkno.
1248	 */
1249	bp = bufq_peek(sc->sc_tab);
1250	pbn = sc->sc_dkdev.dk_label->d_partitions[rdpart(bp->b_dev)].p_offset;
1251	if ((sp->c_fef & FEF_CU) != 0 || (sp->c_fef & FEF_DR) != 0 ||
1252	    (sp->c_ief & IEF_RRMASK) != 0) {
1253		hwbn = RDBTOS(pbn + bp->b_blkno);
1254		pbn = bp->b_blkno;
1255	} else {
1256		hwbn = sp->c_blk;
1257		pbn = RDSTOB(hwbn) - pbn;
1258	}
1259	/*
1260	 * Now output a generic message suitable for badsect.
1261	 * Note that we don't use harderr cuz it just prints
1262	 * out b_blkno which is just the beginning block number
1263	 * of the transfer, not necessary where the error occurred.
1264	 */
1265	printf("%s%c: hard error sn%" PRId64 "\n", device_xname(sc->sc_dev),
1266	    'a' + rdpart(bp->b_dev), pbn);
1267	/*
1268	 * Now report the status as returned by the hardware with
1269	 * attempt at interpretation (unless debugging).
1270	 */
1271	printf("%s %s error:", device_xname(sc->sc_dev),
1272	    (bp->b_flags & B_READ) != 0 ? "read" : "write");
1273#ifdef DEBUG
1274	if (rddebug & RDB_ERROR) {
1275		/* status info */
1276		printf("\n    volume: %d, unit: %d\n",
1277		    (sp->c_vu >> 4) & 0xF, sp->c_vu & 0xF);
1278		rdprinterr("reject", sp->c_ref, err_reject);
1279		rdprinterr("fault", sp->c_fef, err_fault);
1280		rdprinterr("access", sp->c_aef, err_access);
1281		rdprinterr("info", sp->c_ief, err_info);
1282		printf("    block: %lld, P1-P10: ", hwbn);
1283		printf("0x%x", *(uint32_t *)&sp->c_raw[0]);
1284		printf("0x%x", *(uint32_t *)&sp->c_raw[4]);
1285		printf("0x%x\n", *(uint16_t *)&sp->c_raw[8]);
1286		/* command */
1287		printf("    ioc: ");
1288		printf("0x%x", *(uint32_t *)&sc->sc_ioc.c_pad);
1289		printf("0x%x", *(uint16_t *)&sc->sc_ioc.c_hiaddr);
1290		printf("0x%x", *(uint32_t *)&sc->sc_ioc.c_addr);
1291		printf("0x%x", *(uint16_t *)&sc->sc_ioc.c_nop2);
1292		printf("0x%x", *(uint32_t *)&sc->sc_ioc.c_len);
1293		printf("0x%x\n", *(uint16_t *)&sc->sc_ioc.c_cmd);
1294		return 1;
1295	}
1296#endif
1297	printf(" v%d u%d, R0x%x F0x%x A0x%x I0x%x\n",
1298	    (sp->c_vu >> 4) & 0xF, sp->c_vu & 0xF,
1299	    sp->c_ref, sp->c_fef, sp->c_aef, sp->c_ief);
1300	printf("P1-P10: ");
1301	printf("0x%x", *(uint32_t *)&sp->c_raw[0]);
1302	printf("0x%x", *(uint32_t *)&sp->c_raw[4]);
1303	printf("0x%x\n", *(uint16_t *)&sp->c_raw[8]);
1304	return 1;
1305}
1306
1307static int
1308rdread(dev_t dev, struct uio *uio, int flags)
1309{
1310
1311	return physio(rdstrategy, NULL, dev, B_READ, minphys, uio);
1312}
1313
1314static int
1315rdwrite(dev_t dev, struct uio *uio, int flags)
1316{
1317
1318	return physio(rdstrategy, NULL, dev, B_WRITE, minphys, uio);
1319}
1320
1321static int
1322rdioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l)
1323{
1324	struct rd_softc *sc = device_lookup_private(&rd_cd, rdunit(dev));
1325	struct disklabel *lp = sc->sc_dkdev.dk_label;
1326	int error, flags;
1327
1328	error = disk_ioctl(&sc->sc_dkdev, dev, cmd, data, flag, l);
1329	if (error != EPASSTHROUGH)
1330		return error;
1331
1332	switch (cmd) {
1333	case DIOCWLABEL:
1334		if ((flag & FWRITE) == 0)
1335			return EBADF;
1336		if (*(int *)data)
1337			sc->sc_flags |= RDF_WLABEL;
1338		else
1339			sc->sc_flags &= ~RDF_WLABEL;
1340		return 0;
1341
1342	case DIOCSDINFO:
1343		if ((flag & FWRITE) == 0)
1344			return EBADF;
1345		return setdisklabel(lp, (struct disklabel *)data,
1346		    (sc->sc_flags & RDF_WLABEL) ? 0 : sc->sc_dkdev.dk_openmask,
1347		    NULL);
1348
1349	case DIOCWDINFO:
1350		if ((flag & FWRITE) == 0)
1351			return EBADF;
1352		error = setdisklabel(lp, (struct disklabel *)data,
1353		    (sc->sc_flags & RDF_WLABEL) ? 0 : sc->sc_dkdev.dk_openmask,
1354		    NULL);
1355		if (error != 0)
1356			return error;
1357		flags = sc->sc_flags;
1358		sc->sc_flags = RDF_ALIVE | RDF_WLABEL;
1359		error = writedisklabel(rdlabdev(dev), rdstrategy, lp, NULL);
1360		sc->sc_flags = flags;
1361		return error;
1362
1363	case DIOCGDEFLABEL:
1364		rdgetdefaultlabel(sc, (struct disklabel *)data);
1365		return 0;
1366
1367	case DIOCCACHESYNC:
1368		/* no cache to be flushed but required to appease raid(4) */
1369		return 0;
1370	}
1371	return EINVAL;
1372}
1373
1374static void
1375rdgetdefaultlabel(struct rd_softc *sc, struct disklabel *lp)
1376{
1377	int type = sc->sc_type;
1378
1379	memset((void *)lp, 0, sizeof(struct disklabel));
1380
1381	lp->d_type = DKTYPE_HPIB;
1382	lp->d_secsize = DEV_BSIZE;
1383	lp->d_nsectors = rdidentinfo[type].ri_nbpt;
1384	lp->d_ntracks = rdidentinfo[type].ri_ntpc;
1385	lp->d_ncylinders = rdidentinfo[type].ri_ncyl;
1386	lp->d_secperunit = rdidentinfo[type].ri_nblocks;
1387	lp->d_secpercyl = lp->d_ntracks * lp->d_nsectors;
1388
1389	strlcpy(lp->d_typename, rdidentinfo[type].ri_desc,
1390	    sizeof(lp->d_typename));
1391	strlcpy(lp->d_packname, "fictitious", sizeof(lp->d_packname));
1392	lp->d_rpm = 3000;
1393	lp->d_interleave = 1;
1394	lp->d_flags = 0;
1395
1396	lp->d_partitions[RAW_PART].p_offset = 0;
1397	lp->d_partitions[RAW_PART].p_size =
1398	    lp->d_secperunit * (lp->d_secsize / DEV_BSIZE);
1399	lp->d_partitions[RAW_PART].p_fstype = FS_UNUSED;
1400	lp->d_npartitions = RAW_PART + 1;
1401
1402	lp->d_magic = DISKMAGIC;
1403	lp->d_magic2 = DISKMAGIC;
1404	lp->d_checksum = dkcksum(lp);
1405}
1406
1407static int
1408rdsize(dev_t dev)
1409{
1410	struct rd_softc *sc;
1411	int psize, didopen = 0;
1412
1413	sc = device_lookup_private(&rd_cd, rdunit(dev));
1414	if (sc == NULL)
1415		return ENXIO;
1416
1417	if ((sc->sc_flags & RDF_ALIVE) == 0)
1418		return ENXIO;
1419
1420	/*
1421	 * We get called very early on (via swapconf)
1422	 * without the device being open so we may need
1423	 * to handle it here.
1424	 */
1425	if (sc->sc_dkdev.dk_openmask == 0) {
1426		if (rdopen(dev, FREAD | FWRITE, S_IFBLK, NULL))
1427			return -1;
1428		didopen = 1;
1429	}
1430	psize = sc->sc_dkdev.dk_label->d_partitions[rdpart(dev)].p_size *
1431	    (sc->sc_dkdev.dk_label->d_secsize / DEV_BSIZE);
1432	if (didopen)
1433		(void)rdclose(dev, FREAD | FWRITE, S_IFBLK, NULL);
1434	return psize;
1435}
1436
1437#ifdef DEBUG
1438static void
1439rdprinterr(const char *str, short err, const char **tab)
1440{
1441	int i;
1442	int printed;
1443
1444	if (err == 0)
1445		return;
1446	printf("    %s error %d field:", str, err);
1447	printed = 0;
1448	for (i = 0; i < 16; i++)
1449		if ((err & (0x8000 >> i)) != 0)
1450			printf("%s%s", printed++ ? " + " : " ", tab[i]);
1451	printf("\n");
1452}
1453#endif
1454
1455static int rddoingadump;	/* simple mutex */
1456
1457/*
1458 * Non-interrupt driven, non-DMA dump routine.
1459 */
1460static int
1461rddump(dev_t dev, daddr_t blkno, void *va, size_t size)
1462{
1463	int sectorsize;		/* size of a disk sector */
1464	int nsects;		/* number of sectors in partition */
1465	int sectoff;		/* sector offset of partition */
1466	int totwrt;		/* total number of sectors left to write */
1467	int nwrt;		/* current number of sectors to write */
1468	int part;
1469	int ctlr, slave;
1470	struct rd_softc *sc;
1471	struct disklabel *lp;
1472	char stat;
1473
1474	/* Check for recursive dump; if so, punt. */
1475	if (rddoingadump)
1476		return EFAULT;
1477	rddoingadump = 1;
1478
1479	/* Decompose unit and partition. */
1480	part = rdpart(dev);
1481
1482	/* Make sure dump device is ok. */
1483	sc = device_lookup_private(&rd_cd, rdunit(dev));
1484	if (sc == NULL)
1485		return ENXIO;
1486
1487	if ((sc->sc_flags & RDF_ALIVE) == 0)
1488		return ENXIO;
1489
1490	ctlr = device_unit(device_parent(sc->sc_dev));
1491	slave = sc->sc_slave;
1492
1493	/*
1494	 * Convert to disk sectors.  Request must be a multiple of size.
1495	 */
1496	lp = sc->sc_dkdev.dk_label;
1497	sectorsize = lp->d_secsize;
1498	if ((size % sectorsize) != 0)
1499		return EFAULT;
1500	totwrt = size / sectorsize;
1501	blkno = dbtob(blkno) / sectorsize;	/* blkno in DEV_BSIZE units */
1502
1503	nsects = lp->d_partitions[part].p_size;
1504	sectoff = lp->d_partitions[part].p_offset;
1505
1506	/* Check transfer bounds against partition size. */
1507	if ((blkno < 0) || (blkno + totwrt) > nsects)
1508		return EINVAL;
1509
1510	/* Offset block number to start of partition. */
1511	blkno += sectoff;
1512
1513	while (totwrt > 0) {
1514		nwrt = totwrt;		/* XXX */
1515#ifndef RD_DUMP_NOT_TRUSTED
1516		/*
1517		 * Fill out and send HPIB command.
1518		 */
1519		sc->sc_ioc.c_unit = C_SUNIT(sc->sc_punit);
1520		sc->sc_ioc.c_volume = C_SVOL(0);
1521		sc->sc_ioc.c_saddr = C_SADDR;
1522		sc->sc_ioc.c_hiaddr = 0;
1523		sc->sc_ioc.c_addr = RDBTOS(blkno);
1524		sc->sc_ioc.c_nop2 = C_NOP;
1525		sc->sc_ioc.c_slen = C_SLEN;
1526		sc->sc_ioc.c_len = nwrt * sectorsize;
1527		sc->sc_ioc.c_cmd = C_WRITE;
1528		hpibsend(ctlr, slave, C_CMD, &sc->sc_ioc.c_unit,
1529		    sizeof(sc->sc_ioc) - 2);
1530		if (hpibswait(ctlr, slave))
1531			return EIO;
1532
1533		/*
1534		 * Send the data.
1535		 */
1536		hpibsend(ctlr, slave, C_EXEC, va, nwrt * sectorsize);
1537		(void)hpibswait(ctlr, slave);
1538		hpibrecv(ctlr, slave, C_QSTAT, &stat, 1);
1539		if (stat)
1540			return EIO;
1541#else /* RD_DUMP_NOT_TRUSTED */
1542		/* Let's just talk about this first... */
1543		printf("%s: dump addr %p, blk %d\n", device_xname(sc->sc_dev),
1544		    va, blkno);
1545		delay(500 * 1000);	/* half a second */
1546#endif /* RD_DUMP_NOT_TRUSTED */
1547
1548		/* update block count */
1549		totwrt -= nwrt;
1550		blkno += nwrt;
1551		va = (uint8_t *)va + sectorsize * nwrt;
1552	}
1553	rddoingadump = 0;
1554	return 0;
1555}
1556