1 /* $NetBSD: rd.c,v 1.26 2009/05/12 14:21:58 cegger Exp $ */
4 * Copyright (c) 1996-2003 The NetBSD Foundation, Inc.
7 * This code is derived from software contributed to The NetBSD Foundation
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
33 * Copyright (c) 1982, 1990, 1993
34 * The Regents of the University of California. All rights reserved.
36 * This code is derived from software contributed to Berkeley by
37 * the Systems Programming Group of the University of Utah Computer
40 * Redistribution and use in source and binary forms, with or without
41 * modification, are permitted provided that the following conditions
43 * 1. Redistributions of source code must retain the above copyright
44 * notice, this list of conditions and the following disclaimer.
45 * 2. Redistributions in binary form must reproduce the above copyright
46 * notice, this list of conditions and the following disclaimer in the
47 * documentation and/or other materials provided with the distribution.
48 * 3. Neither the name of the University nor the names of its contributors
49 * may be used to endorse or promote products derived from this software
50 * without specific prior written permission.
52 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
53 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
54 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
55 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
56 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
57 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
58 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
59 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
60 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
61 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
64 * from: Utah $Hdr: rd.c 1.44 92/12/26$
66 * @(#)rd.c 8.2 (Berkeley) 5/19/94
70 * Copyright (c) 1988 University of Utah.
72 * This code is derived from software contributed to Berkeley by
73 * the Systems Programming Group of the University of Utah Computer
76 * Redistribution and use in source and binary forms, with or without
77 * modification, are permitted provided that the following conditions
79 * 1. Redistributions of source code must retain the above copyright
80 * notice, this list of conditions and the following disclaimer.
81 * 2. Redistributions in binary form must reproduce the above copyright
82 * notice, this list of conditions and the following disclaimer in the
83 * documentation and/or other materials provided with the distribution.
84 * 3. All advertising materials mentioning features or use of this software
85 * must display the following acknowledgement:
86 * This product includes software developed by the University of
87 * California, Berkeley and its contributors.
88 * 4. Neither the name of the University nor the names of its contributors
89 * may be used to endorse or promote products derived from this software
90 * without specific prior written permission.
92 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
93 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
94 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
95 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
96 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
97 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
98 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
99 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
100 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
101 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
104 * from: Utah $Hdr: rd.c 1.44 92/12/26$
106 * @(#)rd.c 8.2 (Berkeley) 5/19/94
110 * CS80/SS80 disk driver
113 #include <sys/cdefs.h>
114 __KERNEL_RCSID(0, "$NetBSD: rd.c,v 1.26 2009/05/12 14:21:58 cegger Exp $");
118 #include <sys/param.h>
119 #include <sys/systm.h>
121 #include <sys/bufq.h>
122 #include <sys/callout.h>
123 #include <sys/conf.h>
124 #include <sys/device.h>
125 #include <sys/disk.h>
126 #include <sys/disklabel.h>
127 #include <sys/endian.h>
128 #include <sys/fcntl.h>
129 #include <sys/ioctl.h>
130 #include <sys/proc.h>
131 #include <sys/stat.h>
137 #include <dev/gpib/gpibvar.h>
138 #include <dev/gpib/cs80busvar.h>
140 #include <dev/gpib/rdreg.h>
144 #define RDB_FOLLOW 0x01
145 #define RDB_STATUS 0x02
146 #define RDB_IDENT 0x04
148 #define RDB_ASYNC 0x10
149 #define RDB_ERROR 0x80
150 #define DPRINTF(mask, str) if (rddebug & (mask)) printf str
152 #define DPRINTF(mask, str) /* nothing */
156 struct device sc_dev
;
157 gpib_chipset_tag_t sc_ic
;
158 gpib_handle_t sc_hdl
;
162 int sc_slave
; /* GPIB slave */
163 int sc_punit
; /* physical unit on slave */
166 #define RDF_ALIVE 0x01
167 #define RDF_SEEK 0x02
168 #define RDF_SWAIT 0x04
169 #define RDF_OPENING 0x08
170 #define RDF_CLOSING 0x10
171 #define RDF_WANTED 0x20
172 #define RDF_WLABEL 0x40
177 struct rd_iocmd sc_ioc
;
178 struct bufq_state
*sc_tab
;
182 struct callout sc_restart_ch
;
185 rndsource_element_t rnd_source
;
189 #define RDUNIT(dev) DISKUNIT(dev)
190 #define RDPART(dev) DISKPART(dev)
191 #define RDMAKEDEV(maj, unit, part) MAKEDISKDEV(maj, unit, part)
192 #define RDLABELDEV(dev) (RDMAKEDEV(major(dev), RDUNIT(dev), RAW_PART))
195 #define RDWAITC 1 /* min time for timeout in seconds */
197 int rderrthresh
= RDRETRY
-1; /* when to start reporting errors */
200 * Misc. HW description, indexed by sc_type.
201 * Used for mapping 256-byte sectors for 512-byte sectors
203 const struct rdidentinfo
{
204 u_int16_t ri_hwid
; /* 2 byte HW id */
205 u_int16_t ri_maxunum
; /* maximum allowed unit number */
206 const char *ri_desc
; /* drive type description */
207 int ri_nbpt
; /* DEV_BSIZE blocks per track */
208 int ri_ntpc
; /* tracks per cylinder */
209 int ri_ncyl
; /* cylinders per unit */
210 int ri_nblocks
; /* DEV_BSIZE blocks on disk */
212 { RD7946AID
, 0, "7945A", NRD7945ABPT
,
213 NRD7945ATRK
, 968, 108416 },
215 { RD9134DID
, 1, "9134D", NRD9134DBPT
,
216 NRD9134DTRK
, 303, 29088 },
218 { RD9134LID
, 1, "9122S", NRD9122SBPT
,
219 NRD9122STRK
, 77, 1232 },
221 { RD7912PID
, 0, "7912P", NRD7912PBPT
,
222 NRD7912PTRK
, 572, 128128 },
224 { RD7914PID
, 0, "7914P", NRD7914PBPT
,
225 NRD7914PTRK
, 1152, 258048 },
227 { RD7958AID
, 0, "7958A", NRD7958ABPT
,
228 NRD7958ATRK
, 1013, 255276 },
230 { RD7957AID
, 0, "7957A", NRD7957ABPT
,
231 NRD7957ATRK
, 1036, 159544 },
233 { RD7933HID
, 0, "7933H", NRD7933HBPT
,
234 NRD7933HTRK
, 1321, 789958 },
236 { RD9134LID
, 1, "9134L", NRD9134LBPT
,
237 NRD9134LTRK
, 973, 77840 },
239 { RD7936HID
, 0, "7936H", NRD7936HBPT
,
240 NRD7936HTRK
, 698, 600978 },
242 { RD7937HID
, 0, "7937H", NRD7937HBPT
,
243 NRD7937HTRK
, 698, 1116102 },
245 { RD7914CTID
, 0, "7914CT", NRD7914PBPT
,
246 NRD7914PTRK
, 1152, 258048 },
248 { RD7946AID
, 0, "7946A", NRD7945ABPT
,
249 NRD7945ATRK
, 968, 108416 },
251 { RD9134LID
, 1, "9122D", NRD9122SBPT
,
252 NRD9122STRK
, 77, 1232 },
254 { RD7957BID
, 0, "7957B", NRD7957BBPT
,
255 NRD7957BTRK
, 1269, 159894 },
257 { RD7958BID
, 0, "7958B", NRD7958BBPT
,
258 NRD7958BTRK
, 786, 297108 },
260 { RD7959BID
, 0, "7959B", NRD7959BBPT
,
261 NRD7959BTRK
, 1572, 594216 },
263 { RD2200AID
, 0, "2200A", NRD2200ABPT
,
264 NRD2200ATRK
, 1449, 654948 },
266 { RD2203AID
, 0, "2203A", NRD2203ABPT
,
267 NRD2203ATRK
, 1449, 1309896 }
269 int numrdidentinfo
= sizeof(rdidentinfo
) / sizeof(rdidentinfo
[0]);
271 int rdlookup(int, int, int);
272 int rdgetinfo(struct rd_softc
*);
273 void rdrestart(void *);
274 struct buf
*rdfinish(struct rd_softc
*, struct buf
*);
276 void rdgetcompatlabel(struct rd_softc
*, struct disklabel
*);
277 void rdgetdefaultlabel(struct rd_softc
*, struct disklabel
*);
278 void rdrestart(void *);
279 void rdustart(struct rd_softc
*);
280 struct buf
*rdfinish(struct rd_softc
*, struct buf
*);
281 void rdcallback(void *, int);
282 void rdstart(struct rd_softc
*);
283 void rdintr(struct rd_softc
*);
284 int rderror(struct rd_softc
*);
286 int rdmatch(device_t
, cfdata_t
, void *);
287 void rdattach(device_t
, device_t
, void *);
289 CFATTACH_DECL(rd
, sizeof(struct rd_softc
),
290 rdmatch
, rdattach
, NULL
, NULL
);
293 dev_type_open(rdopen
);
294 dev_type_close(rdclose
);
295 dev_type_read(rdread
);
296 dev_type_write(rdwrite
);
297 dev_type_ioctl(rdioctl
);
298 dev_type_strategy(rdstrategy
);
299 dev_type_dump(rddump
);
300 dev_type_size(rdsize
);
302 const struct bdevsw rd_bdevsw
= {
303 rdopen
, rdclose
, rdstrategy
, rdioctl
, rddump
, rdsize
, D_DISK
306 const struct cdevsw rd_cdevsw
= {
307 rdopen
, rdclose
, rdread
, rdwrite
, rdioctl
,
308 nostop
, notty
, nopoll
, nommap
, nokqfilter
, D_DISK
311 extern struct cfdriver rd_cd
;
314 rdlookup(int id
, int slave
, int punit
)
318 for (i
= 0; i
< numrdidentinfo
; i
++) {
319 if (rdidentinfo
[i
].ri_hwid
== id
)
322 if (i
== numrdidentinfo
|| punit
> rdidentinfo
[i
].ri_maxunum
)
328 rdmatch(device_t parent
, cfdata_t match
, void *aux
)
330 struct cs80bus_attach_args
*ca
= aux
;
332 if (rdlookup(ca
->ca_id
, ca
->ca_slave
, ca
->ca_punit
) < 0)
338 rdattach(device_t parent
, device_t self
, void *aux
)
340 struct rd_softc
*sc
= device_private(self
);
341 struct cs80bus_attach_args
*ca
= aux
;
342 struct cs80_description csd
;
346 sc
->sc_ic
= ca
->ca_ic
;
347 sc
->sc_slave
= ca
->ca_slave
;
348 sc
->sc_punit
= ca
->ca_punit
;
350 if ((type
= rdlookup(ca
->ca_id
, ca
->ca_slave
, ca
->ca_punit
)) < 0)
353 if (cs80reset(parent
, sc
->sc_slave
, sc
->sc_punit
)) {
355 aprint_error_dev(&sc
->sc_dev
, "can't reset device\n");
359 if (cs80describe(parent
, sc
->sc_slave
, sc
->sc_punit
, &csd
)) {
361 aprint_error_dev(&sc
->sc_dev
, "didn't respond to describe command\n");
364 memset(name
, 0, sizeof(name
));
365 for (i
=0, n
=0; i
<3; i
++) {
366 name
[n
++] = (csd
.d_name
[i
] >> 4) + '0';
367 name
[n
++] = (csd
.d_name
[i
] & 0x0f) + '0';
371 if (rddebug
& RDB_IDENT
) {
372 printf("\n%s: name: ('%s')\n",
373 device_xname(&sc
->sc_dev
), name
);
374 printf(" iuw %x, maxxfr %d, ctype %d\n",
375 csd
.d_iuw
, csd
.d_cmaxxfr
, csd
.d_ctype
);
376 printf(" utype %d, bps %d, blkbuf %d, burst %d, blktime %d\n",
377 csd
.d_utype
, csd
.d_sectsize
,
378 csd
.d_blkbuf
, csd
.d_burstsize
, csd
.d_blocktime
);
379 printf(" avxfr %d, ort %d, atp %d, maxint %d, fv %x, rv %x\n",
380 csd
.d_uavexfr
, csd
.d_retry
, csd
.d_access
,
381 csd
.d_maxint
, csd
.d_fvbyte
, csd
.d_rvbyte
);
382 printf(" maxcyl/head/sect %d/%d/%d, maxvsect %d, inter %d\n",
383 csd
.d_maxcylhead
>> 8, csd
.d_maxcylhead
& 0xff,
384 csd
.d_maxsect
, csd
.d_maxvsectl
, csd
.d_interleave
);
385 printf("%s", device_xname(&sc
->sc_dev
));
390 * Take care of a couple of anomolies:
391 * 1. 7945A and 7946A both return same HW id
392 * 2. 9122S and 9134D both return same HW id
393 * 3. 9122D and 9134L both return same HW id
397 if (memcmp(name
, "079450", 6) == 0)
404 if (memcmp(name
, "091340", 6) == 0)
411 if (memcmp(name
, "091220", 6) == 0)
421 * XXX We use DEV_BSIZE instead of the sector size value pulled
422 * XXX off the driver because all of this code assumes 512 byte
425 printf(": %s\n", rdidentinfo
[type
].ri_desc
);
426 printf("%s: %d cylinders, %d heads, %d blocks, %d bytes/block\n",
427 device_xname(&sc
->sc_dev
), rdidentinfo
[type
].ri_ncyl
,
428 rdidentinfo
[type
].ri_ntpc
, rdidentinfo
[type
].ri_nblocks
,
431 bufq_alloc(&sc
->sc_tab
, "fcfs", 0);
434 * Initialize and attach the disk structure.
436 memset(&sc
->sc_dk
, 0, sizeof(sc
->sc_dk
));
437 disk_init(&sc
->sc_dk
, device_xname(&sc
->sc_dev
), NULL
);
438 disk_attach(&sc
->sc_dk
);
440 callout_init(&sc
->sc_restart_ch
, 0);
442 if (gpibregister(sc
->sc_ic
, sc
->sc_slave
, rdcallback
, sc
,
444 aprint_error_dev(&sc
->sc_dev
, "can't register callback\n");
448 sc
->sc_flags
= RDF_ALIVE
;
450 /* always report errors */
451 if (rddebug
& RDB_ERROR
)
456 * attach the device into the random source list
458 rnd_attach_source(&sc
->rnd_source
, device_xname(&sc
->sc_dev
),
464 * Read or construct a disklabel
467 rdgetinfo(struct rd_softc
*sc
)
469 struct disklabel
*lp
= sc
->sc_dk
.dk_label
;
470 struct partition
*pi
;
473 memset(sc
->sc_dk
.dk_cpulabel
, 0, sizeof(struct cpu_disklabel
));
475 rdgetdefaultlabel(sc
, lp
);
478 * Call the generic disklabel extraction routine
480 msg
= readdisklabel(RDMAKEDEV(0, device_unit(&sc
->sc_dev
), RAW_PART
),
481 rdstrategy
, lp
, NULL
);
485 pi
= lp
->d_partitions
;
486 printf("%s: WARNING: %s\n", device_xname(&sc
->sc_dev
), msg
);
488 pi
[RAW_PART
].p_size
= rdidentinfo
[sc
->sc_type
].ri_nblocks
;
489 lp
->d_npartitions
= RAW_PART
+1;
496 rdopen(dev_t dev
, int flags
, int mode
, struct lwp
*l
)
499 int error
, mask
, part
;
501 sc
= device_lookup_private(&rd_cd
, RDUNIT(dev
));
502 if (sc
== NULL
|| (sc
->sc_flags
& RDF_ALIVE
) ==0)
506 * Wait for any pending opens/closes to complete
508 while (sc
->sc_flags
& (RDF_OPENING
| RDF_CLOSING
))
509 (void) tsleep(sc
, PRIBIO
, "rdopen", 0);
512 * On first open, get label and partition info.
513 * We may block reading the label, so be careful
514 * to stop any other opens.
516 if (sc
->sc_dk
.dk_openmask
== 0) {
517 sc
->sc_flags
|= RDF_OPENING
;
518 error
= rdgetinfo(sc
);
519 sc
->sc_flags
&= ~RDF_OPENING
;
528 /* Check that the partition exists. */
529 if (part
!= RAW_PART
&& (part
> sc
->sc_dk
.dk_label
->d_npartitions
||
530 sc
->sc_dk
.dk_label
->d_partitions
[part
].p_fstype
== FS_UNUSED
))
533 /* Ensure only one open at a time. */
536 sc
->sc_dk
.dk_copenmask
|= mask
;
539 sc
->sc_dk
.dk_bopenmask
|= mask
;
542 sc
->sc_dk
.dk_openmask
=
543 sc
->sc_dk
.dk_copenmask
| sc
->sc_dk
.dk_bopenmask
;
549 rdclose(dev_t dev
, int flag
, int mode
, struct lwp
*l
)
555 sc
= device_lookup_private(&rd_cd
, RDUNIT(dev
));
561 mask
= 1 << RDPART(dev
);
563 dk
->dk_copenmask
&= ~mask
;
565 dk
->dk_bopenmask
&= ~mask
;
566 dk
->dk_openmask
= dk
->dk_copenmask
| dk
->dk_bopenmask
;
568 * On last close, we wait for all activity to cease since
569 * the label/parition info will become invalid. Since we
570 * might sleep, we must block any opens while we are here.
571 * Note we don't have to about other closes since we know
572 * we are the last one.
574 if (dk
->dk_openmask
== 0) {
575 sc
->sc_flags
|= RDF_CLOSING
;
577 while (sc
->sc_active
) {
578 sc
->sc_flags
|= RDF_WANTED
;
579 (void) tsleep(&sc
->sc_tab
, PRIBIO
, "rdclose", 0);
582 sc
->sc_flags
&= ~(RDF_CLOSING
| RDF_WLABEL
);
589 rdstrategy(struct buf
*bp
)
592 struct partition
*pinfo
;
597 sc
= device_lookup_private(&rd_cd
, RDUNIT(bp
->b_dev
));
600 ("rdstrategy(%p): dev %" PRIx64
", bn %" PRId64
", bcount %d, %c\n",
601 bp
, bp
->b_dev
, bp
->b_blkno
, bp
->b_bcount
,
602 (bp
->b_flags
& B_READ
) ? 'R' : 'W'));
605 sz
= howmany(bp
->b_bcount
, DEV_BSIZE
);
606 pinfo
= &sc
->sc_dk
.dk_label
->d_partitions
[RDPART(bp
->b_dev
)];
608 /* Don't perform partition translation on RAW_PART. */
609 offset
= (RDPART(bp
->b_dev
) == RAW_PART
) ? 0 : pinfo
->p_offset
;
611 if (RDPART(bp
->b_dev
) != RAW_PART
) {
613 * XXX This block of code belongs in
614 * XXX bounds_check_with_label()
617 if (bn
< 0 || bn
+ sz
> pinfo
->p_size
) {
618 sz
= pinfo
->p_size
- bn
;
620 bp
->b_resid
= bp
->b_bcount
;
624 bp
->b_error
= EINVAL
;
627 bp
->b_bcount
= dbtob(sz
);
630 * Check for write to write protected label
632 if (bn
+ offset
<= LABELSECTOR
&&
634 bn
+ offset
+ sz
> LABELSECTOR
&&
636 !(bp
->b_flags
& B_READ
) && !(sc
->sc_flags
& RDF_WLABEL
)) {
641 bp
->b_rawblkno
= bn
+ offset
;
643 bufq_put(sc
->sc_tab
, bp
);
644 if (sc
->sc_active
== 0) {
655 * Called from timeout() when handling maintenance releases
656 * callout from timeouts
662 rdustart((struct rd_softc
*)arg
);
667 /* called by rdstrategy() to start a block transfer */
668 /* called by rdrestart() when handingly timeouts */
669 /* called by rdintr() */
671 rdustart(struct rd_softc
*sc
)
675 bp
= bufq_peek(sc
->sc_tab
);
676 sc
->sc_addr
= bp
->b_data
;
677 sc
->sc_resid
= bp
->b_bcount
;
678 if (gpibrequest(sc
->sc_ic
, sc
->sc_hdl
))
683 rdfinish(struct rd_softc
*sc
, struct buf
*bp
)
687 (void)bufq_get(sc
->sc_tab
);
690 gpibrelease(sc
->sc_ic
, sc
->sc_hdl
);
691 if ((bp
= bufq_peek(sc
->sc_tab
)) != NULL
)
694 if (sc
->sc_flags
& RDF_WANTED
) {
695 sc
->sc_flags
&= ~RDF_WANTED
;
696 wakeup((void *)&sc
->sc_tab
);
702 rdcallback(void *v
, int action
)
704 struct rd_softc
*sc
= v
;
706 DPRINTF(RDB_FOLLOW
, ("rdcallback: v=%p, action=%d\n", v
, action
));
717 DPRINTF(RDB_ERROR
, ("rdcallback: unknown action %d\n",
725 /* called from rdustart() to start a transfer */
726 /* called from gpib interface as the initiator */
728 rdstart(struct rd_softc
*sc
)
730 struct buf
*bp
= bufq_peek(sc
->sc_tab
);
731 int part
, slave
, punit
;
733 slave
= sc
->sc_slave
;
734 punit
= sc
->sc_punit
;
736 DPRINTF(RDB_FOLLOW
, ("rdstart(%s): bp %p, %c\n",
737 device_xname(&sc
->sc_dev
), bp
, (bp
->b_flags
& B_READ
) ? 'R' : 'W'));
741 part
= RDPART(bp
->b_dev
);
742 sc
->sc_flags
|= RDF_SEEK
;
743 sc
->sc_ioc
.c_unit
= CS80CMD_SUNIT(punit
);
744 sc
->sc_ioc
.c_volume
= CS80CMD_SVOL(0);
745 sc
->sc_ioc
.c_saddr
= CS80CMD_SADDR
;
746 sc
->sc_ioc
.c_hiaddr
= htobe16(0);
747 sc
->sc_ioc
.c_addr
= htobe32(RDBTOS(bp
->b_rawblkno
));
748 sc
->sc_ioc
.c_nop2
= CS80CMD_NOP
;
749 sc
->sc_ioc
.c_slen
= CS80CMD_SLEN
;
750 sc
->sc_ioc
.c_len
= htobe32(sc
->sc_resid
);
751 sc
->sc_ioc
.c_cmd
= bp
->b_flags
& B_READ
? CS80CMD_READ
: CS80CMD_WRITE
;
753 if (gpibsend(sc
->sc_ic
, slave
, CS80CMD_SCMD
, &sc
->sc_ioc
.c_unit
,
754 sizeof(sc
->sc_ioc
)-1) == sizeof(sc
->sc_ioc
)-1) {
755 /* Instrumentation. */
756 disk_busy(&sc
->sc_dk
);
757 iostat_seek(sc
->sc_dk
.dk_stats
);
758 gpibawait(sc
->sc_ic
);
762 * Experience has shown that the gpibwait in this gpibsend will
763 * occasionally timeout. It appears to occur mostly on old 7914
764 * drives with full maintenance tracks. We should probably
765 * integrate this with the backoff code in rderror.
769 ("rdstart: cmd %x adr %ul blk %" PRId64
" len %d ecnt %d\n",
770 sc
->sc_ioc
.c_cmd
, sc
->sc_ioc
.c_addr
, bp
->b_blkno
, sc
->sc_resid
,
773 sc
->sc_flags
&= ~RDF_SEEK
;
774 cs80reset(device_parent(&sc
->sc_dev
), slave
, punit
);
775 if (sc
->sc_errcnt
++ < RDRETRY
)
777 printf("%s: rdstart err: cmd 0x%x sect %uld blk %" PRId64
" len %d\n",
778 device_xname(&sc
->sc_dev
), sc
->sc_ioc
.c_cmd
, sc
->sc_ioc
.c_addr
,
779 bp
->b_blkno
, sc
->sc_resid
);
781 bp
= rdfinish(sc
, bp
);
783 sc
->sc_addr
= bp
->b_data
;
784 sc
->sc_resid
= bp
->b_bcount
;
785 if (gpibrequest(sc
->sc_ic
, sc
->sc_hdl
))
791 rdintr(struct rd_softc
*sc
)
794 u_int8_t stat
= 13; /* in case gpibrecv fails */
795 int rv
, dir
, restart
, slave
;
797 slave
= sc
->sc_slave
;
798 bp
= bufq_peek(sc
->sc_tab
);
800 DPRINTF(RDB_FOLLOW
, ("rdintr(%s): bp %p, %c, flags %x\n",
801 device_xname(&sc
->sc_dev
), bp
, (bp
->b_flags
& B_READ
) ? 'R' : 'W',
804 disk_unbusy(&sc
->sc_dk
, (bp
->b_bcount
- bp
->b_resid
),
805 (bp
->b_flags
& B_READ
));
807 if (sc
->sc_flags
& RDF_SEEK
) {
808 sc
->sc_flags
&= ~RDF_SEEK
;
809 dir
= (bp
->b_flags
& B_READ
? GPIB_READ
: GPIB_WRITE
);
810 gpibxfer(sc
->sc_ic
, slave
, CS80CMD_EXEC
, sc
->sc_addr
,
811 sc
->sc_resid
, dir
, dir
== GPIB_READ
);
812 disk_busy(&sc
->sc_dk
);
815 if ((sc
->sc_flags
& RDF_SWAIT
) == 0) {
816 if (gpibpptest(sc
->sc_ic
, slave
) == 0) {
817 /* Instrumentation. */
818 disk_busy(&sc
->sc_dk
);
819 sc
->sc_flags
|= RDF_SWAIT
;
820 gpibawait(sc
->sc_ic
);
824 sc
->sc_flags
&= ~RDF_SWAIT
;
825 rv
= gpibrecv(sc
->sc_ic
, slave
, CS80CMD_QSTAT
, &stat
, 1);
826 if (rv
!= 1 || stat
) {
828 ("rdintr: receive failed (rv=%d) or bad stat %d\n", rv
,
830 restart
= rderror(sc
);
831 if (sc
->sc_errcnt
++ < RDRETRY
) {
838 if (rdfinish(sc
, bp
) != NULL
)
841 rnd_add_uint32(&sc
->rnd_source
, bp
->b_blkno
);
847 * Returns 1 if request should be restarted,
848 * 0 if we should just quietly give up.
851 rderror(struct rd_softc
*sc
)
853 struct cs80_stat css
;
857 DPRINTF(RDB_FOLLOW
, ("rderror: sc=%p\n", sc
));
859 if (cs80status(device_parent(&sc
->sc_dev
), sc
->sc_slave
,
860 sc
->sc_punit
, &css
)) {
861 cs80reset(device_parent(&sc
->sc_dev
), sc
->sc_slave
,
866 if (rddebug
& RDB_ERROR
) { /* status info */
867 printf("\n volume: %d, unit: %d\n",
868 (css
.c_vu
>>4)&0xF, css
.c_vu
&0xF);
869 printf(" reject 0x%x\n", css
.c_ref
);
870 printf(" fault 0x%x\n", css
.c_fef
);
871 printf(" access 0x%x\n", css
.c_aef
);
872 printf(" info 0x%x\n", css
.c_ief
);
873 printf(" block, P1-P10: ");
874 printf("0x%x", *(u_int32_t
*)&css
.c_raw
[0]);
875 printf("0x%x", *(u_int32_t
*)&css
.c_raw
[4]);
876 printf("0x%x\n", *(u_int16_t
*)&css
.c_raw
[8]);
879 if (css
.c_fef
& FEF_REXMT
)
881 if (css
.c_fef
& FEF_PF
) {
882 cs80reset(device_parent(&sc
->sc_dev
), sc
->sc_slave
,
887 * Unit requests release for internal maintenance.
888 * We just delay awhile and try again later. Use expontially
889 * increasing backoff ala ethernet drivers since we don't really
890 * know how long the maintenance will take. With RDWAITC and
891 * RDRETRY as defined, the range is 1 to 32 seconds.
893 if (css
.c_fef
& FEF_IMR
) {
895 int rdtimo
= RDWAITC
<< sc
->sc_errcnt
;
897 ("%s: internal maintenance, %d-second timeout\n",
898 device_xname(&sc
->sc_dev
), rdtimo
));
899 gpibrelease(sc
->sc_ic
, sc
->sc_hdl
);
900 callout_reset(&sc
->sc_restart_ch
, rdtimo
* hz
, rdrestart
, sc
);
904 * Only report error if we have reached the error reporting
905 * threshhold. By default, this will only report after the
906 * retry limit has been exceeded.
908 if (sc
->sc_errcnt
< rderrthresh
)
912 * First conjure up the block number at which the error occurred.
914 bp
= bufq_peek(sc
->sc_tab
);
915 pbn
= sc
->sc_dk
.dk_label
->d_partitions
[RDPART(bp
->b_dev
)].p_offset
;
916 if ((css
.c_fef
& FEF_CU
) || (css
.c_fef
& FEF_DR
) ||
917 (css
.c_ief
& IEF_RRMASK
)) {
919 * Not all errors report a block number, just use b_blkno.
921 hwbn
= RDBTOS(pbn
+ bp
->b_blkno
);
925 pbn
= RDSTOB(hwbn
) - pbn
;
928 if (rddebug
& RDB_ERROR
) { /* status info */
929 printf("\n volume: %d, unit: %d\n",
930 (css
.c_vu
>>4)&0xF, css
.c_vu
&0xF);
931 printf(" reject 0x%x\n", css
.c_ref
);
932 printf(" fault 0x%x\n", css
.c_fef
);
933 printf(" access 0x%x\n", css
.c_aef
);
934 printf(" info 0x%x\n", css
.c_ief
);
935 printf(" block, P1-P10: ");
936 printf(" block: %" PRId64
", P1-P10: ", hwbn
);
937 printf("0x%x", *(u_int32_t
*)&css
.c_raw
[0]);
938 printf("0x%x", *(u_int32_t
*)&css
.c_raw
[4]);
939 printf("0x%x\n", *(u_int16_t
*)&css
.c_raw
[8]);
943 if (rddebug
& RDB_ERROR
) { /* command */
945 printf("0x%x", *(u_int32_t
*)&sc
->sc_ioc
.c_pad
);
946 printf("0x%x", *(u_int16_t
*)&sc
->sc_ioc
.c_hiaddr
);
947 printf("0x%x", *(u_int32_t
*)&sc
->sc_ioc
.c_addr
);
948 printf("0x%x", *(u_int16_t
*)&sc
->sc_ioc
.c_nop2
);
949 printf("0x%x", *(u_int32_t
*)&sc
->sc_ioc
.c_len
);
950 printf("0x%x\n", *(u_int16_t
*)&sc
->sc_ioc
.c_cmd
);
955 * Now output a generic message suitable for badsect.
956 * Note that we don't use harderr because it just prints
957 * out b_blkno which is just the beginning block number
958 * of the transfer, not necessary where the error occurred.
960 printf("%s%c: hard error, sector number %" PRId64
"\n",
961 device_xname(&sc
->sc_dev
), 'a'+RDPART(bp
->b_dev
), pbn
);
963 * Now report the status as returned by the hardware with
964 * attempt at interpretation.
966 printf("%s %s error:", device_xname(&sc
->sc_dev
),
967 (bp
->b_flags
& B_READ
) ? "read" : "write");
968 printf(" unit %d, volume %d R0x%x F0x%x A0x%x I0x%x\n",
969 css
.c_vu
&0xF, (css
.c_vu
>>4)&0xF,
970 css
.c_ref
, css
.c_fef
, css
.c_aef
, css
.c_ief
);
972 printf("0x%x ", *(u_int32_t
*)&css
.c_raw
[0]);
973 printf("0x%x ", *(u_int32_t
*)&css
.c_raw
[4]);
974 printf("0x%x\n", *(u_int16_t
*)&css
.c_raw
[8]);
980 rdread(dev_t dev
, struct uio
*uio
, int flags
)
983 return (physio(rdstrategy
, NULL
, dev
, B_READ
, minphys
, uio
));
987 rdwrite(dev_t dev
, struct uio
*uio
, int flags
)
990 return (physio(rdstrategy
, NULL
, dev
, B_WRITE
, minphys
, uio
));
994 rdioctl(dev_t dev
, u_long cmd
, void *data
, int flag
, struct lwp
*l
)
997 struct disklabel
*lp
;
1000 sc
= device_lookup_private(&rd_cd
, RDUNIT(dev
));
1003 lp
= sc
->sc_dk
.dk_label
;
1005 DPRINTF(RDB_FOLLOW
, ("rdioctl: sc=%p\n", sc
));
1009 *(struct disklabel
*)data
= *lp
;
1013 ((struct partinfo
*)data
)->disklab
= lp
;
1014 ((struct partinfo
*)data
)->part
=
1015 &lp
->d_partitions
[RDPART(dev
)];
1019 if ((flag
& FWRITE
) == 0)
1022 sc
->sc_flags
|= RDF_WLABEL
;
1024 sc
->sc_flags
&= ~RDF_WLABEL
;
1028 if ((flag
& FWRITE
) == 0)
1030 return (setdisklabel(lp
, (struct disklabel
*)data
,
1031 (sc
->sc_flags
& RDF_WLABEL
) ? 0 : sc
->sc_dk
.dk_openmask
,
1032 (struct cpu_disklabel
*)0));
1035 if ((flag
& FWRITE
) == 0)
1037 error
= setdisklabel(lp
, (struct disklabel
*)data
,
1038 (sc
->sc_flags
& RDF_WLABEL
) ? 0 : sc
->sc_dk
.dk_openmask
,
1039 (struct cpu_disklabel
*)0);
1042 flags
= sc
->sc_flags
;
1043 sc
->sc_flags
= RDF_ALIVE
| RDF_WLABEL
;
1044 error
= writedisklabel(RDLABELDEV(dev
), rdstrategy
, lp
,
1045 (struct cpu_disklabel
*)0);
1046 sc
->sc_flags
= flags
;
1050 rdgetdefaultlabel(sc
, (struct disklabel
*)data
);
1057 rdgetdefaultlabel(struct rd_softc
*sc
, struct disklabel
*lp
)
1059 int type
= sc
->sc_type
;
1061 memset((void *)lp
, 0, sizeof(struct disklabel
));
1063 lp
->d_type
= DTYPE_HPIB
/* DTYPE_GPIB */;
1064 lp
->d_secsize
= DEV_BSIZE
;
1065 lp
->d_nsectors
= rdidentinfo
[type
].ri_nbpt
;
1066 lp
->d_ntracks
= rdidentinfo
[type
].ri_ntpc
;
1067 lp
->d_ncylinders
= rdidentinfo
[type
].ri_ncyl
;
1068 lp
->d_secpercyl
= lp
->d_ntracks
* lp
->d_nsectors
;
1069 lp
->d_secperunit
= lp
->d_ncylinders
* lp
->d_secpercyl
;
1071 strncpy(lp
->d_typename
, rdidentinfo
[type
].ri_desc
, 16);
1072 strncpy(lp
->d_packname
, "fictitious", 16);
1074 lp
->d_interleave
= 1;
1077 lp
->d_partitions
[RAW_PART
].p_offset
= 0;
1078 lp
->d_partitions
[RAW_PART
].p_size
=
1079 lp
->d_secperunit
* (lp
->d_secsize
/ DEV_BSIZE
);
1080 lp
->d_partitions
[RAW_PART
].p_fstype
= FS_UNUSED
;
1081 lp
->d_npartitions
= RAW_PART
+ 1;
1083 lp
->d_magic
= DISKMAGIC
;
1084 lp
->d_magic2
= DISKMAGIC
;
1085 lp
->d_checksum
= dkcksum(lp
);
1091 struct rd_softc
*sc
;
1092 int psize
, didopen
= 0;
1094 sc
= device_lookup_private(&rd_cd
, RDUNIT(dev
));
1095 if (sc
== NULL
|| (sc
->sc_flags
& RDF_ALIVE
) == 0)
1099 * We get called very early on (via swapconf)
1100 * without the device being open so we may need
1101 * to handle it here.
1103 if (sc
->sc_dk
.dk_openmask
== 0) {
1104 if (rdopen(dev
, FREAD
| FWRITE
, S_IFBLK
, NULL
))
1108 psize
= sc
->sc_dk
.dk_label
->d_partitions
[RDPART(dev
)].p_size
*
1109 (sc
->sc_dk
.dk_label
->d_secsize
/ DEV_BSIZE
);
1111 (void) rdclose(dev
, FREAD
| FWRITE
, S_IFBLK
, NULL
);
1116 static int rddoingadump
; /* simple mutex */
1119 * Non-interrupt driven, non-dma dump routine.
1122 rddump(dev_t dev
, daddr_t blkno
, void *va
, size_t size
)
1124 struct rd_softc
*sc
;
1125 int sectorsize
; /* size of a disk sector */
1126 int nsects
; /* number of sectors in partition */
1127 int sectoff
; /* sector offset of partition */
1128 int totwrt
; /* total number of sectors left to write */
1129 int nwrt
; /* current number of sectors to write */
1131 struct disklabel
*lp
;
1134 /* Check for recursive dump; if so, punt. */
1139 sc
= device_lookup_private(&rd_cd
, RDUNIT(dev
));
1140 if (sc
== NULL
|| (sc
->sc_flags
& RDF_ALIVE
) == 0)
1143 DPRINTF(RDB_FOLLOW
, ("rddump: sc=%p\n", sc
));
1145 slave
= sc
->sc_slave
;
1148 * Convert to disk sectors. Request must be a multiple of size.
1150 lp
= sc
->sc_dk
.dk_label
;
1151 sectorsize
= lp
->d_secsize
;
1152 if ((size
% sectorsize
) != 0)
1154 totwrt
= size
/ sectorsize
;
1155 blkno
= dbtob(blkno
) / sectorsize
; /* blkno in DEV_BSIZE units */
1157 nsects
= lp
->d_partitions
[RDPART(dev
)].p_size
;
1158 sectoff
= lp
->d_partitions
[RDPART(dev
)].p_offset
;
1160 /* Check transfer bounds against partition size. */
1161 if ((blkno
< 0) || (blkno
+ totwrt
) > nsects
)
1164 /* Offset block number to start of partition. */
1167 while (totwrt
> 0) {
1168 nwrt
= totwrt
; /* XXX */
1169 #ifndef RD_DUMP_NOT_TRUSTED
1171 * Fill out and send GPIB command.
1173 sc
->sc_ioc
.c_unit
= CS80CMD_SUNIT(sc
->sc_punit
);
1174 sc
->sc_ioc
.c_volume
= CS80CMD_SVOL(0);
1175 sc
->sc_ioc
.c_saddr
= CS80CMD_SADDR
;
1176 sc
->sc_ioc
.c_hiaddr
= 0;
1177 sc
->sc_ioc
.c_addr
= RDBTOS(blkno
);
1178 sc
->sc_ioc
.c_nop2
= CS80CMD_NOP
;
1179 sc
->sc_ioc
.c_slen
= CS80CMD_SLEN
;
1180 sc
->sc_ioc
.c_len
= nwrt
* sectorsize
;
1181 sc
->sc_ioc
.c_cmd
= CS80CMD_WRITE
;
1182 (void) gpibsend(sc
->sc_ic
, slave
, CS80CMD_SCMD
,
1183 &sc
->sc_ioc
.c_unit
, sizeof(sc
->sc_ioc
)-3);
1184 if (gpibswait(sc
->sc_ic
, slave
))
1189 (void) gpibsend(sc
->sc_ic
, slave
, CS80CMD_EXEC
, va
,
1191 (void) gpibswait(sc
->sc_ic
, slave
);
1192 (void) gpibrecv(sc
->sc_ic
, slave
, CS80CMD_QSTAT
, &stat
, 1);
1195 #else /* RD_DUMP_NOT_TRUSTED */
1196 /* Let's just talk about this first... */
1197 printf("%s: dump addr %p, blk %d\n", device_xname(&sc
->sc_dev
),
1199 delay(500 * 1000); /* half a second */
1200 #endif /* RD_DUMP_NOT_TRUSTED */
1202 /* update block count */
1205 va
= (char *)va
+ sectorsize
* nwrt
;