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