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