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