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