xref: /netbsd-src/sys/dev/gpib/rd.c (revision 99b1bc684787d9d58fb5d515fbc4577adf6d1b2c)
1*99b1bc68Sandvar /*	$NetBSD: rd.c,v 1.45 2023/02/12 16:04:57 andvar Exp $ */
2473eb467Sgmcgarry 
3473eb467Sgmcgarry /*-
4473eb467Sgmcgarry  * Copyright (c) 1996-2003 The NetBSD Foundation, Inc.
5473eb467Sgmcgarry  * All rights reserved.
6473eb467Sgmcgarry  *
7473eb467Sgmcgarry  * This code is derived from software contributed to The NetBSD Foundation
8473eb467Sgmcgarry  * by Jason R. Thorpe.
9473eb467Sgmcgarry  *
10473eb467Sgmcgarry  * Redistribution and use in source and binary forms, with or without
11473eb467Sgmcgarry  * modification, are permitted provided that the following conditions
12473eb467Sgmcgarry  * are met:
13473eb467Sgmcgarry  * 1. Redistributions of source code must retain the above copyright
14473eb467Sgmcgarry  *    notice, this list of conditions and the following disclaimer.
15473eb467Sgmcgarry  * 2. Redistributions in binary form must reproduce the above copyright
16473eb467Sgmcgarry  *    notice, this list of conditions and the following disclaimer in the
17473eb467Sgmcgarry  *    documentation and/or other materials provided with the distribution.
18473eb467Sgmcgarry  *
19473eb467Sgmcgarry  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20473eb467Sgmcgarry  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21473eb467Sgmcgarry  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22473eb467Sgmcgarry  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23473eb467Sgmcgarry  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24473eb467Sgmcgarry  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25473eb467Sgmcgarry  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26473eb467Sgmcgarry  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27473eb467Sgmcgarry  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28473eb467Sgmcgarry  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29473eb467Sgmcgarry  * POSSIBILITY OF SUCH DAMAGE.
30473eb467Sgmcgarry  */
31473eb467Sgmcgarry 
32473eb467Sgmcgarry /*
339b6bd2d9Srmind  * Copyright (c) 1988 University of Utah.
34473eb467Sgmcgarry  * Copyright (c) 1982, 1990, 1993
35473eb467Sgmcgarry  *	The Regents of the University of California.  All rights reserved.
36473eb467Sgmcgarry  *
37473eb467Sgmcgarry  * This code is derived from software contributed to Berkeley by
38473eb467Sgmcgarry  * the Systems Programming Group of the University of Utah Computer
39473eb467Sgmcgarry  * Science Department.
40473eb467Sgmcgarry  *
41473eb467Sgmcgarry  * Redistribution and use in source and binary forms, with or without
42473eb467Sgmcgarry  * modification, are permitted provided that the following conditions
43473eb467Sgmcgarry  * are met:
44473eb467Sgmcgarry  * 1. Redistributions of source code must retain the above copyright
45473eb467Sgmcgarry  *    notice, this list of conditions and the following disclaimer.
46473eb467Sgmcgarry  * 2. Redistributions in binary form must reproduce the above copyright
47473eb467Sgmcgarry  *    notice, this list of conditions and the following disclaimer in the
48473eb467Sgmcgarry  *    documentation and/or other materials provided with the distribution.
49aad01611Sagc  * 3. Neither the name of the University nor the names of its contributors
50aad01611Sagc  *    may be used to endorse or promote products derived from this software
51aad01611Sagc  *    without specific prior written permission.
52aad01611Sagc  *
53aad01611Sagc  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
54aad01611Sagc  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
55aad01611Sagc  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
56aad01611Sagc  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
57aad01611Sagc  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
58aad01611Sagc  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
59aad01611Sagc  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
60aad01611Sagc  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
61aad01611Sagc  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
62aad01611Sagc  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
63aad01611Sagc  * SUCH DAMAGE.
64aad01611Sagc  *
65aad01611Sagc  * from: Utah $Hdr: rd.c 1.44 92/12/26$
66aad01611Sagc  *
67aad01611Sagc  *	@(#)rd.c	8.2 (Berkeley) 5/19/94
68aad01611Sagc  */
69aad01611Sagc 
70aad01611Sagc /*
71473eb467Sgmcgarry  * CS80/SS80 disk driver
72473eb467Sgmcgarry  */
73473eb467Sgmcgarry 
74473eb467Sgmcgarry #include <sys/cdefs.h>
75*99b1bc68Sandvar __KERNEL_RCSID(0, "$NetBSD: rd.c,v 1.45 2023/02/12 16:04:57 andvar Exp $");
76473eb467Sgmcgarry 
77473eb467Sgmcgarry #include <sys/param.h>
78473eb467Sgmcgarry #include <sys/systm.h>
79473eb467Sgmcgarry #include <sys/buf.h>
8005f25dccSyamt #include <sys/bufq.h>
81473eb467Sgmcgarry #include <sys/callout.h>
82473eb467Sgmcgarry #include <sys/conf.h>
83473eb467Sgmcgarry #include <sys/device.h>
84473eb467Sgmcgarry #include <sys/disk.h>
85473eb467Sgmcgarry #include <sys/disklabel.h>
86473eb467Sgmcgarry #include <sys/endian.h>
87473eb467Sgmcgarry #include <sys/fcntl.h>
88473eb467Sgmcgarry #include <sys/ioctl.h>
89473eb467Sgmcgarry #include <sys/proc.h>
90473eb467Sgmcgarry #include <sys/stat.h>
91473eb467Sgmcgarry 
92233f556cSriastradh #include <sys/rndsource.h>
93473eb467Sgmcgarry 
94473eb467Sgmcgarry #include <dev/gpib/gpibvar.h>
95473eb467Sgmcgarry #include <dev/gpib/cs80busvar.h>
96473eb467Sgmcgarry 
97473eb467Sgmcgarry #include <dev/gpib/rdreg.h>
98473eb467Sgmcgarry 
9982b8cabaSriastradh #include "ioconf.h"
10082b8cabaSriastradh 
101473eb467Sgmcgarry #ifdef DEBUG
102473eb467Sgmcgarry int	rddebug = 0xff;
103473eb467Sgmcgarry #define RDB_FOLLOW	0x01
104473eb467Sgmcgarry #define RDB_STATUS	0x02
105473eb467Sgmcgarry #define RDB_IDENT	0x04
106473eb467Sgmcgarry #define RDB_IO		0x08
107473eb467Sgmcgarry #define RDB_ASYNC	0x10
108473eb467Sgmcgarry #define RDB_ERROR	0x80
109473eb467Sgmcgarry #define DPRINTF(mask, str)	if (rddebug & (mask)) printf str
110473eb467Sgmcgarry #else
111473eb467Sgmcgarry #define DPRINTF(mask, str)	/* nothing */
112473eb467Sgmcgarry #endif
113473eb467Sgmcgarry 
114473eb467Sgmcgarry struct	rd_softc {
115cbab9cadSchs 	device_t sc_dev;
116473eb467Sgmcgarry 	gpib_chipset_tag_t sc_ic;
117473eb467Sgmcgarry 	gpib_handle_t sc_hdl;
118473eb467Sgmcgarry 
119473eb467Sgmcgarry 	struct	disk sc_dk;
120473eb467Sgmcgarry 
121473eb467Sgmcgarry 	int	sc_slave;		/* GPIB slave */
122473eb467Sgmcgarry 	int	sc_punit;		/* physical unit on slave */
123473eb467Sgmcgarry 
124473eb467Sgmcgarry 	int	sc_flags;
125473eb467Sgmcgarry #define	RDF_ALIVE	0x01
126473eb467Sgmcgarry #define	RDF_SEEK	0x02
127473eb467Sgmcgarry #define RDF_SWAIT	0x04
128473eb467Sgmcgarry #define RDF_OPENING	0x08
129473eb467Sgmcgarry #define RDF_CLOSING	0x10
130473eb467Sgmcgarry #define RDF_WANTED	0x20
131473eb467Sgmcgarry #define RDF_WLABEL	0x40
132473eb467Sgmcgarry 
133473eb467Sgmcgarry 	u_int16_t sc_type;
134473eb467Sgmcgarry 	u_int8_t *sc_addr;
135473eb467Sgmcgarry 	int	sc_resid;
136473eb467Sgmcgarry 	struct	rd_iocmd sc_ioc;
137aec75b1cSyamt 	struct	bufq_state *sc_tab;
138473eb467Sgmcgarry 	int	sc_active;
139473eb467Sgmcgarry 	int	sc_errcnt;
140473eb467Sgmcgarry 
141473eb467Sgmcgarry 	struct	callout sc_restart_ch;
142473eb467Sgmcgarry 
1433afd44cfStls 	krndsource_t rnd_source;
144473eb467Sgmcgarry };
145473eb467Sgmcgarry 
146473eb467Sgmcgarry #define RDUNIT(dev)			DISKUNIT(dev)
147473eb467Sgmcgarry #define RDPART(dev)			DISKPART(dev)
148473eb467Sgmcgarry #define RDMAKEDEV(maj, unit, part)	MAKEDISKDEV(maj, unit, part)
149473eb467Sgmcgarry #define RDLABELDEV(dev)	(RDMAKEDEV(major(dev), RDUNIT(dev), RAW_PART))
150473eb467Sgmcgarry 
151473eb467Sgmcgarry #define	RDRETRY		5
152473eb467Sgmcgarry #define RDWAITC		1	/* min time for timeout in seconds */
153473eb467Sgmcgarry 
154473eb467Sgmcgarry int	rderrthresh = RDRETRY-1;	/* when to start reporting errors */
155473eb467Sgmcgarry 
156473eb467Sgmcgarry /*
157473eb467Sgmcgarry  * Misc. HW description, indexed by sc_type.
158473eb467Sgmcgarry  * Used for mapping 256-byte sectors for 512-byte sectors
159473eb467Sgmcgarry  */
160473eb467Sgmcgarry const struct rdidentinfo {
161473eb467Sgmcgarry 	u_int16_t ri_hwid;		/* 2 byte HW id */
162473eb467Sgmcgarry 	u_int16_t ri_maxunum;		/* maximum allowed unit number */
16322974bb6Scube 	const char *ri_desc;		/* drive type description */
164473eb467Sgmcgarry 	int	ri_nbpt;		/* DEV_BSIZE blocks per track */
165473eb467Sgmcgarry 	int	ri_ntpc;		/* tracks per cylinder */
166473eb467Sgmcgarry 	int	ri_ncyl;		/* cylinders per unit */
167473eb467Sgmcgarry 	int	ri_nblocks;		/* DEV_BSIZE blocks on disk */
168473eb467Sgmcgarry } rdidentinfo[] = {
169473eb467Sgmcgarry 	{ RD7946AID,	0,	"7945A",	NRD7945ABPT,
170473eb467Sgmcgarry 	  NRD7945ATRK,	968,	 108416 },
171473eb467Sgmcgarry 
172473eb467Sgmcgarry 	{ RD9134DID,	1,	"9134D",	NRD9134DBPT,
173473eb467Sgmcgarry 	  NRD9134DTRK,	303,	  29088 },
174473eb467Sgmcgarry 
175473eb467Sgmcgarry 	{ RD9134LID,	1,	"9122S",	NRD9122SBPT,
176473eb467Sgmcgarry 	  NRD9122STRK,	77,	   1232 },
177473eb467Sgmcgarry 
178473eb467Sgmcgarry 	{ RD7912PID,	0,	"7912P",	NRD7912PBPT,
179473eb467Sgmcgarry 	  NRD7912PTRK,	572,	 128128 },
180473eb467Sgmcgarry 
181473eb467Sgmcgarry 	{ RD7914PID,	0,	"7914P",	NRD7914PBPT,
182473eb467Sgmcgarry 	  NRD7914PTRK,	1152,	 258048 },
183473eb467Sgmcgarry 
184473eb467Sgmcgarry 	{ RD7958AID,	0,	"7958A",	NRD7958ABPT,
185473eb467Sgmcgarry 	  NRD7958ATRK,	1013,	 255276 },
186473eb467Sgmcgarry 
187473eb467Sgmcgarry 	{ RD7957AID,	0,	"7957A",	NRD7957ABPT,
188473eb467Sgmcgarry 	  NRD7957ATRK,	1036,	 159544 },
189473eb467Sgmcgarry 
190473eb467Sgmcgarry 	{ RD7933HID,	0,	"7933H",	NRD7933HBPT,
191473eb467Sgmcgarry 	  NRD7933HTRK,	1321,	 789958 },
192473eb467Sgmcgarry 
193473eb467Sgmcgarry 	{ RD9134LID,	1,	"9134L",	NRD9134LBPT,
194473eb467Sgmcgarry 	  NRD9134LTRK,	973,	  77840 },
195473eb467Sgmcgarry 
196473eb467Sgmcgarry 	{ RD7936HID,	0,	"7936H",	NRD7936HBPT,
197473eb467Sgmcgarry 	  NRD7936HTRK,	698,	 600978 },
198473eb467Sgmcgarry 
199473eb467Sgmcgarry 	{ RD7937HID,	0,	"7937H",	NRD7937HBPT,
200473eb467Sgmcgarry 	  NRD7937HTRK,	698,	1116102 },
201473eb467Sgmcgarry 
202473eb467Sgmcgarry 	{ RD7914CTID,	0,	"7914CT",	NRD7914PBPT,
203473eb467Sgmcgarry 	  NRD7914PTRK,	1152,	 258048 },
204473eb467Sgmcgarry 
205473eb467Sgmcgarry 	{ RD7946AID,	0,	"7946A",	NRD7945ABPT,
206473eb467Sgmcgarry 	  NRD7945ATRK,	968,	 108416 },
207473eb467Sgmcgarry 
208473eb467Sgmcgarry 	{ RD9134LID,	1,	"9122D",	NRD9122SBPT,
209473eb467Sgmcgarry 	  NRD9122STRK,	77,	   1232 },
210473eb467Sgmcgarry 
211473eb467Sgmcgarry 	{ RD7957BID,	0,	"7957B",	NRD7957BBPT,
212473eb467Sgmcgarry 	  NRD7957BTRK,	1269,	 159894 },
213473eb467Sgmcgarry 
214473eb467Sgmcgarry 	{ RD7958BID,	0,	"7958B",	NRD7958BBPT,
215473eb467Sgmcgarry 	  NRD7958BTRK,	786,	 297108 },
216473eb467Sgmcgarry 
217473eb467Sgmcgarry 	{ RD7959BID,	0,	"7959B",	NRD7959BBPT,
218473eb467Sgmcgarry 	  NRD7959BTRK,	1572,	 594216 },
219473eb467Sgmcgarry 
220473eb467Sgmcgarry 	{ RD2200AID,	0,	"2200A",	NRD2200ABPT,
221473eb467Sgmcgarry 	  NRD2200ATRK,	1449,	 654948 },
222473eb467Sgmcgarry 
223473eb467Sgmcgarry 	{ RD2203AID,	0,	"2203A",	NRD2203ABPT,
224473eb467Sgmcgarry 	  NRD2203ATRK,	1449,	1309896 }
225473eb467Sgmcgarry };
226473eb467Sgmcgarry int numrdidentinfo = sizeof(rdidentinfo) / sizeof(rdidentinfo[0]);
227473eb467Sgmcgarry 
228473eb467Sgmcgarry int	rdlookup(int, int, int);
229473eb467Sgmcgarry int	rdgetinfo(struct rd_softc *);
230473eb467Sgmcgarry void	rdrestart(void *);
231473eb467Sgmcgarry struct buf *rdfinish(struct rd_softc *, struct buf *);
232473eb467Sgmcgarry 
233473eb467Sgmcgarry void	rdgetcompatlabel(struct rd_softc *, struct disklabel *);
234473eb467Sgmcgarry void	rdgetdefaultlabel(struct rd_softc *, struct disklabel *);
235473eb467Sgmcgarry void	rdrestart(void *);
236473eb467Sgmcgarry void	rdustart(struct rd_softc *);
237473eb467Sgmcgarry struct buf *rdfinish(struct rd_softc *, struct buf *);
238473eb467Sgmcgarry void	rdcallback(void *, int);
239473eb467Sgmcgarry void	rdstart(struct rd_softc *);
240473eb467Sgmcgarry void	rdintr(struct rd_softc *);
241473eb467Sgmcgarry int	rderror(struct rd_softc *);
242473eb467Sgmcgarry 
243529e91fcScegger int	rdmatch(device_t, cfdata_t, void *);
244529e91fcScegger void	rdattach(device_t, device_t, void *);
245473eb467Sgmcgarry 
246cbab9cadSchs CFATTACH_DECL_NEW(rd, sizeof(struct rd_softc),
247473eb467Sgmcgarry 	rdmatch, rdattach, NULL, NULL);
248473eb467Sgmcgarry 
249473eb467Sgmcgarry 
250473eb467Sgmcgarry dev_type_open(rdopen);
251473eb467Sgmcgarry dev_type_close(rdclose);
252473eb467Sgmcgarry dev_type_read(rdread);
253473eb467Sgmcgarry dev_type_write(rdwrite);
254473eb467Sgmcgarry dev_type_ioctl(rdioctl);
255473eb467Sgmcgarry dev_type_strategy(rdstrategy);
256473eb467Sgmcgarry dev_type_dump(rddump);
257473eb467Sgmcgarry dev_type_size(rdsize);
258473eb467Sgmcgarry 
259473eb467Sgmcgarry const struct bdevsw rd_bdevsw = {
260a68f9396Sdholland 	.d_open = rdopen,
261a68f9396Sdholland 	.d_close = rdclose,
262a68f9396Sdholland 	.d_strategy = rdstrategy,
263a68f9396Sdholland 	.d_ioctl = rdioctl,
264a68f9396Sdholland 	.d_dump = rddump,
265a68f9396Sdholland 	.d_psize = rdsize,
2668c70ef39Sdholland 	.d_discard = nodiscard,
267a68f9396Sdholland 	.d_flag = D_DISK
268473eb467Sgmcgarry };
269473eb467Sgmcgarry 
270473eb467Sgmcgarry const struct cdevsw rd_cdevsw = {
271a68f9396Sdholland 	.d_open = rdopen,
272a68f9396Sdholland 	.d_close = rdclose,
273a68f9396Sdholland 	.d_read = rdread,
274a68f9396Sdholland 	.d_write = rdwrite,
275a68f9396Sdholland 	.d_ioctl = rdioctl,
276a68f9396Sdholland 	.d_stop = nostop,
277a68f9396Sdholland 	.d_tty = notty,
278a68f9396Sdholland 	.d_poll = nopoll,
279a68f9396Sdholland 	.d_mmap = nommap,
280a68f9396Sdholland 	.d_kqfilter = nokqfilter,
281f9228f42Sdholland 	.d_discard = nodiscard,
282a68f9396Sdholland 	.d_flag = D_DISK
283473eb467Sgmcgarry };
284473eb467Sgmcgarry 
285473eb467Sgmcgarry int
rdlookup(int id,int slave,int punit)286454af1c0Sdsl rdlookup(int id, int slave, int punit)
287473eb467Sgmcgarry {
288473eb467Sgmcgarry 	int i;
289473eb467Sgmcgarry 
290473eb467Sgmcgarry 	for (i = 0; i < numrdidentinfo; i++) {
291473eb467Sgmcgarry 		if (rdidentinfo[i].ri_hwid == id)
292473eb467Sgmcgarry 			break;
293473eb467Sgmcgarry 	}
294473eb467Sgmcgarry 	if (i == numrdidentinfo || punit > rdidentinfo[i].ri_maxunum)
295473eb467Sgmcgarry 		return (-1);
296473eb467Sgmcgarry 	return (i);
297473eb467Sgmcgarry }
298473eb467Sgmcgarry 
299473eb467Sgmcgarry int
rdmatch(device_t parent,cfdata_t match,void * aux)300529e91fcScegger rdmatch(device_t parent, cfdata_t match, void *aux)
301473eb467Sgmcgarry {
302473eb467Sgmcgarry 	struct cs80bus_attach_args *ca = aux;
303473eb467Sgmcgarry 
304473eb467Sgmcgarry 	if (rdlookup(ca->ca_id, ca->ca_slave, ca->ca_punit) < 0)
305473eb467Sgmcgarry 		return (0);
306473eb467Sgmcgarry 	return (1);
307473eb467Sgmcgarry }
308473eb467Sgmcgarry 
309473eb467Sgmcgarry void
rdattach(device_t parent,device_t self,void * aux)310529e91fcScegger rdattach(device_t parent, device_t self, void *aux)
311473eb467Sgmcgarry {
31292c7bba3Sthorpej 	struct rd_softc *sc = device_private(self);
313473eb467Sgmcgarry 	struct cs80bus_attach_args *ca = aux;
314473eb467Sgmcgarry 	struct cs80_description csd;
315473eb467Sgmcgarry 	char name[7];
316473eb467Sgmcgarry 	int type, i, n;
317473eb467Sgmcgarry 
318cbab9cadSchs 	sc->sc_dev = self;
319473eb467Sgmcgarry 	sc->sc_ic = ca->ca_ic;
320473eb467Sgmcgarry 	sc->sc_slave = ca->ca_slave;
321473eb467Sgmcgarry 	sc->sc_punit = ca->ca_punit;
322473eb467Sgmcgarry 
323473eb467Sgmcgarry 	if ((type = rdlookup(ca->ca_id, ca->ca_slave, ca->ca_punit)) < 0)
324473eb467Sgmcgarry 		return;
325473eb467Sgmcgarry 
326473eb467Sgmcgarry 	if (cs80reset(parent, sc->sc_slave, sc->sc_punit)) {
3271b044f41Scegger 		aprint_normal("\n");
328cbab9cadSchs 		aprint_error_dev(sc->sc_dev, "can't reset device\n");
329473eb467Sgmcgarry 		return;
330473eb467Sgmcgarry 	}
331473eb467Sgmcgarry 
332473eb467Sgmcgarry 	if (cs80describe(parent, sc->sc_slave, sc->sc_punit, &csd)) {
3331b044f41Scegger 		aprint_normal("\n");
33471fbb921Smsaitoh 		aprint_error_dev(sc->sc_dev,
33571fbb921Smsaitoh 		    "didn't respond to describe command\n");
336473eb467Sgmcgarry 		return;
337473eb467Sgmcgarry 	}
338473eb467Sgmcgarry 	memset(name, 0, sizeof(name));
339473eb467Sgmcgarry 	for (i=0, n=0; i<3; i++) {
340473eb467Sgmcgarry 		name[n++] = (csd.d_name[i] >> 4) + '0';
341473eb467Sgmcgarry 		name[n++] = (csd.d_name[i] & 0x0f) + '0';
342473eb467Sgmcgarry 	}
343473eb467Sgmcgarry 
344473eb467Sgmcgarry #ifdef DEBUG
345473eb467Sgmcgarry 	if (rddebug & RDB_IDENT) {
346473eb467Sgmcgarry 		printf("\n%s: name: ('%s')\n",
347cbab9cadSchs 		    device_xname(sc->sc_dev), name);
348473eb467Sgmcgarry 		printf("  iuw %x, maxxfr %d, ctype %d\n",
349473eb467Sgmcgarry 		    csd.d_iuw, csd.d_cmaxxfr, csd.d_ctype);
350473eb467Sgmcgarry 		printf("  utype %d, bps %d, blkbuf %d, burst %d, blktime %d\n",
351473eb467Sgmcgarry 		    csd.d_utype, csd.d_sectsize,
352473eb467Sgmcgarry 		    csd.d_blkbuf, csd.d_burstsize, csd.d_blocktime);
353473eb467Sgmcgarry 		printf("  avxfr %d, ort %d, atp %d, maxint %d, fv %x, rv %x\n",
354473eb467Sgmcgarry 		    csd.d_uavexfr, csd.d_retry, csd.d_access,
355473eb467Sgmcgarry 		    csd.d_maxint, csd.d_fvbyte, csd.d_rvbyte);
356473eb467Sgmcgarry 		printf("  maxcyl/head/sect %d/%d/%d, maxvsect %d, inter %d\n",
357473eb467Sgmcgarry 		    csd.d_maxcylhead >> 8, csd.d_maxcylhead & 0xff,
358473eb467Sgmcgarry 		    csd.d_maxsect, csd.d_maxvsectl, csd.d_interleave);
359cbab9cadSchs 		printf("%s", device_xname(sc->sc_dev));
360473eb467Sgmcgarry 	}
361473eb467Sgmcgarry #endif
362473eb467Sgmcgarry 
363473eb467Sgmcgarry 	/*
364*99b1bc68Sandvar 	 * Take care of a couple of anomalies:
365473eb467Sgmcgarry 	 * 1. 7945A and 7946A both return same HW id
366473eb467Sgmcgarry 	 * 2. 9122S and 9134D both return same HW id
367473eb467Sgmcgarry 	 * 3. 9122D and 9134L both return same HW id
368473eb467Sgmcgarry 	 */
369473eb467Sgmcgarry 	switch (ca->ca_id) {
370473eb467Sgmcgarry 	case RD7946AID:
371473eb467Sgmcgarry 		if (memcmp(name, "079450", 6) == 0)
372473eb467Sgmcgarry 			type = RD7945A;
373473eb467Sgmcgarry 		else
374473eb467Sgmcgarry 			type = RD7946A;
375473eb467Sgmcgarry 		break;
376473eb467Sgmcgarry 
377473eb467Sgmcgarry 	case RD9134LID:
378473eb467Sgmcgarry 		if (memcmp(name, "091340", 6) == 0)
379473eb467Sgmcgarry 			type = RD9134L;
380473eb467Sgmcgarry 		else
381473eb467Sgmcgarry 			type = RD9122D;
382473eb467Sgmcgarry 		break;
383473eb467Sgmcgarry 
384473eb467Sgmcgarry 	case RD9134DID:
385473eb467Sgmcgarry 		if (memcmp(name, "091220", 6) == 0)
386473eb467Sgmcgarry 			type = RD9122S;
387473eb467Sgmcgarry 		else
388473eb467Sgmcgarry 			type = RD9134D;
389473eb467Sgmcgarry 		break;
390473eb467Sgmcgarry 	}
391473eb467Sgmcgarry 
392473eb467Sgmcgarry 	sc->sc_type = type;
393473eb467Sgmcgarry 
394473eb467Sgmcgarry 	/*
395473eb467Sgmcgarry 	 * XXX We use DEV_BSIZE instead of the sector size value pulled
396473eb467Sgmcgarry 	 * XXX off the driver because all of this code assumes 512 byte
397473eb467Sgmcgarry 	 * XXX blocks.  ICK!
398473eb467Sgmcgarry 	 */
399473eb467Sgmcgarry 	printf(": %s\n", rdidentinfo[type].ri_desc);
400473eb467Sgmcgarry 	printf("%s: %d cylinders, %d heads, %d blocks, %d bytes/block\n",
401cbab9cadSchs 	    device_xname(sc->sc_dev), rdidentinfo[type].ri_ncyl,
402473eb467Sgmcgarry 	    rdidentinfo[type].ri_ntpc, rdidentinfo[type].ri_nblocks,
403473eb467Sgmcgarry 	    DEV_BSIZE);
404473eb467Sgmcgarry 
405aec75b1cSyamt 	bufq_alloc(&sc->sc_tab, "fcfs", 0);
406473eb467Sgmcgarry 
407473eb467Sgmcgarry 	/*
408473eb467Sgmcgarry 	 * Initialize and attach the disk structure.
409473eb467Sgmcgarry 	 */
410473eb467Sgmcgarry 	memset(&sc->sc_dk, 0, sizeof(sc->sc_dk));
411cbab9cadSchs 	disk_init(&sc->sc_dk, device_xname(sc->sc_dev), NULL);
412473eb467Sgmcgarry 	disk_attach(&sc->sc_dk);
413473eb467Sgmcgarry 
41488ab7da9Sad 	callout_init(&sc->sc_restart_ch, 0);
415473eb467Sgmcgarry 
416473eb467Sgmcgarry 	if (gpibregister(sc->sc_ic, sc->sc_slave, rdcallback, sc,
417473eb467Sgmcgarry 	    &sc->sc_hdl)) {
418cbab9cadSchs 		aprint_error_dev(sc->sc_dev, "can't register callback\n");
419473eb467Sgmcgarry 		return;
420473eb467Sgmcgarry 	}
421473eb467Sgmcgarry 
422473eb467Sgmcgarry 	sc->sc_flags = RDF_ALIVE;
423473eb467Sgmcgarry #ifdef DEBUG
424473eb467Sgmcgarry 	/* always report errors */
425473eb467Sgmcgarry 	if (rddebug & RDB_ERROR)
426473eb467Sgmcgarry 		rderrthresh = 0;
427473eb467Sgmcgarry #endif
428473eb467Sgmcgarry 	/*
429473eb467Sgmcgarry 	 * attach the device into the random source list
430473eb467Sgmcgarry 	 */
431cbab9cadSchs 	rnd_attach_source(&sc->rnd_source, device_xname(sc->sc_dev),
432ea6af427Stls 			  RND_TYPE_DISK, RND_FLAG_DEFAULT);
433473eb467Sgmcgarry }
434473eb467Sgmcgarry 
435473eb467Sgmcgarry /*
4365d1e8b27Swiz  * Read or construct a disklabel
437473eb467Sgmcgarry  */
438473eb467Sgmcgarry int
rdgetinfo(struct rd_softc * sc)439454af1c0Sdsl rdgetinfo(struct rd_softc *sc)
440473eb467Sgmcgarry {
441473eb467Sgmcgarry 	struct disklabel *lp = sc->sc_dk.dk_label;
442473eb467Sgmcgarry 	struct partition *pi;
443473eb467Sgmcgarry 	const char *msg;
444473eb467Sgmcgarry 
445473eb467Sgmcgarry 	memset(sc->sc_dk.dk_cpulabel, 0, sizeof(struct cpu_disklabel));
446473eb467Sgmcgarry 
447473eb467Sgmcgarry 	rdgetdefaultlabel(sc, lp);
448473eb467Sgmcgarry 
449473eb467Sgmcgarry 	/*
450473eb467Sgmcgarry 	 * Call the generic disklabel extraction routine
451473eb467Sgmcgarry 	 */
452cbab9cadSchs 	msg = readdisklabel(RDMAKEDEV(0, device_unit(sc->sc_dev), RAW_PART),
453473eb467Sgmcgarry 	    rdstrategy, lp, NULL);
454473eb467Sgmcgarry 	if (msg == NULL)
455473eb467Sgmcgarry 		return (0);
456473eb467Sgmcgarry 
457473eb467Sgmcgarry 	pi = lp->d_partitions;
458cbab9cadSchs 	printf("%s: WARNING: %s\n", device_xname(sc->sc_dev), msg);
4598657dbc0Sthorpej 
460473eb467Sgmcgarry 	pi[RAW_PART].p_size = rdidentinfo[sc->sc_type].ri_nblocks;
461473eb467Sgmcgarry 	lp->d_npartitions = RAW_PART+1;
462473eb467Sgmcgarry 	pi[0].p_size = 0;
4638657dbc0Sthorpej 
464473eb467Sgmcgarry 	return (0);
465473eb467Sgmcgarry }
466473eb467Sgmcgarry 
467473eb467Sgmcgarry int
rdopen(dev_t dev,int flags,int mode,struct lwp * l)4683e484e61Scegger rdopen(dev_t dev, int flags, int mode, struct lwp *l)
469473eb467Sgmcgarry {
470473eb467Sgmcgarry 	struct rd_softc *sc;
471473eb467Sgmcgarry 	int error, mask, part;
472473eb467Sgmcgarry 
4733e484e61Scegger 	sc = device_lookup_private(&rd_cd, RDUNIT(dev));
474473eb467Sgmcgarry 	if (sc == NULL || (sc->sc_flags & RDF_ALIVE) ==0)
475473eb467Sgmcgarry 		return (ENXIO);
476473eb467Sgmcgarry 
477473eb467Sgmcgarry 	/*
478473eb467Sgmcgarry 	 * Wait for any pending opens/closes to complete
479473eb467Sgmcgarry 	 */
480473eb467Sgmcgarry 	while (sc->sc_flags & (RDF_OPENING | RDF_CLOSING))
481473eb467Sgmcgarry 		(void) tsleep(sc, PRIBIO, "rdopen", 0);
482473eb467Sgmcgarry 
483473eb467Sgmcgarry 	/*
484473eb467Sgmcgarry 	 * On first open, get label and partition info.
485473eb467Sgmcgarry 	 * We may block reading the label, so be careful
486473eb467Sgmcgarry 	 * to stop any other opens.
487473eb467Sgmcgarry 	 */
488473eb467Sgmcgarry 	if (sc->sc_dk.dk_openmask == 0) {
489473eb467Sgmcgarry 		sc->sc_flags |= RDF_OPENING;
490473eb467Sgmcgarry 		error = rdgetinfo(sc);
491473eb467Sgmcgarry 		sc->sc_flags &= ~RDF_OPENING;
49253524e44Schristos 		wakeup((void *)sc);
493473eb467Sgmcgarry 		if (error)
494473eb467Sgmcgarry 			return (error);
495473eb467Sgmcgarry 	}
496473eb467Sgmcgarry 
497473eb467Sgmcgarry 	part = RDPART(dev);
498473eb467Sgmcgarry 	mask = 1 << part;
499473eb467Sgmcgarry 
500473eb467Sgmcgarry 	/* Check that the partition exists. */
501473eb467Sgmcgarry 	if (part != RAW_PART && (part > sc->sc_dk.dk_label->d_npartitions ||
502473eb467Sgmcgarry 	    sc->sc_dk.dk_label->d_partitions[part].p_fstype == FS_UNUSED))
503473eb467Sgmcgarry 		return (ENXIO);
504473eb467Sgmcgarry 
505473eb467Sgmcgarry 	/* Ensure only one open at a time. */
506473eb467Sgmcgarry 	switch (mode) {
507473eb467Sgmcgarry 	case S_IFCHR:
508473eb467Sgmcgarry 		sc->sc_dk.dk_copenmask |= mask;
509473eb467Sgmcgarry 		break;
510473eb467Sgmcgarry 	case S_IFBLK:
511473eb467Sgmcgarry 		sc->sc_dk.dk_bopenmask |= mask;
512473eb467Sgmcgarry 		break;
513473eb467Sgmcgarry 	}
514473eb467Sgmcgarry 	sc->sc_dk.dk_openmask =
515473eb467Sgmcgarry 	    sc->sc_dk.dk_copenmask | sc->sc_dk.dk_bopenmask;
516473eb467Sgmcgarry 
517473eb467Sgmcgarry 	return (0);
518473eb467Sgmcgarry }
519473eb467Sgmcgarry 
520473eb467Sgmcgarry int
rdclose(dev_t dev,int flag,int mode,struct lwp * l)5213e484e61Scegger rdclose(dev_t dev, int flag, int mode, struct lwp *l)
522473eb467Sgmcgarry {
523473eb467Sgmcgarry 	struct rd_softc *sc;
524473eb467Sgmcgarry 	struct disk *dk;
525473eb467Sgmcgarry 	int mask, s;
526473eb467Sgmcgarry 
5273e484e61Scegger 	sc = device_lookup_private(&rd_cd, RDUNIT(dev));
528473eb467Sgmcgarry 	if (sc == NULL)
529473eb467Sgmcgarry 		return (ENXIO);
530473eb467Sgmcgarry 
531473eb467Sgmcgarry 	dk = &sc->sc_dk;
532473eb467Sgmcgarry 
533473eb467Sgmcgarry 	mask = 1 << RDPART(dev);
534473eb467Sgmcgarry 	if (mode == S_IFCHR)
535473eb467Sgmcgarry 		dk->dk_copenmask &= ~mask;
536473eb467Sgmcgarry 	else
537473eb467Sgmcgarry 		dk->dk_bopenmask &= ~mask;
538473eb467Sgmcgarry 	dk->dk_openmask = dk->dk_copenmask | dk->dk_bopenmask;
539473eb467Sgmcgarry 	/*
540473eb467Sgmcgarry 	 * On last close, we wait for all activity to cease since
541811d5a8bSmsaitoh 	 * the label/partition info will become invalid.  Since we
542473eb467Sgmcgarry 	 * might sleep, we must block any opens while we are here.
543473eb467Sgmcgarry 	 * Note we don't have to about other closes since we know
544473eb467Sgmcgarry 	 * we are the last one.
545473eb467Sgmcgarry 	 */
546473eb467Sgmcgarry 	if (dk->dk_openmask == 0) {
547473eb467Sgmcgarry 		sc->sc_flags |= RDF_CLOSING;
548473eb467Sgmcgarry 		s = splbio();
549473eb467Sgmcgarry 		while (sc->sc_active) {
550473eb467Sgmcgarry 			sc->sc_flags |= RDF_WANTED;
551473eb467Sgmcgarry 			(void) tsleep(&sc->sc_tab, PRIBIO, "rdclose", 0);
552473eb467Sgmcgarry 		}
553473eb467Sgmcgarry 		splx(s);
554473eb467Sgmcgarry 		sc->sc_flags &= ~(RDF_CLOSING | RDF_WLABEL);
55553524e44Schristos 		wakeup((void *)sc);
556473eb467Sgmcgarry 	}
557473eb467Sgmcgarry 	return (0);
558473eb467Sgmcgarry }
559473eb467Sgmcgarry 
560473eb467Sgmcgarry void
rdstrategy(struct buf * bp)5613e484e61Scegger rdstrategy(struct buf *bp)
562473eb467Sgmcgarry {
563473eb467Sgmcgarry 	struct rd_softc *sc;
564473eb467Sgmcgarry 	struct partition *pinfo;
565473eb467Sgmcgarry 	daddr_t bn;
566473eb467Sgmcgarry 	int sz, s;
567473eb467Sgmcgarry 	int offset;
568473eb467Sgmcgarry 
5693e484e61Scegger 	sc = device_lookup_private(&rd_cd, RDUNIT(bp->b_dev));
570473eb467Sgmcgarry 
571473eb467Sgmcgarry 	DPRINTF(RDB_FOLLOW,
572d25ce32eStsutsui 	    ("rdstrategy(%p): dev %" PRIx64 ", bn %" PRId64 ", bcount %d, %c\n",
573473eb467Sgmcgarry 	    bp, bp->b_dev, bp->b_blkno, bp->b_bcount,
574473eb467Sgmcgarry 	    (bp->b_flags & B_READ) ? 'R' : 'W'));
575473eb467Sgmcgarry 
576473eb467Sgmcgarry 	bn = bp->b_blkno;
577473eb467Sgmcgarry 	sz = howmany(bp->b_bcount, DEV_BSIZE);
578473eb467Sgmcgarry 	pinfo = &sc->sc_dk.dk_label->d_partitions[RDPART(bp->b_dev)];
579473eb467Sgmcgarry 
580473eb467Sgmcgarry 	/* Don't perform partition translation on RAW_PART. */
581473eb467Sgmcgarry 	offset = (RDPART(bp->b_dev) == RAW_PART) ? 0 : pinfo->p_offset;
582473eb467Sgmcgarry 
583473eb467Sgmcgarry 	if (RDPART(bp->b_dev) != RAW_PART) {
584473eb467Sgmcgarry 		/*
585473eb467Sgmcgarry 		 * XXX This block of code belongs in
586473eb467Sgmcgarry 		 * XXX bounds_check_with_label()
587473eb467Sgmcgarry 		 */
588473eb467Sgmcgarry 
589473eb467Sgmcgarry 		if (bn < 0 || bn + sz > pinfo->p_size) {
590473eb467Sgmcgarry 			sz = pinfo->p_size - bn;
591473eb467Sgmcgarry 			if (sz == 0) {
592473eb467Sgmcgarry 				bp->b_resid = bp->b_bcount;
593473eb467Sgmcgarry 				goto done;
594473eb467Sgmcgarry 			}
595473eb467Sgmcgarry 			if (sz < 0) {
596473eb467Sgmcgarry 				bp->b_error = EINVAL;
59766fefd11Sad 				goto done;
598473eb467Sgmcgarry 			}
599473eb467Sgmcgarry 			bp->b_bcount = dbtob(sz);
600473eb467Sgmcgarry 		}
601473eb467Sgmcgarry 		/*
602473eb467Sgmcgarry 		 * Check for write to write protected label
603473eb467Sgmcgarry 		 */
604473eb467Sgmcgarry 		if (bn + offset <= LABELSECTOR &&
605473eb467Sgmcgarry #if LABELSECTOR != 0
606473eb467Sgmcgarry 		    bn + offset + sz > LABELSECTOR &&
607473eb467Sgmcgarry #endif
608473eb467Sgmcgarry 		    !(bp->b_flags & B_READ) && !(sc->sc_flags & RDF_WLABEL)) {
609473eb467Sgmcgarry 			bp->b_error = EROFS;
61066fefd11Sad 			goto done;
611473eb467Sgmcgarry 		}
612473eb467Sgmcgarry 	}
613473eb467Sgmcgarry 	bp->b_rawblkno = bn + offset;
614473eb467Sgmcgarry 	s = splbio();
61570de9736Syamt 	bufq_put(sc->sc_tab, bp);
616473eb467Sgmcgarry 	if (sc->sc_active == 0) {
617473eb467Sgmcgarry 		sc->sc_active = 1;
618473eb467Sgmcgarry 		rdustart(sc);
619473eb467Sgmcgarry 	}
620473eb467Sgmcgarry 	splx(s);
621473eb467Sgmcgarry 	return;
622473eb467Sgmcgarry done:
623473eb467Sgmcgarry 	biodone(bp);
624473eb467Sgmcgarry }
625473eb467Sgmcgarry 
626473eb467Sgmcgarry /*
627473eb467Sgmcgarry  * Called from timeout() when handling maintenance releases
628473eb467Sgmcgarry  * callout from timeouts
629473eb467Sgmcgarry  */
630473eb467Sgmcgarry void
rdrestart(void * arg)631454af1c0Sdsl rdrestart(void *arg)
632473eb467Sgmcgarry {
633473eb467Sgmcgarry 	int s = splbio();
634473eb467Sgmcgarry 	rdustart((struct rd_softc *)arg);
635473eb467Sgmcgarry 	splx(s);
636473eb467Sgmcgarry }
637473eb467Sgmcgarry 
638473eb467Sgmcgarry 
639473eb467Sgmcgarry /* called by rdstrategy() to start a block transfer */
640473eb467Sgmcgarry /* called by rdrestart() when handingly timeouts */
641473eb467Sgmcgarry /* called by rdintr() */
642473eb467Sgmcgarry void
rdustart(struct rd_softc * sc)643454af1c0Sdsl rdustart(struct rd_softc *sc)
644473eb467Sgmcgarry {
645473eb467Sgmcgarry 	struct buf *bp;
646473eb467Sgmcgarry 
64770de9736Syamt 	bp = bufq_peek(sc->sc_tab);
648473eb467Sgmcgarry 	sc->sc_addr = bp->b_data;
649473eb467Sgmcgarry 	sc->sc_resid = bp->b_bcount;
650473eb467Sgmcgarry 	if (gpibrequest(sc->sc_ic, sc->sc_hdl))
651473eb467Sgmcgarry 		rdstart(sc);
652473eb467Sgmcgarry }
653473eb467Sgmcgarry 
654473eb467Sgmcgarry struct buf *
rdfinish(struct rd_softc * sc,struct buf * bp)655454af1c0Sdsl rdfinish(struct rd_softc *sc, struct buf *bp)
656473eb467Sgmcgarry {
657473eb467Sgmcgarry 
658473eb467Sgmcgarry 	sc->sc_errcnt = 0;
65970de9736Syamt 	(void)bufq_get(sc->sc_tab);
660473eb467Sgmcgarry 	bp->b_resid = 0;
661473eb467Sgmcgarry 	biodone(bp);
662473eb467Sgmcgarry 	gpibrelease(sc->sc_ic, sc->sc_hdl);
66370de9736Syamt 	if ((bp = bufq_peek(sc->sc_tab)) != NULL)
664473eb467Sgmcgarry 		return (bp);
665473eb467Sgmcgarry 	sc->sc_active = 0;
666473eb467Sgmcgarry 	if (sc->sc_flags & RDF_WANTED) {
667473eb467Sgmcgarry 		sc->sc_flags &= ~RDF_WANTED;
66853524e44Schristos 		wakeup((void *)&sc->sc_tab);
669473eb467Sgmcgarry 	}
670473eb467Sgmcgarry 	return (NULL);
671473eb467Sgmcgarry }
672473eb467Sgmcgarry 
673473eb467Sgmcgarry void
rdcallback(void * v,int action)674454af1c0Sdsl rdcallback(void *v, int action)
675473eb467Sgmcgarry {
676473eb467Sgmcgarry 	struct rd_softc *sc = v;
677473eb467Sgmcgarry 
678473eb467Sgmcgarry 	DPRINTF(RDB_FOLLOW, ("rdcallback: v=%p, action=%d\n", v, action));
679473eb467Sgmcgarry 
680473eb467Sgmcgarry 	switch (action) {
681473eb467Sgmcgarry 	case GPIBCBF_START:
682473eb467Sgmcgarry 		rdstart(sc);
683473eb467Sgmcgarry 		break;
684473eb467Sgmcgarry 	case GPIBCBF_INTR:
685473eb467Sgmcgarry 		rdintr(sc);
686473eb467Sgmcgarry 		break;
687473eb467Sgmcgarry #ifdef DEBUG
688473eb467Sgmcgarry 	default:
689473eb467Sgmcgarry 		DPRINTF(RDB_ERROR, ("rdcallback: unknown action %d\n",
690473eb467Sgmcgarry 		    action));
691473eb467Sgmcgarry 		break;
692473eb467Sgmcgarry #endif
693473eb467Sgmcgarry 	}
694473eb467Sgmcgarry }
695473eb467Sgmcgarry 
696473eb467Sgmcgarry 
697473eb467Sgmcgarry /* called from rdustart() to start a transfer */
698473eb467Sgmcgarry /* called from gpib interface as the initiator */
699473eb467Sgmcgarry void
rdstart(struct rd_softc * sc)700454af1c0Sdsl rdstart(struct rd_softc *sc)
701473eb467Sgmcgarry {
70270de9736Syamt 	struct buf *bp = bufq_peek(sc->sc_tab);
703e91bfe1bSchristos 	int slave, punit;
704473eb467Sgmcgarry 
705473eb467Sgmcgarry 	slave = sc->sc_slave;
706473eb467Sgmcgarry 	punit = sc->sc_punit;
707473eb467Sgmcgarry 
708473eb467Sgmcgarry 	DPRINTF(RDB_FOLLOW, ("rdstart(%s): bp %p, %c\n",
709cbab9cadSchs 	    device_xname(sc->sc_dev), bp, (bp->b_flags & B_READ) ? 'R' : 'W'));
710473eb467Sgmcgarry 
711473eb467Sgmcgarry again:
712473eb467Sgmcgarry 
713473eb467Sgmcgarry 	sc->sc_flags |= RDF_SEEK;
714473eb467Sgmcgarry 	sc->sc_ioc.c_unit = CS80CMD_SUNIT(punit);
715473eb467Sgmcgarry 	sc->sc_ioc.c_volume = CS80CMD_SVOL(0);
716473eb467Sgmcgarry 	sc->sc_ioc.c_saddr = CS80CMD_SADDR;
717473eb467Sgmcgarry 	sc->sc_ioc.c_hiaddr = htobe16(0);
718473eb467Sgmcgarry 	sc->sc_ioc.c_addr = htobe32(RDBTOS(bp->b_rawblkno));
719473eb467Sgmcgarry 	sc->sc_ioc.c_nop2 = CS80CMD_NOP;
720473eb467Sgmcgarry 	sc->sc_ioc.c_slen = CS80CMD_SLEN;
721473eb467Sgmcgarry 	sc->sc_ioc.c_len = htobe32(sc->sc_resid);
722473eb467Sgmcgarry 	sc->sc_ioc.c_cmd = bp->b_flags & B_READ ? CS80CMD_READ : CS80CMD_WRITE;
723473eb467Sgmcgarry 
724473eb467Sgmcgarry 	if (gpibsend(sc->sc_ic, slave, CS80CMD_SCMD, &sc->sc_ioc.c_unit,
725473eb467Sgmcgarry 	    sizeof(sc->sc_ioc)-1) == sizeof(sc->sc_ioc)-1) {
726473eb467Sgmcgarry 		/* Instrumentation. */
727473eb467Sgmcgarry 		disk_busy(&sc->sc_dk);
7283c0adb7dSblymn 		iostat_seek(sc->sc_dk.dk_stats);
729473eb467Sgmcgarry 		gpibawait(sc->sc_ic);
730473eb467Sgmcgarry 		return;
731473eb467Sgmcgarry 	}
732473eb467Sgmcgarry 	/*
733473eb467Sgmcgarry 	 * Experience has shown that the gpibwait in this gpibsend will
734473eb467Sgmcgarry 	 * occasionally timeout.  It appears to occur mostly on old 7914
735473eb467Sgmcgarry 	 * drives with full maintenance tracks.  We should probably
736473eb467Sgmcgarry 	 * integrate this with the backoff code in rderror.
737473eb467Sgmcgarry 	 */
738473eb467Sgmcgarry 
739473eb467Sgmcgarry 	DPRINTF(RDB_ERROR,
740473eb467Sgmcgarry 	    ("rdstart: cmd %x adr %ul blk %" PRId64 " len %d ecnt %d\n",
741473eb467Sgmcgarry 	    sc->sc_ioc.c_cmd, sc->sc_ioc.c_addr, bp->b_blkno, sc->sc_resid,
742473eb467Sgmcgarry 	     sc->sc_errcnt));
743473eb467Sgmcgarry 
744473eb467Sgmcgarry 	sc->sc_flags &= ~RDF_SEEK;
745cbab9cadSchs 	cs80reset(device_parent(sc->sc_dev), slave, punit);
746473eb467Sgmcgarry 	if (sc->sc_errcnt++ < RDRETRY)
747473eb467Sgmcgarry 		goto again;
748473eb467Sgmcgarry 	printf("%s: rdstart err: cmd 0x%x sect %uld blk %" PRId64 " len %d\n",
749cbab9cadSchs 	       device_xname(sc->sc_dev), sc->sc_ioc.c_cmd, sc->sc_ioc.c_addr,
750473eb467Sgmcgarry 	       bp->b_blkno, sc->sc_resid);
751473eb467Sgmcgarry 	bp->b_error = EIO;
752473eb467Sgmcgarry 	bp = rdfinish(sc, bp);
753473eb467Sgmcgarry 	if (bp) {
754473eb467Sgmcgarry 		sc->sc_addr = bp->b_data;
755473eb467Sgmcgarry 		sc->sc_resid = bp->b_bcount;
756473eb467Sgmcgarry 		if (gpibrequest(sc->sc_ic, sc->sc_hdl))
757473eb467Sgmcgarry 			goto again;
758473eb467Sgmcgarry 	}
759473eb467Sgmcgarry }
760473eb467Sgmcgarry 
761473eb467Sgmcgarry void
rdintr(struct rd_softc * sc)762454af1c0Sdsl rdintr(struct rd_softc *sc)
763473eb467Sgmcgarry {
764473eb467Sgmcgarry 	struct buf *bp;
765473eb467Sgmcgarry 	u_int8_t stat = 13;	/* in case gpibrecv fails */
766473eb467Sgmcgarry 	int rv, dir, restart, slave;
767473eb467Sgmcgarry 
768473eb467Sgmcgarry 	slave = sc->sc_slave;
76970de9736Syamt 	bp = bufq_peek(sc->sc_tab);
770473eb467Sgmcgarry 
771473eb467Sgmcgarry 	DPRINTF(RDB_FOLLOW, ("rdintr(%s): bp %p, %c, flags %x\n",
772cbab9cadSchs 	    device_xname(sc->sc_dev), bp, (bp->b_flags & B_READ) ? 'R' : 'W',
773473eb467Sgmcgarry 	    sc->sc_flags));
774473eb467Sgmcgarry 
775473eb467Sgmcgarry 	disk_unbusy(&sc->sc_dk, (bp->b_bcount - bp->b_resid),
776473eb467Sgmcgarry 		(bp->b_flags & B_READ));
777473eb467Sgmcgarry 
778473eb467Sgmcgarry 	if (sc->sc_flags & RDF_SEEK) {
779473eb467Sgmcgarry 		sc->sc_flags &= ~RDF_SEEK;
780473eb467Sgmcgarry 		dir = (bp->b_flags & B_READ ? GPIB_READ : GPIB_WRITE);
781473eb467Sgmcgarry 		gpibxfer(sc->sc_ic, slave, CS80CMD_EXEC, sc->sc_addr,
782473eb467Sgmcgarry 		    sc->sc_resid, dir, dir == GPIB_READ);
783473eb467Sgmcgarry 		disk_busy(&sc->sc_dk);
784473eb467Sgmcgarry 		return;
785473eb467Sgmcgarry 	}
786473eb467Sgmcgarry 	if ((sc->sc_flags & RDF_SWAIT) == 0) {
787473eb467Sgmcgarry 		if (gpibpptest(sc->sc_ic, slave) == 0) {
788473eb467Sgmcgarry 			/* Instrumentation. */
789473eb467Sgmcgarry 			disk_busy(&sc->sc_dk);
790473eb467Sgmcgarry 			sc->sc_flags |= RDF_SWAIT;
791473eb467Sgmcgarry 			gpibawait(sc->sc_ic);
792473eb467Sgmcgarry 			return;
793473eb467Sgmcgarry 		}
794473eb467Sgmcgarry 	} else
795473eb467Sgmcgarry 		sc->sc_flags &= ~RDF_SWAIT;
796473eb467Sgmcgarry 	rv = gpibrecv(sc->sc_ic, slave, CS80CMD_QSTAT, &stat, 1);
797473eb467Sgmcgarry 	if (rv != 1 || stat) {
798473eb467Sgmcgarry 		DPRINTF(RDB_ERROR,
799473eb467Sgmcgarry 		    ("rdintr: receive failed (rv=%d) or bad stat %d\n", rv,
800473eb467Sgmcgarry 		     stat));
801473eb467Sgmcgarry 		restart = rderror(sc);
802473eb467Sgmcgarry 		if (sc->sc_errcnt++ < RDRETRY) {
803473eb467Sgmcgarry 			if (restart)
804473eb467Sgmcgarry 				rdstart(sc);
805473eb467Sgmcgarry 			return;
806473eb467Sgmcgarry 		}
807473eb467Sgmcgarry 		bp->b_error = EIO;
808473eb467Sgmcgarry 	}
809473eb467Sgmcgarry 	if (rdfinish(sc, bp) != NULL)
810473eb467Sgmcgarry 		rdustart(sc);
811473eb467Sgmcgarry 	rnd_add_uint32(&sc->rnd_source, bp->b_blkno);
812473eb467Sgmcgarry }
813473eb467Sgmcgarry 
814473eb467Sgmcgarry /*
815473eb467Sgmcgarry  * Deal with errors.
816473eb467Sgmcgarry  * Returns 1 if request should be restarted,
817473eb467Sgmcgarry  * 0 if we should just quietly give up.
818473eb467Sgmcgarry  */
819473eb467Sgmcgarry int
rderror(struct rd_softc * sc)820454af1c0Sdsl rderror(struct rd_softc *sc)
821473eb467Sgmcgarry {
822473eb467Sgmcgarry 	struct cs80_stat css;
823473eb467Sgmcgarry 	struct buf *bp;
824473eb467Sgmcgarry 	daddr_t hwbn, pbn;
825473eb467Sgmcgarry 
826473eb467Sgmcgarry 	DPRINTF(RDB_FOLLOW, ("rderror: sc=%p\n", sc));
827473eb467Sgmcgarry 
828cbab9cadSchs 	if (cs80status(device_parent(sc->sc_dev), sc->sc_slave,
829473eb467Sgmcgarry 	    sc->sc_punit, &css)) {
830cbab9cadSchs 		cs80reset(device_parent(sc->sc_dev), sc->sc_slave,
831246504f9Sthorpej 		    sc->sc_punit);
832473eb467Sgmcgarry 		return (1);
833473eb467Sgmcgarry 	}
834473eb467Sgmcgarry #ifdef DEBUG
835473eb467Sgmcgarry 	if (rddebug & RDB_ERROR) {			/* status info */
836473eb467Sgmcgarry 		printf("\n    volume: %d, unit: %d\n",
837473eb467Sgmcgarry 		       (css.c_vu>>4)&0xF, css.c_vu&0xF);
838473eb467Sgmcgarry 		printf("    reject 0x%x\n", css.c_ref);
839473eb467Sgmcgarry 		printf("    fault 0x%x\n", css.c_fef);
840473eb467Sgmcgarry 		printf("    access 0x%x\n", css.c_aef);
841473eb467Sgmcgarry 		printf("    info 0x%x\n", css.c_ief);
842473eb467Sgmcgarry 		printf("    block,  P1-P10: ");
843473eb467Sgmcgarry 		printf("0x%x", *(u_int32_t *)&css.c_raw[0]);
844473eb467Sgmcgarry 		printf("0x%x", *(u_int32_t *)&css.c_raw[4]);
845473eb467Sgmcgarry 		printf("0x%x\n", *(u_int16_t *)&css.c_raw[8]);
846473eb467Sgmcgarry 	}
847473eb467Sgmcgarry #endif
848473eb467Sgmcgarry 	if (css.c_fef & FEF_REXMT)
849473eb467Sgmcgarry 		return (1);
850473eb467Sgmcgarry 	if (css.c_fef & FEF_PF) {
851cbab9cadSchs 		cs80reset(device_parent(sc->sc_dev), sc->sc_slave,
852246504f9Sthorpej 		    sc->sc_punit);
853473eb467Sgmcgarry 		return (1);
854473eb467Sgmcgarry 	}
855473eb467Sgmcgarry 	/*
856473eb467Sgmcgarry 	 * Unit requests release for internal maintenance.
857*99b1bc68Sandvar 	 * We just delay awhile and try again later.  Use exponentially
858473eb467Sgmcgarry 	 * increasing backoff ala ethernet drivers since we don't really
859473eb467Sgmcgarry 	 * know how long the maintenance will take.  With RDWAITC and
860473eb467Sgmcgarry 	 * RDRETRY as defined, the range is 1 to 32 seconds.
861473eb467Sgmcgarry 	 */
862473eb467Sgmcgarry 	if (css.c_fef & FEF_IMR) {
863473eb467Sgmcgarry 		extern int hz;
864473eb467Sgmcgarry 		int rdtimo = RDWAITC << sc->sc_errcnt;
865473eb467Sgmcgarry 		DPRINTF(RDB_STATUS,
866473eb467Sgmcgarry 		    ("%s: internal maintenance, %d-second timeout\n",
867cbab9cadSchs 		    device_xname(sc->sc_dev), rdtimo));
868473eb467Sgmcgarry 		gpibrelease(sc->sc_ic, sc->sc_hdl);
869473eb467Sgmcgarry 		callout_reset(&sc->sc_restart_ch, rdtimo * hz, rdrestart, sc);
870473eb467Sgmcgarry 		return (0);
871473eb467Sgmcgarry 	}
872473eb467Sgmcgarry 	/*
873473eb467Sgmcgarry 	 * Only report error if we have reached the error reporting
87440be87aeSandvar 	 * threshold.  By default, this will only report after the
875473eb467Sgmcgarry 	 * retry limit has been exceeded.
876473eb467Sgmcgarry 	 */
877473eb467Sgmcgarry 	if (sc->sc_errcnt < rderrthresh)
878473eb467Sgmcgarry 		return (1);
879473eb467Sgmcgarry 
880473eb467Sgmcgarry 	/*
881473eb467Sgmcgarry 	 * First conjure up the block number at which the error occurred.
882473eb467Sgmcgarry  	 */
88370de9736Syamt 	bp = bufq_peek(sc->sc_tab);
884473eb467Sgmcgarry 	pbn = sc->sc_dk.dk_label->d_partitions[RDPART(bp->b_dev)].p_offset;
885473eb467Sgmcgarry 	if ((css.c_fef & FEF_CU) || (css.c_fef & FEF_DR) ||
886473eb467Sgmcgarry 	    (css.c_ief & IEF_RRMASK)) {
887473eb467Sgmcgarry 		/*
888473eb467Sgmcgarry 		 * Not all errors report a block number, just use b_blkno.
889473eb467Sgmcgarry 		 */
890473eb467Sgmcgarry 		hwbn = RDBTOS(pbn + bp->b_blkno);
891473eb467Sgmcgarry 		pbn = bp->b_blkno;
892473eb467Sgmcgarry 	} else {
893473eb467Sgmcgarry 		hwbn = css.c_blk;
894473eb467Sgmcgarry 		pbn = RDSTOB(hwbn) - pbn;
895473eb467Sgmcgarry 	}
896473eb467Sgmcgarry #ifdef DEBUG
897473eb467Sgmcgarry 	if (rddebug & RDB_ERROR) {			/* status info */
898473eb467Sgmcgarry 		printf("\n    volume: %d, unit: %d\n",
899473eb467Sgmcgarry 		       (css.c_vu>>4)&0xF, css.c_vu&0xF);
900473eb467Sgmcgarry 		printf("    reject 0x%x\n", css.c_ref);
901473eb467Sgmcgarry 		printf("    fault 0x%x\n", css.c_fef);
902473eb467Sgmcgarry 		printf("    access 0x%x\n", css.c_aef);
903473eb467Sgmcgarry 		printf("    info 0x%x\n", css.c_ief);
904473eb467Sgmcgarry 		printf("    block,  P1-P10: ");
905473eb467Sgmcgarry 		printf("    block: %" PRId64 ", P1-P10: ", hwbn);
906473eb467Sgmcgarry 		printf("0x%x", *(u_int32_t *)&css.c_raw[0]);
907473eb467Sgmcgarry 		printf("0x%x", *(u_int32_t *)&css.c_raw[4]);
908473eb467Sgmcgarry 		printf("0x%x\n", *(u_int16_t *)&css.c_raw[8]);
909473eb467Sgmcgarry 	}
910473eb467Sgmcgarry #endif
911473eb467Sgmcgarry #ifdef DEBUG
912473eb467Sgmcgarry 	if (rddebug & RDB_ERROR) {			/* command */
913473eb467Sgmcgarry 		printf("    ioc: ");
914473eb467Sgmcgarry 		printf("0x%x", *(u_int32_t *)&sc->sc_ioc.c_pad);
915473eb467Sgmcgarry 		printf("0x%x", *(u_int16_t *)&sc->sc_ioc.c_hiaddr);
916473eb467Sgmcgarry 		printf("0x%x", *(u_int32_t *)&sc->sc_ioc.c_addr);
917473eb467Sgmcgarry 		printf("0x%x", *(u_int16_t *)&sc->sc_ioc.c_nop2);
918473eb467Sgmcgarry 		printf("0x%x", *(u_int32_t *)&sc->sc_ioc.c_len);
919473eb467Sgmcgarry 		printf("0x%x\n", *(u_int16_t *)&sc->sc_ioc.c_cmd);
920473eb467Sgmcgarry 		return (1);
921473eb467Sgmcgarry 	}
922473eb467Sgmcgarry #endif
923473eb467Sgmcgarry 	/*
924473eb467Sgmcgarry 	 * Now output a generic message suitable for badsect.
925473eb467Sgmcgarry 	 * Note that we don't use harderr because it just prints
926473eb467Sgmcgarry 	 * out b_blkno which is just the beginning block number
927473eb467Sgmcgarry 	 * of the transfer, not necessary where the error occurred.
928473eb467Sgmcgarry 	 */
929473eb467Sgmcgarry 	printf("%s%c: hard error, sector number %" PRId64 "\n",
930cbab9cadSchs 	    device_xname(sc->sc_dev), 'a'+RDPART(bp->b_dev), pbn);
931473eb467Sgmcgarry 	/*
932473eb467Sgmcgarry 	 * Now report the status as returned by the hardware with
933473eb467Sgmcgarry 	 * attempt at interpretation.
934473eb467Sgmcgarry 	 */
935cbab9cadSchs 	printf("%s %s error:", device_xname(sc->sc_dev),
936473eb467Sgmcgarry 	    (bp->b_flags & B_READ) ? "read" : "write");
937473eb467Sgmcgarry 	printf(" unit %d, volume %d R0x%x F0x%x A0x%x I0x%x\n",
938473eb467Sgmcgarry 	       css.c_vu&0xF, (css.c_vu>>4)&0xF,
939473eb467Sgmcgarry 	       css.c_ref, css.c_fef, css.c_aef, css.c_ief);
940473eb467Sgmcgarry 	printf("P1-P10: ");
941473eb467Sgmcgarry 	printf("0x%x ", *(u_int32_t *)&css.c_raw[0]);
942473eb467Sgmcgarry 	printf("0x%x ", *(u_int32_t *)&css.c_raw[4]);
943473eb467Sgmcgarry 	printf("0x%x\n", *(u_int16_t *)&css.c_raw[8]);
944473eb467Sgmcgarry 
945473eb467Sgmcgarry 	return (1);
946473eb467Sgmcgarry }
947473eb467Sgmcgarry 
948473eb467Sgmcgarry int
rdread(dev_t dev,struct uio * uio,int flags)949454af1c0Sdsl rdread(dev_t dev, struct uio *uio, int flags)
950473eb467Sgmcgarry {
951473eb467Sgmcgarry 
952473eb467Sgmcgarry 	return (physio(rdstrategy, NULL, dev, B_READ, minphys, uio));
953473eb467Sgmcgarry }
954473eb467Sgmcgarry 
955473eb467Sgmcgarry int
rdwrite(dev_t dev,struct uio * uio,int flags)956454af1c0Sdsl rdwrite(dev_t dev, struct uio *uio, int flags)
957473eb467Sgmcgarry {
958473eb467Sgmcgarry 
959473eb467Sgmcgarry 	return (physio(rdstrategy, NULL, dev, B_WRITE, minphys, uio));
960473eb467Sgmcgarry }
961473eb467Sgmcgarry 
962473eb467Sgmcgarry int
rdioctl(dev_t dev,u_long cmd,void * data,int flag,struct lwp * l)9633e484e61Scegger rdioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l)
964473eb467Sgmcgarry {
965473eb467Sgmcgarry 	struct rd_softc *sc;
966473eb467Sgmcgarry 	struct disklabel *lp;
967473eb467Sgmcgarry 	int error, flags;
968473eb467Sgmcgarry 
9693e484e61Scegger 	sc = device_lookup_private(&rd_cd, RDUNIT(dev));
970473eb467Sgmcgarry 	if (sc == NULL)
971473eb467Sgmcgarry 		return (ENXIO);
972473eb467Sgmcgarry 	lp = sc->sc_dk.dk_label;
973473eb467Sgmcgarry 
974473eb467Sgmcgarry 	DPRINTF(RDB_FOLLOW, ("rdioctl: sc=%p\n", sc));
975473eb467Sgmcgarry 
976df05bb66Schristos 	error = disk_ioctl(&sc->sc_dk, dev, cmd, data, flag, l);
977c60db2e9Schristos 	if (error != EPASSTHROUGH)
978c60db2e9Schristos 		return error;
979c60db2e9Schristos 
980473eb467Sgmcgarry 	switch (cmd) {
981473eb467Sgmcgarry 	case DIOCWLABEL:
982473eb467Sgmcgarry 		if ((flag & FWRITE) == 0)
983473eb467Sgmcgarry 			return (EBADF);
984473eb467Sgmcgarry 		if (*(int *)data)
985473eb467Sgmcgarry 			sc->sc_flags |= RDF_WLABEL;
986473eb467Sgmcgarry 		else
987473eb467Sgmcgarry 			sc->sc_flags &= ~RDF_WLABEL;
988473eb467Sgmcgarry 		return (0);
989473eb467Sgmcgarry 
990473eb467Sgmcgarry 	case DIOCSDINFO:
991473eb467Sgmcgarry 		if ((flag & FWRITE) == 0)
992473eb467Sgmcgarry 			return (EBADF);
993473eb467Sgmcgarry 		return (setdisklabel(lp, (struct disklabel *)data,
994473eb467Sgmcgarry 		    (sc->sc_flags & RDF_WLABEL) ? 0 : sc->sc_dk.dk_openmask,
995473eb467Sgmcgarry 		    (struct cpu_disklabel *)0));
996473eb467Sgmcgarry 
997473eb467Sgmcgarry 	case DIOCWDINFO:
998473eb467Sgmcgarry 		if ((flag & FWRITE) == 0)
999473eb467Sgmcgarry 			return (EBADF);
1000473eb467Sgmcgarry 		error = setdisklabel(lp, (struct disklabel *)data,
1001473eb467Sgmcgarry 		    (sc->sc_flags & RDF_WLABEL) ? 0 : sc->sc_dk.dk_openmask,
1002473eb467Sgmcgarry 		    (struct cpu_disklabel *)0);
1003473eb467Sgmcgarry 		if (error)
1004473eb467Sgmcgarry 			return (error);
1005473eb467Sgmcgarry 		flags = sc->sc_flags;
1006473eb467Sgmcgarry 		sc->sc_flags = RDF_ALIVE | RDF_WLABEL;
1007473eb467Sgmcgarry 		error = writedisklabel(RDLABELDEV(dev), rdstrategy, lp,
1008473eb467Sgmcgarry 		    (struct cpu_disklabel *)0);
1009473eb467Sgmcgarry 		sc->sc_flags = flags;
1010473eb467Sgmcgarry 		return (error);
1011473eb467Sgmcgarry 
1012473eb467Sgmcgarry 	case DIOCGDEFLABEL:
1013473eb467Sgmcgarry 		rdgetdefaultlabel(sc, (struct disklabel *)data);
1014473eb467Sgmcgarry 		return (0);
1015473eb467Sgmcgarry 	}
1016473eb467Sgmcgarry 	return (EINVAL);
1017473eb467Sgmcgarry }
1018473eb467Sgmcgarry 
1019473eb467Sgmcgarry void
rdgetdefaultlabel(struct rd_softc * sc,struct disklabel * lp)1020454af1c0Sdsl rdgetdefaultlabel(struct rd_softc *sc, struct disklabel *lp)
1021473eb467Sgmcgarry {
1022473eb467Sgmcgarry 	int type = sc->sc_type;
1023473eb467Sgmcgarry 
102453524e44Schristos 	memset((void *)lp, 0, sizeof(struct disklabel));
1025473eb467Sgmcgarry 
1026c182898bSchristos 	lp->d_type = DKTYPE_HPIB /* DKTYPE_GPIB */;
1027473eb467Sgmcgarry 	lp->d_secsize = DEV_BSIZE;
1028473eb467Sgmcgarry 	lp->d_nsectors = rdidentinfo[type].ri_nbpt;
1029473eb467Sgmcgarry 	lp->d_ntracks = rdidentinfo[type].ri_ntpc;
1030473eb467Sgmcgarry 	lp->d_ncylinders = rdidentinfo[type].ri_ncyl;
1031473eb467Sgmcgarry 	lp->d_secpercyl = lp->d_ntracks * lp->d_nsectors;
1032473eb467Sgmcgarry 	lp->d_secperunit = lp->d_ncylinders * lp->d_secpercyl;
1033473eb467Sgmcgarry 
1034473eb467Sgmcgarry 	strncpy(lp->d_typename, rdidentinfo[type].ri_desc, 16);
1035473eb467Sgmcgarry 	strncpy(lp->d_packname, "fictitious", 16);
1036473eb467Sgmcgarry 	lp->d_rpm = 3000;
1037473eb467Sgmcgarry 	lp->d_interleave = 1;
1038473eb467Sgmcgarry 	lp->d_flags = 0;
1039473eb467Sgmcgarry 
1040473eb467Sgmcgarry 	lp->d_partitions[RAW_PART].p_offset = 0;
1041473eb467Sgmcgarry 	lp->d_partitions[RAW_PART].p_size =
1042473eb467Sgmcgarry 	    lp->d_secperunit * (lp->d_secsize / DEV_BSIZE);
1043473eb467Sgmcgarry 	lp->d_partitions[RAW_PART].p_fstype = FS_UNUSED;
1044473eb467Sgmcgarry 	lp->d_npartitions = RAW_PART + 1;
1045473eb467Sgmcgarry 
1046473eb467Sgmcgarry 	lp->d_magic = DISKMAGIC;
1047473eb467Sgmcgarry 	lp->d_magic2 = DISKMAGIC;
1048473eb467Sgmcgarry 	lp->d_checksum = dkcksum(lp);
1049473eb467Sgmcgarry }
1050473eb467Sgmcgarry 
1051473eb467Sgmcgarry int
rdsize(dev_t dev)10523e484e61Scegger rdsize(dev_t dev)
1053473eb467Sgmcgarry {
1054473eb467Sgmcgarry 	struct rd_softc *sc;
1055473eb467Sgmcgarry 	int psize, didopen = 0;
1056473eb467Sgmcgarry 
10573e484e61Scegger 	sc = device_lookup_private(&rd_cd, RDUNIT(dev));
1058473eb467Sgmcgarry 	if (sc == NULL || (sc->sc_flags & RDF_ALIVE) == 0)
1059473eb467Sgmcgarry 		return (-1);
1060473eb467Sgmcgarry 
1061473eb467Sgmcgarry 	/*
1062473eb467Sgmcgarry 	 * We get called very early on (via swapconf)
1063473eb467Sgmcgarry 	 * without the device being open so we may need
1064473eb467Sgmcgarry 	 * to handle it here.
1065473eb467Sgmcgarry 	 */
1066473eb467Sgmcgarry 	if (sc->sc_dk.dk_openmask == 0) {
1067473eb467Sgmcgarry 		if (rdopen(dev, FREAD | FWRITE, S_IFBLK, NULL))
1068473eb467Sgmcgarry 			return (-1);
1069473eb467Sgmcgarry 		didopen = 1;
1070473eb467Sgmcgarry 	}
1071473eb467Sgmcgarry 	psize = sc->sc_dk.dk_label->d_partitions[RDPART(dev)].p_size *
1072473eb467Sgmcgarry 	    (sc->sc_dk.dk_label->d_secsize / DEV_BSIZE);
1073473eb467Sgmcgarry 	if (didopen)
1074473eb467Sgmcgarry 		(void) rdclose(dev, FREAD | FWRITE, S_IFBLK, NULL);
1075473eb467Sgmcgarry 	return (psize);
1076473eb467Sgmcgarry }
1077473eb467Sgmcgarry 
1078473eb467Sgmcgarry 
1079473eb467Sgmcgarry static int rddoingadump;	/* simple mutex */
1080473eb467Sgmcgarry 
1081473eb467Sgmcgarry /*
1082473eb467Sgmcgarry  * Non-interrupt driven, non-dma dump routine.
1083473eb467Sgmcgarry  */
1084473eb467Sgmcgarry int
rddump(dev_t dev,daddr_t blkno,void * va,size_t size)10853e484e61Scegger rddump(dev_t dev, daddr_t blkno, void *va, size_t size)
1086473eb467Sgmcgarry {
1087473eb467Sgmcgarry 	struct rd_softc *sc;
1088473eb467Sgmcgarry 	int sectorsize;		/* size of a disk sector */
1089473eb467Sgmcgarry 	int nsects;		/* number of sectors in partition */
1090473eb467Sgmcgarry 	int sectoff;		/* sector offset of partition */
1091473eb467Sgmcgarry 	int totwrt;		/* total number of sectors left to write */
1092473eb467Sgmcgarry 	int nwrt;		/* current number of sectors to write */
1093473eb467Sgmcgarry 	int slave;
1094473eb467Sgmcgarry 	struct disklabel *lp;
1095473eb467Sgmcgarry 	u_int8_t stat;
1096473eb467Sgmcgarry 
1097473eb467Sgmcgarry 	/* Check for recursive dump; if so, punt. */
1098473eb467Sgmcgarry 	if (rddoingadump)
1099473eb467Sgmcgarry 		return (EFAULT);
1100473eb467Sgmcgarry 	rddoingadump = 1;
1101473eb467Sgmcgarry 
11023e484e61Scegger 	sc = device_lookup_private(&rd_cd, RDUNIT(dev));
1103473eb467Sgmcgarry 	if (sc == NULL || (sc->sc_flags & RDF_ALIVE) == 0)
1104473eb467Sgmcgarry 		return (ENXIO);
1105473eb467Sgmcgarry 
1106473eb467Sgmcgarry 	DPRINTF(RDB_FOLLOW, ("rddump: sc=%p\n", sc));
1107473eb467Sgmcgarry 
1108473eb467Sgmcgarry 	slave = sc->sc_slave;
1109473eb467Sgmcgarry 
1110473eb467Sgmcgarry 	/*
1111473eb467Sgmcgarry 	 * Convert to disk sectors.  Request must be a multiple of size.
1112473eb467Sgmcgarry 	 */
1113473eb467Sgmcgarry 	lp = sc->sc_dk.dk_label;
1114473eb467Sgmcgarry 	sectorsize = lp->d_secsize;
1115473eb467Sgmcgarry 	if ((size % sectorsize) != 0)
1116473eb467Sgmcgarry 		return (EFAULT);
1117473eb467Sgmcgarry 	totwrt = size / sectorsize;
1118473eb467Sgmcgarry 	blkno = dbtob(blkno) / sectorsize;	/* blkno in DEV_BSIZE units */
1119473eb467Sgmcgarry 
1120473eb467Sgmcgarry 	nsects = lp->d_partitions[RDPART(dev)].p_size;
1121473eb467Sgmcgarry 	sectoff = lp->d_partitions[RDPART(dev)].p_offset;
1122473eb467Sgmcgarry 
1123473eb467Sgmcgarry 	/* Check transfer bounds against partition size. */
1124473eb467Sgmcgarry 	if ((blkno < 0) || (blkno + totwrt) > nsects)
1125473eb467Sgmcgarry 		return (EINVAL);
1126473eb467Sgmcgarry 
1127473eb467Sgmcgarry 	/* Offset block number to start of partition. */
1128473eb467Sgmcgarry 	blkno += sectoff;
1129473eb467Sgmcgarry 
1130473eb467Sgmcgarry 	while (totwrt > 0) {
1131473eb467Sgmcgarry 		nwrt = totwrt;		/* XXX */
1132473eb467Sgmcgarry #ifndef RD_DUMP_NOT_TRUSTED
1133473eb467Sgmcgarry 		/*
1134473eb467Sgmcgarry 		 * Fill out and send GPIB command.
1135473eb467Sgmcgarry 		 */
1136473eb467Sgmcgarry 		sc->sc_ioc.c_unit = CS80CMD_SUNIT(sc->sc_punit);
1137473eb467Sgmcgarry 		sc->sc_ioc.c_volume = CS80CMD_SVOL(0);
1138473eb467Sgmcgarry 		sc->sc_ioc.c_saddr = CS80CMD_SADDR;
1139473eb467Sgmcgarry 		sc->sc_ioc.c_hiaddr = 0;
1140473eb467Sgmcgarry 		sc->sc_ioc.c_addr = RDBTOS(blkno);
1141473eb467Sgmcgarry 		sc->sc_ioc.c_nop2 = CS80CMD_NOP;
1142473eb467Sgmcgarry 		sc->sc_ioc.c_slen = CS80CMD_SLEN;
1143473eb467Sgmcgarry 		sc->sc_ioc.c_len = nwrt * sectorsize;
1144473eb467Sgmcgarry 		sc->sc_ioc.c_cmd = CS80CMD_WRITE;
1145473eb467Sgmcgarry 		(void) gpibsend(sc->sc_ic, slave, CS80CMD_SCMD,
1146473eb467Sgmcgarry 		    &sc->sc_ioc.c_unit, sizeof(sc->sc_ioc)-3);
1147473eb467Sgmcgarry 		if (gpibswait(sc->sc_ic, slave))
1148473eb467Sgmcgarry 			return (EIO);
1149473eb467Sgmcgarry 		/*
1150473eb467Sgmcgarry 		 * Send the data.
1151473eb467Sgmcgarry 		 */
1152473eb467Sgmcgarry 		(void) gpibsend(sc->sc_ic, slave, CS80CMD_EXEC, va,
1153473eb467Sgmcgarry 		    nwrt * sectorsize);
1154473eb467Sgmcgarry 		(void) gpibswait(sc->sc_ic, slave);
1155473eb467Sgmcgarry 		(void) gpibrecv(sc->sc_ic, slave, CS80CMD_QSTAT, &stat, 1);
1156473eb467Sgmcgarry 		if (stat)
1157473eb467Sgmcgarry 			return (EIO);
1158473eb467Sgmcgarry #else /* RD_DUMP_NOT_TRUSTED */
1159473eb467Sgmcgarry 		/* Let's just talk about this first... */
1160cbab9cadSchs 		printf("%s: dump addr %p, blk %d\n", device_xname(sc->sc_dev),
1161473eb467Sgmcgarry 		    va, blkno);
1162473eb467Sgmcgarry 		delay(500 * 1000);	/* half a second */
1163473eb467Sgmcgarry #endif /* RD_DUMP_NOT_TRUSTED */
1164473eb467Sgmcgarry 
1165473eb467Sgmcgarry 		/* update block count */
1166473eb467Sgmcgarry 		totwrt -= nwrt;
1167473eb467Sgmcgarry 		blkno += nwrt;
1168d25ce32eStsutsui 		va = (char *)va + sectorsize * nwrt;
1169473eb467Sgmcgarry 	}
1170473eb467Sgmcgarry 	rddoingadump = 0;
1171473eb467Sgmcgarry 	return (0);
1172473eb467Sgmcgarry }
1173