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