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