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