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