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