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