1 /* $NetBSD: hp.c,v 1.46 2008/03/11 05:34:02 matt Exp $ */
3 * Copyright (c) 1996 Ludd, University of Lule}, Sweden.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. All advertising materials mentioning features or use of this software
15 * must display the following acknowledgement:
16 * This product includes software developed at Ludd, University of
17 * Lule}, Sweden and its contributors.
18 * 4. The name of the author may not be used to endorse or promote products
19 * derived from this software without specific prior written permission
21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
26 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
30 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34 * Simple device driver routine for massbuss disks.
36 * Fix support for Standard DEC BAD144 bad block forwarding.
37 * Be able to to handle soft/hard transfer errors.
38 * Handle non-data transfer interrupts.
39 * Autoconfiguration of disk drives 'on the fly'.
40 * Handle disk media changes.
41 * Dual-port operations should be supported.
44 #include <sys/cdefs.h>
45 __KERNEL_RCSID(0, "$NetBSD: hp.c,v 1.46 2008/03/11 05:34:02 matt Exp $");
47 #include <sys/param.h>
48 #include <sys/systm.h>
49 #include <sys/device.h>
50 #include <sys/disklabel.h>
56 #include <sys/ioccom.h>
57 #include <sys/fcntl.h>
58 #include <sys/syslog.h>
59 #include <sys/reboot.h>
61 #include <sys/event.h>
63 #include <machine/bus.h>
64 #include <machine/trap.h>
65 #include <machine/pte.h>
66 #include <machine/mtpr.h>
67 #include <machine/cpu.h>
69 #include <vax/mba/mbavar.h>
70 #include <vax/mba/mbareg.h>
71 #include <vax/mba/hpreg.h>
79 bus_space_tag_t sc_iot
;
80 bus_space_handle_t sc_ioh
;
81 struct mba_device sc_md
; /* Common struct used by mbaqueue. */
82 int sc_wlabel
; /* Disklabel area is writable */
85 int hpmatch(device_t
, cfdata_t
, void *);
86 void hpattach(device_t
, device_t
, void *);
87 void hpstart(struct mba_device
*);
88 int hpattn(struct mba_device
*);
89 enum xfer_action
hpfinish(struct mba_device
*, int, int *);
91 CFATTACH_DECL_NEW(hp
, sizeof(struct hp_softc
),
92 hpmatch
, hpattach
, NULL
, NULL
);
94 static dev_type_open(hpopen
);
95 static dev_type_close(hpclose
);
96 static dev_type_read(hpread
);
97 static dev_type_write(hpwrite
);
98 static dev_type_ioctl(hpioctl
);
99 static dev_type_strategy(hpstrategy
);
100 static dev_type_size(hppsize
);
102 const struct bdevsw hp_bdevsw
= {
105 .d_strategy
= hpstrategy
,
112 const struct cdevsw hp_cdevsw
= {
122 .d_kqfilter
= nokqfilter
,
126 #define HP_WCSR(reg, val) \
127 bus_space_write_4(sc->sc_iot, sc->sc_ioh, (reg), (val))
128 #define HP_RCSR(reg) \
129 bus_space_read_4(sc->sc_iot, sc->sc_ioh, (reg))
133 * Check if this is a disk drive; done by checking type from mbaattach.
136 hpmatch(device_t parent
, cfdata_t cf
, void *aux
)
138 struct mba_attach_args
* const ma
= aux
;
140 if (cf
->cf_loc
[MBACF_DRIVE
] != MBACF_DRIVE_DEFAULT
&&
141 cf
->cf_loc
[MBACF_DRIVE
] != ma
->ma_unit
)
144 if (ma
->ma_devtyp
!= MB_RP
)
151 * Disk drive found; fake a disklabel and try to read the real one.
152 * If the on-disk label can't be read; we lose.
155 hpattach(device_t parent
, device_t self
, void *aux
)
157 struct hp_softc
* const sc
= device_private(self
);
158 struct mba_softc
* const ms
= device_private(parent
);
159 struct mba_attach_args
* const ma
= aux
;
160 struct disklabel
*dl
;
164 sc
->sc_iot
= ma
->ma_iot
;
165 sc
->sc_ioh
= ma
->ma_ioh
;
168 * Init the common struct for both the adapter and its slaves.
170 bufq_alloc(&sc
->sc_md
.md_q
, "disksort", BUFQ_SORT_CYLINDER
);
171 sc
->sc_md
.md_softc
= sc
; /* Pointer to this softc */
172 sc
->sc_md
.md_mba
= ms
; /* Pointer to parent softc */
173 sc
->sc_md
.md_start
= hpstart
; /* Disk start routine */
174 sc
->sc_md
.md_attn
= hpattn
; /* Disk attention routine */
175 sc
->sc_md
.md_finish
= hpfinish
; /* Disk xfer finish routine */
177 ms
->sc_md
[ma
->ma_unit
] = &sc
->sc_md
; /* Per-unit backpointer */
180 * Init and attach the disk structure.
182 disk_init(&sc
->sc_disk
, device_xname(sc
->sc_dev
), NULL
);
183 disk_attach(&sc
->sc_disk
);
186 * Fake a disklabel to be able to read in the real label.
188 dl
= sc
->sc_disk
.dk_label
;
190 dl
->d_secsize
= DEV_BSIZE
;
193 dl
->d_secpercyl
= 32;
198 if ((msg
= readdisklabel(makedev(0, device_unit(self
) * 8), hpstrategy
,
201 printf(": %s, size = %d sectors\n", dl
->d_typename
, dl
->d_secperunit
);
206 hpstrategy(struct buf
*bp
)
210 struct disklabel
*lp
;
213 unit
= DISKUNIT(bp
->b_dev
);
214 sc
= device_lookup_private(&hp_cd
, unit
);
215 lp
= sc
->sc_disk
.dk_label
;
217 err
= bounds_check_with_label(&sc
->sc_disk
, bp
, sc
->sc_wlabel
);
222 bp
->b_blkno
+ lp
->d_partitions
[DISKPART(bp
->b_dev
)].p_offset
;
223 bp
->b_cylinder
= bp
->b_rawblkno
/ lp
->d_secpercyl
;
227 gp
= bufq_peek(sc
->sc_md
.md_q
);
228 bufq_put(sc
->sc_md
.md_q
, bp
);
230 mbaqueue(&sc
->sc_md
);
236 bp
->b_resid
= bp
->b_bcount
;
241 * Start transfer on given disk. Called from mbastart().
244 hpstart(struct mba_device
*md
)
246 struct hp_softc
* const sc
= md
->md_softc
;
247 struct disklabel
* const lp
= sc
->sc_disk
.dk_label
;
248 struct buf
*bp
= bufq_peek(md
->md_q
);
249 unsigned bn
, cn
, sn
, tn
;
252 * Collect statistics.
254 disk_busy(&sc
->sc_disk
);
255 iostat_seek(sc
->sc_disk
.dk_stats
);
259 cn
= bn
/ lp
->d_secpercyl
;
260 sn
= bn
% lp
->d_secpercyl
;
261 tn
= sn
/ lp
->d_nsectors
;
262 sn
= sn
% lp
->d_nsectors
;
267 HP_WCSR(HP_DA
, (tn
<< 8) | sn
);
268 if (bp
->b_flags
& B_READ
)
269 HP_WCSR(HP_CS1
, HPCS_READ
);
271 HP_WCSR(HP_CS1
, HPCS_WRITE
);
275 hpopen(dev_t dev
, int flag
, int fmt
, struct lwp
*l
)
278 int part
= DISKPART(dev
);
280 sc
= device_lookup_private(&hp_cd
, DISKUNIT(dev
));
284 if (part
>= sc
->sc_disk
.dk_label
->d_npartitions
)
289 sc
->sc_disk
.dk_copenmask
|= (1 << part
);
293 sc
->sc_disk
.dk_bopenmask
|= (1 << part
);
296 sc
->sc_disk
.dk_openmask
=
297 sc
->sc_disk
.dk_copenmask
| sc
->sc_disk
.dk_bopenmask
;
303 hpclose(dev_t dev
, int flag
, int fmt
, struct lwp
*l
)
305 struct hp_softc
* const sc
= device_lookup_private(&hp_cd
, DISKUNIT(dev
));
306 const int part
= DISKPART(dev
);
310 sc
->sc_disk
.dk_copenmask
&= ~(1 << part
);
314 sc
->sc_disk
.dk_bopenmask
&= ~(1 << part
);
317 sc
->sc_disk
.dk_openmask
=
318 sc
->sc_disk
.dk_copenmask
| sc
->sc_disk
.dk_bopenmask
;
324 hpioctl(dev_t dev
, u_long cmd
, void *addr
, int flag
, struct lwp
*l
)
326 struct hp_softc
* const sc
= device_lookup_private(&hp_cd
, DISKUNIT(dev
));
327 struct disklabel
* const lp
= sc
->sc_disk
.dk_label
;
332 *(struct disklabel
*)addr
= *lp
;
336 ((struct partinfo
*)addr
)->disklab
= lp
;
337 ((struct partinfo
*)addr
)->part
=
338 &lp
->d_partitions
[DISKPART(dev
)];
342 if ((flag
& FWRITE
) == 0)
345 return setdisklabel(lp
, (struct disklabel
*)addr
, 0, 0);
348 if ((flag
& FWRITE
) == 0)
352 error
= writedisklabel(dev
, hpstrategy
, lp
, 0);
357 if ((flag
& FWRITE
) == 0)
369 * Called when a transfer is finished. Check if transfer went OK,
370 * Return info about what-to-do-now.
373 hpfinish(struct mba_device
*md
, int mbasr
, int *attn
)
375 struct hp_softc
* const sc
= md
->md_softc
;
376 struct buf
*bp
= bufq_peek(md
->md_q
);
380 er1
= HP_RCSR(HP_ER1
);
381 er2
= HP_RCSR(HP_ER2
);
386 switch (ffs(er1
) - 1) {
391 case HPER1_DCK
: /* Corrected? data read. Just notice. */
392 bc
= bus_space_read_4(md
->md_mba
->sc_iot
,
393 md
->md_mba
->sc_ioh
, MBA_BC
);
395 diskerr(bp
, hp_cd
.cd_name
, "soft ecc", LOG_PRINTF
,
396 btodb(bp
->b_bcount
- byte
), sc
->sc_disk
.dk_label
);
397 er1
&= ~(1<<HPER1_DCK
);
401 aprint_error_dev(sc
->sc_dev
, "drive error: er1 %x er2 %x\n",
410 mbasr
&= ~(MBASR_DTBUSY
|MBASR_DTCMP
|MBASR_ATTN
);
412 aprint_error_dev(sc
->sc_dev
, "massbuss error: %x\n", mbasr
);
414 bufq_peek(md
->md_q
)->b_resid
= 0;
415 disk_unbusy(&sc
->sc_disk
, bufq_peek(md
->md_q
)->b_bcount
,
416 (bp
->b_flags
& B_READ
));
421 * Non-data transfer interrupt; like volume change.
424 hpattn(struct mba_device
*md
)
426 struct hp_softc
* const sc
= md
->md_softc
;
429 er1
= HP_RCSR(HP_ER1
);
430 er2
= HP_RCSR(HP_ER2
);
432 aprint_error_dev(sc
->sc_dev
, "Attention! er1 %x er2 %x\n", er1
, er2
);
440 struct hp_softc
* const sc
= device_lookup_private(&hp_cd
, DISKUNIT(dev
));
441 const int part
= DISKPART(dev
);
443 if (sc
== NULL
|| part
>= sc
->sc_disk
.dk_label
->d_npartitions
)
446 return sc
->sc_disk
.dk_label
->d_partitions
[part
].p_size
*
447 (sc
->sc_disk
.dk_label
->d_secsize
/ DEV_BSIZE
);
451 hpread(dev_t dev
, struct uio
*uio
, int ioflag
)
453 return (physio(hpstrategy
, NULL
, dev
, B_READ
, minphys
, uio
));
457 hpwrite(dev_t dev
, struct uio
*uio
, int ioflag
)
459 return (physio(hpstrategy
, NULL
, dev
, B_WRITE
, minphys
, uio
));