xref: /netbsd-src/sys/arch/vax/mba/hp.c (revision 6a6027692662ba623e7bf5274322989a7b5d1440)
1 /*	$NetBSD: hp.c,v 1.54 2017/05/22 17:13:09 ragge Exp $ */
2 /*
3  * Copyright (c) 1996 Ludd, University of Lule}, Sweden.
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
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  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25  */
26 
27 /*
28  * Simple device driver routine for massbuss disks.
29  * TODO:
30  *  Fix support for Standard DEC BAD144 bad block forwarding.
31  *  Be able to to handle soft/hard transfer errors.
32  *  Handle non-data transfer interrupts.
33  *  Autoconfiguration of disk drives 'on the fly'.
34  *  Handle disk media changes.
35  *  Dual-port operations should be supported.
36  */
37 
38 #include <sys/cdefs.h>
39 __KERNEL_RCSID(0, "$NetBSD: hp.c,v 1.54 2017/05/22 17:13:09 ragge Exp $");
40 
41 #include <sys/param.h>
42 #include <sys/systm.h>
43 #include <sys/bus.h>
44 #include <sys/cpu.h>
45 #include <sys/device.h>
46 #include <sys/disklabel.h>
47 #include <sys/disk.h>
48 #include <sys/dkio.h>
49 #include <sys/buf.h>
50 #include <sys/bufq.h>
51 #include <sys/stat.h>
52 #include <sys/ioccom.h>
53 #include <sys/fcntl.h>
54 #include <sys/conf.h>
55 #include <sys/event.h>
56 #include <sys/syslog.h>
57 
58 #include <vax/mba/mbavar.h>
59 #include <vax/mba/mbareg.h>
60 #include <vax/mba/hpreg.h>
61 
62 #include "ioconf.h"
63 #include "locators.h"
64 
65 struct hp_softc {
66 	device_t sc_dev;
67 	struct disk sc_disk;
68 	bus_space_tag_t sc_iot;
69 	bus_space_handle_t sc_ioh;
70 	struct mba_device sc_md;	/* Common struct used by mbaqueue. */
71 	int sc_wlabel;			/* Disklabel area is writable */
72 };
73 
74 int     hpmatch(device_t, cfdata_t, void *);
75 void    hpattach(device_t, device_t, void *);
76 void	hpstart(struct mba_device *);
77 int	hpattn(struct mba_device *);
78 enum	xfer_action hpfinish(struct mba_device *, int, int *);
79 
80 CFATTACH_DECL_NEW(hp, sizeof(struct hp_softc),
81     hpmatch, hpattach, NULL, NULL);
82 
83 static dev_type_open(hpopen);
84 static dev_type_close(hpclose);
85 static dev_type_read(hpread);
86 static dev_type_write(hpwrite);
87 static dev_type_ioctl(hpioctl);
88 static dev_type_strategy(hpstrategy);
89 static dev_type_size(hppsize);
90 
91 const struct bdevsw hp_bdevsw = {
92 	.d_open = hpopen,
93 	.d_close = hpclose,
94 	.d_strategy = hpstrategy,
95 	.d_ioctl = hpioctl,
96 	.d_dump = nulldump,
97 	.d_psize = hppsize,
98 	.d_discard = nodiscard,
99 	.d_flag = D_DISK
100 };
101 
102 const struct cdevsw hp_cdevsw = {
103 	.d_open = hpopen,
104 	.d_close = hpclose,
105 	.d_read = hpread,
106 	.d_write = hpwrite,
107 	.d_ioctl = hpioctl,
108 	.d_stop = nostop,
109 	.d_tty = notty,
110 	.d_poll = nopoll,
111 	.d_mmap = nommap,
112 	.d_kqfilter = nokqfilter,
113 	.d_discard = nodiscard,
114 	.d_flag = D_DISK
115 };
116 
117 #define HP_WCSR(reg, val) \
118 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, (reg), (val))
119 #define HP_RCSR(reg) \
120 	bus_space_read_4(sc->sc_iot, sc->sc_ioh, (reg))
121 
122 
123 /*
124  * Check if this is a disk drive; done by checking type from mbaattach.
125  */
126 int
hpmatch(device_t parent,cfdata_t cf,void * aux)127 hpmatch(device_t parent, cfdata_t cf, void *aux)
128 {
129 	struct mba_attach_args * const ma = aux;
130 
131 	if (cf->cf_loc[MBACF_DRIVE] != MBACF_DRIVE_DEFAULT &&
132 	    cf->cf_loc[MBACF_DRIVE] != ma->ma_unit)
133 		return 0;
134 
135 	if (ma->ma_devtyp != MB_RP)
136 		return 0;
137 
138 	return 1;
139 }
140 
141 /*
142  * Disk drive found; fake a disklabel and try to read the real one.
143  * If the on-disk label can't be read; we lose.
144  */
145 void
hpattach(device_t parent,device_t self,void * aux)146 hpattach(device_t parent, device_t self, void *aux)
147 {
148 	struct hp_softc * const sc = device_private(self);
149 	struct mba_softc * const ms = device_private(parent);
150 	struct mba_attach_args * const ma = aux;
151 	struct disklabel *dl;
152 	const char *msg;
153 
154 	sc->sc_dev = self;
155 	sc->sc_iot = ma->ma_iot;
156 	sc->sc_ioh = ma->ma_ioh;
157 
158 	/*
159 	 * Init the common struct for both the adapter and its slaves.
160 	 */
161 	bufq_alloc(&sc->sc_md.md_q, "disksort", BUFQ_SORT_CYLINDER);
162 	sc->sc_md.md_softc = sc;		/* Pointer to this softc */
163 	sc->sc_md.md_mba = ms;			/* Pointer to parent softc */
164 	sc->sc_md.md_start = hpstart;		/* Disk start routine */
165 	sc->sc_md.md_attn = hpattn;		/* Disk attention routine */
166 	sc->sc_md.md_finish = hpfinish;		/* Disk xfer finish routine */
167 
168 	ms->sc_md[ma->ma_unit] = &sc->sc_md;	/* Per-unit backpointer */
169 
170 	/*
171 	 * Init and attach the disk structure.
172 	 */
173 	disk_init(&sc->sc_disk, device_xname(sc->sc_dev), NULL);
174 	disk_attach(&sc->sc_disk);
175 
176 	/*
177 	 * Fake a disklabel to be able to read in the real label.
178 	 */
179 	dl = sc->sc_disk.dk_label;
180 
181 	dl->d_secsize = DEV_BSIZE;
182 	dl->d_ntracks = 1;
183 	dl->d_nsectors = 32;
184 	dl->d_secpercyl = 32;
185 
186 	/*
187 	 * Read in label.
188 	 */
189 	if ((msg = readdisklabel(makedev(0, device_unit(self) * 8), hpstrategy,
190 	    dl, NULL)) != NULL)
191 		printf(": %s", msg);
192 	printf(": %s, size = %d sectors\n", dl->d_typename, dl->d_secperunit);
193 }
194 
195 
196 void
hpstrategy(struct buf * bp)197 hpstrategy(struct buf *bp)
198 {
199 	struct hp_softc *sc;
200 	struct buf *gp;
201 	struct disklabel *lp;
202 	int unit, s, err;
203 
204 	unit = DISKUNIT(bp->b_dev);
205 	sc = device_lookup_private(&hp_cd, unit);
206 	lp = sc->sc_disk.dk_label;
207 
208 	err = bounds_check_with_label(&sc->sc_disk, bp, sc->sc_wlabel);
209 	if (err <= 0)
210 		goto done;
211 
212 	bp->b_rawblkno =
213 	    bp->b_blkno + lp->d_partitions[DISKPART(bp->b_dev)].p_offset;
214 	bp->b_cylinder = bp->b_rawblkno / lp->d_secpercyl;
215 
216 	s = splbio();
217 
218 	gp = bufq_peek(sc->sc_md.md_q);
219 	bufq_put(sc->sc_md.md_q, bp);
220 	if (gp == 0)
221 		mbaqueue(&sc->sc_md);
222 
223 	splx(s);
224 	return;
225 
226 done:
227 	bp->b_resid = bp->b_bcount;
228 	biodone(bp);
229 }
230 
231 /*
232  * Start transfer on given disk. Called from mbastart().
233  */
234 void
hpstart(struct mba_device * md)235 hpstart(struct mba_device *md)
236 {
237 	struct hp_softc * const sc = md->md_softc;
238 	struct disklabel * const lp = sc->sc_disk.dk_label;
239 	struct buf *bp = bufq_peek(md->md_q);
240 	unsigned bn, cn, sn, tn;
241 
242 	/*
243 	 * Collect statistics.
244 	 */
245 	disk_busy(&sc->sc_disk);
246 	iostat_seek(sc->sc_disk.dk_stats);
247 
248 	bn = bp->b_rawblkno;
249 	if (bn) {
250 		cn = bn / lp->d_secpercyl;
251 		sn = bn % lp->d_secpercyl;
252 		tn = sn / lp->d_nsectors;
253 		sn = sn % lp->d_nsectors;
254 	} else
255 		cn = sn = tn = 0;
256 
257 	HP_WCSR(HP_DC, cn);
258 	HP_WCSR(HP_DA, (tn << 8) | sn);
259 	if (bp->b_flags & B_READ)
260 		HP_WCSR(HP_CS1, HPCS_READ);
261 	else
262 		HP_WCSR(HP_CS1, HPCS_WRITE);
263 }
264 
265 int
hpopen(dev_t dev,int flag,int fmt,struct lwp * l)266 hpopen(dev_t dev, int flag, int fmt, struct lwp *l)
267 {
268 	struct hp_softc *sc;
269 	int	part = DISKPART(dev);
270 
271 	sc = device_lookup_private(&hp_cd, DISKUNIT(dev));
272 	if (sc == NULL)
273 		return ENXIO;
274 
275 	if (part >= sc->sc_disk.dk_label->d_npartitions)
276 		return ENXIO;
277 
278 	switch (fmt) {
279 	case S_IFCHR:
280 		sc->sc_disk.dk_copenmask |= (1 << part);
281 		break;
282 
283 	case S_IFBLK:
284 		sc->sc_disk.dk_bopenmask |= (1 << part);
285 		break;
286 	}
287 	sc->sc_disk.dk_openmask =
288 	    sc->sc_disk.dk_copenmask | sc->sc_disk.dk_bopenmask;
289 
290 	return 0;
291 }
292 
293 int
hpclose(dev_t dev,int flag,int fmt,struct lwp * l)294 hpclose(dev_t dev, int flag, int fmt, struct lwp *l)
295 {
296 	struct hp_softc * const sc = device_lookup_private(&hp_cd, DISKUNIT(dev));
297 	const int part = DISKPART(dev);
298 
299 	switch (fmt) {
300 	case S_IFCHR:
301 		sc->sc_disk.dk_copenmask &= ~(1 << part);
302 		break;
303 
304 	case S_IFBLK:
305 		sc->sc_disk.dk_bopenmask &= ~(1 << part);
306 		break;
307 	}
308 	sc->sc_disk.dk_openmask =
309 	    sc->sc_disk.dk_copenmask | sc->sc_disk.dk_bopenmask;
310 
311 	return 0;
312 }
313 
314 int
hpioctl(dev_t dev,u_long cmd,void * addr,int flag,struct lwp * l)315 hpioctl(dev_t dev, u_long cmd, void *addr, int flag, struct lwp *l)
316 {
317 	struct hp_softc * const sc = device_lookup_private(&hp_cd, DISKUNIT(dev));
318 	struct disklabel * const lp = sc->sc_disk.dk_label;
319 	int	error;
320 
321 	error = disk_ioctl(&sc->sc_disk, dev, cmd, addr, flag, l);
322 	if (error != EPASSTHROUGH)
323 		return error;
324 
325 	switch (cmd) {
326 	case DIOCSDINFO:
327 		if ((flag & FWRITE) == 0)
328 			return EBADF;
329 
330 		return setdisklabel(lp, (struct disklabel *)addr, 0, 0);
331 
332 	case DIOCWDINFO:
333 		if ((flag & FWRITE) == 0)
334 			error = EBADF;
335 		else {
336 			sc->sc_wlabel = 1;
337 			error = writedisklabel(dev, hpstrategy, lp, 0);
338 			sc->sc_wlabel = 0;
339 		}
340 		return error;
341 	case DIOCWLABEL:
342 		if ((flag & FWRITE) == 0)
343 			return EBADF;
344 		sc->sc_wlabel = 1;
345 		break;
346 
347 	default:
348 		return ENOTTY;
349 	}
350 	return 0;
351 }
352 
353 /*
354  * Called when a transfer is finished. Check if transfer went OK,
355  * Return info about what-to-do-now.
356  */
357 enum xfer_action
hpfinish(struct mba_device * md,int mbasr,int * attn)358 hpfinish(struct mba_device *md, int mbasr, int *attn)
359 {
360 	struct hp_softc * const sc = md->md_softc;
361 	struct buf *bp = bufq_peek(md->md_q);
362 	int er1, er2, bc;
363 	unsigned byte;
364 
365 	er1 = HP_RCSR(HP_ER1);
366 	er2 = HP_RCSR(HP_ER2);
367 	HP_WCSR(HP_ER1, 0);
368 	HP_WCSR(HP_ER2, 0);
369 
370 hper1:
371 	switch (ffs(er1) - 1) {
372 	case -1:
373 		HP_WCSR(HP_ER1, 0);
374 		goto hper2;
375 
376 	case HPER1_DCK: /* Corrected? data read. Just notice. */
377 		bc = bus_space_read_4(md->md_mba->sc_iot,
378 		    md->md_mba->sc_ioh, MBA_BC);
379 		byte = ~(bc >> 16);
380 		diskerr(bp, hp_cd.cd_name, "soft ecc", LOG_PRINTF,
381 		    btodb(bp->b_bcount - byte), sc->sc_disk.dk_label);
382 		er1 &= ~(1<<HPER1_DCK);
383 		break;
384 
385 	default:
386 		aprint_error_dev(sc->sc_dev, "drive error: er1 %x er2 %x\n",
387 		    er1, er2);
388 		HP_WCSR(HP_ER1, 0);
389 		HP_WCSR(HP_ER2, 0);
390 		goto hper2;
391 	}
392 	goto hper1;
393 
394 hper2:
395 	mbasr &= ~(MBASR_DTBUSY|MBASR_DTCMP|MBASR_ATTN);
396 	if (mbasr)
397 		aprint_error_dev(sc->sc_dev, "massbuss error: %x\n", mbasr);
398 
399 	bufq_peek(md->md_q)->b_resid = 0;
400 	disk_unbusy(&sc->sc_disk, bufq_peek(md->md_q)->b_bcount,
401 	    (bp->b_flags & B_READ));
402 	return XFER_FINISH;
403 }
404 
405 /*
406  * Non-data transfer interrupt; like volume change.
407  */
408 int
hpattn(struct mba_device * md)409 hpattn(struct mba_device *md)
410 {
411 	struct hp_softc * const sc = md->md_softc;
412 	int	er1, er2;
413 
414         er1 = HP_RCSR(HP_ER1);
415         er2 = HP_RCSR(HP_ER2);
416 
417 	aprint_error_dev(sc->sc_dev, "Attention! er1 %x er2 %x\n", er1, er2);
418 	return 0;
419 }
420 
421 
422 int
hppsize(dev_t dev)423 hppsize(dev_t dev)
424 {
425 	struct hp_softc * const sc = device_lookup_private(&hp_cd, DISKUNIT(dev));
426 	const int part = DISKPART(dev);
427 
428 	if (sc == NULL || part >= sc->sc_disk.dk_label->d_npartitions)
429 		return -1;
430 
431 	return sc->sc_disk.dk_label->d_partitions[part].p_size *
432 	    (sc->sc_disk.dk_label->d_secsize / DEV_BSIZE);
433 }
434 
435 int
hpread(dev_t dev,struct uio * uio,int ioflag)436 hpread(dev_t dev, struct uio *uio, int ioflag)
437 {
438 	return (physio(hpstrategy, NULL, dev, B_READ, minphys, uio));
439 }
440 
441 int
hpwrite(dev_t dev,struct uio * uio,int ioflag)442 hpwrite(dev_t dev, struct uio *uio, int ioflag)
443 {
444 	return (physio(hpstrategy, NULL, dev, B_WRITE, minphys, uio));
445 }
446