Home | History | Annotate | Line # | Download | only in mscp
mscp_disk.c revision 1.25
      1 /*	$NetBSD: mscp_disk.c,v 1.25 2000/05/27 04:52:35 thorpej Exp $	*/
      2 /*
      3  * Copyright (c) 1996 Ludd, University of Lule}, Sweden.
      4  * Copyright (c) 1988 Regents of the University of California.
      5  * All rights reserved.
      6  *
      7  * This code is derived from software contributed to Berkeley by
      8  * Chris Torek.
      9  *
     10  * Redistribution and use in source and binary forms, with or without
     11  * modification, are permitted provided that the following conditions
     12  * are met:
     13  * 1. Redistributions of source code must retain the above copyright
     14  *    notice, this list of conditions and the following disclaimer.
     15  * 2. Redistributions in binary form must reproduce the above copyright
     16  *    notice, this list of conditions and the following disclaimer in the
     17  *    documentation and/or other materials provided with the distribution.
     18  * 3. All advertising materials mentioning features or use of this software
     19  *    must display the following acknowledgement:
     20  *	This product includes software developed by the University of
     21  *	California, Berkeley and its contributors.
     22  * 4. Neither the name of the University nor the names of its contributors
     23  *    may be used to endorse or promote products derived from this software
     24  *    without specific prior written permission.
     25  *
     26  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     27  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     28  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     29  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     30  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     31  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     32  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     33  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     34  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     35  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     36  * SUCH DAMAGE.
     37  *
     38  *	@(#)uda.c	7.32 (Berkeley) 2/13/91
     39  */
     40 
     41 /*
     42  * RA disk device driver
     43  * RX MSCP floppy disk device driver
     44  */
     45 
     46 /*
     47  * TODO
     48  *	write bad block forwarding code
     49  */
     50 
     51 #include <sys/param.h>
     52 #include <sys/buf.h>
     53 #include <sys/device.h>
     54 #include <sys/disk.h>
     55 #include <sys/disklabel.h>
     56 #include <sys/ioctl.h>
     57 #include <sys/stat.h>
     58 #include <sys/fcntl.h>
     59 #include <sys/reboot.h>
     60 #include <sys/proc.h>
     61 #include <sys/systm.h>
     62 
     63 #include <ufs/ufs/dinode.h>
     64 #include <ufs/ffs/fs.h>
     65 
     66 #include <machine/bus.h>
     67 #include <machine/cpu.h>
     68 
     69 #include <dev/mscp/mscp.h>
     70 #include <dev/mscp/mscpreg.h>
     71 #include <dev/mscp/mscpvar.h>
     72 
     73 #include "locators.h"
     74 #include "ioconf.h"
     75 #include "ra.h"
     76 
     77 #define RAMAJOR 9	/* RA major device number XXX */
     78 
     79 /*
     80  * Drive status, per drive
     81  */
     82 struct ra_softc {
     83 	struct	device ra_dev;	/* Autoconf struct */
     84 	struct	disk ra_disk;
     85 	int	ra_state;	/* open/closed state */
     86 	u_long	ra_mediaid;	/* media id */
     87 	int	ra_hwunit;	/* Hardware unit number */
     88 	int	ra_havelabel;	/* true if we have a label */
     89 	int	ra_wlabel;	/* label sector is currently writable */
     90 };
     91 
     92 #define rx_softc ra_softc
     93 
     94 void	rxattach __P((struct device *, struct device *, void *));
     95 int	rx_putonline __P((struct rx_softc *));
     96 void	rrmakelabel __P((struct disklabel *, long));
     97 
     98 #if NRA
     99 
    100 int	ramatch __P((struct device *, struct cfdata *, void *));
    101 void	raattach __P((struct device *, struct device *, void *));
    102 int	raopen __P((dev_t, int, int, struct proc *));
    103 int	raclose __P((dev_t, int, int, struct proc *));
    104 void	rastrategy __P((struct buf *));
    105 int	raread __P((dev_t, struct uio *));
    106 int	rawrite __P((dev_t, struct uio *));
    107 int	raioctl __P((dev_t, int, caddr_t, int, struct proc *));
    108 int	radump __P((dev_t, daddr_t, caddr_t, size_t));
    109 int	rasize __P((dev_t));
    110 int	ra_putonline __P((struct ra_softc *));
    111 
    112 struct	cfattach ra_ca = {
    113 	sizeof(struct ra_softc), ramatch, rxattach
    114 };
    115 
    116 /*
    117  * More driver definitions, for generic MSCP code.
    118  */
    119 
    120 int
    121 ramatch(parent, cf, aux)
    122 	struct	device *parent;
    123 	struct	cfdata *cf;
    124 	void	*aux;
    125 {
    126 	struct	drive_attach_args *da = aux;
    127 	struct	mscp *mp = da->da_mp;
    128 
    129 	if ((da->da_typ & MSCPBUS_DISK) == 0)
    130 		return 0;
    131 	if (cf->cf_loc[MSCPBUSCF_DRIVE] != MSCPBUSCF_DRIVE_DEFAULT &&
    132 	    cf->cf_loc[MSCPBUSCF_DRIVE] != mp->mscp_unit)
    133 		return 0;
    134 	/*
    135 	 * Check if this disk is a floppy; then don't configure it.
    136 	 * Seems to be a safe way to test it per Chris Torek.
    137 	 */
    138 	if (MSCP_MID_ECH(1, mp->mscp_guse.guse_mediaid) == 'X' - '@')
    139 		return 0;
    140 	return 1;
    141 }
    142 
    143 /*
    144  * (Try to) put the drive online. This is done the first time the
    145  * drive is opened, or if it har fallen offline.
    146  */
    147 int
    148 ra_putonline(ra)
    149 	struct ra_softc *ra;
    150 {
    151 	struct	disklabel *dl;
    152 	char *msg;
    153 
    154 	if (rx_putonline(ra) != MSCP_DONE)
    155 		return MSCP_FAILED;
    156 
    157 	dl = ra->ra_disk.dk_label;
    158 
    159 	ra->ra_state = DK_RDLABEL;
    160 	printf("%s", ra->ra_dev.dv_xname);
    161 	if ((msg = readdisklabel(MAKEDISKDEV(RAMAJOR, ra->ra_dev.dv_unit,
    162 	    RAW_PART), rastrategy, dl, NULL)) != NULL)
    163 		printf(": %s", msg);
    164 	else {
    165 		ra->ra_havelabel = 1;
    166 		ra->ra_state = DK_OPEN;
    167 	}
    168 
    169 	printf(": size %d sectors\n", dl->d_secperunit);
    170 
    171 	return MSCP_DONE;
    172 }
    173 
    174 /*
    175  * Open a drive.
    176  */
    177 /*ARGSUSED*/
    178 int
    179 raopen(dev, flag, fmt, p)
    180 	dev_t dev;
    181 	int flag, fmt;
    182 	struct	proc *p;
    183 {
    184 	struct ra_softc *ra;
    185 	int part, unit, mask;
    186 	/*
    187 	 * Make sure this is a reasonable open request.
    188 	 */
    189 	unit = DISKUNIT(dev);
    190 	if (unit >= ra_cd.cd_ndevs)
    191 		return ENXIO;
    192 	ra = ra_cd.cd_devs[unit];
    193 	if (ra == 0)
    194 		return ENXIO;
    195 
    196 	/*
    197 	 * If this is the first open; we must first try to put
    198 	 * the disk online (and read the label).
    199 	 */
    200 	if (ra->ra_state == DK_CLOSED)
    201 		if (ra_putonline(ra) == MSCP_FAILED)
    202 			return ENXIO;
    203 
    204 	/* If the disk has no label; allow writing everywhere */
    205 	if (ra->ra_havelabel == 0)
    206 		ra->ra_wlabel = 1;
    207 
    208 	part = DISKPART(dev);
    209 	if (part >= ra->ra_disk.dk_label->d_npartitions)
    210 		return ENXIO;
    211 
    212 	/*
    213 	 * Wait for the state to settle
    214 	 */
    215 #if notyet
    216 	while (ra->ra_state != DK_OPEN)
    217 		if ((error = tsleep((caddr_t)ra, (PZERO + 1) | PCATCH,
    218 		    devopn, 0))) {
    219 			splx(s);
    220 			return (error);
    221 		}
    222 #endif
    223 
    224 	mask = 1 << part;
    225 
    226 	switch (fmt) {
    227 	case S_IFCHR:
    228 		ra->ra_disk.dk_copenmask |= mask;
    229 		break;
    230 	case S_IFBLK:
    231 		ra->ra_disk.dk_bopenmask |= mask;
    232 		break;
    233 	}
    234 	ra->ra_disk.dk_openmask |= mask;
    235 	return 0;
    236 }
    237 
    238 /* ARGSUSED */
    239 int
    240 raclose(dev, flags, fmt, p)
    241 	dev_t dev;
    242 	int flags, fmt;
    243 	struct	proc *p;
    244 {
    245 	int unit = DISKUNIT(dev);
    246 	struct ra_softc *ra = ra_cd.cd_devs[unit];
    247 	int mask = (1 << DISKPART(dev));
    248 
    249 	switch (fmt) {
    250 	case S_IFCHR:
    251 		ra->ra_disk.dk_copenmask &= ~mask;
    252 		break;
    253 	case S_IFBLK:
    254 		ra->ra_disk.dk_bopenmask &= ~mask;
    255 		break;
    256 	}
    257 	ra->ra_disk.dk_openmask =
    258 	    ra->ra_disk.dk_copenmask | ra->ra_disk.dk_bopenmask;
    259 
    260 	/*
    261 	 * Should wait for I/O to complete on this partition even if
    262 	 * others are open, but wait for work on blkflush().
    263 	 */
    264 #if notyet
    265 	if (ra->ra_openpart == 0) {
    266 		s = splimp();
    267 		while (BUFQ_FIRST(&udautab[unit]) != NULL)
    268 			(void) tsleep(&udautab[unit], PZERO - 1,
    269 			    "raclose", 0);
    270 		splx(s);
    271 		ra->ra_state = CLOSED;
    272 		ra->ra_wlabel = 0;
    273 	}
    274 #endif
    275 	return (0);
    276 }
    277 
    278 /*
    279  * Queue a transfer request, and if possible, hand it to the controller.
    280  */
    281 void
    282 rastrategy(bp)
    283 	struct buf *bp;
    284 {
    285 	int unit;
    286 	struct ra_softc *ra;
    287 	/*
    288 	 * Make sure this is a reasonable drive to use.
    289 	 */
    290 	unit = DISKUNIT(bp->b_dev);
    291 	if (unit > ra_cd.cd_ndevs || (ra = ra_cd.cd_devs[unit]) == NULL) {
    292 		bp->b_error = ENXIO;
    293 		bp->b_flags |= B_ERROR;
    294 		goto done;
    295 	}
    296 	/*
    297 	 * If drive is open `raw' or reading label, let it at it.
    298 	 */
    299 	if (ra->ra_state == DK_RDLABEL) {
    300 		mscp_strategy(bp, ra->ra_dev.dv_parent);
    301 		return;
    302 	}
    303 
    304 	/* If disk is not online, try to put it online */
    305 	if (ra->ra_state == DK_CLOSED)
    306 		if (ra_putonline(ra) == MSCP_FAILED) {
    307 			bp->b_flags |= B_ERROR;
    308 			bp->b_error = EIO;
    309 			goto done;
    310 		}
    311 
    312 	/*
    313 	 * Determine the size of the transfer, and make sure it is
    314 	 * within the boundaries of the partition.
    315 	 */
    316 	if (bounds_check_with_label(bp, ra->ra_disk.dk_label,
    317 	    ra->ra_wlabel) <= 0)
    318 		goto done;
    319 
    320 	/* Make some statistics... /bqt */
    321 	ra->ra_disk.dk_xfer++;
    322 	ra->ra_disk.dk_bytes += bp->b_bcount;
    323 	mscp_strategy(bp, ra->ra_dev.dv_parent);
    324 	return;
    325 
    326 done:
    327 	biodone(bp);
    328 }
    329 
    330 int
    331 raread(dev, uio)
    332 	dev_t dev;
    333 	struct uio *uio;
    334 {
    335 
    336 	return (physio(rastrategy, NULL, dev, B_READ, minphys, uio));
    337 }
    338 
    339 int
    340 rawrite(dev, uio)
    341 	dev_t dev;
    342 	struct uio *uio;
    343 {
    344 
    345 	return (physio(rastrategy, NULL, dev, B_WRITE, minphys, uio));
    346 }
    347 
    348 /*
    349  * I/O controls.
    350  */
    351 int
    352 raioctl(dev, cmd, data, flag, p)
    353 	dev_t dev;
    354 	int cmd;
    355 	caddr_t data;
    356 	int flag;
    357 	struct proc *p;
    358 {
    359 	int unit = DISKUNIT(dev);
    360 	struct disklabel *lp, *tp;
    361 	struct ra_softc *ra = ra_cd.cd_devs[unit];
    362 	int error = 0;
    363 
    364 	lp = ra->ra_disk.dk_label;
    365 
    366 	switch (cmd) {
    367 
    368 	case DIOCGDINFO:
    369 		bcopy(lp, data, sizeof (struct disklabel));
    370 		break;
    371 
    372 	case DIOCGPART:
    373 		((struct partinfo *)data)->disklab = lp;
    374 		((struct partinfo *)data)->part =
    375 		    &lp->d_partitions[DISKPART(dev)];
    376 		break;
    377 
    378 	case DIOCWDINFO:
    379 	case DIOCSDINFO:
    380 		if ((flag & FWRITE) == 0)
    381 			error = EBADF;
    382 		else {
    383 			error = setdisklabel(lp, (struct disklabel *)data,0,0);
    384 			if ((error == 0) && (cmd == DIOCWDINFO)) {
    385 				ra->ra_wlabel = 1;
    386 				error = writedisklabel(dev, rastrategy, lp,0);
    387 				ra->ra_wlabel = 0;
    388 			}
    389 		}
    390 		break;
    391 
    392 	case DIOCWLABEL:
    393 		if ((flag & FWRITE) == 0)
    394 			error = EBADF;
    395 		else
    396 			ra->ra_wlabel = 1;
    397 		break;
    398 
    399 	case DIOCGDEFLABEL:
    400 		tp = (struct disklabel *)data;
    401 		bzero(data, sizeof(struct disklabel));
    402 		tp->d_secsize = lp->d_secsize;
    403 		tp->d_nsectors = lp->d_nsectors;
    404 		tp->d_ntracks = lp->d_ntracks;
    405 		tp->d_ncylinders = lp->d_ncylinders;
    406 		tp->d_secpercyl = lp->d_secpercyl;
    407 		tp->d_secperunit = lp->d_secperunit;
    408 		tp->d_type = DTYPE_MSCP;
    409 		tp->d_rpm = 3600;
    410 		rrmakelabel(tp, ra->ra_mediaid);
    411 		break;
    412 
    413 	default:
    414 		error = ENOTTY;
    415 		break;
    416 	}
    417 	return (error);
    418 }
    419 
    420 
    421 int
    422 radump(dev, blkno, va, size)
    423 	dev_t	dev;
    424 	daddr_t blkno;
    425 	caddr_t va;
    426 	size_t	size;
    427 {
    428 	return ENXIO;
    429 }
    430 
    431 /*
    432  * Return the size of a partition, if known, or -1 if not.
    433  */
    434 int
    435 rasize(dev)
    436 	dev_t dev;
    437 {
    438 	int unit = DISKUNIT(dev);
    439 	struct ra_softc *ra;
    440 
    441 	if (unit >= ra_cd.cd_ndevs || ra_cd.cd_devs[unit] == 0)
    442 		return -1;
    443 
    444 	ra = ra_cd.cd_devs[unit];
    445 
    446 	if (ra->ra_state == DK_CLOSED)
    447 		if (ra_putonline(ra) == MSCP_FAILED)
    448 			return -1;
    449 
    450 	return ra->ra_disk.dk_label->d_partitions[DISKPART(dev)].p_size *
    451 	    (ra->ra_disk.dk_label->d_secsize / DEV_BSIZE);
    452 }
    453 
    454 #endif /* NRA */
    455 
    456 #if NRX
    457 
    458 int	rxmatch __P((struct device *, struct cfdata *, void *));
    459 int	rxopen __P((dev_t, int, int, struct proc *));
    460 int	rxclose __P((dev_t, int, int, struct proc *));
    461 void	rxstrategy __P((struct buf *));
    462 int	rxread __P((dev_t, struct uio *));
    463 int	rxwrite __P((dev_t, struct uio *));
    464 int	rxioctl __P((dev_t, int, caddr_t, int, struct proc *));
    465 int	rxdump __P((dev_t, daddr_t, caddr_t, size_t));
    466 int	rxsize __P((dev_t));
    467 
    468 struct	cfattach rx_ca = {
    469 	sizeof(struct rx_softc), rxmatch, rxattach
    470 };
    471 
    472 /*
    473  * More driver definitions, for generic MSCP code.
    474  */
    475 
    476 int
    477 rxmatch(parent, cf, aux)
    478 	struct	device *parent;
    479 	struct	cfdata *cf;
    480 	void	*aux;
    481 {
    482 	struct	drive_attach_args *da = aux;
    483 	struct	mscp *mp = da->da_mp;
    484 
    485 	if ((da->da_typ & MSCPBUS_DISK) == 0)
    486 		return 0;
    487 	if (cf->cf_loc[MSCPBUSCF_DRIVE] != MSCPBUSCF_DRIVE_DEFAULT &&
    488 	    cf->cf_loc[MSCPBUSCF_DRIVE] != mp->mscp_unit)
    489 		return 0;
    490 	/*
    491 	 * Check if this disk is a floppy; then configure it.
    492 	 * Seems to be a safe way to test it per Chris Torek.
    493 	 */
    494 	if (MSCP_MID_ECH(1, mp->mscp_guse.guse_mediaid) == 'X' - '@')
    495 		return 1;
    496 	return 0;
    497 }
    498 
    499 #endif /* NRX */
    500 
    501 /*
    502  * The attach routine only checks and prints drive type.
    503  * Bringing the disk online is done when the disk is accessed
    504  * the first time.
    505  */
    506 void
    507 rxattach(parent, self, aux)
    508 	struct	device *parent, *self;
    509 	void	*aux;
    510 {
    511 	struct	rx_softc *rx = (void *)self;
    512 	struct	drive_attach_args *da = aux;
    513 	struct	mscp *mp = da->da_mp;
    514 	struct	mscp_softc *mi = (void *)parent;
    515 	struct	disklabel *dl;
    516 
    517 	rx->ra_mediaid = mp->mscp_guse.guse_mediaid;
    518 	rx->ra_state = DK_CLOSED;
    519 	rx->ra_hwunit = mp->mscp_unit;
    520 	mi->mi_dp[mp->mscp_unit] = self;
    521 
    522 	rx->ra_disk.dk_name = rx->ra_dev.dv_xname;
    523 	disk_attach((struct disk *)&rx->ra_disk);
    524 
    525 	/* Fill in what we know. The actual size is gotten later */
    526 	dl = rx->ra_disk.dk_label;
    527 
    528 	dl->d_secsize = DEV_BSIZE;
    529 	dl->d_nsectors = mp->mscp_guse.guse_nspt;
    530 	dl->d_ntracks = mp->mscp_guse.guse_ngpc * mp->mscp_guse.guse_group;
    531 	dl->d_secpercyl = dl->d_nsectors * dl->d_ntracks;
    532 	disk_printtype(mp->mscp_unit, mp->mscp_guse.guse_mediaid);
    533 #ifdef DEBUG
    534 	printf("%s: nspt %d group %d ngpc %d rct %d nrpt %d nrct %d\n",
    535 	    self->dv_xname, mp->mscp_guse.guse_nspt, mp->mscp_guse.guse_group,
    536 	    mp->mscp_guse.guse_ngpc, mp->mscp_guse.guse_rctsize,
    537 	    mp->mscp_guse.guse_nrpt, mp->mscp_guse.guse_nrct);
    538 #endif
    539 }
    540 
    541 /*
    542  * (Try to) put the drive online. This is done the first time the
    543  * drive is opened, or if it har fallen offline.
    544  */
    545 int
    546 rx_putonline(rx)
    547 	struct rx_softc *rx;
    548 {
    549 	struct	mscp *mp;
    550 	struct	mscp_softc *mi = (struct mscp_softc *)rx->ra_dev.dv_parent;
    551 	volatile int i;
    552 
    553 	rx->ra_state = DK_CLOSED;
    554 	mp = mscp_getcp(mi, MSCP_WAIT);
    555 	mp->mscp_opcode = M_OP_ONLINE;
    556 	mp->mscp_unit = rx->ra_hwunit;
    557 	mp->mscp_cmdref = 1;
    558 	*mp->mscp_addr |= MSCP_OWN | MSCP_INT;
    559 
    560 	/* Poll away */
    561 	i = bus_space_read_2(mi->mi_iot, mi->mi_iph, 0);
    562 	if (tsleep(&rx->ra_dev.dv_unit, PRIBIO, "rxonline", 100*100))
    563 		rx->ra_state = DK_CLOSED;
    564 
    565 	if (rx->ra_state == DK_CLOSED)
    566 		return MSCP_FAILED;
    567 
    568 	return MSCP_DONE;
    569 }
    570 
    571 #if NRX
    572 
    573 /*
    574  * Open a drive.
    575  */
    576 /*ARGSUSED*/
    577 int
    578 rxopen(dev, flag, fmt, p)
    579 	dev_t dev;
    580 	int flag, fmt;
    581 	struct	proc *p;
    582 {
    583 	struct rx_softc *rx;
    584 	int unit;
    585 
    586 	/*
    587 	 * Make sure this is a reasonable open request.
    588 	 */
    589 	unit = DISKUNIT(dev);
    590 	if (unit >= rx_cd.cd_ndevs)
    591 		return ENXIO;
    592 	rx = rx_cd.cd_devs[unit];
    593 	if (rx == 0)
    594 		return ENXIO;
    595 
    596 	/*
    597 	 * If this is the first open; we must first try to put
    598 	 * the disk online (and read the label).
    599 	 */
    600 	if (rx->ra_state == DK_CLOSED)
    601 		if (rx_putonline(rx) == MSCP_FAILED)
    602 			return ENXIO;
    603 
    604 	return 0;
    605 }
    606 
    607 /* ARGSUSED */
    608 int
    609 rxclose(dev, flags, fmt, p)
    610 	dev_t dev;
    611 	int flags, fmt;
    612 	struct	proc *p;
    613 {
    614 	return (0);
    615 }
    616 
    617 /*
    618  * Queue a transfer request, and if possible, hand it to the controller.
    619  *
    620  * This routine is broken into two so that the internal version
    621  * udastrat1() can be called by the (nonexistent, as yet) bad block
    622  * revectoring routine.
    623  */
    624 void
    625 rxstrategy(bp)
    626 	struct buf *bp;
    627 {
    628 	int unit;
    629 	struct rx_softc *rx;
    630 
    631 	/*
    632 	 * Make sure this is a reasonable drive to use.
    633 	 */
    634 	unit = DISKUNIT(bp->b_dev);
    635 	if (unit > rx_cd.cd_ndevs || (rx = rx_cd.cd_devs[unit]) == NULL) {
    636 		bp->b_error = ENXIO;
    637 		bp->b_flags |= B_ERROR;
    638 		goto done;
    639 	}
    640 
    641 	/* If disk is not online, try to put it online */
    642 	if (rx->ra_state == DK_CLOSED)
    643 		if (rx_putonline(rx) == MSCP_FAILED) {
    644 			bp->b_flags |= B_ERROR;
    645 			bp->b_error = EIO;
    646 			goto done;
    647 		}
    648 
    649 	/*
    650 	 * Determine the size of the transfer, and make sure it is
    651 	 * within the boundaries of the partition.
    652 	 */
    653 	if (bp->b_blkno >= rx->ra_disk.dk_label->d_secperunit) {
    654 		bp->b_resid = bp->b_bcount;
    655 		goto done;
    656 	}
    657 
    658 	/* Make some statistics... /bqt */
    659 	rx->ra_disk.dk_xfer++;
    660 	rx->ra_disk.dk_bytes += bp->b_bcount;
    661 	mscp_strategy(bp, rx->ra_dev.dv_parent);
    662 	return;
    663 
    664 done:
    665 	biodone(bp);
    666 }
    667 
    668 int
    669 rxread(dev, uio)
    670 	dev_t dev;
    671 	struct uio *uio;
    672 {
    673 
    674 	return (physio(rxstrategy, NULL, dev, B_READ, minphys, uio));
    675 }
    676 
    677 int
    678 rxwrite(dev, uio)
    679 	dev_t dev;
    680 	struct uio *uio;
    681 {
    682 
    683 	return (physio(rxstrategy, NULL, dev, B_WRITE, minphys, uio));
    684 }
    685 
    686 /*
    687  * I/O controls.
    688  */
    689 int
    690 rxioctl(dev, cmd, data, flag, p)
    691 	dev_t dev;
    692 	int cmd;
    693 	caddr_t data;
    694 	int flag;
    695 	struct proc *p;
    696 {
    697 	int unit = DISKUNIT(dev);
    698 	struct disklabel *lp;
    699 	struct rx_softc *rx = rx_cd.cd_devs[unit];
    700 	int error = 0;
    701 
    702 	lp = rx->ra_disk.dk_label;
    703 
    704 	switch (cmd) {
    705 
    706 	case DIOCGDINFO:
    707 		bcopy(lp, data, sizeof (struct disklabel));
    708 		break;
    709 
    710 	case DIOCGPART:
    711 		((struct partinfo *)data)->disklab = lp;
    712 		((struct partinfo *)data)->part =
    713 		    &lp->d_partitions[DISKPART(dev)];
    714 		break;
    715 
    716 
    717 	case DIOCWDINFO:
    718 	case DIOCSDINFO:
    719 	case DIOCWLABEL:
    720 		break;
    721 
    722 	default:
    723 		error = ENOTTY;
    724 		break;
    725 	}
    726 	return (error);
    727 }
    728 
    729 int
    730 rxdump(dev, blkno, va, size)
    731 	dev_t dev;
    732 	daddr_t blkno;
    733 	caddr_t va;
    734 	size_t size;
    735 {
    736 
    737 	/* Not likely. */
    738 	return ENXIO;
    739 }
    740 
    741 int
    742 rxsize(dev)
    743 	dev_t dev;
    744 {
    745 
    746 	return -1;
    747 }
    748 
    749 #endif /* NRX */
    750 
    751 void	rrdgram __P((struct device *, struct mscp *, struct mscp_softc *));
    752 void	rriodone __P((struct device *, struct buf *));
    753 int	rronline __P((struct device *, struct mscp *));
    754 int	rrgotstatus __P((struct device *, struct mscp *));
    755 void	rrreplace __P((struct device *, struct mscp *));
    756 int	rrioerror __P((struct device *, struct mscp *, struct buf *));
    757 void	rrfillin __P((struct buf *, struct mscp *));
    758 void	rrbb __P((struct device *, struct mscp *, struct buf *));
    759 
    760 
    761 struct	mscp_device ra_device = {
    762 	rrdgram,
    763 	rriodone,
    764 	rronline,
    765 	rrgotstatus,
    766 	rrreplace,
    767 	rrioerror,
    768 	rrbb,
    769 	rrfillin,
    770 };
    771 
    772 /*
    773  * Handle an error datagram.
    774  * This can come from an unconfigured drive as well.
    775  */
    776 void
    777 rrdgram(usc, mp, mi)
    778 	struct device *usc;
    779 	struct mscp *mp;
    780 	struct mscp_softc *mi;
    781 {
    782 	if (mscp_decodeerror(usc == NULL?"unconf disk" : usc->dv_xname, mp, mi))
    783 		return;
    784 	/*
    785 	 * SDI status information bytes 10 and 11 are the microprocessor
    786 	 * error code and front panel code respectively.  These vary per
    787 	 * drive type and are printed purely for field service information.
    788 	 */
    789 	if (mp->mscp_format == M_FM_SDI)
    790 		printf("\tsdi uproc error code 0x%x, front panel code 0x%x\n",
    791 			mp->mscp_erd.erd_sdistat[10],
    792 			mp->mscp_erd.erd_sdistat[11]);
    793 }
    794 
    795 void
    796 rriodone(usc, bp)
    797 	struct device *usc;
    798 	struct buf *bp;
    799 {
    800 
    801 	biodone(bp);
    802 }
    803 
    804 /*
    805  * A drive came on line.  Check its type and size.  Return DONE if
    806  * we think the drive is truly on line.	 In any case, awaken anyone
    807  * sleeping on the drive on-line-ness.
    808  */
    809 int
    810 rronline(usc, mp)
    811 	struct device *usc;
    812 	struct mscp *mp;
    813 {
    814 	struct rx_softc *rx = (struct rx_softc *)usc;
    815 	struct disklabel *dl;
    816 
    817 	wakeup((caddr_t)&usc->dv_unit);
    818 	if ((mp->mscp_status & M_ST_MASK) != M_ST_SUCCESS) {
    819 		printf("%s: attempt to bring on line failed: ", usc->dv_xname);
    820 		mscp_printevent(mp);
    821 		return (MSCP_FAILED);
    822 	}
    823 
    824 	rx->ra_state = DK_OPEN;
    825 
    826 	dl = rx->ra_disk.dk_label;
    827 	dl->d_secperunit = (daddr_t)mp->mscp_onle.onle_unitsize;
    828 
    829 	if (dl->d_secpercyl) {
    830 		dl->d_ncylinders = dl->d_secperunit/dl->d_secpercyl;
    831 		dl->d_type = DTYPE_MSCP;
    832 		dl->d_rpm = 3600;
    833 	} else {
    834 		dl->d_type = DTYPE_FLOPPY;
    835 		dl->d_rpm = 300;
    836 	}
    837 	rrmakelabel(dl, rx->ra_mediaid);
    838 
    839 	return (MSCP_DONE);
    840 }
    841 
    842 void
    843 rrmakelabel(dl, type)
    844 	struct disklabel *dl;
    845 	long type;
    846 {
    847 	int n, p = 0;
    848 
    849 	dl->d_bbsize = BBSIZE;
    850 	dl->d_sbsize = SBSIZE;
    851 
    852 	/* Create the disk name for disklabel. Phew... */
    853 	dl->d_typename[p++] = MSCP_MID_CHAR(2, type);
    854 	dl->d_typename[p++] = MSCP_MID_CHAR(1, type);
    855 	if (MSCP_MID_ECH(0, type))
    856 		dl->d_typename[p++] = MSCP_MID_CHAR(0, type);
    857 	n = MSCP_MID_NUM(type);
    858 	if (n > 99) {
    859 		dl->d_typename[p++] = '1';
    860 		n -= 100;
    861 	}
    862 	if (n > 9) {
    863 		dl->d_typename[p++] = (n / 10) + '0';
    864 		n %= 10;
    865 	}
    866 	dl->d_typename[p++] = n + '0';
    867 	dl->d_typename[p] = 0;
    868 	dl->d_npartitions = MAXPARTITIONS;
    869 	dl->d_partitions[0].p_size = dl->d_partitions[2].p_size =
    870 	    dl->d_secperunit;
    871 	dl->d_partitions[0].p_offset = dl->d_partitions[2].p_offset = 0;
    872 	dl->d_interleave = dl->d_headswitch = 1;
    873 	dl->d_magic = dl->d_magic2 = DISKMAGIC;
    874 	dl->d_checksum = dkcksum(dl);
    875 }
    876 
    877 /*
    878  * We got some (configured) unit's status.  Return DONE if it succeeded.
    879  */
    880 int
    881 rrgotstatus(usc, mp)
    882 	struct device *usc;
    883 	struct mscp *mp;
    884 {
    885 	if ((mp->mscp_status & M_ST_MASK) != M_ST_SUCCESS) {
    886 		printf("%s: attempt to get status failed: ", usc->dv_xname);
    887 		mscp_printevent(mp);
    888 		return (MSCP_FAILED);
    889 	}
    890 	/* record for (future) bad block forwarding and whatever else */
    891 #ifdef notyet
    892 	uda_rasave(ui->ui_unit, mp, 1);
    893 #endif
    894 	return (MSCP_DONE);
    895 }
    896 
    897 /*
    898  * A replace operation finished.
    899  */
    900 /*ARGSUSED*/
    901 void
    902 rrreplace(usc, mp)
    903 	struct device *usc;
    904 	struct mscp *mp;
    905 {
    906 
    907 	panic("udareplace");
    908 }
    909 
    910 /*
    911  * A transfer failed.  We get a chance to fix or restart it.
    912  * Need to write the bad block forwaring code first....
    913  */
    914 /*ARGSUSED*/
    915 int
    916 rrioerror(usc, mp, bp)
    917 	struct device *usc;
    918 	struct mscp *mp;
    919 	struct buf *bp;
    920 {
    921 	struct ra_softc *ra = (void *)usc;
    922 	int code = mp->mscp_event;
    923 
    924 	switch (code & M_ST_MASK) {
    925 	/* The unit has fallen offline. Try to figure out why. */
    926 	case M_ST_OFFLINE:
    927 		bp->b_flags |= B_ERROR;
    928 		bp->b_error = EIO;
    929 		ra->ra_state = DK_CLOSED;
    930 		if (code & M_OFFLINE_UNMOUNTED)
    931 			printf("%s: not mounted/spun down\n", usc->dv_xname);
    932 		if (code & M_OFFLINE_DUPLICATE)
    933 			printf("%s: duplicate unit number!!!\n", usc->dv_xname);
    934 		return MSCP_DONE;
    935 
    936 	case M_ST_AVAILABLE:
    937 		ra->ra_state = DK_CLOSED; /* Force another online */
    938 		return MSCP_DONE;
    939 
    940 	default:
    941 		printf("%s:", usc->dv_xname);
    942 		break;
    943 	}
    944 	return (MSCP_FAILED);
    945 }
    946 
    947 /*
    948  * Fill in disk addresses in a mscp packet waiting for transfer.
    949  */
    950 void
    951 rrfillin(bp, mp)
    952 	struct buf *bp;
    953 	struct mscp *mp;
    954 {
    955 	struct rx_softc *rx = 0; /* Wall */
    956 	struct disklabel *lp;
    957 	int unit = DISKUNIT(bp->b_dev);
    958 	int part = DISKPART(bp->b_dev);
    959 
    960 #if NRA
    961 	if (major(bp->b_dev) == RAMAJOR)
    962 		rx = ra_cd.cd_devs[unit];
    963 #endif
    964 #if NRX
    965 	if (major(bp->b_dev) != RAMAJOR)
    966 		rx = rx_cd.cd_devs[unit];
    967 #endif
    968 	lp = rx->ra_disk.dk_label;
    969 
    970 	mp->mscp_seq.seq_lbn = lp->d_partitions[part].p_offset + bp->b_blkno;
    971 	mp->mscp_unit = rx->ra_hwunit;
    972 	mp->mscp_seq.seq_bytecount = bp->b_bcount;
    973 }
    974 
    975 /*
    976  * A bad block related operation finished.
    977  */
    978 /*ARGSUSED*/
    979 void
    980 rrbb(usc, mp, bp)
    981 	struct device *usc;
    982 	struct mscp *mp;
    983 	struct buf *bp;
    984 {
    985 
    986 	panic("udabb");
    987 }
    988