xref: /netbsd-src/sys/dev/mscp/mscp_disk.c (revision 3b01aba77a7a698587faaae455bbfe740923c1f5)
1 /*	$NetBSD: mscp_disk.c,v 1.29 2001/04/12 20:13:26 thorpej Exp $	*/
2 /*
3  * Copyright (c) 1996 Ludd, University of Lule}, Sweden.
4  * Copyright (c) 1988 Regents of the University of California.
5  * All rights reserved.
6  *
7  * This code is derived from software contributed to Berkeley by
8  * Chris Torek.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
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.
18  * 3. All advertising materials mentioning features or use of this software
19  *    must display the following acknowledgement:
20  *	This product includes software developed by the University of
21  *	California, Berkeley and its contributors.
22  * 4. Neither the name of the University nor the names of its contributors
23  *    may be used to endorse or promote products derived from this software
24  *    without specific prior written permission.
25  *
26  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
27  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
30  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36  * SUCH DAMAGE.
37  *
38  *	@(#)uda.c	7.32 (Berkeley) 2/13/91
39  */
40 
41 /*
42  * RA disk device driver
43  * RX MSCP floppy disk device driver
44  */
45 
46 /*
47  * TODO
48  *	write bad block forwarding code
49  */
50 
51 #include <sys/param.h>
52 #include <sys/buf.h>
53 #include <sys/device.h>
54 #include <sys/disk.h>
55 #include <sys/disklabel.h>
56 #include <sys/ioctl.h>
57 #include <sys/stat.h>
58 #include <sys/fcntl.h>
59 #include <sys/reboot.h>
60 #include <sys/proc.h>
61 #include <sys/systm.h>
62 
63 #include <ufs/ufs/dinode.h>
64 #include <ufs/ffs/fs.h>
65 
66 #include <machine/bus.h>
67 #include <machine/cpu.h>
68 
69 #include <dev/mscp/mscp.h>
70 #include <dev/mscp/mscpreg.h>
71 #include <dev/mscp/mscpvar.h>
72 
73 #include "locators.h"
74 #include "ioconf.h"
75 #include "ra.h"
76 
77 #define RAMAJOR 9	/* RA major device number XXX */
78 
79 /*
80  * Drive status, per drive
81  */
82 struct ra_softc {
83 	struct	device ra_dev;	/* Autoconf struct */
84 	struct	disk ra_disk;
85 	int	ra_state;	/* open/closed state */
86 	u_long	ra_mediaid;	/* media id */
87 	int	ra_hwunit;	/* Hardware unit number */
88 	int	ra_havelabel;	/* true if we have a label */
89 	int	ra_wlabel;	/* label sector is currently writable */
90 };
91 
92 #define rx_softc ra_softc
93 
94 void	rxattach __P((struct device *, struct device *, void *));
95 int	rx_putonline __P((struct rx_softc *));
96 void	rrmakelabel __P((struct disklabel *, long));
97 
98 #if NRA
99 
100 int	ramatch __P((struct device *, struct cfdata *, void *));
101 void	raattach __P((struct device *, struct device *, void *));
102 int	raopen __P((dev_t, int, int, struct proc *));
103 int	raclose __P((dev_t, int, int, struct proc *));
104 void	rastrategy __P((struct buf *));
105 int	raread __P((dev_t, struct uio *));
106 int	rawrite __P((dev_t, struct uio *));
107 int	raioctl __P((dev_t, int, caddr_t, int, struct proc *));
108 int	radump __P((dev_t, daddr_t, caddr_t, size_t));
109 int	rasize __P((dev_t));
110 int	ra_putonline __P((struct ra_softc *));
111 
112 struct	cfattach ra_ca = {
113 	sizeof(struct ra_softc), ramatch, rxattach
114 };
115 
116 /*
117  * More driver definitions, for generic MSCP code.
118  */
119 
120 int
121 ramatch(parent, cf, aux)
122 	struct	device *parent;
123 	struct	cfdata *cf;
124 	void	*aux;
125 {
126 	struct	drive_attach_args *da = aux;
127 	struct	mscp *mp = da->da_mp;
128 
129 	if ((da->da_typ & MSCPBUS_DISK) == 0)
130 		return 0;
131 	if (cf->cf_loc[MSCPBUSCF_DRIVE] != MSCPBUSCF_DRIVE_DEFAULT &&
132 	    cf->cf_loc[MSCPBUSCF_DRIVE] != mp->mscp_unit)
133 		return 0;
134 	/*
135 	 * Check if this disk is a floppy; then don't configure it.
136 	 * Seems to be a safe way to test it per Chris Torek.
137 	 */
138 	if (MSCP_MID_ECH(1, mp->mscp_guse.guse_mediaid) == 'X' - '@')
139 		return 0;
140 	return 1;
141 }
142 
143 /*
144  * (Try to) put the drive online. This is done the first time the
145  * drive is opened, or if it har fallen offline.
146  */
147 int
148 ra_putonline(ra)
149 	struct ra_softc *ra;
150 {
151 	struct	disklabel *dl;
152 	char *msg;
153 
154 	if (rx_putonline(ra) != MSCP_DONE)
155 		return MSCP_FAILED;
156 
157 	dl = ra->ra_disk.dk_label;
158 
159 	ra->ra_state = DK_RDLABEL;
160 	printf("%s", ra->ra_dev.dv_xname);
161 	if ((msg = readdisklabel(MAKEDISKDEV(RAMAJOR, ra->ra_dev.dv_unit,
162 	    RAW_PART), rastrategy, dl, NULL)) != NULL)
163 		printf(": %s", msg);
164 	else {
165 		ra->ra_havelabel = 1;
166 		ra->ra_state = DK_OPEN;
167 	}
168 
169 	printf(": size %d sectors\n", dl->d_secperunit);
170 
171 	return MSCP_DONE;
172 }
173 
174 /*
175  * Open a drive.
176  */
177 /*ARGSUSED*/
178 int
179 raopen(dev, flag, fmt, p)
180 	dev_t dev;
181 	int flag, fmt;
182 	struct	proc *p;
183 {
184 	struct ra_softc *ra;
185 	int part, unit, mask;
186 	/*
187 	 * Make sure this is a reasonable open request.
188 	 */
189 	unit = DISKUNIT(dev);
190 	if (unit >= ra_cd.cd_ndevs)
191 		return ENXIO;
192 	ra = ra_cd.cd_devs[unit];
193 	if (ra == 0)
194 		return ENXIO;
195 
196 	/*
197 	 * If this is the first open; we must first try to put
198 	 * the disk online (and read the label).
199 	 */
200 	if (ra->ra_state == DK_CLOSED)
201 		if (ra_putonline(ra) == MSCP_FAILED)
202 			return ENXIO;
203 
204 	/* If the disk has no label; allow writing everywhere */
205 	if (ra->ra_havelabel == 0)
206 		ra->ra_wlabel = 1;
207 
208 	part = DISKPART(dev);
209 	if (part >= ra->ra_disk.dk_label->d_npartitions)
210 		return ENXIO;
211 
212 	/*
213 	 * Wait for the state to settle
214 	 */
215 #if notyet
216 	while (ra->ra_state != DK_OPEN)
217 		if ((error = tsleep((caddr_t)ra, (PZERO + 1) | PCATCH,
218 		    devopn, 0))) {
219 			splx(s);
220 			return (error);
221 		}
222 #endif
223 
224 	mask = 1 << part;
225 
226 	switch (fmt) {
227 	case S_IFCHR:
228 		ra->ra_disk.dk_copenmask |= mask;
229 		break;
230 	case S_IFBLK:
231 		ra->ra_disk.dk_bopenmask |= mask;
232 		break;
233 	}
234 	ra->ra_disk.dk_openmask |= mask;
235 	return 0;
236 }
237 
238 /* ARGSUSED */
239 int
240 raclose(dev, flags, fmt, p)
241 	dev_t dev;
242 	int flags, fmt;
243 	struct	proc *p;
244 {
245 	int unit = DISKUNIT(dev);
246 	struct ra_softc *ra = ra_cd.cd_devs[unit];
247 	int mask = (1 << DISKPART(dev));
248 
249 	switch (fmt) {
250 	case S_IFCHR:
251 		ra->ra_disk.dk_copenmask &= ~mask;
252 		break;
253 	case S_IFBLK:
254 		ra->ra_disk.dk_bopenmask &= ~mask;
255 		break;
256 	}
257 	ra->ra_disk.dk_openmask =
258 	    ra->ra_disk.dk_copenmask | ra->ra_disk.dk_bopenmask;
259 
260 	/*
261 	 * Should wait for I/O to complete on this partition even if
262 	 * others are open, but wait for work on blkflush().
263 	 */
264 #if notyet
265 	if (ra->ra_openpart == 0) {
266 		s = spluba();
267 		while (BUFQ_FIRST(&udautab[unit]) != NULL)
268 			(void) tsleep(&udautab[unit], PZERO - 1,
269 			    "raclose", 0);
270 		splx(s);
271 		ra->ra_state = CLOSED;
272 		ra->ra_wlabel = 0;
273 	}
274 #endif
275 	return (0);
276 }
277 
278 /*
279  * Queue a transfer request, and if possible, hand it to the controller.
280  */
281 void
282 rastrategy(bp)
283 	struct buf *bp;
284 {
285 	int unit;
286 	struct ra_softc *ra;
287 	/*
288 	 * Make sure this is a reasonable drive to use.
289 	 */
290 	unit = DISKUNIT(bp->b_dev);
291 	if (unit > ra_cd.cd_ndevs || (ra = ra_cd.cd_devs[unit]) == NULL) {
292 		bp->b_error = ENXIO;
293 		bp->b_flags |= B_ERROR;
294 		goto done;
295 	}
296 	/*
297 	 * If drive is open `raw' or reading label, let it at it.
298 	 */
299 	if (ra->ra_state == DK_RDLABEL) {
300 		mscp_strategy(bp, ra->ra_dev.dv_parent);
301 		return;
302 	}
303 
304 	/* If disk is not online, try to put it online */
305 	if (ra->ra_state == DK_CLOSED)
306 		if (ra_putonline(ra) == MSCP_FAILED) {
307 			bp->b_flags |= B_ERROR;
308 			bp->b_error = EIO;
309 			goto done;
310 		}
311 
312 	/*
313 	 * Determine the size of the transfer, and make sure it is
314 	 * within the boundaries of the partition.
315 	 */
316 	if (bounds_check_with_label(bp, ra->ra_disk.dk_label,
317 	    ra->ra_wlabel) <= 0)
318 		goto done;
319 
320 	/* Make some statistics... /bqt */
321 	ra->ra_disk.dk_xfer++;
322 	ra->ra_disk.dk_bytes += bp->b_bcount;
323 	mscp_strategy(bp, ra->ra_dev.dv_parent);
324 	return;
325 
326 done:
327 	biodone(bp);
328 }
329 
330 int
331 raread(dev, uio)
332 	dev_t dev;
333 	struct uio *uio;
334 {
335 
336 	return (physio(rastrategy, NULL, dev, B_READ, minphys, uio));
337 }
338 
339 int
340 rawrite(dev, uio)
341 	dev_t dev;
342 	struct uio *uio;
343 {
344 
345 	return (physio(rastrategy, NULL, dev, B_WRITE, minphys, uio));
346 }
347 
348 /*
349  * I/O controls.
350  */
351 int
352 raioctl(dev, cmd, data, flag, p)
353 	dev_t dev;
354 	int cmd;
355 	caddr_t data;
356 	int flag;
357 	struct proc *p;
358 {
359 	int unit = DISKUNIT(dev);
360 	struct disklabel *lp, *tp;
361 	struct ra_softc *ra = ra_cd.cd_devs[unit];
362 	int error = 0;
363 #ifdef __HAVE_OLD_DISKLABEL
364 	struct disklabel newlabel;
365 #endif
366 
367 	lp = ra->ra_disk.dk_label;
368 
369 	switch (cmd) {
370 
371 	case DIOCGDINFO:
372 		bcopy(lp, data, sizeof (struct disklabel));
373 		break;
374 #ifdef __HAVE_OLD_DISKLABEL
375 	case ODIOCGDINFO:
376 		bcopy(lp, &newlabel, sizeof disklabel);
377 		if (newlabel.d_npartitions > OLDMAXPARTITIONS)
378 			return ENOTTY;
379 		bcopy(&newlabel, data, sizeof (struct olddisklabel));
380 		break;
381 #endif
382 
383 	case DIOCGPART:
384 		((struct partinfo *)data)->disklab = lp;
385 		((struct partinfo *)data)->part =
386 		    &lp->d_partitions[DISKPART(dev)];
387 		break;
388 
389 	case DIOCWDINFO:
390 	case DIOCSDINFO:
391 #ifdef __HAVE_OLD_DISKLABEL
392 	case ODIOCWDINFO:
393 	case ODIOCSDINFO:
394 		if (cmd == ODIOCSDINFO || xfer == ODIOCWDINFO) {
395 			memset(&newlabel, 0, sizeof newlabel);
396 			memcpy(&newlabel, data, sizeof (struct olddisklabel));
397 			tp = &newlabel;
398 		} else
399 #endif
400 		tp = (struct disklabel *)data;
401 
402 		if ((flag & FWRITE) == 0)
403 			error = EBADF;
404 		else {
405 			error = setdisklabel(lp, tp, 0, 0);
406 			if ((error == 0) && (cmd == DIOCWDINFO
407 #ifdef __HAVE_OLD_DISKLABEL
408 			    || cmd == ODIOCWDINFO
409 #else
410 			    )) {
411 #endif
412 				ra->ra_wlabel = 1;
413 				error = writedisklabel(dev, rastrategy, lp,0);
414 				ra->ra_wlabel = 0;
415 			}
416 		}
417 		break;
418 
419 	case DIOCWLABEL:
420 		if ((flag & FWRITE) == 0)
421 			error = EBADF;
422 		else
423 			ra->ra_wlabel = 1;
424 		break;
425 
426 	case DIOCGDEFLABEL:
427 #ifdef __HAVE_OLD_DISKLABEL
428 	case ODIOCGDEFLABEL:
429 		if (cmd == ODIOCGDEFLABEL)
430 			tp = &newlabel;
431 		else
432 #else
433 		tp = (struct disklabel *)data;
434 #endif
435 		bzero(tp, sizeof(struct disklabel));
436 		tp->d_secsize = lp->d_secsize;
437 		tp->d_nsectors = lp->d_nsectors;
438 		tp->d_ntracks = lp->d_ntracks;
439 		tp->d_ncylinders = lp->d_ncylinders;
440 		tp->d_secpercyl = lp->d_secpercyl;
441 		tp->d_secperunit = lp->d_secperunit;
442 		tp->d_type = DTYPE_MSCP;
443 		tp->d_rpm = 3600;
444 		rrmakelabel(tp, ra->ra_mediaid);
445 #ifdef __HAVE_OLD_DISKLABEL
446 		if (cmd == ODIOCGDEFLABEL) {
447 			if (tp->d_npartitions > OLDMAXPARTITIONS)
448 				return ENOTTY;
449 			memcpy(data, tp, sizeof (struct olddisklabel));
450 		}
451 #endif
452 		break;
453 
454 	default:
455 		error = ENOTTY;
456 		break;
457 	}
458 	return (error);
459 }
460 
461 
462 int
463 radump(dev, blkno, va, size)
464 	dev_t	dev;
465 	daddr_t blkno;
466 	caddr_t va;
467 	size_t	size;
468 {
469 	return ENXIO;
470 }
471 
472 /*
473  * Return the size of a partition, if known, or -1 if not.
474  */
475 int
476 rasize(dev)
477 	dev_t dev;
478 {
479 	int unit = DISKUNIT(dev);
480 	struct ra_softc *ra;
481 
482 	if (unit >= ra_cd.cd_ndevs || ra_cd.cd_devs[unit] == 0)
483 		return -1;
484 
485 	ra = ra_cd.cd_devs[unit];
486 
487 	if (ra->ra_state == DK_CLOSED)
488 		if (ra_putonline(ra) == MSCP_FAILED)
489 			return -1;
490 
491 	return ra->ra_disk.dk_label->d_partitions[DISKPART(dev)].p_size *
492 	    (ra->ra_disk.dk_label->d_secsize / DEV_BSIZE);
493 }
494 
495 #endif /* NRA */
496 
497 #if NRX
498 
499 int	rxmatch __P((struct device *, struct cfdata *, void *));
500 int	rxopen __P((dev_t, int, int, struct proc *));
501 int	rxclose __P((dev_t, int, int, struct proc *));
502 void	rxstrategy __P((struct buf *));
503 int	rxread __P((dev_t, struct uio *));
504 int	rxwrite __P((dev_t, struct uio *));
505 int	rxioctl __P((dev_t, int, caddr_t, int, struct proc *));
506 int	rxdump __P((dev_t, daddr_t, caddr_t, size_t));
507 int	rxsize __P((dev_t));
508 
509 struct	cfattach rx_ca = {
510 	sizeof(struct rx_softc), rxmatch, rxattach
511 };
512 
513 /*
514  * More driver definitions, for generic MSCP code.
515  */
516 
517 int
518 rxmatch(parent, cf, aux)
519 	struct	device *parent;
520 	struct	cfdata *cf;
521 	void	*aux;
522 {
523 	struct	drive_attach_args *da = aux;
524 	struct	mscp *mp = da->da_mp;
525 
526 	if ((da->da_typ & MSCPBUS_DISK) == 0)
527 		return 0;
528 	if (cf->cf_loc[MSCPBUSCF_DRIVE] != MSCPBUSCF_DRIVE_DEFAULT &&
529 	    cf->cf_loc[MSCPBUSCF_DRIVE] != mp->mscp_unit)
530 		return 0;
531 	/*
532 	 * Check if this disk is a floppy; then configure it.
533 	 * Seems to be a safe way to test it per Chris Torek.
534 	 */
535 	if (MSCP_MID_ECH(1, mp->mscp_guse.guse_mediaid) == 'X' - '@')
536 		return 1;
537 	return 0;
538 }
539 
540 #endif /* NRX */
541 
542 /*
543  * The attach routine only checks and prints drive type.
544  * Bringing the disk online is done when the disk is accessed
545  * the first time.
546  */
547 void
548 rxattach(parent, self, aux)
549 	struct	device *parent, *self;
550 	void	*aux;
551 {
552 	struct	rx_softc *rx = (void *)self;
553 	struct	drive_attach_args *da = aux;
554 	struct	mscp *mp = da->da_mp;
555 	struct	mscp_softc *mi = (void *)parent;
556 	struct	disklabel *dl;
557 
558 	rx->ra_mediaid = mp->mscp_guse.guse_mediaid;
559 	rx->ra_state = DK_CLOSED;
560 	rx->ra_hwunit = mp->mscp_unit;
561 	mi->mi_dp[mp->mscp_unit] = self;
562 
563 	rx->ra_disk.dk_name = rx->ra_dev.dv_xname;
564 	disk_attach((struct disk *)&rx->ra_disk);
565 
566 	/* Fill in what we know. The actual size is gotten later */
567 	dl = rx->ra_disk.dk_label;
568 
569 	dl->d_secsize = DEV_BSIZE;
570 	dl->d_nsectors = mp->mscp_guse.guse_nspt;
571 	dl->d_ntracks = mp->mscp_guse.guse_ngpc * mp->mscp_guse.guse_group;
572 	dl->d_secpercyl = dl->d_nsectors * dl->d_ntracks;
573 	disk_printtype(mp->mscp_unit, mp->mscp_guse.guse_mediaid);
574 #ifdef DEBUG
575 	printf("%s: nspt %d group %d ngpc %d rct %d nrpt %d nrct %d\n",
576 	    self->dv_xname, mp->mscp_guse.guse_nspt, mp->mscp_guse.guse_group,
577 	    mp->mscp_guse.guse_ngpc, mp->mscp_guse.guse_rctsize,
578 	    mp->mscp_guse.guse_nrpt, mp->mscp_guse.guse_nrct);
579 #endif
580 }
581 
582 /*
583  * (Try to) put the drive online. This is done the first time the
584  * drive is opened, or if it har fallen offline.
585  */
586 int
587 rx_putonline(rx)
588 	struct rx_softc *rx;
589 {
590 	struct	mscp *mp;
591 	struct	mscp_softc *mi = (struct mscp_softc *)rx->ra_dev.dv_parent;
592 	volatile int i;
593 
594 	rx->ra_state = DK_CLOSED;
595 	mp = mscp_getcp(mi, MSCP_WAIT);
596 	mp->mscp_opcode = M_OP_ONLINE;
597 	mp->mscp_unit = rx->ra_hwunit;
598 	mp->mscp_cmdref = 1;
599 	*mp->mscp_addr |= MSCP_OWN | MSCP_INT;
600 
601 	/* Poll away */
602 	i = bus_space_read_2(mi->mi_iot, mi->mi_iph, 0);
603 	if (tsleep(&rx->ra_dev.dv_unit, PRIBIO, "rxonline", 100*100))
604 		rx->ra_state = DK_CLOSED;
605 
606 	if (rx->ra_state == DK_CLOSED)
607 		return MSCP_FAILED;
608 
609 	return MSCP_DONE;
610 }
611 
612 #if NRX
613 
614 /*
615  * Open a drive.
616  */
617 /*ARGSUSED*/
618 int
619 rxopen(dev, flag, fmt, p)
620 	dev_t dev;
621 	int flag, fmt;
622 	struct	proc *p;
623 {
624 	struct rx_softc *rx;
625 	int unit;
626 
627 	/*
628 	 * Make sure this is a reasonable open request.
629 	 */
630 	unit = DISKUNIT(dev);
631 	if (unit >= rx_cd.cd_ndevs)
632 		return ENXIO;
633 	rx = rx_cd.cd_devs[unit];
634 	if (rx == 0)
635 		return ENXIO;
636 
637 	/*
638 	 * If this is the first open; we must first try to put
639 	 * the disk online (and read the label).
640 	 */
641 	if (rx->ra_state == DK_CLOSED)
642 		if (rx_putonline(rx) == MSCP_FAILED)
643 			return ENXIO;
644 
645 	return 0;
646 }
647 
648 /* ARGSUSED */
649 int
650 rxclose(dev, flags, fmt, p)
651 	dev_t dev;
652 	int flags, fmt;
653 	struct	proc *p;
654 {
655 	return (0);
656 }
657 
658 /*
659  * Queue a transfer request, and if possible, hand it to the controller.
660  *
661  * This routine is broken into two so that the internal version
662  * udastrat1() can be called by the (nonexistent, as yet) bad block
663  * revectoring routine.
664  */
665 void
666 rxstrategy(bp)
667 	struct buf *bp;
668 {
669 	int unit;
670 	struct rx_softc *rx;
671 
672 	/*
673 	 * Make sure this is a reasonable drive to use.
674 	 */
675 	unit = DISKUNIT(bp->b_dev);
676 	if (unit > rx_cd.cd_ndevs || (rx = rx_cd.cd_devs[unit]) == NULL) {
677 		bp->b_error = ENXIO;
678 		bp->b_flags |= B_ERROR;
679 		goto done;
680 	}
681 
682 	/* If disk is not online, try to put it online */
683 	if (rx->ra_state == DK_CLOSED)
684 		if (rx_putonline(rx) == MSCP_FAILED) {
685 			bp->b_flags |= B_ERROR;
686 			bp->b_error = EIO;
687 			goto done;
688 		}
689 
690 	/*
691 	 * Determine the size of the transfer, and make sure it is
692 	 * within the boundaries of the partition.
693 	 */
694 	if (bp->b_blkno >= rx->ra_disk.dk_label->d_secperunit) {
695 		bp->b_resid = bp->b_bcount;
696 		goto done;
697 	}
698 
699 	/* Make some statistics... /bqt */
700 	rx->ra_disk.dk_xfer++;
701 	rx->ra_disk.dk_bytes += bp->b_bcount;
702 	mscp_strategy(bp, rx->ra_dev.dv_parent);
703 	return;
704 
705 done:
706 	biodone(bp);
707 }
708 
709 int
710 rxread(dev, uio)
711 	dev_t dev;
712 	struct uio *uio;
713 {
714 
715 	return (physio(rxstrategy, NULL, dev, B_READ, minphys, uio));
716 }
717 
718 int
719 rxwrite(dev, uio)
720 	dev_t dev;
721 	struct uio *uio;
722 {
723 
724 	return (physio(rxstrategy, NULL, dev, B_WRITE, minphys, uio));
725 }
726 
727 /*
728  * I/O controls.
729  */
730 int
731 rxioctl(dev, cmd, data, flag, p)
732 	dev_t dev;
733 	int cmd;
734 	caddr_t data;
735 	int flag;
736 	struct proc *p;
737 {
738 	int unit = DISKUNIT(dev);
739 	struct disklabel *lp;
740 	struct rx_softc *rx = rx_cd.cd_devs[unit];
741 	int error = 0;
742 
743 	lp = rx->ra_disk.dk_label;
744 
745 	switch (cmd) {
746 
747 	case DIOCGDINFO:
748 		bcopy(lp, data, sizeof (struct disklabel));
749 		break;
750 
751 	case DIOCGPART:
752 		((struct partinfo *)data)->disklab = lp;
753 		((struct partinfo *)data)->part =
754 		    &lp->d_partitions[DISKPART(dev)];
755 		break;
756 
757 
758 	case DIOCWDINFO:
759 	case DIOCSDINFO:
760 	case DIOCWLABEL:
761 		break;
762 
763 	default:
764 		error = ENOTTY;
765 		break;
766 	}
767 	return (error);
768 }
769 
770 int
771 rxdump(dev, blkno, va, size)
772 	dev_t dev;
773 	daddr_t blkno;
774 	caddr_t va;
775 	size_t size;
776 {
777 
778 	/* Not likely. */
779 	return ENXIO;
780 }
781 
782 int
783 rxsize(dev)
784 	dev_t dev;
785 {
786 
787 	return -1;
788 }
789 
790 #endif /* NRX */
791 
792 void	rrdgram __P((struct device *, struct mscp *, struct mscp_softc *));
793 void	rriodone __P((struct device *, struct buf *));
794 int	rronline __P((struct device *, struct mscp *));
795 int	rrgotstatus __P((struct device *, struct mscp *));
796 void	rrreplace __P((struct device *, struct mscp *));
797 int	rrioerror __P((struct device *, struct mscp *, struct buf *));
798 void	rrfillin __P((struct buf *, struct mscp *));
799 void	rrbb __P((struct device *, struct mscp *, struct buf *));
800 
801 
802 struct	mscp_device ra_device = {
803 	rrdgram,
804 	rriodone,
805 	rronline,
806 	rrgotstatus,
807 	rrreplace,
808 	rrioerror,
809 	rrbb,
810 	rrfillin,
811 };
812 
813 /*
814  * Handle an error datagram.
815  * This can come from an unconfigured drive as well.
816  */
817 void
818 rrdgram(usc, mp, mi)
819 	struct device *usc;
820 	struct mscp *mp;
821 	struct mscp_softc *mi;
822 {
823 	if (mscp_decodeerror(usc == NULL?"unconf disk" : usc->dv_xname, mp, mi))
824 		return;
825 	/*
826 	 * SDI status information bytes 10 and 11 are the microprocessor
827 	 * error code and front panel code respectively.  These vary per
828 	 * drive type and are printed purely for field service information.
829 	 */
830 	if (mp->mscp_format == M_FM_SDI)
831 		printf("\tsdi uproc error code 0x%x, front panel code 0x%x\n",
832 			mp->mscp_erd.erd_sdistat[10],
833 			mp->mscp_erd.erd_sdistat[11]);
834 }
835 
836 void
837 rriodone(usc, bp)
838 	struct device *usc;
839 	struct buf *bp;
840 {
841 
842 	biodone(bp);
843 }
844 
845 /*
846  * A drive came on line.  Check its type and size.  Return DONE if
847  * we think the drive is truly on line.	 In any case, awaken anyone
848  * sleeping on the drive on-line-ness.
849  */
850 int
851 rronline(usc, mp)
852 	struct device *usc;
853 	struct mscp *mp;
854 {
855 	struct rx_softc *rx = (struct rx_softc *)usc;
856 	struct disklabel *dl;
857 
858 	wakeup((caddr_t)&usc->dv_unit);
859 	if ((mp->mscp_status & M_ST_MASK) != M_ST_SUCCESS) {
860 		printf("%s: attempt to bring on line failed: ", usc->dv_xname);
861 		mscp_printevent(mp);
862 		return (MSCP_FAILED);
863 	}
864 
865 	rx->ra_state = DK_OPEN;
866 
867 	dl = rx->ra_disk.dk_label;
868 	dl->d_secperunit = (daddr_t)mp->mscp_onle.onle_unitsize;
869 
870 	if (dl->d_secpercyl) {
871 		dl->d_ncylinders = dl->d_secperunit/dl->d_secpercyl;
872 		dl->d_type = DTYPE_MSCP;
873 		dl->d_rpm = 3600;
874 	} else {
875 		dl->d_type = DTYPE_FLOPPY;
876 		dl->d_rpm = 300;
877 	}
878 	rrmakelabel(dl, rx->ra_mediaid);
879 
880 	return (MSCP_DONE);
881 }
882 
883 void
884 rrmakelabel(dl, type)
885 	struct disklabel *dl;
886 	long type;
887 {
888 	int n, p = 0;
889 
890 	dl->d_bbsize = BBSIZE;
891 	dl->d_sbsize = SBSIZE;
892 
893 	/* Create the disk name for disklabel. Phew... */
894 	dl->d_typename[p++] = MSCP_MID_CHAR(2, type);
895 	dl->d_typename[p++] = MSCP_MID_CHAR(1, type);
896 	if (MSCP_MID_ECH(0, type))
897 		dl->d_typename[p++] = MSCP_MID_CHAR(0, type);
898 	n = MSCP_MID_NUM(type);
899 	if (n > 99) {
900 		dl->d_typename[p++] = '1';
901 		n -= 100;
902 	}
903 	if (n > 9) {
904 		dl->d_typename[p++] = (n / 10) + '0';
905 		n %= 10;
906 	}
907 	dl->d_typename[p++] = n + '0';
908 	dl->d_typename[p] = 0;
909 	dl->d_npartitions = MAXPARTITIONS;
910 	dl->d_partitions[0].p_size = dl->d_partitions[2].p_size =
911 	    dl->d_secperunit;
912 	dl->d_partitions[0].p_offset = dl->d_partitions[2].p_offset = 0;
913 	dl->d_interleave = dl->d_headswitch = 1;
914 	dl->d_magic = dl->d_magic2 = DISKMAGIC;
915 	dl->d_checksum = dkcksum(dl);
916 }
917 
918 /*
919  * We got some (configured) unit's status.  Return DONE if it succeeded.
920  */
921 int
922 rrgotstatus(usc, mp)
923 	struct device *usc;
924 	struct mscp *mp;
925 {
926 	if ((mp->mscp_status & M_ST_MASK) != M_ST_SUCCESS) {
927 		printf("%s: attempt to get status failed: ", usc->dv_xname);
928 		mscp_printevent(mp);
929 		return (MSCP_FAILED);
930 	}
931 	/* record for (future) bad block forwarding and whatever else */
932 #ifdef notyet
933 	uda_rasave(ui->ui_unit, mp, 1);
934 #endif
935 	return (MSCP_DONE);
936 }
937 
938 /*
939  * A replace operation finished.
940  */
941 /*ARGSUSED*/
942 void
943 rrreplace(usc, mp)
944 	struct device *usc;
945 	struct mscp *mp;
946 {
947 
948 	panic("udareplace");
949 }
950 
951 /*
952  * A transfer failed.  We get a chance to fix or restart it.
953  * Need to write the bad block forwaring code first....
954  */
955 /*ARGSUSED*/
956 int
957 rrioerror(usc, mp, bp)
958 	struct device *usc;
959 	struct mscp *mp;
960 	struct buf *bp;
961 {
962 	struct ra_softc *ra = (void *)usc;
963 	int code = mp->mscp_event;
964 
965 	switch (code & M_ST_MASK) {
966 	/* The unit has fallen offline. Try to figure out why. */
967 	case M_ST_OFFLINE:
968 		bp->b_flags |= B_ERROR;
969 		bp->b_error = EIO;
970 		ra->ra_state = DK_CLOSED;
971 		if (code & M_OFFLINE_UNMOUNTED)
972 			printf("%s: not mounted/spun down\n", usc->dv_xname);
973 		if (code & M_OFFLINE_DUPLICATE)
974 			printf("%s: duplicate unit number!!!\n", usc->dv_xname);
975 		return MSCP_DONE;
976 
977 	case M_ST_AVAILABLE:
978 		ra->ra_state = DK_CLOSED; /* Force another online */
979 		return MSCP_DONE;
980 
981 	default:
982 		printf("%s:", usc->dv_xname);
983 		break;
984 	}
985 	return (MSCP_FAILED);
986 }
987 
988 /*
989  * Fill in disk addresses in a mscp packet waiting for transfer.
990  */
991 void
992 rrfillin(bp, mp)
993 	struct buf *bp;
994 	struct mscp *mp;
995 {
996 	struct rx_softc *rx = 0; /* Wall */
997 	struct disklabel *lp;
998 	int unit = DISKUNIT(bp->b_dev);
999 	int part = DISKPART(bp->b_dev);
1000 
1001 #if NRA
1002 	if (major(bp->b_dev) == RAMAJOR)
1003 		rx = ra_cd.cd_devs[unit];
1004 #endif
1005 #if NRX
1006 	if (major(bp->b_dev) != RAMAJOR)
1007 		rx = rx_cd.cd_devs[unit];
1008 #endif
1009 	lp = rx->ra_disk.dk_label;
1010 
1011 	mp->mscp_seq.seq_lbn = lp->d_partitions[part].p_offset + bp->b_blkno;
1012 	mp->mscp_unit = rx->ra_hwunit;
1013 	mp->mscp_seq.seq_bytecount = bp->b_bcount;
1014 }
1015 
1016 /*
1017  * A bad block related operation finished.
1018  */
1019 /*ARGSUSED*/
1020 void
1021 rrbb(usc, mp, bp)
1022 	struct device *usc;
1023 	struct mscp *mp;
1024 	struct buf *bp;
1025 {
1026 
1027 	panic("udabb");
1028 }
1029