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