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