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