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