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