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