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