xref: /netbsd-src/sys/dev/mscp/mscp_disk.c (revision b8ecfcfef0e343ad71faea7a54fb5fcb42ad4e27)
1 /*	$NetBSD: mscp_disk.c,v 1.82 2014/11/09 10:10:08 mlelstv 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.82 2014/11/09 10:10:08 mlelstv 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 	case DIOCMWEDGES:
534 	    {
535 	    	if ((flag & FWRITE) == 0)
536 			return (EBADF);
537 
538 		dkwedge_discover(&ra->ra_disk);
539 		return 0;
540 	    }
541 
542 	default:
543 		error = ENOTTY;
544 		break;
545 	}
546 	return (error);
547 }
548 
549 int
550 radump(dev_t dev, daddr_t blkno, void *va, size_t size)
551 {
552 	return ENXIO;
553 }
554 
555 /*
556  * Return the size of a partition, if known, or -1 if not.
557  */
558 int
559 rasize(dev_t dev)
560 {
561 	struct ra_softc *ra = mscp_device_lookup(dev);
562 
563 	if (!ra)
564 		return -1;
565 
566 	if (ra->ra_state == DK_CLOSED)
567 		if (ra_putonline(dev, ra) == MSCP_FAILED)
568 			return -1;
569 
570 	return ra->ra_disk.dk_label->d_partitions[DISKPART(dev)].p_size *
571 	    (ra->ra_disk.dk_label->d_secsize / DEV_BSIZE);
572 }
573 
574 #endif /* NRA || NRACD || NRX */
575 
576 #if NRX
577 
578 int	rxmatch(device_t, cfdata_t, void *);
579 
580 CFATTACH_DECL_NEW(rx, sizeof(struct rx_softc),
581     rxmatch, raattach, NULL, NULL);
582 
583 dev_type_open(rxopen);
584 dev_type_read(rxread);
585 dev_type_write(rxwrite);
586 dev_type_ioctl(rxioctl);
587 dev_type_strategy(rxstrategy);
588 dev_type_dump(radump);
589 dev_type_size(rxsize);
590 
591 const struct bdevsw rx_bdevsw = {
592 	.d_open = rxopen,
593 	.d_close = nullclose,
594 	.d_strategy = rxstrategy,
595 	.d_ioctl = rxioctl,
596 	.d_dump = radump,
597 	.d_psize = rxsize,
598 	.d_discard = nodiscard,
599 	.d_flag = D_DISK
600 };
601 
602 const struct cdevsw rx_cdevsw = {
603 	.d_open = rxopen,
604 	.d_close = nullclose,
605 	.d_read = rxread,
606 	.d_write = rxwrite,
607 	.d_ioctl = rxioctl,
608 	.d_stop = nostop,
609 	.d_tty = notty,
610 	.d_poll = nopoll,
611 	.d_mmap = nommap,
612 	.d_kqfilter = nokqfilter,
613 	.d_discard = nodiscard,
614 	.d_flag = D_DISK
615 };
616 
617 static struct dkdriver rxdkdriver = {
618 	rxstrategy, minphys
619 };
620 
621 /*
622  * More driver definitions, for generic MSCP code.
623  */
624 
625 int
626 rxmatch(device_t parent, cfdata_t cf, void *aux)
627 {
628 	struct	drive_attach_args *da = aux;
629 	struct	mscp *mp = da->da_mp;
630 
631 	if ((da->da_typ & MSCPBUS_DISK) == 0)
632 		return 0;
633 	if (cf->cf_loc[MSCPBUSCF_DRIVE] != MSCPBUSCF_DRIVE_DEFAULT &&
634 	    cf->cf_loc[MSCPBUSCF_DRIVE] != mp->mscp_unit)
635 		return 0;
636 	/*
637 	 * Check if this disk is a floppy (RX)
638 	 * Seems to be a safe way to test it per Chris Torek.
639 	 */
640 	if (MSCP_MID_ECH(1, mp->mscp_guse.guse_mediaid) == 'X' - '@')
641 		return 1;
642 	return 0;
643 }
644 
645 #endif /* NRX */
646 
647 #if NRACD
648 
649 /* Use almost all ra* routines for racd */
650 
651 int	racdmatch(device_t, cfdata_t, void *);
652 
653 CFATTACH_DECL_NEW(racd, sizeof(struct racd_softc),
654     racdmatch, raattach, NULL, NULL);
655 
656 dev_type_open(raopen);
657 dev_type_read(raread);
658 dev_type_write(rawrite);
659 dev_type_ioctl(raioctl);
660 dev_type_strategy(rastrategy);
661 dev_type_dump(radump);
662 dev_type_size(rasize);
663 
664 const struct bdevsw racd_bdevsw = {
665 	.d_open = raopen,
666 	.d_close = nullclose,
667 	.d_strategy = rastrategy,
668 	.d_ioctl = raioctl,
669 	.d_dump = radump,
670 	.d_psize = rasize,
671 	.d_discard = nodiscard,
672 	.d_flag = D_DISK
673 };
674 
675 const struct cdevsw racd_cdevsw = {
676 	.d_open = raopen,
677 	.d_close = nullclose,
678 	.d_read = raread,
679 	.d_write = rawrite,
680 	.d_ioctl = raioctl,
681 	.d_stop = nostop,
682 	.d_tty = notty,
683 	.d_poll = nopoll,
684 	.d_mmap = nommap,
685 	.d_kqfilter = nokqfilter,
686 	.d_discard = nodiscard,
687 	.d_flag = D_DISK
688 };
689 
690 static struct dkdriver racddkdriver = {
691 	rastrategy, minphys
692 };
693 
694 /*
695  * More driver definitions, for generic MSCP code.
696  */
697 
698 int
699 racdmatch(device_t parent, cfdata_t cf, void *aux)
700 {
701 	struct	drive_attach_args *da = aux;
702 	struct	mscp *mp = da->da_mp;
703 
704 	if ((da->da_typ & MSCPBUS_DISK) == 0)
705 		return 0;
706 	if (cf->cf_loc[MSCPBUSCF_DRIVE] != MSCPBUSCF_DRIVE_DEFAULT &&
707 	    cf->cf_loc[MSCPBUSCF_DRIVE] != mp->mscp_unit)
708 		return 0;
709 	/*
710 	 * Check if this disk is a CD (RRD)
711 	 */
712 	if (MSCP_MID_ECH(1, mp->mscp_guse.guse_mediaid) == 'R' - '@')
713 		return 1;
714 	return 0;
715 }
716 
717 #endif /* NRACD */
718 
719 /*
720  * The attach routine only checks and prints drive type.
721  * Bringing the disk online is done when the disk is accessed
722  * the first time.
723  */
724 void
725 raattach(device_t parent, device_t self, void *aux)
726 {
727 	struct	rx_softc *rx = device_private(self);
728 	struct	drive_attach_args *da = aux;
729 	struct	mscp *mp = da->da_mp;
730 	struct	mscp_softc *mi = device_private(parent);
731 	struct	disklabel *dl;
732 
733 	rx->ra_dev = self;
734 	rx->ra_mediaid = mp->mscp_guse.guse_mediaid;
735 	rx->ra_state = DK_CLOSED;
736 	rx->ra_hwunit = mp->mscp_unit;
737 	mi->mi_dp[mp->mscp_unit] = self;
738 
739 #if NRX
740 	if (MSCP_MID_ECH(1, mp->mscp_guse.guse_mediaid) == 'X' - '@')
741 		disk_init((struct disk *)&rx->ra_disk, device_xname(rx->ra_dev),
742 		    &rxdkdriver);
743 #endif
744 #if NRACD
745 	if (MSCP_MID_ECH(1, mp->mscp_guse.guse_mediaid) == 'R' - '@')
746 		disk_init((struct disk *)&rx->ra_disk, device_xname(rx->ra_dev),
747 		    &racddkdriver);
748 #endif
749 #if NRA
750 	if (MSCP_MID_ECH(1, mp->mscp_guse.guse_mediaid) != 'X' - '@' &&
751 	    MSCP_MID_ECH(1, mp->mscp_guse.guse_mediaid) != 'R' - '@')
752 		disk_init((struct disk *)&rx->ra_disk, device_xname(rx->ra_dev),
753 		    &radkdriver);
754 #endif
755 	disk_attach(&rx->ra_disk);
756 
757 	/* Fill in what we know. The actual size is gotten later */
758 	dl = rx->ra_disk.dk_label;
759 
760 	dl->d_secsize = DEV_BSIZE;
761 	dl->d_nsectors = mp->mscp_guse.guse_nspt;
762 	dl->d_ntracks = mp->mscp_guse.guse_ngpc * mp->mscp_guse.guse_group;
763 	dl->d_secpercyl = dl->d_nsectors * dl->d_ntracks;
764 	disk_printtype(mp->mscp_unit, mp->mscp_guse.guse_mediaid);
765 #ifdef DEBUG
766 	printf("%s: nspt %d group %d ngpc %d rct %d nrpt %d nrct %d\n",
767 	    device_xname(self), mp->mscp_guse.guse_nspt, mp->mscp_guse.guse_group,
768 	    mp->mscp_guse.guse_ngpc, mp->mscp_guse.guse_rctsize,
769 	    mp->mscp_guse.guse_nrpt, mp->mscp_guse.guse_nrct);
770 #endif
771 	if (MSCP_MID_ECH(1, mp->mscp_guse.guse_mediaid) != 'X' - '@') {
772 		/*
773 		 * XXX We should try to discover wedges here, but
774 		 * XXX that would mean being able to do I/O.  Should
775 		 * XXX use config_defer() here.
776 		 */
777 	}
778 }
779 
780 /*
781  * (Try to) put the drive online. This is done the first time the
782  * drive is opened, or if it har fallen offline.
783  */
784 int
785 rx_putonline(struct rx_softc *rx)
786 {
787 	struct	mscp *mp;
788 	struct	mscp_softc *mi = device_private(device_parent(rx->ra_dev));
789 
790 	rx->ra_state = DK_CLOSED;
791 	mp = mscp_getcp(mi, MSCP_WAIT);
792 	mp->mscp_opcode = M_OP_ONLINE;
793 	mp->mscp_unit = rx->ra_hwunit;
794 	mp->mscp_cmdref = 1;
795 	*mp->mscp_addr |= MSCP_OWN | MSCP_INT;
796 
797 	/* Poll away */
798 	bus_space_read_2(mi->mi_iot, mi->mi_iph, 0);
799 	if (tsleep(&rx->ra_state, PRIBIO, "rxonline", 100*100))
800 		rx->ra_state = DK_CLOSED;
801 
802 	if (rx->ra_state == DK_CLOSED)
803 		return MSCP_FAILED;
804 
805 	return MSCP_DONE;
806 }
807 
808 #if NRX
809 
810 /*
811  * Open a drive.
812  */
813 /*ARGSUSED*/
814 int
815 rxopen(dev_t dev, int flag, int fmt, struct lwp *l)
816 {
817 	struct rx_softc *rx;
818 	int unit;
819 
820 	/*
821 	 * Make sure this is a reasonable open request.
822 	 */
823 	unit = DISKUNIT(dev);
824 	rx = device_lookup_private(&rx_cd, unit);
825 	if (!rx)
826 		return ENXIO;
827 
828 	/*
829 	 * If this is the first open; we must first try to put
830 	 * the disk online (and read the label).
831 	 */
832 	if (rx->ra_state == DK_CLOSED)
833 		if (rx_putonline(rx) == MSCP_FAILED)
834 			return ENXIO;
835 
836 	return 0;
837 }
838 
839 /*
840  * Queue a transfer request, and if possible, hand it to the controller.
841  *
842  * This routine is broken into two so that the internal version
843  * udastrat1() can be called by the (nonexistent, as yet) bad block
844  * revectoring routine.
845  */
846 void
847 rxstrategy(struct buf *bp)
848 {
849 	int unit;
850 	struct rx_softc *rx;
851 	int b;
852 
853 	/*
854 	 * Make sure this is a reasonable drive to use.
855 	 */
856 	unit = DISKUNIT(bp->b_dev);
857 	if ((rx = device_lookup_private(&rx_cd, unit)) == NULL) {
858 		bp->b_error = ENXIO;
859 		goto done;
860 	}
861 
862 	/* If disk is not online, try to put it online */
863 	if (rx->ra_state == DK_CLOSED)
864 		if (rx_putonline(rx) == MSCP_FAILED) {
865 			bp->b_error = EIO;
866 			goto done;
867 		}
868 
869 	/*
870 	 * Determine the size of the transfer, and make sure it is
871 	 * within the boundaries of the partition.
872 	 */
873 	if (bp->b_blkno >= rx->ra_disk.dk_label->d_secperunit) {
874 		bp->b_resid = bp->b_bcount;
875 		goto done;
876 	}
877 
878 	/* Make some statistics... /bqt */
879 	b = splbio();
880 	disk_busy(&rx->ra_disk);
881 	splx(b);
882 	mscp_strategy(bp, device_parent(rx->ra_dev));
883 	return;
884 
885 done:
886 	biodone(bp);
887 }
888 
889 int
890 rxread(dev_t dev, struct uio *uio, int flag)
891 {
892 
893 	return (physio(rxstrategy, NULL, dev, B_READ, minphys, uio));
894 }
895 
896 int
897 rxwrite(dev_t dev, struct uio *uio, int flag)
898 {
899 
900 	return (physio(rxstrategy, NULL, dev, B_WRITE, minphys, uio));
901 }
902 
903 /*
904  * I/O controls.
905  */
906 int
907 rxioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l)
908 {
909 	int unit = DISKUNIT(dev);
910 	struct disklabel *lp;
911 	struct rx_softc *rx = device_lookup_private(&rx_cd, unit);
912 	int error = 0;
913 
914 	lp = rx->ra_disk.dk_label;
915 
916 	switch (cmd) {
917 
918 	case DIOCGDINFO:
919 		memcpy(data, lp, sizeof (struct disklabel));
920 		break;
921 
922 	case DIOCGPART:
923 		((struct partinfo *)data)->disklab = lp;
924 		((struct partinfo *)data)->part =
925 		    &lp->d_partitions[DISKPART(dev)];
926 		break;
927 
928 
929 	case DIOCWDINFO:
930 	case DIOCSDINFO:
931 	case DIOCWLABEL:
932 		break;
933 
934 	default:
935 		error = ENOTTY;
936 		break;
937 	}
938 	return (error);
939 }
940 
941 int
942 rxsize(dev_t dev)
943 {
944 
945 	return -1;
946 }
947 
948 #endif /* NRX */
949 
950 void	rrdgram(device_t, struct mscp *, struct mscp_softc *);
951 void	rriodone(device_t, struct buf *);
952 int	rronline(device_t, struct mscp *);
953 int	rrgotstatus(device_t, struct mscp *);
954 void	rrreplace(device_t, struct mscp *);
955 int	rrioerror(device_t, struct mscp *, struct buf *);
956 void	rrfillin(struct buf *, struct mscp *);
957 void	rrbb(device_t, struct mscp *, struct buf *);
958 
959 
960 struct	mscp_device ra_device = {
961 	rrdgram,
962 	rriodone,
963 	rronline,
964 	rrgotstatus,
965 	rrreplace,
966 	rrioerror,
967 	rrbb,
968 	rrfillin,
969 };
970 
971 /*
972  * Handle an error datagram.
973  * This can come from an unconfigured drive as well.
974  */
975 void
976 rrdgram(device_t usc, struct mscp *mp, struct mscp_softc *mi)
977 {
978 	if (mscp_decodeerror(usc == NULL?"unconf disk" : device_xname(usc), mp, mi))
979 		return;
980 	/*
981 	 * SDI status information bytes 10 and 11 are the microprocessor
982 	 * error code and front panel code respectively.  These vary per
983 	 * drive type and are printed purely for field service information.
984 	 */
985 	if (mp->mscp_format == M_FM_SDI)
986 		printf("\tsdi uproc error code 0x%x, front panel code 0x%x\n",
987 			mp->mscp_erd.erd_sdistat[10],
988 			mp->mscp_erd.erd_sdistat[11]);
989 }
990 
991 
992 void
993 rriodone(device_t usc, struct buf *bp)
994 {
995 	struct ra_softc *ra = device_private(usc);
996 
997 	disk_unbusy(&ra->ra_disk, bp->b_bcount, (bp->b_flags & B_READ));
998 
999 	biodone(bp);
1000 }
1001 
1002 /*
1003  * A drive came on line.  Check its type and size.  Return DONE if
1004  * we think the drive is truly on line.	 In any case, awaken anyone
1005  * sleeping on the drive on-line-ness.
1006  */
1007 int
1008 rronline(device_t usc, struct mscp *mp)
1009 {
1010 	struct ra_softc *ra = device_private(usc);
1011 	struct disklabel *dl;
1012 
1013 	wakeup((void *)&ra->ra_state);
1014 	if ((mp->mscp_status & M_ST_MASK) != M_ST_SUCCESS) {
1015 		aprint_error_dev(usc, "attempt to bring on line failed: ");
1016 		mscp_printevent(mp);
1017 		return (MSCP_FAILED);
1018 	}
1019 
1020 	ra->ra_state = DK_OPEN;
1021 
1022 	dl = ra->ra_disk.dk_label;
1023 	dl->d_secperunit = (daddr_t)mp->mscp_onle.onle_unitsize;
1024 
1025 	if (dl->d_secpercyl) {
1026 		dl->d_ncylinders = dl->d_secperunit/dl->d_secpercyl;
1027 		dl->d_type = DTYPE_MSCP;
1028 		dl->d_rpm = 3600;
1029 	} else {
1030 		dl->d_type = DTYPE_FLOPPY;
1031 		dl->d_rpm = 300;
1032 	}
1033 	rrmakelabel(dl, ra->ra_mediaid);
1034 
1035 	return (MSCP_DONE);
1036 }
1037 
1038 void
1039 rrmakelabel(struct disklabel *dl, long type)
1040 {
1041 	int n, p = 0;
1042 
1043 	dl->d_bbsize = BBSIZE;
1044 	dl->d_sbsize = SBLOCKSIZE;
1045 
1046 	/* Create the disk name for disklabel. Phew... */
1047 	dl->d_typename[p++] = MSCP_MID_CHAR(2, type);
1048 	dl->d_typename[p++] = MSCP_MID_CHAR(1, type);
1049 	if (MSCP_MID_ECH(0, type))
1050 		dl->d_typename[p++] = MSCP_MID_CHAR(0, type);
1051 	n = MSCP_MID_NUM(type);
1052 	if (n > 99) {
1053 		dl->d_typename[p++] = '1';
1054 		n -= 100;
1055 	}
1056 	if (n > 9) {
1057 		dl->d_typename[p++] = (n / 10) + '0';
1058 		n %= 10;
1059 	}
1060 	dl->d_typename[p++] = n + '0';
1061 	dl->d_typename[p] = 0;
1062 	dl->d_npartitions = MAXPARTITIONS;
1063 	dl->d_partitions[0].p_size = dl->d_partitions[2].p_size =
1064 	    dl->d_secperunit;
1065 	dl->d_partitions[0].p_offset = dl->d_partitions[2].p_offset = 0;
1066 	dl->d_interleave = dl->d_headswitch = 1;
1067 	dl->d_magic = dl->d_magic2 = DISKMAGIC;
1068 	dl->d_checksum = dkcksum(dl);
1069 }
1070 
1071 /*
1072  * We got some (configured) unit's status.  Return DONE if it succeeded.
1073  */
1074 int
1075 rrgotstatus(device_t usc, struct mscp *mp)
1076 {
1077 	if ((mp->mscp_status & M_ST_MASK) != M_ST_SUCCESS) {
1078 		aprint_error_dev(usc, "attempt to get status failed: ");
1079 		mscp_printevent(mp);
1080 		return (MSCP_FAILED);
1081 	}
1082 	/* record for (future) bad block forwarding and whatever else */
1083 #ifdef notyet
1084 	uda_rasave(ui->ui_unit, mp, 1);
1085 #endif
1086 	return (MSCP_DONE);
1087 }
1088 
1089 /*
1090  * A replace operation finished.
1091  */
1092 /*ARGSUSED*/
1093 void
1094 rrreplace(device_t usc, struct mscp *mp)
1095 {
1096 
1097 	panic("udareplace");
1098 }
1099 
1100 /*
1101  * A transfer failed.  We get a chance to fix or restart it.
1102  * Need to write the bad block forwaring code first....
1103  */
1104 /*ARGSUSED*/
1105 int
1106 rrioerror(device_t usc, struct mscp *mp, struct buf *bp)
1107 {
1108 	struct ra_softc *ra = device_private(usc);
1109 	int code = mp->mscp_event;
1110 
1111 	switch (code & M_ST_MASK) {
1112 	/* The unit has fallen offline. Try to figure out why. */
1113 	case M_ST_OFFLINE:
1114 		bp->b_error = EIO;
1115 		ra->ra_state = DK_CLOSED;
1116 		if (code & M_OFFLINE_UNMOUNTED)
1117 			aprint_error_dev(usc, "not mounted/spun down\n");
1118 		if (code & M_OFFLINE_DUPLICATE)
1119 			aprint_error_dev(usc, "duplicate unit number!!!\n");
1120 		return MSCP_DONE;
1121 
1122 	case M_ST_AVAILABLE:
1123 		ra->ra_state = DK_CLOSED; /* Force another online */
1124 		return MSCP_DONE;
1125 
1126 	default:
1127 		printf("%s:", device_xname(usc));
1128 		break;
1129 	}
1130 	return (MSCP_FAILED);
1131 }
1132 
1133 /*
1134  * Fill in disk addresses in a mscp packet waiting for transfer.
1135  */
1136 void
1137 rrfillin(struct buf *bp, struct mscp *mp)
1138 {
1139 	struct ra_softc *ra;
1140 	struct disklabel *lp;
1141 	int part = DISKPART(bp->b_dev);
1142 
1143 	ra = mscp_device_lookup(bp->b_dev);
1144 	lp = ra->ra_disk.dk_label;
1145 
1146 	mp->mscp_seq.seq_lbn = lp->d_partitions[part].p_offset + bp->b_blkno;
1147 	mp->mscp_unit = ra->ra_hwunit;
1148 	mp->mscp_seq.seq_bytecount = bp->b_bcount;
1149 }
1150 
1151 /*
1152  * A bad block related operation finished.
1153  */
1154 /*ARGSUSED*/
1155 void
1156 rrbb(device_t usc, struct mscp *mp, struct buf *bp)
1157 {
1158 
1159 	panic("udabb");
1160 }
1161 
1162 /*
1163  * (Try to) put the drive online. This is done the first time the
1164  * drive is opened, or if it has fallen offline.
1165  */
1166 int
1167 ra_putonline(dev_t dev, struct ra_softc *ra)
1168 {
1169 	struct	disklabel *dl;
1170 	const char *msg;
1171 
1172 	if (rx_putonline(ra) != MSCP_DONE)
1173 		return MSCP_FAILED;
1174 
1175 	dl = ra->ra_disk.dk_label;
1176 
1177 	ra->ra_state = DK_RDLABEL;
1178 	printf("%s", device_xname(ra->ra_dev));
1179 	if ((msg = readdisklabel(
1180 	    MAKEDISKDEV(major(dev), device_unit(ra->ra_dev), RAW_PART),
1181 	    rastrategy, dl, NULL)) == NULL) {
1182 		ra->ra_havelabel = 1;
1183 		ra->ra_state = DK_OPEN;
1184 	}
1185 #if NRACD
1186 	else if (cdevsw_lookup(dev) == &racd_cdevsw) {
1187 		dl->d_partitions[0].p_offset = 0;
1188 		dl->d_partitions[0].p_size = dl->d_secperunit;
1189 		dl->d_partitions[0].p_fstype = FS_ISO9660;
1190 	}
1191 #endif /* NRACD */
1192 	else {
1193 		printf(": %s", msg);
1194 	}
1195 
1196 	printf(": size %d sectors\n", dl->d_secperunit);
1197 
1198 	return MSCP_DONE;
1199 }
1200 
1201 
1202 static inline struct ra_softc *
1203 mscp_device_lookup(dev_t dev)
1204 {
1205 	struct ra_softc *ra;
1206 	int unit;
1207 
1208 	unit = DISKUNIT(dev);
1209 #if NRA
1210 	if (cdevsw_lookup(dev) == &ra_cdevsw)
1211 		ra = device_lookup_private(&ra_cd, unit);
1212 	else
1213 #endif
1214 #if NRACD
1215 	if (cdevsw_lookup(dev) == &racd_cdevsw)
1216 		ra = device_lookup_private(&racd_cd, unit);
1217 	else
1218 #endif
1219 #if NRX
1220 	if (cdevsw_lookup(dev) == &rx_cdevsw)
1221 		ra = device_lookup_private(&rx_cd, unit);
1222 	else
1223 #endif
1224 		panic("mscp_device_lookup: unexpected major %"PRIu32" unit %u",
1225 		    major(dev), unit);
1226 	return ra;
1227 }
1228