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